Jump to content

reepblue

Developers
  • Posts

    2,486
  • Joined

  • Last visited

Blog Entries posted by reepblue

  1. 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.
  2. reepblue

    Cyclone
    As a teenager, I've spent thousands of hours with the Source SDK. It was really cool how Valve gave people the real tools to develop and create maps and mods. Overtime I got to see and take apart games to see how they actually work.
    Overtime, the indie engine market took over, and making Source mods is now just a terrible experience. Hammer crashes more frequently and the SDK branch of the engine has old bugs that were never patched. I want the excitement I had of making maps and cool features to be part of Cyclone as a package. Leadwerks has a very intuitive interface, and with a Lua Sandbox, many possibilities open up.
    As of the last update shipped today, anyone with a license of Leadwerks Game Engine has the ability to create custom maps and scripts and share them with others. This is the first step to see if anyone would be interested if they had the tools in their holster.
    There's now a batch file called "create_mod_env.bat" which will create a Leadwerks project within the game directory by default. You can edit the batch file to define a different path if you wish. You'll also receive a few example maps showing the logic of the game. Import the project in Leadwerks, and you should be good to go! When you're ready to share, zip up the map and chapter script and tell people to install it in a folder called "Addons" within the game's directory.
    While this is only the first draft of this, I'm interested to see where it will end up. I hope you all find it interesting and motivating.
  3. 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.
  4. 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.
     

  5. reepblue
    Loading sounds in Leadwerks has always been straight forward. A sound file is loaded from the disk, and with the Source class emits the sound in 3D space. The sound entity also has a play function, but it's only really good for UI sounds. There is also Entity::EmitSound() which will play the sound at the entity's location. (You can also throw in a Source, but it'll auto release the object when it's done.)
    While this is OK for small games, larger games in which sounds may change might mean you have to open your class, and adjust the sounds accordingly. What if you use the sound in multiple places and you're happy with the volume and pitch settings from an earlier implementation? You could just redefine the source in a different actor, but why should you?
    A solution I came up with comes from SoundScripts from the Source Engine. With that engine, you had to define each sound as a SoundScript entry. This allowed you to define a sound once, and it allowed for other sound settings such as multiple sounds per entry. I thought this over, and with JSON, we can easily create a similar system for Leadwerks 4 and the new engine.
    I first started with a dummy script so I can figure out how I wanted the end result to be.
    { "soundData": { "Error": { "file": "Sound/error.wav", "volume": 1.0, "pitch": 1.0, "range": 0.25 }, "RandomSound": { "files": { "file1": "Sound/Test/tone1.wav", "file2": "Sound/Test/tone2.wav", "file3": "Sound/Test/tone3.wav" }, "volume": 1.0, "pitch": 1.0, "range": 0.25 } } } In this script, we have two sound entries. We have an error sound (Which is suppose to be the fall back sound for an invalid sound entry) and we have a sound entry that holds multiple files. We want a simple, straight forward. entry like "Error" to work, while also supporting something "RandomSound" which can be used for something like footstep sounds.
    The script is streamed and stored into multiple structs in a std::map at the application start. We use the key for the name, and the value is the struct.
    typedef struct { std::string files[128]; char filecount; float volume; float pitch; float range; bool loopmode; } sounddata_t; std::map<std::string, sounddata_t> scriptedsounds; Also notice that we don't store any pointers, just information. To do the next bit, I decided to derive off of the engine's Source class and call it "Speaker". The Speaker class allows us to load sounds via the script entry, and support multiple sounds.
    You create one like this, and you have all the functionalities with the Source as before, but a few differences.
    // Speaker: auto speaker = CreateSpeaker("RandomSound"); When you use Play() with the speaker class and if the sound entry has a "files" table array, it'll pick a sound at random. You can also use PlayIndex() to play the sound entry in the array. I also added a SetSourceEntity() function which will create a pivot, parent to the target entity. From there, the Play function will always play from the pivot's position. This is a good alternative to Entity::EmitSound(), as you don't need to Copy/Instance the Source before calling the function as that function releases the Source as mentioned earlier. Just play the speaker, and you'll be fine! You can also change the sound entry at anytime by calling SetSoundEntry(const std::string pSoundEntryName); The creation of the Speaker class will start the JSON phrasing. If it has already been done, it will not do it again.
    Having sounds being loaded and stored like this opens up a lot of possibles. One thing I plan on implementing is a volume modifier which will adjust the volume based on the games volume setting.Right now, it uses the defined volume setting. It's also a part of another system I have in the works.
  6. reepblue

    Cyclone
    It's been roughly over a year since active development started on this project. Today, I'm excited to announce that Cyclone now has a "Coming Soon" page on the Steam Store! This marks a huge milestone for the project and I'm looking forward to getting this out as soon as possible. 
    Cyclone is planned on being released as an Early Access title. Releasing into Early Access will grant a layer of feedback, bug reports, and ideas that can help build the remainder features, as well as additional content. So much was done, yet there's much more to do before the planned Early Access release scheduled for Q2 2022! 
    If you are looking forward to Cyclone, please consider adding it to your wishlist and/or giving it a follow to be informed about future updates. 
     
  7. 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!
  8. reepblue
    There has been some discussion regarding on how to set collision shapes for your models. For 95% of models, you should be building shapes with the Model Viewer as described here. In some cases, the model artist might want a custom shape to be made. In this post, I'll be going over how I import models into Leadwerks, and building custom shapes.
    A few notes first. I use Blender; Blender 2.79b to be exact. I haven't get got the hang of 2.80 and until the new engine's art pipeline is fully online, I don't see a use for it. Leadwerks 4 uses Blinn-Phong rendering so the PBR stuff makes no sense for Leadwerks 4. So for this, I'll be posting screenshots from 2.79b. I should also mentioned that a feature I use in my process isn't present in the Linux build of the editor, which is the collapse tool. (Tools->Collapse). Doing the collapsing via a terminal will cause the models to crash the editor. This seems to be a known bug, as you don't see that feature in the Linux editor.
    Lets say you created a tube model such as this one and you want the player and objects to go into the tube:

    If you tried to make a shape doing the Concave settings, not only it'll be really slow to generate, but the results will not be good. We could make a shape based on the wire frame, but this is a high poly model. What we need to do is make a new mesh, import both models  to the editor, collapse them both, build the shapes for both, and delete the low poly model while making the high poly read the low poly's generated shape.
     
    First to get it out of the way, apply the scale and rotation of the model. This will make Y forward and the scale will be (1,1,1) when you import it into Leadwerks.

     
    Next we need a low poly model.

    This is the same proportions as our high poly. Apply the scale and rotation as the same as the high poly. I also set the max draw time to solid, but this is optional.

    Next, name your High poly and the low poly you're going to be using for the shape appropriately.

    Now lets, export each object as a FBX. For this my high poly is going out as tube.fbx, and my low poly shape is going out as tubeshape.fbx. Here are my export settings:

    If you saved the files in a Leadwerks project while the editor was opened, the editor would have auto convert the files to the .mdl file format. Open the high poly model (tube.fbx) and first collapse it and give it any shape. (Give it a box shape to save time.) you need to assign a shape to the high poly so the mdl file is linked to a phys file. Do the same with the low poly, but you're gonna set the shape as poly mesh.


    Close the model viewer, and then go into the directory where the models are placed. We are now going to delete the box shape of our high poly, and trick it into loading the low poly shape by renaming the shape file of the low poly to be what the previous shape of the high poly was. In other words, we are making tubeshape.phy into tube.phy.
    Before:

    After:

    Notice the time stamp and the size of tubeshape.phy from before being the same as tube.phy in the after screen cap. This should be your end result.

    Notice that the shape isn't sold but now a tube. Objects can go into the tube with no issues. Now, there is another way that uses limb names to generate physics automatically. However, there are a lot of issues I came across using this method such as the shape not being parented to the model when the model moved via physics or a joint. With this way, you have a custom shape, the model is optimized because it doesn't have any children nodes, and everything is clean and tidy!

     
  9. reepblue
    Back in July, I set out to create a base for creating a version of Cyclone with Ultra Engine. I've gotten a lot of feedback from the release and started to conceptualize ideas on how to prevent or limit on making the same mistakes.
    One major goal I had was to compartmentalize the system. This should just exist on it's own and game code should just lay on top of this. This was possible thanks to the event system which cuts down on the number of pointers that need to be passed. Components can just listen to events from the program and act accordingly. 
    Lastly, I've made the decision to open source this on GitHub as this is the kind of thing that users think about when it's too late. People just want to work on their cool games and not worry about the window or if a setting will be applied correctly. 
    So here are 6 reasons/features of the Ultra Game System! 
    1. Window Management
    One of the top complaints I got with Cyclone is that users could not resize the window in-game. This was an engine limitation of Leadwerks This is now possible in Ultra Engine but it needs some elbow grease to make it work. The Game System does this for you. All you need to do is call GetProgram()->ResizeApp() and the graphics window class will recreate the window and framebuffer for you. By default, pressing F11 will swap between windowed mode and full screen. 
    2. Out-Of-Game Settings
    The Game System has an isolated window application for changing settings. The idea behind this is so there's a way to modify any window or graphics setting if an in-game one is unavailable. You probably shouldn't ship with just this solution as many people prefer to edit any setting within the game itself. 
    This is accessible by using the -settings flag with the program.
    3. Action Based Input System
    Years of research into this paid off when the Input Update for Cyclone released. The knowledge was carried over for the Game System. Only this time it's more dynamic! 
    Simply set the controls in your main.cpp file:
    // Define default controls. static void InstallControls(shared_ptr<GameController> controller) { if (controller == NULL) return; // Program actions controller->SetAction("Pause", BUTTON_KEY_ESCAPE); controller->SetAction("Terminate", BUTTON_KEY_END); controller->SetAction("ConsoleApp", BUTTON_KEY_F1); controller->SetAction("Fullscreen", BUTTON_KEY_F11); controller->SetAction("Screenshot", BUTTON_KEY_F2); controller->SetAction("Quick Save", BUTTON_KEY_F5); controller->SetAction("Quick Load", BUTTON_KEY_F6); // Camera ButtonAxis moveaxis = { BUTTON_KEY_W, BUTTON_KEY_S, BUTTON_KEY_A, BUTTON_KEY_D }; controller->SetAction("Movement", moveaxis, "InGameControls"); controller->SetAction("Camera", AXIS_MOUSE, "InGameControls"); controller->SetAction("Sprint", BUTTON_KEY_SHIFT, "InGameControls"); controller->SetAction("Crouch", BUTTON_KEY_CONTROL, "InGameControls"); controller->SetAction("Climb", BUTTON_KEY_Q, "InGameControls"); controller->SetAction("Desent", BUTTON_KEY_E, "InGameControls"); controller->SetAction("Jump", BUTTON_KEY_SPACE, "InGameControls"); // Settings controller->SetSetting("Raw Mouse", false); controller->SetSetting("Inverse Mouse", false); controller->SetSetting("Mouse Smoothing", 0.0f); controller->SetSetting("Mouse Look Speed", 1.0f); } Then deriving your components off of the GameObject class, you can use GetInput() for input functionality. 
    virtual void UpdateInput() { // Movement if (allowmovement) { float speed = movespeed / 60.0f; if (GetInput()->Down("Sprint")) { speed *= 10.0f; } else if (GetInput()->Down("Crouch")) { speed *= 0.25f; } if (GetInput()->Down("Climb")) GetEntity()->Translate(0, speed, 0); if (GetInput()->Down("Desent")) GetEntity()->Translate(0, -speed, 0); auto axis = GetInput()->Axis("Movement"); GetEntity()->Move(axis.x * speed, 0, axis.y * speed); } } Best part is the "Controls" tab will reflect whatever you have defined!

    4. User Input via Console
    Having a developer console is essential for developing any game! The Game System has a very simple but flexible console that doesn't need any commands registered beforehand. To define a new command, just poll the EVENT_CONSOLEEXECUTE id in your component's ProcessEvent function.
    virtual void Start() { Listen(EVENT_CONSOLEEXECUTE, GetProgram()); } virtual bool ProcessEvent(const Event& e) { if (e.id == EVENT_CONSOLEEXECUTE) { auto line = e.text.Split(" "); auto cmd = line[0].ToString(); if (line.size() > 1 && !line[1].empty()) { if (cmd == "crosshair") { bool hide = (bool)line[1].ToInt(); hudcamera->SetHidden(!hide); Print(QuoteString(cmd) + " has been set to: " + line[1]); } } } } 5. Sound Managment
    A layer of functionality in the Game System allows for cleaner sound origination and playback. You can store sound variables (files, volume, pitch, range, etc) within a JSON script.
    { "audioProfile": { "file": "Sound/radio_dreamlandloop_mono.wav", "volume": 0.5, "range": 35.0, "loop": true } } Then load the file with the GameSpeaker class.
    auto file = "Sound/Profiles/Radio.json"; shared_ptr<GameSpeaker> speaker = CreateGameSpeaker(file, GetEntity()->GetPosition()); The GameSpeaker has Save/Load functions so the speaker's time and state can be restored. Here's an example of creating and restoring a GameSpeaker.
    virtual bool Load(table& properties, shared_ptr<Stream> binstream, shared_ptr<Map> scene, const LoadFlags flags) { Print("Loading component " + QuoteWString(name)); if (speaker) { if (!properties["componentspeaker"].is_null()) speaker->Load(properties["componentspeaker"], binstream, scene, flags); } else { auto file = "Sound/Profiles/Radio.json"; speaker = CreateGameSpeaker(file, GetEntity()->GetPosition()); if (!properties["componentspeaker"].is_null()) speaker->Load(properties["componentspeaker"], binstream, scene, flags); } return true; } virtual bool Save(table& properties, shared_ptr<Stream> binstream, shared_ptr<Map> scene, const SaveFlags flags) { properties["componentspeaker"] = {}; if (speaker) speaker->Save(properties["componentspeaker"], binstream, scene, flags); return true; } As of right now, the sound system doesn't support audio filters as I feel that the filter should be applied within a volume (or to the listener) and not the sound/speaker itself. I'm still thinking about how that should work. 
    6. Better Render Layer Managment
    Intergrated today, The Canvas class is a great way to ensure that there is one camera per render layer. I ran into an issue where a component would draw 2D graphics to the framebuffer, but when there were multiple instances of them, multiple cameras were being made and drawing over each other. Using GetCanvas() can prevent this from happening.
    auto canvas = GetCanvas(world, RENDERLAYER_HUD); auto sprite = CreateSprite(world, 1.0f, 1.0f); sprite->SetPosition((float)sz.x / 2, (float)sz.y / 2); RenderToCanvas(sprite, canvas); The Game System will be my main focus until the Ultra Engine version of Cyclone starts development which will use this as a foundation.  I'll also be working on other small things to share so be on the lookout for those! 
  10. 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,
  11. 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.
  12. 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.
  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
    For who those who don't know (or remember) Vectronic was my first person puzzler project I was developing from 2013-2016 starting with the Source Engine and then onto Leadwerks. The goal of the project was to create a puzzle game and allow people the assets to make their own puzzles. Although it never saw it's end, you can still play the demo here.
    So what happened? Vectronic was how I pretty much learned a lot about programing, art and game design in general. I kept going back working on it for a month or so and then stop because I would hit a road block with assets, code, performance, or time. I made a lot of cool things too that just never saw the light. Over the years however, I also noticed I don't have patience to work on one game alone for months at a time. I do however like to play around with stuff so I began to think: "What if I had a project for me to tinker with and post it publicly every so often?" I'm more busy than I was in the past so time is more limited. However, I've probably written Vectronic game code over 50 times and I now know the right way of doing such. So what's the plan?
    After some experimentation, I've decided to go ahead and start a new project taking everything I did and learned with Vectronic and making a base template for people can use for their own purposes. My packaged game will be free to download and play (Because it's just me playing around) while the assets and will be posted on the Leadwerks Marketplace for a charge.The package will contain all assets to build your own test chambers, and you'll also get the original source files too! My release game will act as an outlet to my tinkerings and provide as an advertisement to the asset pack.
    With the code, the idea is that everything will be modular and users can easily create their own power balls to do various of things. The power balls can now be applied to any entity under certain conditions so there is no need for a VecBox.lua script anymore. There will be plenty of examples for many to see how things were done. I learn best by references and examples, and having code, art, and maps accessible should help new users into learning game design, or aiding developers in assets to start their ideas.
    I've decided to change the name to Vec-Tec as the asset pack will be in the Vec-Tec Research Center. Also with the new approach, I think it's time to drop the name Ive been using for four years. You can give Vec-Tec a try right now here!  It's very minimal, there is no art, but the foundation is there. VR is now gonna be a thing with this, If you have a VR HMD, you can play any map in Roomscale VR!
    I hope this is a start of a remarkable development. I hope you are interested and see value in this  project. You can find the project page here for the latest updates and releases.
  15. reepblue

    Cyclone
    From its initial concept in 2017 through the last sixteen months of development, I am ecstatic to announce that the free demo of Cyclone is now available in preparation for the June Steam Next Fest!  This demo includes three maps from the main game showcasing the functionalities of Cyclone and various puzzle elements.  
    The demo is available right on the Steam Store page!
    Cyclone on Steam (steampowered.com)
    While this is both an exciting and a scary time. I can't stress enough that your feedback will be very helpful as we get closer to the Early Access release date of June 23rd, 2022. Please let me know what you think publicly right here on UltraEngine.com, privately via a DM or my inbox of sferriolo@reepsoftworks.com.


  16. 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!
  17. reepblue
    I'm excited to announce that Cyclone will be participating in Steam Next Fest 2022! While I'll not be live streaming, a playable demo will be available during the festival. The demo will act like an even softer release than the Early Access release, which should roll into the planned release date of June 23rd, 2022!

     
    Add it to your wish list on Steam: https://store.steampowered.com/app/1803590/Cyclone/
    Check out the itch.io Page: https://reepblue.itch.io/cyclone
    Join my public Discord: https://discord.gg/Hh7Ss9fWaW
  18. reepblue

    Cyclone
    The time finally came to revamp the main menu for Cyclone. Doing menu work for me is really hard to get into but once I'm knee deep into it, it's all I want to do. I decided now is the time to work on a semi-final menu system due to the following.
    I just finished Steam Input and the menu wasn't compatible. The white text on a bright background was hard to make out. I only had a "New Game" option. There was no way to jump to a map you wanted to play without the console enabled. The first step was to figure out how to integrate the GUI with Steam input. The Leadwerks GUI system is from my experience is an unfinished predecessor of the same GUI calls of the Ultra App Kit. The input was really for a mouse and keyboard but I didn't want to bother learning imgui or another API. One thing that made it really complex is that Leadwerks uses Lua scripts for the GUI draw and event queue commands, 
    In the end, I just did a Steam Input binding to control the mouse with the touchpad or a joystick and told the OS to simulate the left mouse being pressed when the action is called. I don't know if this will get me any approval badges, but now you can control the menu with just the controller. The extra parameters don't seem to do anything but I kept them in. Regardless, it works. We don't have to call any "Legacy Keys" for the bindings!
    //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CycloneMenu::OnUpdate() { if (!Hidden()) { if (Input::ActionHit(ACTION_MENUSELECT)) { EventQueue::Emit(Event::MouseDown, Window::GetCurrent(), Key::LButton, Window::GetCurrent()->GetMousePosition().x, Window::GetCurrent()->GetMousePosition().y); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CycloneMenu::ProcessEvent(const Leadwerks::Event iEvent) { ... else if (iEvent.id == Event::MouseDown) { // A hacky way of doing this. #ifdef _WIN32 INPUT Inputs[3] = { 0 }; Inputs[0].type = INPUT_MOUSE; Inputs[0].mi.dx = Window::GetCurrent()->GetMousePosition().x; // desired X coordinate Inputs[0].mi.dy = Window::GetCurrent()->GetMousePosition().y; // desired Y coordinate //Inputs[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; Inputs[1].type = INPUT_MOUSE; Inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; Inputs[2].type = INPUT_MOUSE; Inputs[2].mi.dwFlags = MOUSEEVENTF_LEFTUP; SendInput(3, Inputs, sizeof(INPUT)); #endif ... } } Now, controlling the mouse with a joystick isn't the best approach. I also had to make my buttons much bigger so it was harder to miss the bounds of the button when using the controller. I also kept all my UI elements in the center of the screen.


    Next was the options menu. I used choice boxes on everything to make it less Mouse centric,

     
    Finally came the new "Play" menu which I wanted to revamp from just a simple button that would load the "start" map. Right now, I'm forecasting only to ship with 10 maps but what about any new maps later on? Would I just add it onto the 10? What if I want to make a set of maps that focus on a theme or a new element? Would that break the progression? What about when custom maps are loaded? People would be going to the "Custom Maps" box more than the "New Game" button by then. It's not like it's a story or anything to justify those maps being held at a different standard than other maps.
    I decided to take a similar approach to the campaigns in Left 4 Dead. The chapters shipped with the game are loaded into the menu first. Then the application looks for anything under the addon's folder and loads those in. Each chapter can have a collection of maps that are easily selected by the user. 

    { "name": "Cyclone 101", "author": "Reep Softworks", "maps": { "Level 0": { "filepath": "Maps/lvl0.map", "imagepath": "Materials/GUI/background_lvl0_artpass1.tex" }, "Level 1": { "filepath": "Maps/lvl1.map" }, "Level 2": { "filepath": "Maps/lvl2.map" } } } Custom maps work the same way no special treatment. This all works with a json script and the application can locate the script in the zip package. Also, if no image is defined for a map, a "NO IMAGE" texture substitutes in.  Just click start, and off you go!


     
    { "name": "MyCoolAddon", "author": "reepblue", "maps": { "The Cool Addon Map": { "filepath": "Maps/addontest.map", "imagepath": "Materials/GUI/loadingscreen.tex" } } } One thing I'm not sure about is splitting my 10 maps in 3 chapters. I did this after feedback of the list being so empty with just one entry. Hopefully I'll have time to make new maps. Being that now I'm free to work on small collections instead of one long track should be motivating. A goal of arranging the maps like this is so I can justify the game based on the amount of content over "how long" it is. 
    It should be really easy to integrate Steam Workshop with this but I'm not going worry about it now, Tonight I'm happy I can play Cyclone with my Steam Controller without reaching for the mouse and keyboard!
  19. 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.
  20. 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!
  21. 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!
  22. 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.
     



  23. 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.
  24. reepblue
    In late 2014, I made the bold decision to focus less with Source Engine mods and pick up an actual engine I could use without legal conflicts or worrying about knowing the right people. At the time, it was like all other options were telling me to forget everything I've picked up through the years of making popular maps and mods and learn something that's completely unique to their software. CSG tools were declared too uncool, and any engine that was nice enough to support it enforced that any and all CSG objects should be removed.
    And there I found Leadwerks. The editor looked and acted like Valve's Hammer Editor and I could code my game in C++. While the Source Engine didn't really use modern C++ (It was more C with classes and a bunch of macros if anything anything) I felt more open to learn this than anything else at the time. Also, my internet wasn't great at the time so the small install size was a plus.
    Only thing that threw me off from the start was that a lot wasn't done for you. With Leadwerks, YOU are in charge of window creation and YOU are in charge of how maps are loaded and cleared. Any engine I've tried, this is done for you and they give you documentation on how their system works for you to read which I'm not a big fan of. 
    After I shipped the Vectronic Demo in 2015, I wanted to have a nice C++ foundation framework to work on. Back then, there wasn't an Actor class to attach C++ functionality to entitles, the animation functionality was in a Lua script, and back then there was no editor materials so you had to make trigger boxes invisible. I wanted something that didn't need Lua to function and make life easier to make maps. I also wanted code for window and world handling to be automatic- to "just work", This started as the LEX template. 
    Looking back, the LEX template is a huge mess of code that did all of that. A demo game was made for a game tournament in 2015 or 2016 (I forgot tbh) called Crawler's Den. The entire game was written in C++. During the development time, my animation code I translated from the Lua variant got adapted into the base engine which made life much easier. This also made animations faster and easier for everybody. I also took time to look into cubemap reflections which I think really pushed for the probes in 4.1. In the end, the template was unstable and hard to work with. I was often afraid to clear and load a new map due to raw pointer issues.
    I instead dropped the idea in favor of a similar system using Lua. Luawerks was everything I wanted LEX to be but much safer. It was more adoptable as most people only have the Standard Edition of Leadwerks. I finished the code and pushed it to the market place.  
    However, I really wanted to make a game with C++ and at this point VR was coming online which C++ is better suited for. 
    For the past 3 or so years, I was writing testing, scrapping and recycling code figuring out the "best" way of a system. I tried to do a translation of Luawerks to C++ but decided against it early on. I figured out why my code was crashing before, what objects I can Release when the entity deletes and overall became better at programming. However, a new engine was on the way and I didn't want to write code if I just had to redo it again.
    I threw the 5 bucks a month for the early subscription at the time for access of the SDK of the new engine. Back then, I thought the new engine was just going to be "Leadwerks but faster" but that wasn't the case. I made a few macro's and #ifdef's to accommodate for this. Over time however, function names were changed, renamed, or removed completely. and the new engine slowly began to do things differently than Leadwerks. 
    It came to a point in which how my systems would work needed to be completely different for both engines. In late 2019, I decided to cut the code in half making one folder called "Core" for core app functionality. That part of the code would be translated for the new engine and tested occasionally. This is also the time when I decided to really look into input functions. The "Game" code was code I would just create as normal and worry about it converting it later a file at a time.  You can play the results here. 
    In early 2020, I started a game project using this base but shelved the project due to the fact I was not happy with getting 150fps on a simple scene. This was also pushed when I threw in a fast VR implantation and thought it was really cool (But really slow!). I also was getting random crashes with an actor over something so something was still up with my design. The new engine was coming a long so I re-structured my base yet again. 
    As of today, after many years of work and research I now have a very clean framework that works on both Leadwerks AND the new engine. I see this as more important than ever now as I expect a lot of people are gonna come in for the new engine and be in the same position I was in 2014. 
    At minimum, this is how your main function should look like and will compile with both engines!
    #include "pch.h" #include "gamewindow.h" #include "stage.h" int main(int argc, const char* argv[]) { // Create Window App auto window = CreateGameWindow("FPSGame"); // Create a stage. auto stage = CreateStage(window); stage->LoadSceneFile("Maps/start.map"); // App Loop. while (window->Closed() == false) { stage->Update(); } } This code will create a window, load a map/scene file and update accordingly. Not only for my games, but this also works really well with my current "non-game" project! 
    I wish to go into how into this deeper at a later date, but I thought I should bring context to the last 5 years. Although I didn't get to build a game within that time, I had a blast figuring all this out. 
    I'll leave off with screen shots. Remember. it's same code base doing the same thing for each engine!
    Leadwerks 4:

    New Engine:

     
  25. reepblue
    After sixteen months of week-by-week development, I'm happy to announce that the anticipated spiritual successor of the Portal mod, Blue Portals is now available for sale as an Early Access title on Steam!
     
    I want to take a moment to thank [b]everyone[/b] who has played the demo and gave feedback. There's still work to be done! Being an Early Access title allows Cyclone to continue keep players involved in the development process to help it evolve into the best it can be! 
    I hope you're all excited as I am to see where Cyclone will be in the near future!
     
    Please enjoy!
     
×
×
  • Create New...