Jump to content

reepblue

Developers
  • Posts

    2,486
  • Joined

  • Last visited

Blog Entries posted by reepblue

  1. reepblue
    Luawerks has been updated to 1.2.6, making some small adjustments and fixes to the system. If you have previously purchased Luawerks, this update is available for free on the Leadwerks Marketplace.
    Following changes include:
    Fixed flag typo correcting LUAWORKS to LUAWERKS Moved error.mat/tex to the Materials/Common folder Added a useuisystem boolean to disable the menu, Adjusted VR mode not to call any UI elements. At this time, this update is only exclusive to the Leadwerks Marketplace.
    About Luawerks
    Luawerks is a Lua framework for video games developed on the Leadwerks Game Engine. It supplies developers with additional functions, handles the game loop and allows them to debug their code with a developers console. With all that out of the way, you can focus on making your game fun!
    You can purchase Luawerks from the Leadwerks Marketplace for $9.99.
    For documentation and bug reporting, please visit the GitHub page.
     
  2. reepblue
    Luawerks has been updated to easily transform any game into a Seated VR compatible one. All what's needed is the application to be launched with "-vr". All what has been added is the tweak discussed here. 
    While Luawerks isn't really ideal for Room scale VR, seated on the other hand works better. The center tracking call gets called every time the game gets unpaused. At this time, the UI doesn't work with VR. Keep in-mind that there might be some tweaking to your game to make it 100% VR compatible. For example, if you launch the FPS template map in VR, the bullets should be based on where the player is looking not the mouse position. Don't want have VR? No problem, this only effects the core files (Window, System, Time) and has no other changes to the UI. VR mode is just a bonus. Of course, you can force it to always boot into VR mode.
    About Luawerks
    Luawerks is a Lua framework for video games developed on the Leadwerks Game Engine. It supplies developers with additional functions, handles the game loop and allows them to debug their code with a developers console. With all that out of the way, you can focus on making your game fun!
    You can purchase Luawerks from the Leadwerks Workshop Store for $9.99.
    For documentation and bug reporting, please visit the GitHub page.
  3. reepblue
    It's been quite a while since I posted here. All is well, and I now have some time to talk to you on where I've been and what I wish to do in the future.
    I started a job back in August and my enormous amount of free time dwindled to a few hours a day. However, I now have an income to support myself and buy new toys. I wanted to get into the Linux ecosystem and further distance myself from the Windows world. So for about $300, I've built a PC with an i3-6100, 4GB of DDR4 Ram, put it in a Mini-ITX case and ran Linux off an SSD. I love the machine, but there isn't really much I can use it for. I didn't put in a GPU in it due to driver inconsistencies, so everything runs off the integrated GPU, which can run HL2/Portal at 60fps at 720p; neat!

    I always wanted to dabble into programming for 2D. While working on 3D games is fun, working on 2D games can go a lot quicker and require less resources and as a solo developer that sounded dandy being the limited time I have now. I decided to buy a Raspberry Pi, and use SDL as my drawing library. I will not go into full detail, but the base operations are done, they just need the kinks worked out. Anyway, here is a tablet I assembled. 

    I have two of em! I had to buy an element 14 PSU and it was cheaper to buy it with another Pi than stand alone; which in the end worked out as programming on that screen is dreadful. All in all, my last few months have been me doing that. I never really booted my new Linux machine nor my Windows PC.
    About a week ago or so, Josh contacted me about a concept I uploaded privately and how he wants it on the new game page. Although I don't think the prototype is good enough to be up there (it crashes, slow loading, etc), I'm definitely interested on picking it back up, and maybe opening it up as some sort of community project thing. All the code is done, it just needs optimization really. I accidentally deleted my source files but Josh was kind enough to decript the zip file. That got me interested back in that Mini-ITX PC I've built back in September. I have a RX480 in the closet that my neighbor gave me a while back (And thank frick, cause those GPU prices are ridiculous these days), and I didn't put it in any PCs before because of the rumblings of poor drivers on Linux, and I was happy with my 750ti for the most part. But I was thinking, maybe if I upgraded the processor and RAM, and installed windows on it I can make PC that's more powerful and smaller than my current Windows PC. 
    Newegg for better or worse is (or was) having a Intel Sale and I got a i5-7600k for $200. I also picked up another 4GB of ram (cause prices are high on that too) in which bumps the machine from a dual core with 4GB of RAM to a Quad-core with 8GB of RAM! All I really need is a new Windows Licence and I'd like to keep my Linux install so I might buy a fresh SSD, but I think I'll just reuse the current one I have. I really hate that I went full circle back to windows, but as long as I keep using Linux and get more and more comfortable with it, if I have to jump ship, I can comfortably do so. I'm just not ready to abandon Windows completely right now.
    Today, is when I realized that I finally have a machine that can do VR. I decided to look at prices for the Rift and Vive to see if the prices went down as the demand settled. And to my luck (again for better or worse) Oculus was having a sale. I decided to go for it as I really don't have the space for full room VR, but now that Leadwerks is coming out with official VR support, I'd like to finally experiment with it! 
    So my biggest worry is jamming everything in that small case. Yes, I have a modular power supply, and everything is still tight! Really hope I can fit the GPU in there! 
  4. reepblue
    Luawerks has been updated this morning, making the console more responsive and a new tab for the Options Menu for user's to bind keys to actions.
    Actions have always been part of Luawerks, but until now, there wasn't really a motive to use them. Now, the Action class look in the config to check what key the user binded to that action. You can read more on how this works here. Like the console, this may be improved more in the future. 
     
    About Luawerks
    Luawerks is a Lua framework for video games developed on the Leadwerks Game Engine. It supplies developers with additional functions, handles the game loop and allows them to debug their code with a developers console. With all that out of the way, you can focus on making your game fun!
    You can purchase Luawerks from the Leadwerks Workshop Store for $9.99.
    For documentation and bug reporting, please visit the GitHub page.

  5. reepblue
    Luawerks has been updated for Leadwerks 4.4, taking advantage of the new GUI system while adding new features and commands that allow you to develop your game better.
     
    Developer Console Refresh
    The Developer Console is the stable of the framework. Thanks to the GUI, you can now scroll through your history, highlight, and move the cursor around! Page through your history using the Page Up and Page Down keys! Having a console is vital for development as it allows developers to change maps and other values in-game instead of restarting the program after changing some code. You can add your own commands easily as well. For more information, see the page about the Console here.

     
    An Integrated Menu
    The standard release of Leadwerks 4.4 comes with a menu. I shipped my own standard menu with Luawerks to be more integrated with the rest of the framework. Unlike the official menu script, the Luawerks menu uses 2 GUI's; one for the main menu, and the other for the panels/windows. You can just edit the main menu without effecting the panels, and vise versa. Menu also calls the panels via console commands. 

     
    The Gotcha's Fixed
    Upon installing Luawerks into the project, I recommended that the user calls SetCamera() instead of Camera:Create(), so that the world class would know what camera to reference. This caused a problem when the user switched maps, so I also requested that the user releases the camera too. I replaced this with a for loop in the GetCamera() function, and calling camera:Release() isn't necessary.
    You can now load maps in-which their names have spaces! 
     
    Load Models as Copies
    I added a second parameter to the LoadModel() function. If set to true, the function will load a model, create and return a copy of the model, and release the original asset. This allows you to manipulate that model without effecting other references. This is great if you want one model to use multiple skins.
    This image shows two of the same models loading two different materials.

     
    Here is an example on how to create a copied/unique model:
    self.mymodel = LoadModel("Models/MyModel.mdl",true)  
    LOD Models [Experimental]
    An experimental feature I've added is an object with multiple models and it switches the models based on the camera's distance from the entity. This only works on Static objects as I didn't calculate velocity and mass.
    You'd need to make it an object script like so:
    function Script:Start() self.model = ModelLOD("Models/LodTest/main.mdl") self.model:Get():SetPosition(self.entity:GetPosition()) self.model:AddLOD("Models/LodTest/lod1.mdl",5) self.model:AddLOD("Models/LodTest/lod2.mdl",10) self.model:AddLOD("Models/LodTest/lod3.mdl",15) end function Script:UpdateWorld() self.model:Update() end As I said before, this was something I was playing with, and I don't think it's ready for full use yet. Although it'll help with poly counts, each ModelLOD needs to be updated to get the distance of the camera, so you'd need to weigh your costs.
    On top of all that, bug fixes were made, new commands were added, and more things are planned for future releases. Documentation will continue to be updated here.
     
    About Luawerks
    Luawerks is a Lua framework for video games developed on the Leadwerks Game Engine. It supplies developers with additional functions, handles the game loop and allows them to debug their code with a developers console. With all that out of the way, you can focus on making your game fun!
    You can purchase Luawerks from the Leadwerks Workshop Store for $9.99.
    For documentation and bug reporting, please visit the GitHub page.
  6. reepblue
    After I've returned from Steam Dev Days, I caught a terrible cold, so my first week home was unproductive when it came to LEX or Blue Portals. But besides that, I had a great time! I mentioned briefly in my last blog post before I went that I was giving LEX some reorganizing and defragmenting. This blog post, I'm going to go more into detail.
     
    LEX2 has a lot of things going for it. The developer console is really handy, the AssetManager prevents crashes and has the ability to pre-loads things for you and the PostStart() command for entities allows you to make entities do things RIGHT AFTER the map loads instead of during the loading process. All very helpful!
     
    Crawler's Den taught me a lot about what I was doing with LEX2, and where I should go. I designed it to be more Lua friendly than the initial release. but also allowed easy C++ classes to be made. Crawler's Den had the challenge of "Make a whole game in Leadwerks using nothing but C++". I know it was do-able, but how hard could it be?
     
    Leadwerks today isn't really as optimized to be developed using C++ as it is to Lua. I had to do go through a lot of hoops with somethings that could have been done easily if I just wrote the game in Lua. For instance, making C++ classes required more thought, and to attach my C++ puppeteers (actors) to entities in the editor, I had to make a Lua script that acted like a Hammer fgd file to sync it's keyvalues, inputs and outputs. Oh and on top of that, I had to make sure that each puppeteer got deleted properly. All and all, it was do-able, just not ideal at all!
     
    I'm switching back to be more focused to making games with Lua for now. I started by making a new project and re-writing the console system to be more flexible. Instead of defining all ConCommands in one cpp file, ConCommands can be defined anywhere now like:
     

    static void ConCommand_SayHi(vector parameters)
    {
    System::Print("Hi")
    }
     
    static ConCommand sayhi("sayhi", ConCommand_SayHi);

     
    With this system, it may be possible to make your own console commands via lua, but I'd have to look into it.
     
    My ExSystem Class is derived from Leadwerks System Class, and it's how to talk to the application directly. It handles the dev console, pausing, resuming, and other states that the application might be in. 90% of ExSystem can be called from Lua.
     
    The Developer console is much more powerful than it ever was. You can now make entities fire script functions or outputs by the entity name, or using !picker when looking at it.
     

    fire <entityname> <functionname>
     
    There are also a lot of Utility functions from the previous codebase. One of my favorites is this function.
     

    inline Leadwerks::Entity* UTIL_PickFromCamera(int pDistance, int pCollisionType=0, float pRadius=0) {
    Leadwerks::PickInfo pickinfo = Leadwerks::PickInfo();
    Leadwerks::Vec3 p0 = UTIL_GetActiveCamera()->GetPosition(true);
    Leadwerks::Vec3 p1 = Leadwerks::Transform::Point(0, 0, pDistance, UTIL_GetActiveCamera(), NULL);
    if (UTIL_GetActiveCamera()->world->Pick(p0, p1, pickinfo, pRadius, false, pCollisionType))
    {
    return pickinfo.entity;
    }
     
    return nullptr;
    }
     
    I also made the settings.config file store in the AppData folder instead of the game's root. While I never had any permission issues with the old way, still best to have the user's settings there.
     
    I merged both the WindowManager and ContextManager to be one class; There is just a WindowManager now. There was no point to have the context be managed in it's own class; definitely now since I took out my UI code I had in there for the console drawing. I also fixed Screenshots being properly placed in it's own Directory in the game's folder!
     
    The World Manager is what got the most fat reduced. Before I had a great chunk of code that was ether commented or ifdef'd out. For example, I had old code for my cubemap factory before the Probes where a thing, and other checks that in the long run might cause more problems later. The World Manager is responsible that when a user want's to load a map, a world get's created or cleared, and PostStart is fired on all entities if they have a script. If the user want's to go back to the menu, the world manager clears, and then releases the world. Something that was 913 lines got reduced to 260, and it does pretty much the exact same thing.
     
    I removed the InputManager as at Dev Days I learned that that Steam will later be able to handle that for you, not exclusive to the Steam Controller. Also, the implementation was really confusing and tricky.
     
    Finally, I removed a bunch of classes that are no longer needed including the Puppeteer class as the focus is now Lua. I want to keep the scope of things small right now. All you need to convert a game using the standard executables to the LEX is to replace the 2 executables and add this self explanatory Lua script that'll override main.lua.
     

    --This function will be called once when the program starts function App:Start() return true end --This function will be called right after when the program starts. function App:PostStart() end --This is our main program loop and will be called continuously until the program ends function App:Loop() return true end --This function is called once when the program pauses time. function App:onpause() end --This function is called once when the program resumes time. function App:onresume() end --This function is called while the program is loading a map. (This is where you draw your loading screen!) function App:OnMapLoad() end --This function is called when the program finished loading a map. function App:OnPostMapLoad() end --This function is called when the program disconnected from a map. function App:OnDisconnect() end --This function is called when the program closes. function App:OnShutdown() end
     
    Since it's really those three files that need to be shipped for the product to work, I can use the the standard Leadwerks Project Manager again. I don't plan on releasing the source code at this time. Maybe when making C++ games becomes more streamlined I'll re-integrate my C++ systems.
     
    There are still somethings to do though:
    Integrate the dev console to the Leadwerks GUI when that's fully done. The CMD using Cin approach that I'm using now is kind of bad.
    Play with the app a few hours a day, fix bugs, build on it a little each week.
    Find a good method in distribution, and keeping people up to date.

     
    In the future, I also hope to add more classes you can use while making gameplay objects. Somethings like a Beam class, and such to make things much more simpler.
     
    I also hacked together this shader that takes in roughness and ao sheets along with the diffuse, normal and spec. My artist gave me some textures right from Mamoset and my goal was to import them to Leadwerks as close as I could. I think they came out really well.
     



  7. reepblue
    Crawler's Den is a demo I made for the Summer Games Tournament this year. You can grab it here. This blog I'd like to share my reflections on developing the project on LEX2 and Leadwerks in general.
     
    When I started the project, my template had no animation manger, and the puppeteer system was just coming online. The goal was to recreate the AI and Events map and write the entire thing in C++. Not only to test the puppeteer system and my ideas on how to link said puppeteers to the flowgraph, but I would have classes to derive from when I start working on Vectronic again.
     
    Right now, LEX2 is a template that gets installed in the Templates folder of the Leadwerks App Directory. However, upon creating a template, I noticed that the project and sources didn't seem to copy over as they did in testing. I think it has to do with the project manager's date based system as I was on the beta branch when I started. So fixing my project was no biggie, but not something I'd like to ship out.
     
    The player was the first thing to get coded as I wrote about here. I based my player code of the Source engine's player because I really like how that feels. It wasn't long until I had a player that can walk, jump, crouch, and use/pickup objects. Neat! I'm really happy how it turned out. There are some improvements I thought I can make, but it was drawing close to the deadline so it has to wait.
     
    The animation system was next. Without it, no gun and no crawlers. I started transferring code line by line but I didn't understand how to convert for inpairs loops to C++. This is when CrazyCarpet got involved as he was very willing to help as he needed an animation system for his stuff too. It took a few days to iron out, and minus slight problems I'm having, it works pretty much the same as it's lua variant. You can read the topic here about it which includes a link to the final code on Aggror's Wiki.
     
    Now having the animation system in place, the weapon was next. I first translated the FPSGun script from 3.2 as it was a lot simpler and it was something to get started. I later added bullets, and allowance of different weapon types although the project would just need a pistol.
     
    The crawler was something I put on the backburner as I never did AI in Leadwerks before. I was aware of the functions, but never needed to use them. This was my first project where I needed to use the navmesh system too. I did level design next because I really wanted to start mapping.
     
    I needed to start from scratch with the map. The AI and Events map used meters instead of centimeters so nothing lined up with the grid anymore. there was once an option to switch between the two measurements, but I guess Josh took it out, or it's under legacy features. Ether way, I wanted to use centimeters. I shelled the map out by eye and feel, I hardly went back to the source material as that would require switching the project and such. I had the map mostly shelled out before I started to work on textures.
     
    I usually use Paint.Net for raster artwork, but I decided for this project to use an older version of Photoshop. Not only because it's "what the pros use" but I want to use a file format that could be readable in other software. PSDs can be read by gimp so if there comes a day in which I'm making games on a non-windows machine, I can still open psds. I should learn how to use gimp and ditch Paint.net as PDN is Windows only. But I wanted to make a game, not learn new software.
     
    Now that I know how to properly port in models from blender, I had a lot of fun modeling for my scene. Making support beams, trims vents, and such was really fun, and everything got imported correctly. I had the best luck using FBX ASCII 6.2 versus the Binary 7.4 option, and Applying scale made sure that everything was sized correctly with a default scale setting as 1,1,1 like it should be. I couldn't remodel everything, I just remodeled things that wouldn't connect together right due to the measurement change. There was some old models I just used the model editors scale tool.
     
    While building my level was really fun, optimizing was the exact opposite. I limited my shadows, optimized my prop settings, made lights smaller, and collapsed a lot of modular pieces together and with my 750Ti, I get 90fps in the first room and 70ish in the showdown room. One thing I always thought was a good idea was to develop on medium range hardware. If you were to develop on lets say a 980Ti, you could get away with a few more expenses, but throw it on an older card, and it might chug, Develop on a mid-range card, and it'll play fine on that, better on newer and powerful hardware. I was cutting batches and polys like crazy but I couldn't get to a point where the entire scene was 100fps. I've added a wireframe view mode to my console options to see what was being drawn that shouldn't in which made me develop a portal volume that could hide, or show all the objects in it's volume while ignoring collapsed brushes.
     

     
    I eventually ditched the portal volumes because of a bug that I didn't feel like fixing, and I only saw 5 more frames in the end which wasn't worth the flowgraph mess I had to do. If I could get it to be automatic and fix that bug, I might re-add it.
     
    There was a time when I sent the project to CrazyCarpet to debug something and this is when I learned that my theory about developing on mid-range hardware was correct. He reported 100-120+ frames on his 980, and for some reason was getting better results on his 750. My PC is no spring chicken, but he was getting 100 frames all round on a 750, meanwhile I drop to 70 on my 750Ti?
     
    While I'm really happy that my pain and suffering resulted in better performance on newer hardware, it'd be great if I could have those results on my end.
     
    The deadline was drawing near, and it was time to do the crawler, and a few other classes. By this time, I've developed and successfully created a way for my puppeteer class to communicate with the flowgraph. In short, each puppeteer has it's own lua script in which you can set the values and write the inputs and outputs to the class. Inputs are handled through a message system while outputs are fired by the entitles component class. I'd have to write another blog on how it works but I'm sure weeks after I do, there might be an official way to link C++ classes to your game and the flowgraph. So I played with that converting more scripts to C++. Then it came time for the crawler.
     
    The crawler was a bit more difficult, and this is when I noticed an issue with the animation manager. It wasn't playing looping animations correctly. A quick line comment of --n fixed this, but to this day there is a problem in which it has a hard time going from attacking to running. It defaults back to it's idle animation and then glides around. Might be my monster code, but I was going on the last few days and the map wasn't done yet.
     
    I was using the beta branch for a while, then Josh pushed a broken build which put me back on 4.1. I noticed the editor runs more smoothly on the default branch than the beta branch. I would think that this has to do with a debug settings or garbage collection that's enabled when Josh does development and only turns it off during prime time. But then, the beta branch was "fixed" so I jumped to that while keeping my game on 4.1 (I archive releases). I noticed a bug with the probes, and my map got corrupted on it. Thankfully I made a backup, so I didn't lose everything. I went back to the speedy stable release, finished my map and went to upload it.
     
    Uploading is always a chore on my connection. I really hate when I spend hours uploading something and then after all that it fails to upload due to some error. This is why the Vectronic Demo is out of date on the game launcher, and why Crawler's Den is only on my dropbox right now. I should have used my mobile data, but I didn't for some reason.
     
    Ether way, besides a few small bugs, the project is out and playable using LEX2. Here is a summary of working with it.
     
    Good:
    No worry about back end stuff, besides somethings I needed to improve thanks to this project, I didn't have to spend a week writing window, context or world code.
    Console was a god send allowing me to easily debug my map in-game. Loading whatever map I want without the editor or hard coding was pretty dope.
    Once they were done, the puppeteers are really neat to work with. They are set up like lua scripts, and all the hooking is done in the base class.
    The precaching and Asset Manager worked amazingly well. No more slowdowns on loading models in real time, and no crashes because you mistyped the path. Really handy!
    I made a volume class for triggers and such. Works way better than collision based ones.

     
    Bad:
    Project's don't copy right with the project manager. Again, might be the date based system.
    The input system isn't done. It uses SDL for it's input handling and there is a bug in which all inputs must be done in UpdateWorld. CrazyCarpet said he'll look at this so we can correctly place movement inputs in UpdatePhysics.
    I feel as though Puppeteers should be called actors. They are called puppeteers because there was a class called Actor which was the actual entity doing the actions instead of a separate class controlling the entity.
    A lot of commented out code. I need to delete some things I've commented out months ago.
    It was kind of a pain to make sure the core code was synced up with the base project, the game project and the git repo. I want it so that all games off of LEX2 use the same Core files.
    Some reason I couldn't derive from my volume triggers....

     
    I have an idea for this going forward but I don't want to express it just yet. No matter how I go forward, the foundation is here to stay. It might get cleaned up, maybe edited a lot, but I don't see a need for a rewrite, it's all solid.
     
    Thank you for reading this, I hope you have fun with Crawler's Den!
  8. reepblue
    I wanted to give you an update since this blog post and let you know how well (or not) I'm following those plans.
     
    Blue Portals: Anniversary Edition (Skip this if you don't care..)
     
    Sunday I pushed a long over due push to Steam for beta testers to play and give feedback. I don't like to push to Steam often as my connection isn't that strong so any uploads bigger then a few megabytes causes an upload failure, I usually split updates into multiple pushes to prevent such problems but sometimes you have to push one large file that'll cause a error. This time I instead used my unlimited 4G mobile data and I had way better luck, and will be using this method from now on.
     
    We right now only have a small handful of testers and I wish to keep it that way for a little while longer. It's interesting to see the same play-tester play the same map in different updates regardless if anything changed. There was one map where no reports or issues where given from this tester last update. I barely changed the room, and this time they informed me that something felt impossible to achieve.
     
    I also keep play-testers out of developer news. This way I can introduce something brand new to them and they can report back if they understood it and/or liked the idea. I really wish I was in a position to watch people using Steam's broadcasting service, but I think even with my mobile data, it'd be unwatchable due to the high ping that wireless services have.
     
    Although I wished the teaser trailer was done last month, I'm happy to report that it's being worked on now. I've got a message this morning that the recording is done. It just needs to be edited and such. Really cool as the mod has a look and feel that we're happy with. I guess it's better that the stuff got recorded today than a month ago as a month ago some models still had their ambient occlusion maps for skins!
     
    Overall, the mod is coming together very nicely. There are a few things I'm worried about but I'm sure time will allow me to answer more questions I have. I'll keep you posted on this as I see it as a major stepping stone.
     
    LEX2
     
    A few hours ago, I pushed a near final build of it. In-short, I've cleaned up the code, deleted useless classes and changed how somethings operate.
     
    For example, LEX2 has this function called AssetManager:PrecacheGlobal(path) which you call when you want something to be pre-loaded in memory so your game can load it later without a hitch. This was done by calling AssetManager:PrecacheGlobal(path) in App:Start() and what it did was load those paths into a list. Then when ever the world loaded a new map, PrecacheList was called which loaded every asset in that list. Although you only needed to define the asset once, it still needed to be loaded multiple times!
     
    In this blog, Josh mentioned that it's possible to load assets into one world and have it just sit in memory while your game world is active. I decided to try this, but I was careful to prevent two worlds from being current at the same time.
     
    First, I retired the old PrecacheList and made a new function.
     

    void AssetManager::PrecacheJunkyard()
    {
    DevMsg("AssetManager: Creating Junkyard.");
     
    // Save the current world if we have one.
    World* oldworld = WORLD;
    junkyard = World::Create();
    World::SetCurrent(junkyard);
     
    // Precache global objects.
    std::list<std::string>::iterator it;
    for (it = precache_list.begin(); it != precache_list.end(); ++it)
    {
    if (it->c_str() != S_NULL)
    {
    AssetManager::Precache(it->c_str());
    }
    }
     
    // Go back to the 'real' world if there was one.
    if (oldworld != NULL)
    {
    World::SetCurrent(oldworld);
    }
    else
    {
    World::SetCurrent(NULL);
    }
     
    }

     
    This will load all the assets in the list that PreacheList used into a different world than the game. Then if there is ever the chance that a world exists when the junkyard world is created, it'll go back to it. To prevent that ever happening though, I made this function not exposed to Lua and have it called at the very end of App::Start() in C++.
     

    bool App::Start()  
    {
    //Create a window
    windowmanager.CreateWindow(System::AppName);
     
    // Create a context
    contextmanager.CreateContext();
     
    ...
     
     
    #ifdef LUA_GAME
    // Finally, test the app script
    if (ScriptApp::Start() == false)
    {
    #ifdef WIN32
    MessageBox(NULL, "Error: Failed to execute App script!", "Critical Error!", MB_OK | MB_IConstop); //MB_ICONWARNING
    #endif
    return false;
    }
    #else
    if (GAME::Start() == false)
    {
    return false;
    }
    #endif
     
    ...
     
    // If the user preached anything in App:Start() or GAME::Start(), load them in another world.
    // The Junkyard world will keep those entities in memory.
    AssetManager::PrecacheJunkyard();
     
    ...
     
    return true;
    }

     
    So then your Lua script will look like this
     

    function App:Start() AssetManager:PrecacheGlobal("Models/Characters/hitbox.mdl") AssetManager:PrecacheGlobal("Models/Junk/cinderblock.mdl") return true end
     
    But wait! What if you want the game to automatically launch a map? I didn't want a conflict where a world would exist, and then another world gets created to spawn assets. For safety measures, I just made a PostStart() function for Lua, and have it called after AssetManager::PrecacheJunkyard().
     

    {
    .....
     
    // If the user preached anything in App:Start() or GAME::Start(), load them in another world.
    // The Junkyard world will keep those entities in memory.
    AssetManager::PrecacheJunkyard();
     
    #ifdef LUA_GAME
    ScriptApp::PostStart();
    #else
    GAME::PostStart();
    #endif
     
    return true;
    }

     

    -- This function will be called right after when the program starts. function App:PostStart() end
     
    I really didn't test what would happen if I did load a map before AssetManager::PrecacheJunkyard(). I assume there would be a pause, as the worlds get swapped around, but I'm a bit too scared to try.. but also kind of curious...
     
    I've also sorted the filesytem. Everything LEX2 is within Source/Core with one cpp file looking like this.
     

    // $PROJECT_NAME_main.cpp.
    #include "Core/base.h"
     
    #ifndef LUA_GAME
    namespace GAME
    {
    // This function will be called once when the program starts.
    bool Start()
    {
    return true;
    }
     
    // This function will be called right after when the program starts.
    void PostStart()
    {
    }
     
    // This is our main program loop and will be called continuously until the program ends.
    bool Loop()
    {
    return true;
    }
     
    // This function is called when the program is loading a map. (This is where you draw your loading screen!)
    void OnMapLoad()
    {
    }
     
    // This function is called when the program is called to pause.
    void onpause()
    {
    }
     
    // This function is called when the program is called to resume.
    void onresume()
    {
    }
     
    // This function is called when the program finished loading a map.
    void OnPostMapLoad()
    {
    }
     
    // This function is called when the program disconnected from a map.
    void OnDisconnect()
    {
    }
     
    // This function is called when the program closes.
    void OnShutdown()
    {
    }
     
    // C++ function only. This is how you link editor entities to your C++ classes
    void LoadEntity(Entity* entity)
    {
    /*
    // Attach loaded entites to puppeteers.
    // This can get long and messy, there is some talk about this getting auto-generated with an offical actor class.
    // Cross your figners for that day....
    Puppeteer* puppeteer = NULL;
    if (entity->GetKeyValue("puppeteer") == "Rocket")
    {
    puppeteer = new Rocket(entity);
    }
    else if (entity->GetKeyValue("puppeteer") =="Demon")
    {
    puppeteer = new Demon(entity);
    }
    else if (entity->GetKeyValue("puppeteer") =="Portal")
    {
    puppeteer = new Portal(entity);
    }
    */
    }
    }
    #endif // !LUA_GAME

     
    As you can see, it's pretty much exactly like App.lua. If LUA_GAME isn't defined, it calls this code instead of the App.lua file. I did this to make making a game for C++ and Lua very similar. There is a function that gets called within the MapHook to link entities to the Puppeteer class which can be linked with one script.
     

    Script.puppeteername="" --choiceedit "Puppeteer" "foo,boo" function Script:Start() -- Attach us to a C++ class like this! self.entity:SetKeyValue("puppeteer",puppeteername) end -- There needs to be a better way of flowgraphing with C++ classes!! function Script:User1()--in self.component:CallOutputs("User1") end function Script:User2()--in self.component:CallOutputs("User2") end function Script:User3()--in self.component:CallOutputs("User3") end function Script:User4()--in self.component:CallOutputs("User4") end
     
     
    Summer Games Tournament
     
    As I stated, I much want to participate in this one. I don't really have much time to make a unique piece, but I want something to stress test LEX2 and see if it can be used easily and effectively. I'm thinking about my take on the AI and Events map from the Advanced First-Person Shooter Template. That map kind of bothers me as the scaling is all wacky (It was made when the editor used Meters) and I feel that it's in the one person team field of difficulty.
     
    Seems easy, where's the challenge? Well, While the end result will be a revision, I want to remodel most assets and code the entire game in C++ using LEX2's puppeteer system! I also will be coding things to my preferences so it's not like I'm just gonna convert existing Lua code to C++.
     
    I had other ideas but this seems like the best one currently. It should be an interesting project, and I'll open-source it when I'm done. Anything I make will be available for others to use in the future. I wish to start tomorrow; or when I wake up as it's past midnight.
     
     
    Steam Dev Days
     
    I'm making arrangements to go to Steam Dev Days this year. I've bought my ticket and I just got a few things to iron out with traveling, hotel, and some company naming conflict. My overall goal is to talk to network with other people, talk about developing games, and learn new things. I'm really stoked about the entire thing.
     
     
    That's all for now, wish me luck!
  9. reepblue
    Through out the Leadwerks community you'll find two types of users. You'll find a large portion of the community using lua, and a small dosage of them using C++. This makes sense as people are more often going to purchase Leadwerks without any DLCs (including the Professional Edition), and get into developing. From experience, Leadwerks at the moment puts it's primary focus on Lua scripts with it's script editor and debugger, flowgraph editor, and the script property system. Everything is pretty straight forward and it's quick and easy to prototype and develop your games. Throw in an entity in the editor, attach a script to it, adjust some values, set up connections and you're done!
     
    You'll also find a smaller chunk of the user base talking about C++. Unfortunately.as of writing this blog post, a life of a C++ user is more difficult. For one thing, we don't have any connection with the editor so any entitys we want to put in our game need to be done during run time. If you made this cool monster in C++, you'd also need to make a system so your level designers (or you) can place them in the levels. Some examples of this is people using editor placed pivot's names as spawn markers. And even if then, you'd have to make a Lua script for that pivot to send any custom/modifiable values or special events to the C++ class. Not to mention, you'll need to search around how to communicate both languages together. And if people are suborn about learning Lua, they'll end up making systems that conflict with existing features/editor Things get messy fast when making gameplay with C++.
     
    Ok, so why do we bother then? While Lua is an ideal choice for gameplay, but what about the rest of your game? You still need to control how your window, context and world handles, how user settings get applied, and a lot other gross stuff that goes into a game. You can use Lua for that, but you'll run into two issues. For one, if you're working with a team, you'll have to trust them not to touch anything relating to the under the hood stuff unless they know what they are doing. You'll also have that paranoia of slow down due to using Interpreter for everything. You'll need a lot of script logic to cause any slow down, but who knows what you're doing when it comes to the background stuff.
     
    My solution is easy, use both together!
     
    My application Leadwerks Extended Executable is designed to handle all the yucky bits in the application side of things while you can use the engine as intended. All it does is instead of launching main.lua, it calls a App class which handles the window, context, and world along with reading user settings. As of version 2, you can communicate to the C++ classes in Lua with the AppManager Class
     

    -- This line will spam We're Connected" if we're in a map. if AppManager:IsConnected() then System:Print("We're Connected") end
     
    All the guts are "locked out" for the rest of the team so you don't need to worry about Mike from the art department accidentally touching the window handling system, and setting the project back a few weeks.
     
    LEX2 also has 2 classes to accommodate for C++ gameplay classes, Actors, and Puppeteers. Puppeteers act like a Lua script. You attach an entity to the class and write the code like if you were writting a Lua Script. We're still lacking an efficient way to connect an editor entity to a class. I tried to use a Lua script, but due to the fact you'd need a script per puppeteer for it's custom values and flowgraph support, you might as well just write the damn code in Lua and be done!
     

    #if !defined( PUPPETEER_H )
    #define PUPPETEER_H
    #pragma once
     
    #include "base.h"
     
    namespace Leadwerks
    {
    // Puppeteer's are pretty much the C++ version of lua scripts.
    // While using this class, keep note that this class doesn't exist in the game world.
    class Puppeteer : public Object
    {
    public:
    Puppeteer(Entity* pEntity);
    virtual ~Puppeteer() {};
     
    virtual void Start() {};
    virtual void PostStart() {};
     
    virtual void Collision(Entity* pEntity, float* position, float* normal, float speed) {};
    virtual void Draw(Camera* camera) {};
    virtual void DrawEach() {};
    virtual void PostRender(Context* context) {};
    virtual void UpdateMatrix() {};
    virtual void UpdatePhysics() {};
    virtual void UpdateWorld() {};
     
    void Detach();
    void RemoveAll();
     
    Entity* GetPuppet()
    {
    return entity;
    }
     
    Entity* entity; // The entity we'll be controlling. Was gonna rename this to 'puppet', but I want programing Puppeteer classes to be the same as scripting in lua.
     
    // We can get script values like this.
    bool GetBoolValue(std::string pValve)
    {
    return entity->GetBool(pValve);
    }
     
    float GetFloatValue(std::string pValve)
    {
    return entity->GetFloat(pValve);
    }
     
    int GetIntValue(std::string pValve)
    {
    return static_cast<int>(entity->GetFloat(pValve));
    }
     
    std::string GetStringValue(std::string pValve)
    {
    return entity->GetString(pValve);
    }
     
    protected:
    static void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed);
    static void DrawHook(Entity* entity);
    static void DrawEachHook(Entity* entity);
    static void PostRenderHook(Entity* entity);
    static void UpdateMatrixHook(Entity* entity);
    static void UpdatePhysicsHook(Entity* entity);
    static void UpdateWorldHook(Entity* entity);
    };
    }
     
    #endif //PUPPETEER_H

     
     
    There are also Actors. Unlike how Puppeteers work in which you assign an entity to it, this time you're building on top of the object. and it exists in the world. It's only really good for players, but I ran into a pickle recently where the player would not spawn in the position I tell it to. I ended up translating the entire code to Lua and it works as intended. with the bonus of the flowgraph mind you.
     

     
    #if !defined( ACTORS_H )
    #define ACTORS_H
    #pragma once
     
    #include "base.h"
     
    namespace Leadwerks
    {
    // Actors are the entites, but behaving like it's under a lua script or Puppeteer.
    // Unlike scripts or Puppeteers, this class was ment to be the base of controlling the ACTUAL entity, without a middle class.
    class PivotActor : public Pivot
    {
    public:
    PivotActor(Entity* parent = NULL);
    virtual ~PivotActor();
     
    virtual void Collision(Entity* entity, float* position, float* normal, float speed) {};
    virtual void Draw(Camera* camera) {};
    virtual void DrawEach() {};
    virtual void PostRender(Context* context) {};
    virtual void UpdateMatrix() {};
    virtual void UpdatePhysics() {};
    virtual void UpdateWorld() {};
     
    protected:
    static void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed);
    static void DrawHook(Entity* entity);
    static void DrawEachHook(Entity* entity);
    static void PostRenderHook(Entity* entity);
    static void UpdateMatrixHook(Entity* entity);
    static void UpdatePhysicsHook(Entity* entity);
    static void UpdateWorldHook(Entity* entity);
    };
     
    class ModelActor : public Model
    {
    public:
    ModelActor(std::string pPath, Entity* parent = NULL);
    virtual ~ModelActor();
     
    virtual void Collision(Entity* entity, float* position, float* normal, float speed) {};
    virtual void Draw(Camera* camera) {};
    virtual void DrawEach() {};
    virtual void PostRender(Context* context) {};
    virtual void UpdateMatrix() {};
    virtual void UpdatePhysics() {};
    virtual void UpdateWorld() {};
     
    protected:
    static void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed);
    static void DrawHook(Entity* entity);
    static void DrawEachHook(Entity* entity);
    static void PostRenderHook(Entity* entity);
    static void UpdateMatrixHook(Entity* entity);
    static void UpdatePhysicsHook(Entity* entity);
    static void UpdateWorldHook(Entity* entity);
    };
     
    class CameraActor : public Camera
    {
    public:
    CameraActor(Entity* parent = NULL);
    virtual ~CameraActor();
     
    virtual void Collision(Entity* entity, float* position, float* normal, float speed) {};
    virtual void Draw(Camera* camera) {};
    virtual void DrawEach() {};
    virtual void PostRender(Context* context) {};
    virtual void UpdateMatrix() {};
    virtual void UpdatePhysics() {};
    virtual void UpdateWorld() {};
     
    protected:
    static void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed);
    static void DrawHook(Entity* entity);
    static void DrawEachHook(Entity* entity);
    static void PostRenderHook(Entity* entity);
    static void UpdateMatrixHook(Entity* entity);
    static void UpdatePhysicsHook(Entity* entity);
    static void UpdateWorldHook(Entity* entity);
    };
     
    // TODO: Maybe make a SpriteActor?
    }
    #endif //ACTORS_H

     
     
    It was kind of hard writing this entry as I work with both languages. I guess the overall message is to chose you're battles and do what's in your skill set and preferences. I'd still love there to be an easy way to code gameplay elements in C++ like I do with Source. The class hierarchy system really comes in handy as you can just make a bunch of base classes and build off of them as needed. Hopefully, this will get addressed soon. In-fact, I actually made this blog post in reflection of this forum post. Maybe someday we can make our games fully in C++ and have access to the flowgraph editor and to be able to set custom properties!
  10. reepblue
    For the past few months, (on top of working on my greenlit mod) I've been developing a new foundation for Vectronic that will take care of all the 'internal yucky bits' such as window/context/world management, and other features and functions. I really wasn't happy how the first implementation came out as I felt like I was taking too much from the developer, and it was messy and confusing to do something simple like adding a loading screen.
     
    LEX2 is more lua friendly, not bloated with scripts that you may or may not use, and has more comments than my Blue Portals 2 video in the code! You just need the executables, App.lua, and engine.pak which contains standard assets that the application will call if something is missing.
     
    You can play with it here. I've used the latest beta with probes so if you don't have the probe beta, don't load map 07 I guess. Here are somethings you might notice looking at scripts or general usage.
     
     
    Developer Console:
     

     
    LEX2 comes with a developer console for visually debugging your game while you play. Draw stats, show physics, show navigation, or change settings on the fly. All commands use the standard system properties.
     

     
    To access the console, the game must be started with -dev or launched from the editor. When the game is paused, it the tilde key (`) and start typing. Hit Enter to submit your command. You can use PageUp and PageDn to scroll through pass commands.
     
    You can type 'help' to report a list of current commands. There is no display box, so it's best used when the game is windowed with the log from the script editor visible.
     
     
    Asset Manager:
     

    self.sound = Sound:Load(AssetManager:Check("Sound/MySound.wav))
     
    Never crash again because you moved something or mistyped an asset. AssetManager:Check() returns a error asset from engine.pak if what you've sent is not found. The game will not start at all unless the error assets are found at startup.
     
    You can also easily preload models for later use with AssetManager:Precache(string). You can also make a Precache list with AssetManager:PrecacheGlobal(string). This is great if you have a model or prefab that might spawn at anytime in any map.
     
     
    PostStart():
     
    PostStart is a command fired after the level loads instead of during it like Start does.
     

    function Script:Start() self.source = Source:Create() self.source:SetVolume(self.volume/100) self.source:SetPitch(self.pitch) self.source:SetLoopMode(self.loop) self.source:SetRange(self.range) self.source:SetPosition(self.entity:GetPosition(true)) end function Script:PostStart() local sound = Sound:Load(AssetManager:Check(self.soundfile)) if sound~=nil then self.source:SetSound(sound) if self.playing==true and self.enabled==true then self.source:Play() end sound:Release() sound=nil end end
     
     
    Input System:
     

    if Input:Forward(true) then self.input[1]=self.input[1]+1 end if Input:Backward(true) then self.input[1]=self.input[1]-1 end if Input:Right(true) then self.input[0]=self.input[0]+1 end if Input:Left(true) then self.input[0]=self.input[0]-1 end
     
    You can now allow your player to change their controls. by calling a general function. Controls can be controlled with System:SetProperty or by editing settings.config. The control commands are based off of the default steam controller layout. I just need too add previous/next weapon, but wasn't 100% sure how I was gonna do that since it may be a scroll wheel.
     
     
    Basic UI System:
     
    Use Lua to create your own UI with LEX2's exposed UI classes. If you replace the app start and loop functions with this code, it'll make a square in the corner with a text button that says "Leadwerks".
     

    --This function will be called once when the program starts function App:Start() Rect = UIRectangle:Create(4,4,200,200) Rect:SetColor(40, 40, 40) Rect:SetBorderLineWidth(4) Rect:SetBorderColor(92, 92, 92) Rect:EnableBorder(true) Rect:Hide() local testfont = Font:Load(AssetManager:Check("Fonts/consola.ttf"), 20) Rect3 = UIText:Create(Rect:GetCenter().x, Rect:GetCenter().y, "Leadwerks", testfont, "Test"); Rect3:Center(); Rect3:SetShadowMode(false) Rect3:SetAsInteractive(true) Rect:AddChild(Rect3); return true end --This is our main program loop and will be called continuously until the program ends function App:Loop() context:SetBlendMode(Blend.Alpha) -- Here is code to darken the scene when the game is paused. if self:IsPaused() and self:IsConnected() then context:SetColor(0,0,0,0.5) context:DrawRect(0,0,context:GetWidth(),context:GetHeight()) end Rect:Update() if (Rect3:GetMouseEvent() == Rect3.MouseLeftUp) then System:Print("Pressed!") elseif(Rect3:GetMouseEvent() == Rect3.MouseOver) then Rect3:SetColor(100, 100, 100) elseif (Rect3:GetMouseEvent() == Rect3.MouseLeftDown) then Rect3:SetColor(80, 80, 80) else Rect3:SetColor(255, 255, 255) end if window:KeyHit(Key.F11) then if (Rect:IsVisible()) then Rect:FadeOut() else Rect:FadeIn() end end context:SetBlendMode(Blend.Solid) return true end
     
    I haven't really did much with the UI as it's a future feature of the engine, plus I've been playing with other stuff. But with UIRectangle and UIText is pretty much the foundation of buttons, sliders and other stuff anyway. Or you can use another UI library if you want.
     
    Again, you can play with it by downloading the project here:
    https://dl.dropboxusercontent.com/u/16218991/Requests/LEX2Test.7z
     
    I'm really stress testing it now making sure I don't have to touch anything when I'm ready to revist Vectronic. Speaking of Vectronic, it's almost been a year since I've released the demo. I might later this week write a blog about it and my battle plan for it.
  11. reepblue
    It's been over a year ago since I've released the Vectronic Demo using Leadwerks. The demo was composed of assets I've made ported from the Source Engine and my lack of understanding of the API and lua scripting at the time. (I'm used to coding everything in C++) As of writing, it has 1,221 subscribers on the Steam Workshop, 25 out of 26 positive ratings, and is the second most subscribed item! So there is sigh that this as a MVP (Minimum Viable Product) was a success. And again, the Game Launcher is in Beta..
     
    Since the demo, the engine got a lot of improvements and features, and I've learned a lot more about game development in general. (Models, Texture making, etc.) Last summer, I sat down to develop a base application for my projects. I wanted the world, context, and window management to be out of the way while making the full game, and I was concerned about a UI as it was a sticking point when I did a Source branch change from the 2013 SDK to the Alien Swarm Branch in favor of better development tools. (That engine is really fragmented when it comes to things like that....)
     
    Once I finished that application; LEX, I then started over developing the game using that template. Two months went by, I've done some interesting puzzles in dev textures.but I felt that one element was taking over the vecball power elements. It was more fun to use that than fire balls at boxes. (And it was more work than the Vecballs) So, I paused development on that project to research if that 'thing I added' would be a better focusing point.
     
    I only spent a week on it. I didn't want to work on it too much, just enough to see if it'll work. It turned out, that minus some placement calculation, it was really fun. As you can see, I don't want to talk about it in-case I decide to go with it.
     
    November was approaching again, and it's a special time for me. In 2010, I released my Portal mod Blue Portals with mostly positive reviews. Every November, I like to do something to give a reason for people to revisit it. Last year (2014) I fixed the mod so it'd work with the steampipe update, and last November, I decided to put the mod on Steam as an "Anniversary Edition"
     
    Although we had massive support about Blue Portals on Steam, there was things I wasn't happy about, and prevented me from putting it on Steam earlier. Some things didn't age well and I've made some poor design choices. There was also some criticism over the difficulty curve (which is kind of common with Portal mods), and somethings just broke. I can spend a few months patching it up, or I can take the extra time and reevaluate the entire project, and have it be a quality mod on Steam. Plus, if the difficulty curve was adjusted, more people can actually play it!
     
    This first started as a revamp project, but slowly became it's separate entity with it's own needs. I'm learning a few new things I've haven't known before, and it's interesting how some concepts/techniques I've learned using Leadwerks came into play here. I was first very worried about Vectronic being on the back burner, but then I realized that it's actually a good thing I take a break from Vectronic for the following reasons:
     

    I can experiment with marketing, community management, updates with little to no risk. I can try something and see how it goes and decide what I did right and/or wrong with that decision and use it in the future.
    I can get used to Steamworks, and have an idea going into Steam Greenlight how it's gonna be, which is a plus over most indie devs who need to take time to learn that stuff.
    Blue Portals: Anniversary Edition can be/will be used as an advertising piece for future projects, I can comfort future consumers with an example of our work before they vote on Greenlight or purchase it on Steam.
    I was really unsure where to take the project, so coming back with a clear head would help. I have a bunch of ideas now, but not gonna jump into anything now.

     
     
    I see the Blue Portals: Anniversary Edition project (BPAE) as a stepping stone for marketing and consumer confidence. Since the mod can be downloaded with zero risk to a consumer, I feel better taking chances with it then I would a product I'd wish to sell. So what's the battle plan?
     

    Continue to develop BPAE. I'm aiming for a December release. Since most research and development have been conducted five years ago, I think if my team and I keep working at it, we can have a polished product on Steam which in return can help sales with Vectronic. I plan on starting to experiment with Marketing next month. I really want to find that "How Early is the right time to show?" mark. My first guess is "When the project has an established direction, but nothing is 100% final just yet.". Which for this project is short of 6 months of development.
     
    Continue to chip away at LEX2 as it's going be the new foundation. Unlike it's predecessor, the solution is very minimal and allows for easy C++ entity implementations. I want to participate in the next Tournament using it to make sure it's all solid and good.
     
    When BPAE is wrapping up, start programming the yucky gross parts like the player and some custom collision rules. Start thinking how everything will tie together and use the new things I learned with BPAE while making design and development choices. I think doing this while BPAE becomes a touch up project will allow me to not feel like I'm doing the same things on two projects.
     
    Start the true cycle of development for Vectronic once BPAE is submitted to be released on Steam.

     
     
    So that's the plan. Taking this one at a time. I'll keep you posted on what I'm doing like always. Although Blue Portals: Anniversary Edition isn't a Leadwerks project, I still think me writing my findings with it can benefit others while making their games. We're all learning here!
  12. reepblue
    If you join the beta branch and updated your projects, you'd probably noticed that the low res Leadwerks 2 icons have now been replaced with high resolution ones that match the rest of the user interface. Decals, Particles Emitters, Cameras, and Probes now have their own icon, and you can tell all entities apart just by looking at them.
     
    I've originally made these a while ago when I noticed that each entity had it's own material and texture, but most of them just recycled the pivot icon. I've released a version on the workshop, and an updated version as part of the LEX template. Yesterday, Josh contacted me about using them in the official build, and I was more than happy to say yes, and make any wanted changes. He mostly wanted the lights to be yellow, and I've changed the angle of the spotlight to be more downward.
     
    Each icon texture is 512x512 uncompressed, and was made using a vector art program so the icons are sharp and clear as possible. These icons will be skipped during the packaging process, so they will not bloat your final game.
     
    You can get these icons by joining the beta branch and updating your project. These icons will be released as part of Leadwerks 4.1. If you think anything needs to be changed, let ether Josh or I know.
     
    I think the only thing left to do is update the light buttons on the side, really. Here's a mock up of what it can look like. To be honest, I think they kind of clash with the other icons as those where shipped with 3.0 which had some sort of a Windows 7 icon pack for everything else.
     

  13. reepblue
    With the recent popular substance shader by Shadmar, more talk and focus has been about cubemap reflections surfaced in the community. Reflections in Leadwerks were done in the past with the SSLR post process shader which made all surfaces reflect the world in real time.
     
     
     
     
    However, it had the following problems:
    It was applied to ALL materials in the scene. If you had a material that wouldn't normally reflect such as concrete or wood, the shader would still effect those materials. Basically, the texture artist had little control.
    The post process shader needed to be first on the list, and some people didn't understand that.
    You could adjust the reflections by the model's alpha color. But if you had any shader that relied on the alpha mask for map blending or something else, you're out of luck!
    The reflections distorted based on camera angle, and not really great for in-game action.
    Like everything OpenGL, there is/was a chance it wouldn't work well with AMD gpus.

     
    This was all we had until in February, Mattline1 posted a blog on his PBR system, which included a block of code that built a world cubemap and swapped the cubemap texture with it. Thankfully, he uploaded is source code so anyone who has the professional edition could download his code and have a look.
     
    While his implementation is very nice, it has the following design flaws for a typical Leadwerks user.
    You needed to use only the PBR shader. Normal Leadwerks shaders didn't render well.
    Needed a Post process effect to adjust the gamma of the scene.

     
    Weeks later, Shadmar uploaded his version of a Substance/PBR shader which allowed users to still use their existing shaders, and gave artists more to work. Since it's a shader, and not a full implementation like Matt's, it didn't have the world reflection system. I've been busy with a lot of Source engine work, but seeing how much interest this is getting lately, I decided to take a few days off and see if I can make my own cubemap system.
     
     
    The Implementation
     
    A disclaimer, this is not a full "How-To" as you'll need to add it to how your application, and it'll most likely do things differently than how I have my application set up.
     
    First, we need to figure out how we are gonna get a world cubemap to a texture. While it's not the most "next-gen" way of doing this, I decided to base my system off of the Source engine because, well I know how it works, and it's pretty simple. It goes like this:
    Mapper places a env_cubemap entity near a shinny surface. (Any material set to use cubemaps.)
     
    Mapper compiles and runs the engine.
     
    Mapper than types "buildcubemaps" into the console.
     
    For each env_cubemap entity, 6 "pictures" are taken (up, down, left, right, forward, and back). than those textures are saved within the bsp.
     
    The map restarts, and the surface will use the near by cubemap texture.

     
    Great, that seems very straight forward, and we can remove steps 2 and 3 as there is no compling in Leadwerks, and everything should just work. The first thing we need is a 3D point in the world that'll act as our env_cubemap.
     

    class Cubemap : public Pivot
    {
    public:
    Cubemap(Vec3 pos = NULL); //lua
    virtual ~Cubemap() {}
    ...
    ...
    ...
    };

     
    We build off of the pivot class because we want this to actually exist in our world, not be a "puppeteer" for a pivot entity. We also have the position being set in the constructor as the only way to get our custom entity into the world is by a lua script. Using ToLua++ we can make a script that we can attach to a pivot/sprite.
     

    function Script:Start() local n = Cubemap:new(self.entity:GetPosition(true)) self.entity:Hide() end
     
    This script will spawn our cubemap entity at our editor placed pivot, then hide the editor placed pivot. Basically, we swap the entities during level load.
     
    This cubemap entity job is to search for near by entites, (Which I currently have set to it's aabb radius + a range float) then change it's surface material with a copy of what it had, only with a different cubemap texture. Early in development, I just have the entity fix the cubemap texture to the current world's skybox to make sure that this would work.
     

     
     
    void Cubemap::SetReflectionTextureToSkybox(Leadwerks::Surface* surf)
    {
    if (WORLD == NULL) { return; }
    if (WORLD->skyboxpath == "") { return; }
    if (!surf) { return; }
     
    Material* mat = surf->GetMaterial();
    if (!mat) { return; }
     
    // Make this faster, if there is any indication of a surface not using the substance shader, abort the cubemap application!
     
    // If there is no cubemap assigned, then we can skip this object.
    if (mat->GetTexture(6) == nullptr) return;
     
    // if the metal value is 0, we can skip.
    int matspecmetalness = mat->GetColor(COLOR_SPECULAR).w;
    if (matspecmetalness == 0 ) return;
     
    Material* copy = (Material*)mat->Copy();
     
    if (copy != NULL)
    {
    Texture* cubeTexture = Texture::Load(WORLD->skyboxpath);
    copy->SetTexture(cubeTexture, 6);
    surf->SetMaterial(copy);
     
    cubeTexture->Release();
    copy->Release();
    }
    }

     
    Before we go into building the world cubemaps, we need to add this to the entity's header. This will make it so we can pass a texture to the entity:
     

    Texture* SavedMap;
    Texture* GetCubemap()
    {
    return SavedMap;
    }

     
    Now to the cubemap factory, which on map load will find all of our cubemap entites, do the texture building or each entity, Set SavedMap to the new cubemap texture, then tell the cubemap entity to look for near by entities so it can do it's replacement job. Thankfully, all the yucky stuff has been done by Matt, so I just needed to cut the stuff I didn't need, and make it handle multiple level loads and disconnects to work with my worldmanager class.
     
    Here's a few snip of this process.
     

     
    bool CubemapFactory::initialize()
    {
    Release();
    ...
    ...
    ...
     
    int i = 0;
    do
    {
    if (WORLD->GetEntity(i)->GetKeyValue("cubemap", "0") == "1")
    {
    Cubemap* pCubemap = dynamic_cast<Cubemap*>(WORLD->GetEntity(i));
    if (pCubemap != NULL)
    {
    // Build the cubemap
    cubeTexture = Leadwerks::Texture::CubeMap(
    reflectionResolution,
    reflectionResolution,
    Leadwerks::Texture::RGBA,
    Leadwerks::Texture::Mipmaps
    );
     
    cubeTexture->BuildMipmaps();
    Leadwerks::OpenGL2Texture* gl2cubeTexture = dynamic_cast<Leadwerks::OpenGL2Texture*>(cubeTexture);
    glActiveTexture(gl2cubeTexture->GetGLTarget());
    glBindTexture(GL_TEXTURE_CUBE_MAP, gl2cubeTexture->gltexturehandle);
    glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
    glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
     
     
    // Apply it!
    GenerateReflection(pCubemap->GetPosition()); //<-- generate first reflection texture
    GenerateReflection(pCubemap->GetPosition()); //<-- use initial texture to generate correct texture
    if (cubeTexture != nullptr)
    {
    pCubemap->SavedMap = cubeTexture;
    }
     
    // Tell the cubemap to look for near by entities, and replace it's cubemap texture with cubeTexture
    pCubemap->SearchForEntites();
    cubeTexture->Release();
    }
    }
    i++;
    } while (i < WORLD->CountEntities());
    ...
    ...
    ...
    CubemapFactory::init = true;
    }

     
    GenerateReflection() is pretty much the same as Matt's PBR project. That function actually does the "camera work", and saves the result in a Texture. This is done on the fly during level transition.
     
     
    Skipping Dynamic Objects
     
    There is just one problem however. Everything is being rendered when the cubemaps are being built. So any enemies, or move-able objects will be baked into a reflection. To fix this, we need to have all objects that can move (Mostly have mass) be hidden, and then re-shown after we've finished the building of cubemaps.
     
    Pretty much.
     

    #define S_NULL ""
    #define ON "1"
     
    void ShowMoveables(Entity* entity)
    {
    if (entity != NULL)
    {
     
    if (entity->Hidden() == true && entity->GetKeyValue("hide_for_cubemap", S_NULL) == ON)
    {
    entity->Show();
    entity->AddForce(Vec3(0, 0, 0)); // <-Wake me!
    entity->SetKeyValue("hide_for_cubemap", S_NULL);
    }
    }
    }
     
    void HideMoveables(Entity* entity)
    {
    if (entity != NULL)
    {
    // Things to look for ar entites with the mass > 0, or have their shadow mode non static!
    if (entity->GetMass() == 0 || entity->GetShadowMode() == Light::Static)
    return;
     
    // Only hide the non-hidden!
    if (entity->Hidden() == false)
    {
    entity->SetKeyValue("hide_for_cubemap", ON);
    entity->Hide();
    }
    }
    }
     
    void MapHook(Entity* entity, Object* extra)
    {
    // For cubemap generation, we don't want anything that's set to move to be built in with our cubemaps.
    HideMoveables(entity);
    }
     
     
    bool WorldManager::Connect(std::string pMapname)
    {
    ...
     
    if (Map::Load(pMapname, &MapHook) == false)
    return false;
    ...
    return true;
    }
     
     
    //--------------------------------------
    // For cubemap building!
    //--------------------------------------
    void WorldManager::MakeMoveablesVisible()
    {
    vector<Entity*>::iterator iter = entities.begin();
    for (iter; iter != entities.end(); iter++)
    {
    Entity* entity = *iter;
    ShowMoveables(entity);
    }
    }

     
    Then back in the initialize function of our cubemap factory before we return true.
     

     
    // Lastly, redraw moveables!
    worldmanager.MakeMoveablesVisible();

     
    And now anything that has mass, or has it's ShadowMode set to Dynamic will not be baked into the reflection!
     
     
    Cleaning up
     
    To make it so that this can work with multiple level loads and when the game "disconnects" (Not in a map), we need to reset everything.
     
    Cubemap factory:
     

     
    void CubemapFactory::Render()
    {
    if (WORLD != NULL || worldmanager.IsConnected() == true)
    {
    if (!CubemapFactory::init) { CubemapFactory::initialize(); }
    WORLD->Render();
    }
    }
     
    void CubemapFactory::Release()
    {
    System::Print("Clearing Cubemaps!");
    CubemapFactory::init = false;
    if (cubeTexture != NULL)
    {
    cubeTexture->Release();
    }
    CubemapFactory::currentContext = nullptr;
    CubemapFactory::reflectionCamera = nullptr;
    CubemapFactory::cubeBuffer = nullptr;
    CubemapFactory::cubeTexture = nullptr;
    }

     
    And instead of calling world->Clear in my world manager, I instead call this function:
     

     
    void WorldManager::ClearWorld()
    {
    CubemapFactory::Release();
    world->Clear();
    }

     
    Calling CubemapFactory::Release() may not be necessary as it's called everytime the factory is initialized, but it doesn't hurt to be safe!
     
     
    Conclusion
     
    It was a ride getting this to work correctly. I'm still not happy about how the cubemaps look for near by entities, but it's better than what we have now, which is nothing, Apperently, Josh is concidering this as a engine feature so all of this work might just be temp until he adds it in, which hopefully will be smoother and less error prone!
     
     
    But what we have a system that works like this:
    Engine loads a map, world created, etc.
     
    A map hook hides any entities that has mass or a dynamic shadow mode.
     
    Cubemap Factory takes it's "pictures" much like Source does when buildcubemaps is executed.
     
    Each cubemap texture is given to the right Cubemap entity, then released.
     
    The cubemap looks for near by entites and swaps the model surface's default cubemap with the one it got from the factory.
     
    Cubemap factory tells the world manager to re-show the entities it hid.
    Things continue as normal.

     


     
     
    So that's it! Thanks for reading!
  14. reepblue
    I almost let a whole week go by without writing a blog, ahh! I've been doing a lot of thinking and experimenting over the last few days, and talking to other people about Vectronic.
     
    Last week, I talked about improving functionalities of the pickup system and the platforms. Although the pickup system is near done, the platform system, well they need work. I made a topic about them here, and kind of left me on a stand still on the project because I see them as a vital piece of the game, and they need to be perfect 100% of the time.
     
    As I mentioned before Vectronic always seemed to feel and play like a demo. there was never more than 3 maps, and the ideas were very basic. The method of slopping out maps quickly, and fine tuning them later is fixing that as there are way more maps than ever, but unfortunately I'm noticing a problem with the actual core gameplay itself, something I would never notice with just a few demo maps.
     
    It seems as though although the box has cool effects attached to them, they mostly need environment elements to really make them shine; which is a problem. The question is, is it the powers attached to the balls, or is it that the balls can only activate the boxes. And if the balls can activate other elements, how would they work, and what problems would it solve? I went back to the project what Vectronic morphed out of to see if those ideas can fix problems that Vectronic has.
     




     
    In the old project, the power was tied to each box, and the player would fire electric bolts at them to activate or deactivate them. I had a cube that reversed it's gravity, (Along with other cubes because I didn't know how to make it so only THAT cube flipped) one that stayed static in the air, a cube that exploded, and a cube that did nothing at all. This method had problems, which I talked about here.
     
    The idea of the flip cube was something I really loved, but I couldn't figure out how to only make that one cube reverse gravity while the others remained normal. Out of curiosity, I decided to quickly script this cube and simply have it flip when the F key was pressed. I got the effect I wanted, but it's not flawless. what I did was when the cube was told to flip, it would use a joint to go to the ceiling. You can ride it up, but the player would clip through the ceiling which I think I can fix on the player side, and you can't pick up a box when the box wants to go up; but again I think I can fix that.I also have ideas on how to make the ghost cube more fun and interesting.
     
    But then comes the question is this really a problem, or is it just me working on an idea as a demo for such a long time that I find it boring? I'm asking a lot of people for input and one person plans on give me a playable prototype of his idea so I'm looking forward to that. I want Vectronic to be the best it can be, and if it ends up being different than the demo or what it ever was, but a lot more fun, so be it.
     
    Besides gameplay, I've also been playing with tolua++, and getting ideas what I wish to do with LEX in the future. There is also the Halloween Game Tournament so maybe my head will clear up when I'm working on that. There have also been some experimentation on art, but I'm not ready to talk about that yet.
  15. reepblue
    Another week, another weekly report. Vectronic is going more smoothly then ever before taking things one at a time, and just shelling out maps and ideas quickly. Last week, I did a few improvements with how the player picks up objects, and fixing the issue of shooting projectiles through objects. I did not shell any more maps because I thought it would be better to focus on a small amount of puzzles at a time, perfecting them before making more maps. For this, I needed help.
     
    As of this week, I quietly put the first test build on in the Dropbox folder which used to host the Source build, and asked a small number of people to test out movement, mouse control, and if everything feels right before I make things more complex.
     
    From the first week of testing, I'm confident that the project is moving in the right direction. From one tester who has played all other builds of Vectronic told me that this current build has better puzzle direction and clarity, and full of gameplay unlike previous builds that was just a bunch of mechanics, pretty rooms, but no gameplay at all. I got recommended a few changes I should make, like making the box heavier so when it crashes to the floor after floating in the air, it does not bounce off a button, or adding a plane of glass to block a more frustrating solution. A few tweaks still need to be made, solutions should just work, and not fully relying on the physics engine. I recall this being a problem with Quadrum Conundrum.
     
    Word of advice though, I learned that play testers hate fully ambient lit rooms, so before you release for testing, atleast put fill lights in. One tester told me it was hard to perceive the room with a full ambient light. I have one map with fill lights as a test, and he reported that when he got to that map, he had a better experience.
     
    I also found out that this method on leak protection didn't work when you packaged your games. It failed to initialize Steamworks although Steam was running. Not sure if this has to do with how packaged games work, or something I did wrong. I could of just uploaded the raw project, but that's a difference of 88MB vs 18MB. I'll work on this for the next build which I plan on posting a new test build biweekly.
     
    VecBall Design
     
    Yesterday, instead of writing this blog post, I was in an art mood, and wanted to put something back online with a model and sounds. I was using the old ball sprite and particle effects from the Demo, and I was really unhappy on how the dispenser looked in Leadwerks compared to how it was in Source. I decided if I was gonna touch anything art related, it was gonna be the basic foundation of the Vecballs themselves.
     
    I already had an idea of how I wanted my balls to look in the previous build. I'm a huge fan of how the Portals where in Portal in pre-release builds, and I wanted to reference that.
     



     
    This portal design required a large amount of textures for the mask, overlay, and other things that portals need. These portals took a whopping 174MB of VRAM PER PORTAL. and this was 2006/2007. I'm told that Valve cut it only because they ran out of memory on the Xbox360. Besides them being memory hoggers, I'm happy that I have them in a mod where they work exactly like how they did in previous builds.
     
    Unlike Portals, I can do a sprial/swirl effect with my vecballs without going over budget. I really liked the idea of the balls being a swirling ball of energy, so this could work. I made a quick texture and effect before I focused more on LEX. I later put what I've did in the Vectronic Demo.
     
    I pretty much just copy and pasted my swirl edits I had before into this build with a few changes. It still needs work, but it's pretty much the same as it is in the Demo, at least for now.
     



     
    Now to the dispenser. What makes Vectronic diffrent from Portal is that you loose your vecballs after each level, requiring you to recollect them in the next map. When I first sat down for the design of the dispensers, I sorta saw them as the item pickup bases in multiplayer games like Unreal Tournament. In Source, the particles stood tall and really stood out. But when I was transferring the design to Leadwerks, no matter what, they appeared washed out. This might be because of the colors, but I could not replicate how they appeared in Source.
     
    So I decided to take the dispenser back to the drawing board. I felt that the bases were too small, and needed a face lift. I quickly made this out of a cylinder in blender, added some base colors, and called it a day. UV sheet is still bad though, something I always have problems with.
     



     
    Attached a few emitters and sprites to it and got this in-engine.
     



     
    This is still not final as the ball sprite can still get washed out in the environment. I'm not gonna worry about it until I start messing with post processing effects and the overall look of the maps. I'm also open to suggestions. It's good for now, and it's a hell of a lot better then how they are in the demo!
     
    So that wraps this weeks report up. I guess this weeks goal is to ask more people to test the seven maps I have and seeing how I can improve those and other things before moving forward.
  16. reepblue
    After a whole summer of working on the LEX template, and learning new things about the engine, I'm happy to say that Vectronic will soon be back on track in full development!
     
    Before I go into full detail, I wish to mention that the Vectronic Demo has been updated with Josh's optimization edits, and the VecBall has a new effect I've made during the development of LEX. If you had sluggish performance before, I recommend you check out the update!
     
    Now that I've got a nice foundation with a menu, a precache system, now what? I was thinking I would just be "upgrading" the Vectronic project to use the LEX template, but looking back on it, I'm not really happy how it is. Back in May, I really just ported textures, sounds, and models from my Source build to Leadwerks to see if a game like Vectronic would work on Leadwerks. Of course, I was still pretty new to lua scripting, and very use to pre-built lighting and such so I did struggle a bit, the demo map was not optimized, and most of my code is a mess. To wrap it up, I mostly did not know what I was doing. I still to this day see that demo map as a map from hell; I've had so many issues with it, but I'm happy how it turned out.
     
    Now 6 months later, I feel like I've learned a lot and ready to get back onto my main project again. I decided the best way to start is to start a new project based off of the LEX project, and redo most things. I've restarted this project many times over for the past few years, but this should be the last time.
     
    Back when I was developing this project on the Source Engine, I've felt like I needed assets to make a game. I thought if I had everything, textures, models, sounds and other assets done, I could build levels like a LEGO set; having all the pieces, and knowing where everything goes. It's a good theory, but it never really worked.
     




    A old Source build of Vectronic.


     
    I only had a few maps per build. The last build had 3 maps, and the build before that had 4 maps. There was never a set of interesting and fun levels, just a
    . Thing was, I was so worried about how things functioned and looked that no build ever got more then a few maps, I was distracted by other things that are not important in the pre-alpha stage of things, and so were my testers, which did not help move the project further ether.. 
    Learning from my mistakes, this time the project is going to start blank almost like the past few years never happened. Doing the reboot this way will force me to worry about scripts, and the actual puzzles. This will also make it easier to optimize the maps when it is time to bring in the assets, and not have what happened with the demo map. No lights, no models, just CSG and a few scripts. If the game is fun with just that, it's easy sailing from there!
     
    Now, that does not mean I'm gonna waste more time by re-scripting, re-modeling, and re-texturing things that are already done. There are somethings I think that can be better, and I do have ideas I wish to try, but not everything needs to be scrapped, somethings just need a revision. I eventually want to give Vectronic a look that only Leadwerks can give as the demo does look like it's running in Source. But right now, the basics need to be done!
     
    I hope to update every week on progress, I'm feeling this Friday I'll talk more about how I'm doing things and short term goals.
  17. reepblue
    Leaks of games happen, and they still happen. You can spend months and months working on your game, only for a server attack or the wrong person to share it with their buddies; which then goes public accidentally, (or intentional). Having an unintended work in progress build out there can give people the wrong idea about your game because there are people out there who think the development process is pretty straight forward.
     
    Let's take a look at the Half-Life 2 leak. The game, and the entire engine code was leaked and the entire thing was very unstable, It was also found out that all those
    were scripted, and broke when you actually play them. A lot of doubts and concerns about the game were made as they felt like they were lied to after seeing videos and screenshots not representing the leak at all. Of course, this later on generated a community of it's own, but that's a rare scenario. 
    Since Leadwerks is far more stable than a Source Engine build from 2003, you can have months of playable work leaked. If you indeed plan to sell your game on Steam or Desura, you most likely don't want you're game freely available. So how can we prevent this?
     
    If you already got a SteamAppID from Valve after a successful Greenlight campaign, there is nothing to worry as users need a key to access your game. But what about if all to your game is dev textures, rough code, and programmer art? If you only have the indie edition, or only use Lua scripts for your game, you can use the Game Launcher, and set your game to "Friends-Only". For games written in C++, or have a modified application, we can't do that as our program does not get uploaded to the workshop. With the Standard Edition of Leadwerks however, we can use more of the Steamworks API.
     
    A friend of mine was talking to me about how an old Source mod use to detect if an invalid Steam user tried to boot the mod, it would not boot. Once I heard this, I was eager to see if I could get a similar system to work.
     
    Every Steam user has a public unique ID that comes in many different forms. Steam and games use this to gather information about the user, among other things. In this case, we are going going to focus on the 64bit FriendID number. Thanks to the Leadwerks API, we can access Steamworks features without our game being on Steam!
     
    Let's us first start with creating a bool function under the main.cpp.
     

    bool CheckSteamID() {
    if (Steamworks::Initialize())
    {
    }
     
    System::Print("Error: Failed to initialize Steam.");
    return false;
    }
     
    So far so good! We make it a bool function so if we are not a fail to load Steamworks, or have the wrong ID, it will return false and close the program. Now let's get the users ID number with:
     

    uint64_t user = Steamworks::GetUserID();  
    As I said before, SteamID's come in various forms. The easiest to get is the 64 bit FriendID which appears in profile urls such as http://steamcommunity.com/profiles/76561197996502882/
     
    As you can see, my SteamID is 76561197996502882. For the rest of this article, I'm gonna use mine in place of where you should put yours. A way to get yours is to go on a site such as http://ihavenfi.net/steamid. Popping in the STEAM_0:0:******** format after putting your ID-less profile URL will give you your FriendID. Remember, these numbers are public, they aren't like credit card numbers, or anything.
     
    So let's continue! For this example, I'm going to use My SteamID. So let's make a simple if statement comparing the account trying to play this game with a hard coded value.
     

    bool CheckSteamID() {
    if (Steamworks::Initialize())
    {
    uint64_t user = Steamworks::GetUserID();
    if (user == 76561197996502882) // Me!
    {
    return true;
    }
    else
    {
    System::Print("Error: Invaild SteamID!");
    return false;
    }
     
    System::Print("Error: Failed to initialize Steam.");
    return false;
    }
     
    With this code, (and I hope you replaced the SteamID), your game will only work for you if you're logged into your account. But you need beta testers, and what about the other developers? Let's Continue by adding more IDs!
     
    As another example, let's grab Josh's SteamID. After all, he's the CEO and should be able to play any LE game he wants. Although his profile is private, we can still grab the ID-less URL which is: http://steamcommunity.com/id/Josh
     
    Pop it in the converter and we get: STEAM 0:0:6085996. Let's pop that value in again and we finally have his FriendID which is: 76561197972437720
     
    Now let's edit that if statement.
     

    if (user == 76561197996502882 // Me! || user == 76561197972437720) // Josh
    {
    return true;
    }
     
    Now, Josh can play our game if he's logged into his Steam account. The best way to get ID's is to make a Steam Group for your testers this way you have all the profiles listed that you need to code in. We're not done yet, we still need to call this function near the start of the main function.
     

    if (!CheckSteamID()) return 0;
     
    Just make sure you comment that out when your game does get to be on steam, or when it releases elsewhere with a different DRM measure if you desire.
     
    With this somewhat messy way, you can restrict your games to certain steam accounts without having your games on steam during development. As a bonus, let's welcome the user in the console to make the tester feel they're special. Put this before the function returns true.
     

    std::string username = Steamworks::GetUserName(user); System::Print("Hello there, " + username + "!");
     
    And that's it! There is most likely other ways of doing this, but this way is the simplest and easiest. If you hard code FriendIDs, and use the stand-alone publishing for beta builds, your game is just a bunch of unplayable bites and bits if it falls into the wrong hands!
  18. reepblue
    After the release of the Vectronic Demo, I started to seek out how to make the game to be able to stand-alone without any additional launchers, batches, or required installations. Shortly after my last blog post, Josh informed me about Inno Setup, and it answered my questions about providing OpenAL if the user did not already have it installed. More about that here. I haven't played with it yet, but it gave me insurance about packaging it up for the final release down the road. Alternatively, Steamworks is also an option, but I'm not touching anything Steamworks related until I get a App ID for the game.
     
    With the Leadwerks Game Launcher, users can edit basic settings such as "Resolution" and "Fullscreen" and any settings that may come in the future. As a stand alone game, it would not have easy to use game launcher, hence a menu with a settings feature is required.
     
    I didn't want to make a launcher, as they are kind of unpopular, and OS exclusive. (You'll have to build a launcher for each platform.) I wanted something already in the application, and can be compiled on multiple platforms minus a few edits here and there. I also wanted most settings to be real time so players can adjust their settings to their likings without needing to restart the game.
     

     
    One thing I really liked about developing mods for the older branch of Source was the gameui system it had. It was simple, reusable, and out of the way. You could edit the res files to customize it if you wish, but it's stock files was enough to get you started; even release with. I wanted my UI to be based on this. Only reason why they retired this UI system in favor of their hell of a client based UI system starting with Left 4 Dead, (I played with it, it was not fun) was due to Console/Controller support. Yes, the Xbox360 controller does work in the old UI, but when you open it's panels, you better have a mouse near by!
     
    However, with things like the Steam Controller, and the fact that Leadwerks is mostly PC based anyway, this UI design will certainly do.
     
    To make it reusable, the UI would have be modified outside of the source code. Changing fonts, colors, titles should not require a recompile. Also, such things like the start map, and background map should also be able to be changed outside of the source. No matter what game it is, it should work.
     
    Finally, to make it out of the way, the entire system would be written in C++, and not interfere with any game logic written in Lua. However, from Lua scripts, you should be able to communicate with it in case you wish the application to disconnect you from a map, or shutdown the application entirely. From lua, you should also be able to grab boolean states like if the app is paused, connected (in-map playing) or disconnected, and not in any map if needed.
     
    So that was the goal, and 3-4 weeks later, the goal was completed with a few bonuses such as a precache list for loading models/prefabs onto memory, a very basic save system, and in dev mode (which is also enabled in debug mode), information about what version of the engine you're running and map name is printed in the top right corner when paused. (Something Source does which I liked.)
     

     

     

    (Could not use media tags due to them being Unlisted)
     
    I'm very happy of the results. Not only this necessary element for a stand alone is done, but this will make my testers happy as they no longer need to edit batch files to configure their settings! I believe that this is necessary, and anyone should be able to have it. After a few more bug fixes, I'll upload the Source files to GitHub along with application releases so even people with the indie version can use it.
     
    Only thing I did not test was the application on Linux since the hard drive in my Linux machine finally died after 7 years of service. Knew it was coming, but still a set back. Hence another reason why I want to make it public, so that it works on all supported platforms and gets more optimized over time. I'm not the best programmer in the world, so every little thing helps!
     
    I'll talk more about this when I put it up. There is a lot of technical stuff about it,
  19. reepblue
    Over 2 weeks ago, I released a small demo showcasing my project's core gameplay on the Leadwerks Engine. Although I'm happy with the demo; it's a good landmark for the project, but it can be better visually and functionality. I learned a lot of new information about the engine on how to better optimize it, multiplatform diffrences, and I grew a slight hatred to a certain brand of GPUs. But the demo on the Game Launcher to me was a success.
     
    The stand-alone version in my opinion was a bit shakey as with stand-alone releases you lose the end user's ease of use when it comes to settings and the requirement of OpenAL. The Vectronic Demo was indeed targeted to work with the Game Launcher from the begining as I wanted to be more focused on the actual game scripting than the dirty stuff such as how settings are loaded, menus, etc. But I also wanted a stand-alone version out due to the launcher being in beta, and I wanted to let people on linux play it.
     
    I took Vectronic to the Portal community to see how they liked it. I mostly got back issues in actually launching the application. Besides the lack of OpenAL, most people did not seem to understand how they can run the Portal 2 (Which runs on a branch of the Source Engine that can run on DX9 cards.), and other games but not Leadwerks; especally on a certain brand of a GPU. One person actually got angry at me because he could not run the game. Overall, it was mostly things that Josh nor I can fix. (i.e it was ether outdated hardware or poor drivers.) However, the OpenAL requirement is something I can look into.
     
    Right now, I'm stepping away from the demo, and focusing on improving the stand-alone experience now since the soultions for the standard edition has been recently optimized. With the Summer Games Tournament coming up, it's a good deadline to stay focused, and to experment with non-Vectronic stuff. After this project is done, Vectronic will be back on track as I kind of need this done before I continue to work on my main project.
     
    I still got Part 2 of My Introduction Entry to write which I share why and how I moved the Project to Leadwerks, but I think I'll write that when I want to look back as right now I want to looking forward. I might also share various techniques I used in the Vectronic Demo as I think it will help with any user of Leadwerks; especially durning the summer tournament. I'll continue to write about whatever I'm working on here.
  20. reepblue
    Note: This is pretty much a copy and paste from this post here with a few tweaks.



    After 3 years of planning, modeling, texturing, and a lot of engine hopping, I was able to create a playable demo in the Leadwerks Engine for Windows and Linux (Debian/Ubuntu/Mint). You can download the demo from this page. A small demo was created not only to test the basic elements of the game in the new engine, but to also give back to those who have been supporting this project since I started talking about it.
     




     



     
    I'm also announcing that from here on out that the development will be more open. How open? Well first you can always check the Trello page to see the progress at any time, If you wish to help, drop me an e-mail. Feed back is welcomed with opened arms. You can do this simply by e-mail or twitter @reepblue. I'll do my best to respond if necessary.
    About Vectronic
    Vectronic is a first-person environmental puzzle game inspired other games of the same genre such as Portal, Quadrum Conundrum, and Q.U.B.E. Players must solve puzzles using special power balls that effect boxes that changes their behavior in the world. For more information, please visit the Q&A. For additional help, click here.
    Please let me know what you think. Although a short primitive demo, this is a big milestone for the project in the indie path.
  21. reepblue

    Cyclone
    Back in the summer of 2017, I started experimenting with the idea of a puzzle game by placing launch pads on surfaces. The first build was very sloppy, and there wasn't any wall launching at this time. This build however was the first step of the experimenting process. Only one map was ever made and I just reused old Vectronic assets. 

     
    I shelved this concept until Winter of 2020 asI developed an itch to work on something and I wanted to get familiar with GIMP. This build again only had one main map along with other sample ideas but it was just another demo. 
    Cyclone Prototype - Work in Progress - Ultra Engine Community - Game Engine for VR
    Although I really liked the direction of the project, I didn't develop further on that iteration after that March, but I did show it to people to get thoughts which were mostly positive. At this time, I wanted to wait until the Ultra Engine shipped to revisit the concept yet again, but eventually I got bored of waiting and figured I'd have to spend a lot of time learning the new systems Instead of using the almost seven years of working with Leadwerks. The plan was to get a small game out within a year. I set my scope to be a simple Portal clone with 10 maps. Anything else I probably would have got overwhelmed and bailed out like I did many times before with other projects.
    I first started working on the foundation code base. I came up with the idea of a Stage Class with it handling all the Actors. The Stage class handles time, map loading, transitions, temp decals, and is responsible for attaching actors to the entitles in the editor via a Lua script. It's also is in-charge of ensuring that a Camera is present at all times. After every map load, a camera is created in which something like a Player actor would point to as it's Camera. It all works very nicely. 
    //========= Copyright Reep Softworks, All rights reserved. ============// // // Purpose: // //=====================================================================// #ifndef STAGE_H #define STAGE_H #if defined( _WIN32 ) #pragma once #endif #include "pch.h" enum StageEvent { /// <summary> // NULL; Use this for the main menu. This is the default. /// </summary> STAGE_EVENTNULL = 0, /// <summary> // Intermission; the event(s) between plays. /// </summary> STAGE_EVENTINTERMISSION, /// <summary> // Transition; Intermission between scenes. /// </summary> STAGE_EVENTTRANSITION, /// <summary> // Play; In-Game /// </summary> STAGE_EVENTPLAY }; struct TransitionData { std::string szMapPath; std::string szLandmarkName; Leadwerks::Entity* pLandmarkEntity; Leadwerks::Vec3 vLandmarkDistance; Leadwerks::Vec3 vCamRot; Leadwerks::Quat qCamQuat; Leadwerks::Vec3 vVelo; void Clear() { szMapPath = ""; szLandmarkName = ""; vLandmarkDistance = Leadwerks::Vec3(); vCamRot = Leadwerks::Vec3(); qCamQuat = Leadwerks::Quat(); vVelo = Leadwerks::Vec3(); pLandmarkEntity = NULL; } }; class StageActor; class GameMenu; class Stage : public Leadwerks::Object { protected: Leadwerks::World* m_pWorld; Leadwerks::Camera* m_pCamera; Leadwerks::Context* m_pFramebuffer; GameMenu* m_pMenu; StageEvent m_hEvent; bool m_bVSync; int m_intFrameLimit; std::string m_szCurrentSceneName; std::string m_szPreviousSceneName; //std::string m_szNextSceneName; bool m_bShowStats; Leadwerks::Vec3 m_vGravity; uint8_t m_intPhysSteps; TransitionData m_hTransitionData; std::vector<StageActor*> m_vActors; void ClearScene(const bool bForce = true); bool LoadSceneFile(const std::string& pszFilePath, const bool bForce = true); void SetStageEvent(const StageEvent& hEvent, const bool bFireFunction = true); void PreTransition(); void PostTransition(); GameMenu* GetGameMenu(); public: Stage() {}; Stage(Leadwerks::Window* pWindow); virtual ~Stage(); // Time: void Pause(const bool bFireOutput = true); void Resume(const bool bFireOutput = true); const bool Paused(); uint64_t GetTime(); const bool TogglePause(const bool bHandleMouse = false); void Update(); void Clear(); bool SafeLoadSceneFile(const std::string& pszFilePath); StageEvent GetCurrentEvent(); Leadwerks::Entity* FindEntity(const std::string& pszName); StageActor* FindActor(const std::string& pszName); Leadwerks::Decal* CreateTempDecal(Leadwerks::Material* pMaterial); //std::string GetCurrentScene(); const bool InPlay(); void Reload(); void DrawStats(const bool bMode); void ToggleStats(); const bool ConsoleShowing(); void SetPhysSteps(const uint8_t iSteps); void SetVSync(const bool bState); Leadwerks::World* GetWorld(); Leadwerks::Camera* GetCamera(); Leadwerks::Context* GetFrameBuffer(); Leadwerks::Widget* GetGameMenuHUD(); void Transition(const std::string& pszFilePath, Leadwerks::Entity* pLandmark); void ShowHUD(); void HideHUD(); //Virtual functions: virtual void Start() {}; virtual void OnUpdate() {}; virtual void OnTick() {}; virtual void PostRender(Leadwerks::Context* pFrameBuffer) {}; virtual void OnNoPlay() {}; virtual void OnPostLoad(Leadwerks::Entity* pEntity) {}; virtual void OnIntermission() {}; virtual void OnTransition() {}; virtual void OnPlay() {}; virtual void OnProcessEvent(const Leadwerks::Event iEvent) {}; virtual void OnPaused() {}; virtual void OnResume() {}; virtual void ScheduleRestart() {}; static Stage* Create(Leadwerks::Window* pWindow); friend class StageActor; }; extern Stage* ActiveStage; extern Stage* CreateStage(Leadwerks::Window* pWindow); #endif // STAGE_H The first few months of development of this system still crashed randomly as I was hard loading the map instead of checking if a string was not empty every frame like how it's set up in the MyGame example. I went back to that approach and the crashing stopped. This did cause very hard to find bug which caused random restarts in then Release build. The issue ended up being that the string I was checking wasn't declared as empty. 
    With a great foundation by February 2021 , I went to getting the Cyclone stuff online. I mostly copied from the 2020 build but it was good enough to get started.  A quick model later, and I had my item dropper in game.
    https://cdn.discordapp.com/attachments/226834351982247936/815726095198322698/unknown.png
    The item dropper was the first item I had to rethink how physics objects would work. The original idea was to have the boxes be an actor that made the impact sounds and other effects when I got to it. However, the entity's actor doesn't get copied when it's instanced.  
    The solution was to have the item dropper create a the box model, and after it instances the model, it also assigns a collision hook to that model. I also apply modifications to the box friction and dampening.
    //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- uint64_t BoxImpactNoiseLastSoundTime; void PuzzleBoxCollisionHook(Entity* entity, Entity* entity2, const Vec3& position, const Vec3& normal, const float speed) { auto self = entity; auto target = entity2; if (self->GetWorld()->GetWaterMode()) { if (self->GetPosition().y < self->GetWorld()->GetWaterHeight()) { DMsg("Puzzlebox below water level. Deleting."); ReleaseGamePlayObject(self); return; } } float fixedSpeed = __FixSpeed(speed); float flSoftThreshhold = 1.5f; float flHardThreshhold = 4.0f; long intMaxFrequency = 300; if (fixedSpeed > flSoftThreshhold) { int collisiontype = target->GetCollisionType(); if (collisiontype == COLLISION_PROP || collisiontype == COLLISION_SCENE) { long t = Leadwerks::Time::GetCurrent(); if (t - BoxImpactNoiseLastSoundTime > intMaxFrequency) { BoxImpactNoiseLastSoundTime = t; if (fixedSpeed > flHardThreshhold) { // HARD self->EmitSound(GetImpactHardSound(), 20.0f, 0.5f, 1.0f, false); } else { // SOFT self->EmitSound(GetImpactSoftSound(), 20.0f, 0.5f, 1.0f, false); } } } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Leadwerks::Model* CreatePuzzleBox(const bool bAttactHook) { auto mdl = Model::Load(PATH_PUZZLEBOX_MDL); ApplyBoxSettings(mdl); if (bAttactHook) mdl->AddHook(Entity::CollisionHook, (void*)PuzzleBoxCollisionHook); return mdl; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Leadwerks::Model* SpawnPuzzleBox(Leadwerks::Model* ModelReference, const Vec3& vPosition) { if (ModelReference == NULL) { ModelReference = CreatePuzzleBox(); } auto newitem = (Model*)ModelReference->Instance(); newitem->SetPosition(vPosition); ApplyBoxSettings(newitem); newitem->AddHook(Entity::CollisionHook, (void*)PuzzleBoxCollisionHook); newitem->Show(); return newitem; } Although adding hooks to entities isn't really considered official, this is only one case out of many that I do this. It's really nice to write a quick function without creating and assigning an actor. The item dropper got improvements down the line to fix some physics issues. (I made the dropper very slippery so there was no friction and it stopped acting weird.) 
    The months rolled on and I kept chipping away at the project. My maps count was increasing every month but there something really bothering me. It was the fly movement.
    In Cyclone, I wanted a way for the player to launch themselves across rooms and deadly pits. I originally just applied velocity to the player character but the results felt terrible. I noticed that the wall launch was smoother if you held the button of the direction you were flying down. This gave me a nice arch instead of a sharp line. I ended up completely rewriting my player code from the ground up. Doing so allowed me to break apart what my Player actually was.
    First. there's the base Player class. This class alone will give you a spectator camera with input controls. Everything regarding the camera is defined in this base class. I also spent the time to work how HUD hints would work. The HUD uses the Leadwerks GUI system but for the HUD, I kept it to simple image drawing on the framebuffer. 
    The base class also controls ambient sound, although it's still a work in progress.
    Base Player Improvements - Work in Progress - Ultra Engine Community - Game Engine for VR
    //========= Copyright Reep Softworks, All rights reserved. ============// // // Purpose: // //=====================================================================// #ifndef PLAYERACTOR_H #define PLAYERACTOR_H #if defined( _WIN32 ) #pragma once #endif #include "pch.h" #include "Input.h" #include "../Classes/StageActor.h" enum CharacterMoveState { CHARACTERSTATE_IDLE = 0, CHARACTERSTATE_WALKING, CHARACTERSTATE_JUMPING, CHARACTERSTATE_FALLING, CHARACTERSTATE_FLYING }; enum ScreenEffect { SCREENEFFECT_NONE = 0, SCREENEFFECT_FADEIN, SCREENEFFECT_FADEOUT, SCREENEFFECT_FLASH, SCREENEFFECT_BLIND, }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- class CommentaryData { public: std::string devname = ""; uint8_t index = 0; uint8_t maxindex = 0; Source* speaker = NULL; ~CommentaryData() { if (speaker) { speaker->Release(); speaker = NULL; } } }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- class PlayerActor : public StageActor { PickInfo* m_pLookTrace; // HUD: bool m_bShowHint; bool m_bShowCommentary; bool m_bShowGameOver; uint64_t m_u64GameOverTime; CharacterMoveState m_hState; std::weak_ptr<CommentaryData> m_pCommentaryData; protected: Listener* m_pListener; bool m_bIsAlive; bool m_bAllowCrosshair; bool m_bSuspendMovement; bool m_bSuspendLook; bool m_bCrouched; bool m_bCrouching; bool m_bWantsToCrouch; Vec3 m_vPushForce; Vec3 m_vCamRotation; Vec3 m_vCameraOffset; float m_flEyeHeight; bool m_bFreeLook; bool m_bFreeMove; Pivot* m_pRotator; uint64_t m_u64QuickSpinInitTime; bool m_bSpinLockX; double m_dCamTopAngle; double m_dCamBtmAngle; float m_flEyeTraceDistance; float m_flInteractDistance; float m_flPickRadius; Action ACTION_MOVEFORWARD; Action ACTION_MOVEBACKWARD; Action ACTION_MOVERIGHT; Action ACTION_MOVELEFT; Action ACTION_INTERACTION; // Effects: ScreenEffect m_hEffectType; Vec4 m_vCurtianColor; float m_flCurtianRate; bool m_bZoomed; bool m_bZoomedIn; Vec3 m_vCamRotationOffset; Vec3 m_vSmoothedCamRotationOffset; const bool ActionHit(const Action actionname); const bool ActionDown(const Action actionname); void SetVelocity(const Vec3 vVelo); void AddForce(const Vec3 vForce); void ChangeMovementState(const CharacterMoveState hState); public: PlayerActor(); virtual ~PlayerActor(); virtual void Start(); virtual void UpdateWorld(); virtual void UpdateMatrix(); virtual bool IsPlayer() { return true; }; virtual bool IsAlive(); virtual void Kill(); virtual void Respawn() {}; void Kick(); virtual void Spawn() {}; virtual void UpdateKeyBindings(); // Quick functions for locking movement/look: virtual void SuspendMovement(const bool bValue) { m_bSuspendMovement = bValue; }; virtual void SuspendLook(const bool bValue) { m_bSuspendLook = bValue; }; // Camera functions: Camera* GetCamera(); Vec3 GetEyePosition(); Vec3 GetEyeAngles(); Quat GetEyeQAngles(); const float GetEyeHeight(); const float GetCrouchedEyeHeight(); virtual const bool CanUnCrouch() { return true; }; virtual void SetEyeHeight(const float flHeight); virtual void SetCameraAngles(Leadwerks::Vec3 vRot); virtual void Teleport(const Vec3& pNewPos, const Vec3& pNewRot, const Vec3& pNewVelocity); const bool FireUseOnEntity(Entity* pEntity); void SetFreeLookMode(const bool bMode); void SetFreeMoveMode(const bool bMode); void UpdateFreeLookMode(); void UpdateFreeMoveMode(); void QuickSpin(); virtual void UpdateCameraHeight(const bool bCrouchState); const float GetEyeTraceDistance() { return m_flEyeTraceDistance; }; Entity* GetEyeLookingAt(); const Vec3 GetEyeLookPositon(); PickInfo* GetEyeTrace() { return m_pLookTrace; }; const float GetPickRadius(); void ForceLookAtPoint(const Vec3& vPos, const bool bLockX = false); const Line3D GetLine(); // Movement + Physics virtual void SetPhysicsMode(const int iMode); const int GetPhysicsMode(); void SetWalkSpeed(const float iSpeed); const int GetWalkSpeed(); virtual void HandleMovement(); virtual const bool IsCrouched(); const bool IsAirbone(); virtual void HandleInteraction(); virtual void SetNoClipMode(const bool bState) {}; CharacterMoveState GetMovementState() { return m_hState; }; Vec3 GetVelocity(); virtual void Push(const int x, const int y, const int z); void ForceJump(const float fJump); // Interaction virtual void OnSuccessfullUse(Entity* pHitEntity) {}; virtual void OnUnSuccessfullUse() {}; virtual bool ShouldSkipUseTest() { return false; }; // Post drawing: void ShowCrosshair(const bool bShow); virtual void PostRender(Context* context); virtual void DrawHUD(Context* pContext); virtual void DrawCurtian(Context* pContext); Widget* GetHUD(); // Effects: virtual void HandleScreenEffects(); void SetCurtianColor(const Vec3& pColor); void PlayScreenEffect(const ScreenEffect iScreenEffect, const Vec3 vColor = Vec3(0), const float flRate = 0.1f); void PlayQuickFlash(const Vec3 vColor = Vec3(1)); void ClearScreenEffect(); void ZoomIn(const float fNewFov, const float flRate); void ZoomOut(const float flRate); // HUD Hint: void ShowHUDHint(const Action actionname, const std::string& pszMessage); void HideHUDHint(); void ShowCommentaryPanel(std::shared_ptr<CommentaryData> pData); void HideCommentaryPanel(); void ShowGameOverScreen(const std::string& pszMessage); }; extern const bool IsPlayerActor(Leadwerks::Entity* pEntity); extern PlayerActor* ToPlayerActor(Leadwerks::Entity* pEntity); extern PlayerActor* GetPlayerActor(); extern const bool IsPlayerLookingAtEntity(Leadwerks::Entity* pEntity); //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- class PlayerProxy : public StageActor { uint64_t m_u64TriggerTime; uint64_t m_u64DelayTime; protected: PlayerActor* GetPlayer(); const bool IsPlayerLookingAtMe(); public: PlayerProxy(); virtual void Start(); virtual void UpdatePhysics(); virtual void ReceiveSignal(const std::string& inputname, Entity* sender); virtual void Trigger() {}; }; class CommentaryNode : public PlayerProxy { bool m_bActive; std::shared_ptr<CommentaryData> m_hData; public: CommentaryNode(); virtual ~CommentaryNode(); virtual void Start(); virtual void UpdateWorld(); virtual bool Use(StageActor* pActor); virtual void Detach(); friend class CommentaryNode; }; class ProxyEndGame : public PlayerProxy { public: virtual void Trigger(); }; class ProxyCurtain : public PlayerProxy { ScreenEffect m_hType; uint64_t m_u64ShowTime; uint64_t m_u64TimeOut; public: // This needs to be PostStart as the player may be placed/loaded after this actor! virtual void PostStart(); virtual void UpdateWorld(); virtual void Trigger(); }; class ProxyHint : public PlayerProxy { uint64_t m_u64ShowTime; uint64_t m_u64TimeOut; public: virtual void Start(); virtual void UpdateWorld(); virtual void Trigger(); }; class ProxyAmbientSound : public PlayerProxy { Source* m_pSpeaker; float m_flMaxVolume; bool m_bActive; public: virtual void Start(); virtual void UpdatePhysics(); void Activate(); virtual void Detach(); friend class ProxyAmbientSound; }; class ProxyLookAtMe : public PlayerProxy { Model* m_pBox; public: virtual void Start(); Model* GetTargetBox(); }; #endif // PLAYERACTOR_H Next, I made an FPSPlayer which is built on top on the PlayerActor class. This transfroms the base class into a FPS character controller with interaction and physics pickup. It also has base code for a weapon. There is also a CyclonePlayer but it really is just a Start function that controls if it should give the player the weapon or not.
    //========= Copyright Reep Softworks, All rights reserved. ============// // // Purpose: // //=====================================================================// #ifndef FPSPLAYER_H #define FPSPLAYER_H #if defined( _WIN32 ) #pragma once #endif #include "pch.h" #include "PlayerActor.h" struct InteractPickupStoredData { float mass; int collisiontype; Vec2 dampinging; Vec2 friction; }; class FPSPlayer; class FPSWeapon : public StageActor { protected: Pivot* m_pSwayPivot; bool m_bHolstered; Model* m_pViewModel; Vec3 m_vModelOffset; Vec3 m_vBaseRotation; FPSPlayer* m_pOwner; public: FPSWeapon(); virtual void Holster() {}; virtual void Unholster() {}; virtual void UpdateHolster() {}; virtual void Fire(const int iMode = 0) {}; virtual void TestPickupState() {}; virtual void Reload() {}; virtual void BeginJump() {}; virtual void ReAdjustViewModel(const float flPlayerFOV); friend class FPSPlayer; }; class FPSWeaponPickup : public StageActor { void GiveWeapon(Entity* entity); public: virtual void Collision(Entity* entity, const Vec3& position, const Vec3& normal, float speed); virtual bool Use(StageActor* pActor); }; class FPSPlayer : public PlayerActor { // Movement + Physics bool m_bCrouchedOldState; bool m_bWalking; float m_flUpdateTick; uint64_t m_intLastStepTime; bool m_bLeftStep; std::string m_pszFootStepSounds[2]; Model* m_pCorpse; uint64_t m_u64PushLaunchTime; Vec3 m_flLastImpactSpeed; // Interaction Vec3 m_vCarryPosition; Quat m_vCarryQuat; Vec3 m_flThrowVelocity; float m_flPickDistance; float m_flCarryDistance; float m_flHoldThreshold; Pivot* m_pRotationCorrection; Joint* m_pEffector; Entity* m_pCarryEntity; protected: Action ACTION_JUMP; Action ACTION_CROUCH; Action ACTION_ZOOM; Action ACTION_FIREPRIMARY; Action ACTION_FIRESECONDARY; Action ACTION_RELOAD; // Weapon Pivot* m_pWeaponTag; //FPSWeapon* m_pActiveWeapon; virtual void PickupObject(Entity* pEntity); virtual void UpdateHeldObject(); virtual void ThrowObject(); void SetThrowVelocity(Vec3 vVelocity); public: FPSPlayer(); virtual ~FPSPlayer(); virtual void Spawn(); virtual void Kill(); virtual void Detach(); virtual void UpdateWorld(); virtual void UpdatePhysics(); virtual void Collision(Entity* entity, const Vec3& position, const Vec3& normal, float speed); virtual void UpdateKeyBindings(); virtual void Respawn(); // Movement + Physics virtual const bool IsCrouched(); virtual const bool CanUnCrouch(); virtual void HandleCrouching(); virtual void HandleCharacterController(); virtual void SetNoClipMode(const bool bState); virtual void UpdateMovement(Vec2 vMovement); virtual void OnUpdateMovement() {} virtual void OnPerStep(); virtual void OnStopMovement() {}; virtual void OnJump(); virtual void OnLand(); virtual bool GetCrouched() { return false; }; const bool IsFlying(); virtual void Push(const int x, const int y, const int z); const float GetFallSpeed(); // Interaction virtual void OnSuccessfullUse(Entity* pHitEntity); virtual void OnUnSuccessfullUse(); virtual bool ShouldSkipUseTest(); virtual void ForceDropObject(); const bool HoldingObject(); // Weapon void GiveWeapon(); FPSWeapon* GetWeapon(); virtual void BuildWeapon(FPSWeapon* pWeapon); void AdjustViewModel(); }; extern const bool IsFPSPlayer(Leadwerks::Entity* pEntity); extern FPSPlayer* ToFPSPlayer(Leadwerks::Entity* pEntity); #endif // FPSPLAYER_H The magic of getting the fly code to work correctly is in this bit. I also force the player to crouch in a ball to make it feel way less awkward. It was really tricky, but it all worked out.
    //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void FPSPlayer::UpdatePhysics() { HandleCharacterController(); UpdateHeldObject(); // This fixes a crash when dying. if (GetEntity()->GetPhysicsMode() == Entity::CharacterPhysics) { // Stop moving me if we're landed and it's been a bit since we were last pushed. if (m_u64PushLaunchTime > 0) { if (GetStage()->GetTime() > m_u64PushLaunchTime + 100) { if (m_vPushForce != Vec3(0) && !IsAirbone()) { DMsg("PlayerActor: Resetting push launch timer."); //GetEntity()->charactercontroller->stepheight = 0.51; m_vPushForce = Vec3(0); SetVelocity(m_vPushForce); m_bWantsToCrouch = false; m_u64PushLaunchTime = 0; } } } } if (GetMovementState() != CHARACTERSTATE_FALLING && GetEntity()->GetVelocity().y < -4.5f) { ChangeMovementState(CHARACTERSTATE_FALLING); } else if (GetMovementState() == CHARACTERSTATE_FALLING && GetEntity()->GetVelocity().y >= 0.0f) { ChangeMovementState(CHARACTERSTATE_IDLE); OnLand(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void FPSPlayer::HandleCharacterController() { if (GetStage()->ConsoleShowing() || m_bSuspendMovement) return; if (GetEntity()->GetPhysicsMode() == Entity::RigidBodyPhysics) return; float jumpinput = m_vPushForce.y; Vec2 movement = Input::GetActionAxis(Input::ToActionAxis(ACTION_MOVEFORWARD, ACTION_MOVEBACKWARD, ACTION_MOVELEFT, ACTION_MOVERIGHT, GAMEPADAXIS_LSTICK)); float speed = g_player_walkspeed; // Handle Crouching HandleCrouching(); if (IsCrouched()) speed = g_player_walkspeed / 2; auto l = movement.Length(); if (l > 0.0) { movement.x = (movement.x / l) * speed; movement.y = (movement.y / l) * speed; } // Handle Jumping if (ActionHit(ACTION_JUMP)) { if (!IsAirbone()) { jumpinput = g_player_jumpforce; ChangeMovementState(CHARACTERSTATE_JUMPING); OnJump(); if (movement.y != 0) movement.y = movement.y * 1.6; if (movement.x == 0 || movement.y == 0) OnPerStep(); } } if (m_u64PushLaunchTime > 0) { if (m_vPushForce.x != 0 || m_vPushForce.z != 0) { movement = Vec2(0); movement += GetEntity()->GetVelocity(true).xz(); //DMsg(movement.ToString()); // Hackory to make the player crouch properly while flying. m_bWantsToCrouch = false; m_bCrouched = true; m_vCameraOffset.y = GetCrouchedEyeHeight(); GetEntity()->SetInput(0, movement.y, movement.x, m_vPushForce.y, m_bCrouched, g_player_maxdecel, g_player_mindecel, true); } } else { UpdateMovement(movement); GetEntity()->SetInput(GetEyeAngles().y, movement.y, movement.x, jumpinput, m_bCrouched, g_player_maxdecel, g_player_mindecel, true); } m_vPushForce.y = 0; } Along with some adjustments to the Cyclone code, Everything was working much better. I continued to make tweaks and changes as I continued along.  A nice bonus was this fixed Cyclones on Ramps which didn't work with my old code which helped me to get another map done.
    Revamped Cyclone Behavior - Work in Progress - Ultra Engine Community - Game Engine for VR
    After 6 months of development, I'm very happy to say that today I hit my first milestone. I have 10 playable maps with everything feeling acceptable. Most gameplay functions are online AND today I squeezed an Addon System to allow custom maps. The game runs with the Lua Sandbox enabled so custom maps can code new content in Lua!
     
    However, the entire game looks like this.

    I think it's safe to say that it's time to close Visual Studio for a bit and open Blender and Gimp on a daily basis. I'll have to open Visual Studio again to code the indicator strips and other effects but I'm really excited to just zone out and work models and textures. (although I don't see myself as the best in that area.) If you're actually interested in helping, my DM is open.
    Right now the plan is to get some maps art up for some screenshots and by late September/October set up Cyclone for Steamworks for an Early Access release Q1 2022. I can beat the game within a few minutes but with the project having zero story it can get more content in the future by me or others thanks to the addon system.
    First thing I need is a logo....
  22. reepblue
    Very happy on how everything is coming along. Blue Portals: Anniversary Edition development is going a tad slower than I wanted it too, but it's coming along nicely. We've finally shipped that
    in late August, and the mod made even more progress since. We just got some unknowns to work out like voice acting and music. I got some puzzles in the pipeline, and the mod right now has 11 playable maps.  
    LEX2 is getting re-organized. I went back to the CMD window based dev console as I plan on adding in the final console with the new GUI once that's done and well documented. I also implemented a Convar system along with a new conommand system. Pretty much, a new foundation is in place, and I shifted my focus to be easier lua development for now. I'll write about it more when I know more on how I wish to accomplish this.
     
    Steam Dev Days is next week! I've spent the last month going through my archive of experiments and prototypes, along with making demo maps for Blue Portals: Anniversary Edition. Chris (my texture artist) is bringing his Surface to showcase our stuff. If you're gonna be attending the event, come find us! We've got a lot to show off and talk about. I'll most likely be posting on my twitter through out the event.
     
    Unfortunately, the surface ran any Leadwerks project terribly, so we are only limited to our Source projects.
     
    That's really it. I know I usually write an essay for blog posts, but I've been busy lately in preparation for Steam Dev Days. I'm really excited, as I never been on that side of the country before!
  23. reepblue
    I've started on my quest to make a full C++ has started today. I've noticed that LEX2 via the project manager didn't copy over as clean as it should, so I had to make the project from scratch which wasn't a big deal (for me). I should look into a way of getting that fixed.
     
    After setting the project up, I noticed a few errors I was getting after I commented out the LUA_GAME preprocessor. It was a quick fix, and development went under way after that.
     
    For this project, I'll need things that's already available in Lua as part of the SDK. The high priorities are the first person player, animation manager, first person weapon (the pistol) and the Crawler's AI. As I said before, I don't want to convert SDK scripts to C++, but instead write the code myself. I'll look at the Lua stuff only if I get stuck.
     
    Today I found out that not everything will work when you convert Lua code to C++. I decided on the player as I've written it for C++ with my actor class, then converted it to Lua because of problems. Now I want to but it back to C++ as a puppeteer. It took a few hours line by line converted the code. When it was all done, I ran into a few issues.
     
    First off was HOW to spawn it? I could use a puppeteer script like I mentioned in my last blog, but the player should be spawned dead last. So the best method was to create the player in LEX2's OnPostMapLoad function.
     

    // This function is called when the program finished loading a map.
    void OnPostMapLoad()
    {
    Entity* puppet = WORLD->FindEntity("Player");
    FPSPlayer* player = new FPSPlayer(puppet);
    }

     
    This function is called at the every end of the level loading process. This is mostly so we don't hear the weapon being picked up while the map is loading, or a spawn sound like the Vectronic Demo.
     
    I was then running into null values that were driving me crazy. I went back and predefined all empty values as NULL and I was still getting a crash. It turns out, I didn't have the bool function returning the right value.
     
    Next was the footstep sounds. As I said before, I copied my fully working Lua player script and I noticed that the footstep sounds were playing too fast. I defined the value lastfootsteptime as an int in the header as 0, but when I did a system print of that value, it'd always return as 1. the fix was to define the variable before the footstep function instead of in the header as so:
     

    int lastfootsteptime = 0;
    void FPSPlayer::UpdateFootsteps()
    {
    if (lastfootsteptime == NULL) { lastfootsteptime = 0; }
     
    // If we're moving and not in the air, play a step sound.
    if (input[0] != 0 || input[1] != 0)
    {
    float speed = entity->GetVelocity().xz().Length();
    if (entity->GetAirborne() == false)
    {
    if (speed > MoveSpeed*0.5)
    {
    long t = Time::GetCurrent();
    long repeatdelay = 500;
    if (t - lastfootsteptime > repeatdelay)
    {
    lastfootsteptime = t;
    PlayFootstepsSound();
    }
    }
    }
    }
    }

     
    Last, I had to fix a Gimbal lock with picked up objects. This was because all variables in Lua and C++ work differently. So when going the lines one by one, I stored rotation values in a Vec3, and not a Quat.
     
    After the first day of my summer game, I got a player that walks around, jumps, can crouch under tight spaces with working sounds! I just got a few things to tweak before going to the next thing which will probably be the animation manager.
  24. reepblue
    Sorry for the whole week of silence, I ran into quite into a number of issues the previous weeks, but I'm ready to talk about them more, and how I it got resolved.
     
    Newton Physics (Or how Leadwerks uses this physics engine) has a problem when a non-physics object collides with a physics object. You expect that if a entity using the Move() function would use it's own shape to push anything out of the way. What actually happens is that since the entity has no mass, the entity pretends the physical object isn't there, and just clips right through it. This is most likely like this by design, but for Vectronic it was a huge issue.
     
    The advertised way of doing platforms is to use the Joint class so the entity will have mass and interact with other physics objects. However, the Vecboxes need to be heavy, I'm talking about setting the mass to 80 to prevent the object from bouncing like a kickball. Increasing the overall world gravity effects the player, and I want the box to be lighter when it's activated by the 0g Ball, which makes it easier to throw. Problem was that if a box was to go on these platforms with the mass I need them to be, the box would overwhelm the joint, and break it.
     
    Platforms is something I see important to the project as by now (in the earlier puzzles) they are used for demonstration of how the 0g cube works, and are in the majority of maps I have already made. If platforms can't work, I was afraid I was back on the bus of looking for another suitable engine for the game. Luckly Einlander came to the rescue and set me something that worked better than all my other attempts.
     
    Einlander's script moves the object from it's resting point to another position similar to the sliding door script. It also updates it's Physics Position and Omega in a function called in UpdateWorld. The result was exactly what I want minus a slight jitter in the box, but I'll take it. After experimenting with it though, I noticed that if a box was only partially on it, the platform would ignore the box, and go right through it; a similar problem I kept having. My fix was to create a trigger that's spawned with the platform with it's shape to handle this case, and behavior with the 0g cube. It's still not 100% perfect, but it's better than what I had before. The project was now back in gear.
     
    Another concern I was having was questioning "How much fun is my game, or is it just work?". Running around, shooting power balls at boxes so they change their properties sounds like a good concept on paper, demo maps, but imagine a full 2 hour game of just that? I was worried that just focusing on that would get really boring; so boring that it might even make people to stop short and refund the game.
     
    As if it was not clear already, Vectronic is a tribute to Portal as if it wasn't for that game, I would not be here talking to you right now. I started to think about Portal, and I started to look at it from a weird light: How would Portal be if momentum (Flinging) wasn't part of the game? There are five chambers, and the BTS areas that require or focus on using Portals to fling over gaps, and a good chunk of code is dedicated to make sure the momentum multiplies when going through each portal until the player or object hits it's max speed. But imagine if the game didn't have it, you'd have a game where you walk into walls to move mostly boxes around. Again, this might not seem so bad, but imagine playing it for 2+ hours with only the original elements; it will be similar to what I have now with Vectronic.
     
    The issue I think is the lack of Player Mobility. From my observations, people like to use their weapon to get to an extreme height. Join any Team Fortress 2 server and you'll see Soilders and Demomans blast jumping, and Scouts double jumping everywhere. With PUNT had something called Punt jumping which was like Rocket Jumping, but you could only do it on certain materials. From the feedback I got, people were most excited about that. Only issue is that it required skill, and it was never fully taught.
     
    I'm currently experimenting with this bounce jumping idea. Imagine rocket jumping only on certain materials, but all you need is to double tap Space. I've got only one map done as a proof of concept and to introduce the idea to others to see if it worked. Two days ago, I shipped the build early while this was still being figured out to see if it was worth the effort. I got a positive vibe from their feedback, I got told it was fun, although they didn't fully understand how to control it. Regardless, this might be because I was calculating how high the jump should be based on the time you're falling, not the speed, but it shows that it's not perfect yet.
     
    I should have more information about it next week (hopefully!). I want to go back and forth with my pre-alpha testers until it's a fun and fully understandable mechanic.
  25. reepblue
    Besides fixing the UV's for the VecDispenser, Adding in the box model, and some added sounds thanks to ThirstyPanther, most of the work this week was done with adjusting scripts so that the game as a whole plays better.
     
     
    Picking Up Objects
     
    Last week, I mention that I adjusted the pickup system so that it will auto center the object when it's picked up. While the stock code for the pickup system is good for occasionally picking up objects, in Vectronic, you're gonna be picking up boxes a lot. Not only that, but some puzzles require you to throw the boxes straight a head. The stock code locks the position and of the pickup with the picker position point which produces results like this.
     



     
    The pickup system needed to feel natural as possible. I wanted the object to tween from the current location to the center of the player's crosshair, much how the pickup system is in Source. It only took an additional transformed point from the camera, and using Math:Curve to translate the two positions together. The box position will always now be centered with the crosshair when picked up.
     



     
    This fix caused a few more problems which I'm still tweaking, I've added collision back to the picked up object, prevented the player picking up the object if they are standing on it, and also made the player auto drop it if the speed of the object is going too fast due to movement speed or violent collisions. It's not perfect now, but I feel that it's better than the stock pickup system, at least for this game.
     
     
    Platforms
     
    Another fix I've made is with the moving platforms. One major I've found with the sliding door script is that if a heavy object is on the joint object, the joint will fail, and fall through the floor. Since the boxes need to be heavy so they don't bounce really high, I felt like this was not a good system for the platforms.
     
    In the demo, I've made a script that just moves the model's position over time, but further playing with this script showed me that there was issues actually pushing the player up, while jointed objects did not have this issue.
     
    So I went back to the sliding door script with the problem of heavy objects effecting them, but lifting the player is fine. I solved this by making the joint object invisible and it's collision set to only collide with the player, and nothing else. Then, have the platform model as it's child which collides with everything else. This solved both problems as heavy boxes don't screw up the platforms as it's not colliding with the platform, but the player and objects can ride with the lifts without any issues!
     



     
    I still need to work on a better way to set the distance, as right now you have to guess and tweak the distance values which I don't seem to like very much. I plan on switching it to a location point instead. Overall, the platforms need to be more user friendly as right now it's just a modded version of the sliding door script. I might work a bit on that this week.
     
    I'll continue to work little by little to get everything as solid as I can. There is also a map in this set that I feel that's not as fun, informative or needed that I want to adjust or replace before working on any new maps. The goal is to get all this basic stuff perfect before continuing.
×
×
  • Create New...