October '20 Update

Published November 07, 2020
Advertisement

Hope everyone had a fine Halloween and is looking forward to Thanksgiving (at least for those in the US).

Recap

  • A refactor of the time tracking gameplay
  • A custom event node that would auto-register for events
  • Build out the framework for the research/tech tree gameplay

Overall I got everything done and a few bonus things. I was especially happy with how the custom blueprint node came together.

Results

Calendar Refactor

Not really much to say here. It was a pretty straight forward separation of functionality from one class to another. Most other systems where interacting with that gameplay through events anyway so it was mostly include fixes so that they could see the event type information when compiling.

Custom Event Node

So this is what the normal event registration looks like:

It's really not that bad, even if the delegate hookup is a little more annoying in blueprint than it is in C++. However it does become a little more annoying when 1) there's quite a few of them and 2) the act of listening lasts for the entire lifetime of the listener.

When that second condition is satisfied I was able to simplify the whole thing down to this:

In addition to being simpler, I was also able to solve a slight annoyance I've always had with the blueprint registration regarding the event type. Because of the way the delegates work (currently) the delegate expects a function with a generic UEventData parameter. In native, I'm able to register functions with the actual event type as the parameter instead. This means that every blueprint event handler has to start off with a cast even though that cast is guaranteed to succeed. Well, since the event type is “built-in” to the custom node and the fact that it is a custom node I could build the cast right into it and the Event Data parameter coming out of the auto-registration node is already the right type.

I also learned a lot more about the blueprint nodes. For starters you'll notice that the auto node has a slightly cleaner node name. The subtitle changes as the event type and window properties are changed, but the main name is not. This is not the case for the regular registration (something I've added to by backlog to address across all my custom nodes). I was also able to figure out how to make it look and behave as close to the UE4 Events as I wanted so they event show up in the UI listing similar to events:

The node is also limited to the Event Graphs since placing them inside of a function graph doesn't make any more sense for these nodes than it does for UE4 Events.

Implementation wise there were a few layers to this. First I needed a hook to know when a new object was created. In theory that hook exists on every object, but I very specifically didn't want to force any sort of “register auto events” call. So this was the engine tweak I suspected I would have to make came in. I added delegates to UE4's Core Delegates structure for: Object creation/destruction, Actor Begin/End Play, Widget Construct/Destruct and ActorComponent Begin/End Play. This allows my Event Manager to register as a third party to be informed when any of these object lifetime events occur. Since the object creation callback would happen even for Actors, Widgets and ActorComponents, I had to had a little bit extra on the Event Manager side to ignore those types and instead do the registration work when the other delegate happened. I didn't build it into the delegate for two reasons: 1) the point at which the object delegate occurs, it doesn't/can't know about any of the other three types because of the modules organization and 2) the fact they should be ignored is because of how the Event Manager wants to match event registration with lifetimes and not anything inherent with the delegate.

Next I created a structure type that would allow me to recognize a very specific form of function in the object's class reflection information. I went with a custom structure not used for anything else so that I was 100% sure that the function existed for this purpose. There's no other reason why anyone would have a function with it in the parameter list. Once I recognized the function, it was pretty easy to call it. My Event Manager already did that as part of it's dispatching to event listeners.

Next was the custom node. Most of the node came together pretty fast. It's not too much different from the other custom node that I've made. It did take a little while to find all the bits I needed to steal from Epic's nodes in order to make it behave the way I wanted throughout the UI.

Lastly, because walking through the reflection for every single object that is created would be mostly useless, I also created an interface that does, well, nothing. The only purpose of the interface is to act as a sort of token that this class supports automatic event registration and that it's worth processing it. I considered making it do something, but those notions where all scuttled by annoying issues with blueprint implementations of the native interface. Plus the desire to avoid a “register events” function that had to be called by the object.

As a bit of an aside: I've been really happy with power and utility I've been able to add to my project by making these custom nodes. I'd even go so far as to say it's one of the most useful skills I've picked up in UE4 and that anyone that's doing C++ code in UE4 would benefit from it. Because of that I was really surprised when I got a response from Epic (in response to a developer portal question regarding some trouble I was having with a node at work) along the lines of: “Our game teams don't really do that.” How could you not! While I will grant that the nodes generated for blueprint callable native functions is pretty good, a custom node can be way more user friendly. I should probably try my hand at a writing a tutorial here for you all…

Tech Tree/Research Gameplay

I got pretty far with this, the only thing that is really missing is the ability for the technology to actually do anything when they are researched. This was because I identified as minor refactor to how state changes are supported in my data objects that I figured I should tackle first. You can read about that in the next section. There was nothing technically interesting with the implementation, but there's a lot to the design side so that what I'll describe. I think the description will sound a whole lot more complicated than it will play just because a lot of it is automated book keeping. I'll start from sort of the bottom of how it all works.

  • At the very bottom are the two forms of Research: Technologies and Refinements. These are the things that the player directly researches and would be most comparable to the class Tech-Tree research from other games (Civilization especially). Technologies unlock new gameplay like ship construction or new weapons and equipment. Refinements are improvements and bonuses to existing gameplay (construction bonuses, damage bonuses, research bonuses, etc). In both cases they can have other Research as prerequisites. How the prerequisites are treated will vary a little, but not in a really significant way. The main difference between the two is that Technology research is a Project, as in it takes time to complete. Refinements on the other hand are instant and require the other strategic resources (like money or metal) to complete.
  • I don't expect the Technologies and Refinements to create a complete tree of interconnected Research. What I expect to happen is for there to actually be a bunch of disconnected chains of research, maybe with some minor branching. For example there would be one chain that progresses the player through ship construction. Each additional stage of Research requires the previous one to be completed first. There would also be a chain of research that progresses the player through improvements in shield generation technology (for example). Neither chain is connected to or influencing the other.
  • Without a full tree to control pacing and limit research options a little I'm trying something that might be a little weird. Each piece of Research is a part of a Research Branch, like Math or Biology. At the moment I'm looking at having 6 Branches to lean into the whole hex motif. As the game progresses you'll apply research progress to each branch. This research progress is separate from and occurring in parallel to research being done to complete Technologies. You'll have a certain amount of “points” (or whatever they're really called in the game) to distribute across the branches and as time passes, those points will translate into research progress. I think of it as if the Branch research is blue sky or theoretical research and the Technologies/Refinements are the more practical or applied research.
  • Eventually when you accumulate enough points you “complete” the branch. At this point two things happen:
    1. based on the branch level, what has been research and what is available to be researched, a new collection of Research is made available
      • It does this through another points system. Each branch level generates a random point value in some range for that level. Each Research option has a point cost. A collection of Research is made available where the point cost of the collection is equal to the random value generated.
      • Because of the randomness inherent in the system, this point system is meant to reduce the “disappointment” of getting less exciting technologies by giving you more of them at the time. Ideally no technology should be disappointing to get… but that's not really how the brain works.
    2. based on the number of times you've completed that branch level (and some other minor factors) there is a chance that the Branch will increase in level.
      • Increasing in level does a couple things, makes existing Branch Research cheaper to be made available and adds Research for that level to the pool of Research the Branch can make available in the future. The cost decrease over time is meant to make it easier to back-fill the tech tree as the game progresses considering how random this stage of research can be.
      • The chance is meant to go up over time so (right now) if you “complete” the branch 10 times you're guaranteed to level up the Branch.
  • So there's sort of this dual crank system to the Branch research. You turn Branch progress gear and each time it completes a rotation, it spits out new research and it might turn the larger Branch level gear.

Of course all this could be for naught! It seems like it could be interesting mechanically but until I get it fleshed out with non-placeholders it's all just theory. Worst case the whole Branch research doesn't work out and I've got to trim it down to just the regular research and build a more traditional technology tree.

One major goal here was to, not prevent exactly, but at least reduce bee lining through technologies. The Civ6 approach is interesting, randomizing the tech tree but that just changes what the line is, not the existence of the line at all.

It's also worth noting that this approach is only intended to be directed towards player progress. This isn't meant to be a Civ-like experience where all the players may or may not be people. It's meant as a more XCom approach where the game is becoming more challenging and research is how you keep pace. So I'm not worried about having to write an AI that can understand, plan and exploit this model of technological progress.

Bonus: State Effect Refactor

So since I punted on making the Research actually do anything, I decided to do a quick refactor of the State Effect objects. These are the usual pattern I've found to work pretty well with UE4 of instanced objects. A cross between the strategy and command pattern. A while back I'd already done a refactor that split off the feature set of affecting tiles to a derived type. This left the State Effect with the ability to apply to a variety of targets (source, owner, target, extra targets). But while considering how the effects would work that would be executed from Research, many of those things didn't make a lot of sense.

So I inserted another layer so that now I have State Effects (source & target), Tactical Effects (+owner, +extra targets) and Tactical Tile Effects (+primary tile, +extra tiles). All my existing effects became Tactical Effects (if they weren't already a Tile Effect) and tactical things like Weapons were updated to have a collection of Tactical Effects instead of just State Effects.

Bonus: Asset Validation

While working on the Research Branches and Research I was trying to add in a bunch of asset validation. It was mostly fine using UE4's MessageLog construct. The only real downside is that MessageLog 1) only works in the editor and 2) was only happening on Editor startup (because the validation existed in an override of PostLoad). I had tried to mitigate #1 by having an #else branch that output to the log and while this worked it wasn't going to be particularly visible to anyone starting the game. So I did a few things:

  1. Create a new virtual Verify function as part of the base Data Definition type that I use for almost all my static data.
  2. Hook up the Verify function so that it's called for any Data Definition on PostLoad.
  3. Hook up the Verify function so that it's called at game startup.
  4. Create a library of asset check message functions that wrap up the MessageLog+Log pattern.
  5. Replace the Log part of that pattern with Redscreens. A redscreen will log the message but it will also so a UI so someone will know that something is wrong.
  6. It turned out that the game startup checks weren't working quite the way I wanted them to because they would be triggered before there was a way to show the UI elements. So I inserted a queuing system that would allow the messages to persist until the UI was possible and then show all the queued messages.

The double messaging I think will work out nicely. Anything I forget/break between sessions will be caught and brought to the fore on Editor startup. Anything I've broken while in the Editor will show up as a Redscreen the next time I run the game. In addition, because of the way the messages work, when I close the game the MessageLog pops back up and I get a full reminder list of all the failed asset checks that occurred.

I know there's some UE4 functionality for asset validation. I haven't looked into it too much, but the little I have it didn't seem to fill all my requirements. But it did seem to be something I could easily layer on top of what I've built if I wanted to do automated asset checking through a commandlet or something.

Bonus: Tech Debt Items

I was able to address a few minor debt issues when I wasn't really feeling like moving onto the next big thing. This time I address some event handling issues and some gameplay. I had a couple of events that weren't really being handled where they should be. The turn ruleset (a FSM that maintains the overall turn sequencing one would expect in a turn-based game) was doing some gameplay checks that it really shouldn't. At the time I wrote it, I didn't really have a better place to put it, but now I've got the Tactical Script and those checks belong there. There was also a weird event type for a weird edge case used to signal things to other (mostly UI) systems. I basically replaced the event with two less weird events and placed them in ways to not have the edge case in the first place. Lastly I addressed an issue (or a bug) where the rules would think that a ship had no actions left when it actually did. This mostly came down to rules not looking at all the information it could. I was deciding based on Movement Points and Energy, which is usually fine. However one of the weapons, the Plasma Bolt, only requires energy to charge and not to actually fire. So if you had ammo for that weapon, but no more energy (because you used it all to charge it) and no more movement the game would cycle your selection to the next ship (or worse end the turn). Now the checks are a little more generic to prevent this sort of thing now with the Plasma Bolt and (hopefully) in the future with other weapons.

Bonus: Side-Side Project

The cliché hobby development: not finishing anything and starting up lots of projects. That is not what I'm hoping to have happen here. I have more than enough on my todo list to keep work on SRPG. However one of the things I've been looking at is my code organization. Currently I've got two plugins and the SRPG game project. I'd like to break at one of those plugins up into multiples in the case of games that don't really need everything that it provides. However that's a little tough to actually reason about with only one “customer”.

To that end, I created a new UE4 project to implement the card game Race for the Galaxy. It's one of my favorites and I've messed around with implementing it before as a text interface. This is meant to be approached more of as an exercise than a project that would ever be released. Kind of like programming blackjack or chess. The goal with it is mostly to clarify some of my assumptions about what is and isn't as portable as I might think. And I'm implementing an existing game because it does make it an implementation exercise. I want all my Designer Brain focused on SRPG. I have more than enough Engineer Brain for an extra little project like this.

I've really only gotten the very barebones skeleton of the project setup with all the UE4 game modes and huds and maps and blueprints to be able to compile and launch an empty map with a message on the hud. Most of the speed of that (did it in a single evening) is probably because of UE4 itself (and my increased familiarity with it) but going forward I expect my plugins to pull more weight with getting this going. I've also fleshed out the collection of objects I'm pretty sure I'll need (it's really not that many: a player, a deck, a couple types of cards), but none of them do anything yet.

November Goals

  • Implement Verify in existing Data Definition types
    • Now that I've got some way to bring configuration problems to the fore, I need to make a pass through all my static data types and add an implementation of the Verify function. Some of the types already have some validation checks, but the new way is better so I'll convert those over. Some don't have any validation so I'll need to decide what constitutes a configuration error for those types.
  • Another custom blueprint node
    • I need to write a custom node to wrap one of the functions that is available for accessing by cache of game state data. The UFUNCTION markup alone doesn't give me the sort of usability features for how I want that function blueprint node to work.
  • Research Effects
    • This is the bit that I punted on for October in order to do the State Effect Refactor. The overall function of Tech Research “works”, but only within the narrow scope of Research. This will give the Technologies and Refinements a way to manipulate the state of the game when they are completed.
    • I've also been working mostly with placeholder data that won't translate into anything in the final game. So as the use case for the first set of game modifications I'll create the research chain that will be used to unlock ship construction as the game progresses.
  • Research UI
    • As seems to by the pattern, now that I have the gameplay for research working it's time to put a front-end on it. I've been testing with various console commands, but that obviously isn't a long-term solution.
  • Whatever I decide to distract myself with in the Race for the Galaxy side-side project

The combination of the Thanksgiving holiday and the ongoing pandemic means that I'll actually have a week of vacation this month that I may be able to devote quite a bit of time to my project. Something may happen the day of, but there'll be no travelling or sight seeing or any of the other things that my girlfriend and I usually get up to for that holiday.

Because of the timing of this blog vs the actual end of the month, I've actually already finished the first two and am well on my way with the Research effects. UI has always seemed to take longer than I expect it to, so it'll be good to have at least the second half of the month to work on that. At least that part of the month has my Thanksgiving vacation for some extra time.

Previous Entry September '20 Update
Next Entry November '20 Update
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement