Hello everyone, and welcome to the end of the longest and shortest month of the year so far. I feel like I’ve probably been repeating myself, but every month seems longer and shorter than the last. And now it’s summer. Last I checked, I was counting down the days until the winter solstice because beyond that, the length of the days would grow. It seems the longer the daylight, the shorter the day.
So what’s been going on on this very long Month?
Hooooooboyy… Recalling this month has been really wild. I have been up to a lot of stuff: daily intensive learning, problem solving, and more; yet in retrospect, I would have figured it was stretched over “the past few months”. No. It was ALL in this month. I’ve actually only been back to work for 2 months. Realizing this has been staggering.
Okay, okay, okay. Less preamble, more amble.
I’ve spent this month continuing forward with my plans towards building up the O3DE version of my Unity Tech that I’ve established over around 5 years of work. The fact I’ve continued to work at this goal and have been grilling at it hard is a good sign that I’m heading in the right direction. It’s been rewarding, promising, and makes me very hopeful to start evolving it, and my own plans for game dev, to be able to make solid progress on the tools, but to also utilize them in the various levels of realization on some small little burst-fire games!
Now let‘s enter the work. Let’s see where we’re at.
So I left you all last Month in Review with the near-conclusion of my “Core” Gem. To reiterate, this is meant to be a module that houses common and core system features that other feature modules (gems) will be able to piggyback from to add wholly unique additional features, while being able to utilize common patterns, functionality, and utilities.
It wrapped up great! I had brought the brunt of it around, got my documentation pretty up to speed, and was ready to make a demo project to present the features in easily digestible ways.
So here we go. The beginning of one of the biggest themes of this month. Logistics.
I start my demo project, enable the Core Gem, and get to work. I can’t create a Demo_Manager, my example of extending the GS_Manager class for your own project needs. Actually, I can’t inherit anything from the core gem. This leaves me dead in the water. The reason for this feeling of looming doom? I also can’t inherit from these various classes in my next feature gem, the absolute crux of the whole reason for making my systems this way. Oh no. Oh no.
I am fairly new to complex C++ systems and structures, so this is all new stuff to me. Clearly, what’s happening is that my Core features are in the ‘wrong scope’ to allow for outside code to be able to point to it and have the C++ builder actually find it and provide its contents to the new code.
So begins a massive delving into, to get this Core gem actually able to be core to anything else but itself. It took me the rest of the week. It killed me, but I managed to arrange and register the various files and things to actually be public and visible to the world of my game systems. What a relief. What a grilling of my understanding of things. I am definitely more of a person than I was the week prior. Awesome, I am now free to build into the world of feature-sets I would LOVE to have available in an open-source game engine of my dreams!
So begins the GS_UI Gem…
Now unbound by my scoping, I am able to make the GS_UI gem, it relies on GS_Core, which is set now to be toggled on automatically if you make your project utilize the GS_UI gem. Super cool. Feels super legitimate, now that the gems are actually affecting the Project Manager and stuff.
So we get into the guts of the UI work. I have my tech for how I like to tackle the system and what I’ll need for things: You can call the UI Manager to spawn a ui from wherever you need, the UI can be targeted and highlight its default buttons to start, using input you can navigate the UI, but it won’t go to menus that are hidden or disabled. Fairly straightforward stuff.
First thing I start with, is trying to get into some of the harder stuff, in order to free up the understanding of whether I can even work at it: UI Animation. Final product UI’s have every single ‘bleep’ and ‘bloop’ and ‘doot’ and ‘deet’ animated, poppy, soundy, and every other ‘-y’ that is necessary for making a professional level production. I spend quite a lot of time in it, but then find out there are many constraints in how the UI system handles Animation.
Currently, you can either make hard hard-coded animation that literally works on a ‘PER element’ basis. So if you want your UI to make a little bouncy ‘doot’ when you highlight it, you have to make a unique one for EVERY button. Otherwise, there’s a scriptual animation method, however, it’s ONLY LUA based. Has all sorts of very universal attributes, but they were all implemented in LUA. Meaning there’s no way to harness it in C++, or in Script Graph scripts. What a slog. WHAT A SLOGGGG.
So I get back into the basic system things: getting managers and basic features in. Going great. But for the life of me, I can’t get my UI components to actually appear in the UI creation window. This is a very critical part, because I need to be able to create UIs to be able to have UIs to use. As far-fetched as that may seem.
So begins.. so continues… Enter my next massively logistical battle.
I am trying to find where and how to get these things to appear in UI Editor. ChatGPT is telling me all this stuff… that is blatantly wrong, or at least not modern in any stretch of how this works. I go on and on, scouring the source code, trying to find a simple example that may lead me to be able to easily just pop similar commands or functions in to get the stuff appearing.
I hit a compile error that’s preventing my project from launching, I spend days trying to problem solve it. I get mistakenly caught up problem solving a warning that seemed to somehow be related, but it turns out it wasn’t. Days pass, I finally realize that my issue came from an error in my Component’s “Reflect” function. A function used to make things appear in the Editor.
Holy sh… Great, okay I can move forward. But still. Nothing is appearing in the editor.
FINALLY, FINALLY, I get things appearing. Turns out it took like 20% as much as I was doing to get it going. And actually just needed me to change the name of a “AppearsInMenu” default that’s already there in every Component Reflect by default.
Change: “Game” to “UI”. Tada!
Okay wow, nice. I can scope my features to be accessible to other systems. I can make Game and UI Components. Going pretty good! I am even figuring out some UI functionality and stuff. Getting fun again.
So I tried to change my “Builder” to Ninja.
Thankfully, this logistic was only a BIT of a slog, and ended up yielding such a massive improvement, I’m less massively pissed off about it.
So, when you’re making C++ code, you need to compile it before you can use it in editor, and in the game itself. This is done, on Windows, with a default windows builder. Turns out that one isn’t very optimized around C++ and building, and building again, and again, etc. I mention in the last Month in Review that it’d take me 2-4 minutes EVERY time, JUST to see that you missed a “;”.
Well. It also turns out that these builder systems make the final “build” in a format custom to how they process the data and make it available to the engine. Which means, to switch to Ninja builder, you need to completely rebuild the entire project from scratch (the systems usually have a cache of things, so you’re not starting from the beginning every time).
“From Scratch” takes my system about 2 hours to do. Woweee. So I wait and wait and wait.
Oops, I didn’t set it up correctly, so despite thinking I was rebuilding with Ninja, I was building again with windows built in. So 2 hours later, I realize I need to REBUILD FROM SCRATCH AGAIN!!! AGHHH AWGHH AAAAA. WHAT A SLLLLOGGGGGG!
But you wouldn’t believe it. After a day and a half of wasted time. Ninja re-builds SO FAST.
What was taking 3 minutes to expose an issue would take about 10 seconds. That is a performance improvement that completely makes all of that wasted time, like, WAY worth it.
On top of that, the reporting on what is causing the issues is far more articulate, which means I can far more easily get to the target of my issue with far less speculation than before.
This improvement, along with my growing familiarity of C++ and the O3DE systems, is getting me through the building and problem solving far faster and with far fewer tries-and-retries before I’m through to some working code.
This is pretty awesome.
So I’m back on the UI wagon. I can work far faster and with like 100x less building overhead.
And things start to roll forward. Who would have imagined?!
I get my UI Manager spawning UI, I have UI windows, and UI pages within windows that can be toggled between, to swap between windows, and things. I won’t get into the nitty gritty, but it allows for fairly exotic combinations of windows that can be changed within bigger more encompassing windows. It should be able to tackle a fair amount.
Then, finally, I’m at the final stage of the UI work (for now), which is to prevent the UI navigation from going to a different, hidden, window. Isolating the windows that should be able to be navigated around from all the rest.
It all goes pretty well. I even create an “ElementGroup” component, that allows you to disable the interaction, the thing that allows UI nav, in through all of it’s children. What’s fun is that it uses a programming pattern called “Recursion” to programmatically step through every child and affect them all the same. Lastly, when it hits an ElementGroup inside of itself, it hands off the processing of THAT groups children to the child ElementGroup. It’s a commonly used feature in other engines, and I was really excited to be able to introduce it to the O3DE UI. I actually intend to give it a little more review and possibly contribute it back to the O3DE source code! That would be my first actual contribution to the engine! Very cool!
Check it out! It’s not pretty but it works! It WOOOOORKS!!!
Fast Fast Fast, on to the Next!
Okay, awesome, foundation for UI tackled. This time around, because of how much of a slog attempting to make demos is, I skip right to the next feature-set. I would rather build momentum around getting prototypes together than to derail myself with tutorials that are not necessary so immediately.
I begin the GS_Unit system. And what a system it is.
A very significant system for most games, having a character that exists in your game world that you can use to affect your will through. Something I’ve done quite a lot of, many times, for Awakened Guardian, and other projects. I’m excited but…
If you’ve ever talked to me, I recurringly say: “I NEVER want to have to make a character move forward, back, left, and right, EVER AGAIN. EVER AGAIN!”
Turns out, making a character go forward, back, left, and right, is really boring, and not very fun, and is necessary for 99% of the games I ever want to make. So I keep fantasizing that there will be a day that I can finally stop having to do it, and instead fall back to a reliable system that can do that.
I was there with the most immediate upgrades/improvements/stabilization of Awakened Guardian, but with the ever looming presence of Unity Corp’s abysmal practices around their Engine, I couldn’t rest easy with just that.
So cue up making a character go forward, back, left, and right. AGAIN. AGAAAIN!
As part of my efforts around this gameplay framework, I’ve been wanting to get ahead of many elements that end up falling to the wayside until the very last moment, suddenly cropping up and being a major crisis at the final throes of making a project.
In this case? Input.
O3DE handles input perfectly fine. However, there are some extraneous features that are not supported. In this case, being able to overwrite input defaults. This is necessary for many aspects of a game project. At the top-most level, many PC games allow complete Input customization. Definitely the most significant feature for a “Overwrite every bit of Input” system. But there are additional ones. Even when bound to a console, and gamepad, you may want to create some accessibility features. Left-handed controls, or, in some cases, One-handed controls.
As a developer, having more granular command over the features you have at hand can most always be worthwhile. Whether you utilize and deploy it or not.
So I returned to the GS_Core and began building GS_Options and the Input System within it. Love it, makes complete sense to have Options in the core, as ANYTHING can introduce options to the system, and ANYTHING can utilize inputs and input settings. I will be migrating support for it to my UI system, for example.
The crux of my input system? The “InputProfile” data class. Using it, you can set any number of inputs, and tie them to events that the game system uses to fire its functionality, all agnostic of what raw inputs come in. This isn’t my first rodeo, and making what I call “packets” is no novel thing. Data oriented design/programming is a common principle in modern game dev, and it makes sense for a reason.
Using a packet, you can define a Unit’s details. Say, Stats. And regardless of how many custom enemies you make, you can just drop this packet into their system and they’ll have those stats. If you need to change a stat, you can just change the packet info and all of a sudden, EVERY enemy that has that stat packet will be updated with no additional effort.
This is also valuable because if you edit an enemy, and suddenly all its settings get reset. Rather than putting back the 75 stats you gave it, you just need to add the packet back in. Tada, returned it to its former glory.
What these packets are, are usually files with a unique filetype, that you can make any number of, and configure very easily within the editor. In Unity it’s called “ScriptableObjects”, and in UE it’s called “DataAssets”.
I haven’t heard of such a thing in O3DE, but can see, within the default projects and things, that there are unique filetypes that you can open in the simple Asset Editor window, and save to your project folders to use wherever you want, by dragging and dropping it into your components in the inspector details.
Awesome, I just need to create my own and get it registered, and boom, I can have my InputProfile packet.
So begins.. Enter… This just in, the next logistical nightmare. WHAT. A. SLOGGGGGGGG!
The customizable nature of O3DE is very powerful, but within the breadth of the capabilities of the engine is a more murky clarity of HOW MUCH one needs to customize to get a more basic feature or system to work.
Using the resources online for the Asset Pipeline, GPT, and scouring the Source Code, I start trying to bring together a custom asset. This involves creating your class that defines the data and guts of the file. Creating a custom handler that registers the file, the class it represents, and processes creating and destroying the custom file into data. You then use a system component to create an instance of the handler, and drive the handler to run its registration to the system so the file can be created, read, and edited, both in the editor and in the standalone release of your game. You can then create a builder that handles processing the file type with the asset processor, in order to properly break down the raw data of the filetype and bring it into the engine in an engine-compatible format called “Assets”.
I’m getting to like, 7 files all necessary to get my InputProfile built into the editor, and I STILL can’t get the custom file to appear in ANY “Create” or “New” menus. I can’t create the file outside of the editor and be able to click into it IN editor and have it present me any editing ability within the engine, just a generic “this is what the file details are”.
This goes on for days. Every day, it’s just getting more dense and complicated, adding more and more files, firing off more and more events and commands all over those files. This is getting absurd.
So guess what? – What?
That massive pipeline of a gajillion files, and registering things everywhere, etc, is for the FULL asset pipeline framework where you’re like… taking a .googlemapsexport file that has 100% complex and custom data, and processing it through the engine systems to make it so you can somehow just “load” your asset and have it apply to in-game systems and logic. This is like how 3D filetypes get introduced, like FBX.
After scouring the source code, and realizing I should look into those basic pre-made filetypes I was looking at as proof it can exist, I found the “GenericAssetHandler”. Turns out, you just need to make a data class and register it with a system component. 2 files, one very basic and can be carried by a premade system component.
You just… create GenericAssetHandler
Holy sh… well awesome. I got it working, I have my custom file type, I can use this workflow for 100 different data assets, and I have the ability to now create profiles, and premade data for pretty well EVERYTHING.
At the end of the day, this is so cool. I now have access to DataAssets for my entire framework. A massive massive gain to my understanding of the engine, and how it can satisfy modern requirements for game development. It’s huge.
So. Just before I put that to rest, I do a huge file cleanup. I created like 6 useless files, and registered the classes all over the systems. Let’s wrap this up, tidy things up, and pass some of this newfound formatting and process I gained over my UI and Unit work back into the GS_Core gem. The whole point of these rapid prototypes were to do exactly this: educate me on how best to handle the systems and processes in order to rapidly improve and modify old systems that were not as fully realized.
And now my asset type doesn’t appear. In fact, the entire Core gem is missing. So all my project levels are breaking due to the absence of components on all the game entities. Come on, WHY?!
I try making fixes, I try rolling back my work, all I get are: “Cannot compile no matter what”, and “Can compile but your entire gem is missing”.
So I continue to roll back work, I continue to edit and change around what I’ve been doing. At this point I lost my entire days work… from like 2 days ago when I was making new work and I wasn’t up ALL night trying to make this thing that worked, work again…
It was a single file reference. Totally indistinguishable. It was included in one file, instead of another.
LOGISTIIIICS! -Shakes Fist in the Air-
I finally break through on the gem, it actually does appear. Phew.
But my asset never reappears…
I continue to make random changes, put a line before another, put a line after another, revert more and more, ask online, ask the bots, absolutely nothing. I try configuring something one way, then convert it back and do another. Absolutely nothing. I cannot make this file work, even though I had it working completely fine before.
So I’m even now comparing line by line with my git comparison of changes. Everything has been either rolled back or is completely inconsequential to the issues I was having. So, as a last-ditch effort, I copied over a “GUID” that was originally set for that file type. A GUID is a “unique to everything else in the system” ID that allows the engine to say “hey I’m using THIS EXACT COMPONENT THAT’S IDENTIFIED BY THIS ID”. I had accidentally lost the number and replaced it with something else later, as, to my understanding, so long as it’s unique to the system, it’s fine. This was an attempt I made after spending like 20 hours problem-solving this. One last-ditch attempt before I reverted everything and started from scratch.
It worked. The file reappeared, and everything worked perfectly. This was literally after I exhausted absolutely every other option I could think of. The sinister part? If I had reverted, and started from scratch, but used the same naming for the file type (which I totally would have done), it likely would have STILL been unable to appear. As the ID was clearly attached to the name of the class. So, unless I thought to call it like “NewInputProfile” it would have continued to be lost.
This was horrific, and a large portion of why this month felt like it was going at a crawl. I kept getting caught in days-long cycles of being completely locked down, not by the content of my functionality, but by the logistical constraints that are necessary to get the content into and working with the system.
Well, now I know some hard truths, and can definitely identify things to check right off the bat next time stuff like this happens.
Okay, sweet, okay, sweet, sweet, I can, I can do my work again?
After I re-create everything I rolled back from my work I sure can! So I did!
I was finally able to dig in again, and work out the path from setting an input profile up to create events from the raw input feed, through to my player controller which is the brain of the player, through to it’s Unit which is the body of the player, and into the input data, then from the input data, into my mover system, and finally into my “FreeMover” component, that is the driver that takes input and drives the unit around in 3D space!
LOOK! LOOOOK! IT HAPPENS!!!
Perfect! I can finally know to expect the data will arrive at my component, and can now get to what I’ll actually do with the input! What a relief. Now I can finally get to making my character move forward, back, left, and right, what a miracle.
And that’s where we find ourselves now!
I have laid the code down for a Grounder, my Free Mover, and as a fun experiment, a slide mover that handles if you’ve walked up too steep a spot. It was a lot of work, filling them all out, but after such an effort, I ended up running out of time for the week and have stopped at the “Does this work in any way whatsoever?” stage of programming. I’ll be returning to that once I send out this Month in Review, actually.
Wrap up time!
So, throughout all this work, despite the overwhelming doubt and struggle, it’s forced me to endure, I have been feeling really excited about everything coming to realization. I am steadily bringing together necessary foundations to making videogames that I’ve been actively stabilizing and modularizing in Unity in the past. I am feeling optimistic and inspired to tackle more of these features to open up the ability for me to put together a small project with the simpler facets of these feature-sets. In fact, I randomly jostled loose a long forgotten little horror game concept I had thought of many years ago, and am feeling the itch to give it a go.
I still have a handful of features I need to prototype before I can get there, but with everything I’ve learned and broken through, I am getting closer to it and am even more excited to learn and grow in my ability to facilitate the creation of these systems. Here’s to being on the up and up!
I am excited for what I’ll be able to report in the June-time Review. I hope you all get to enjoy some of this summer and have your own challenging, yet thriving, month ahead.
Til next time.
In Conclusion
So with that said. I leave you for another month. Looking towards improving everything that has been hitting me, as I can. I have tackled this Month in Review for one. You always gotta keep on keeping on.
I hope you all have a great March! I’ll see you then!