Finishing up the Project

This is the last week of this project. Since the beginning of the project and especially after the little crunch to create the intermediate presentation, we booked the whole week to create the presentation. The only leftover I planned into that timeframe was to package the final builds for Windows and Android, and the possibility of appearing bugs in the building process. Unfortunately, we were way off that plan…

Little Things

I will do a quick listing here, to cover most of the little things:

  • Generators’ Blast ability does not destroy its own drones anymore
  • New Drone model implemented
  • Some of the HUD element placeholders got replaced with their proper versions
  • The option to select different drone types got removed from the Mainframe, as we removed every other drone from the scope, expect the Sentry
  • Adding Game Over Conditions for both players
  • Defender’s Energy Pickups only visible by him only
  • Replacing every Billboard by PaperSprites to finally get rid of that Billboard flickering problem
  • Generator Abilities only activate if there is enough energy in stock, also a fail sound was added as a feedback
  • A lot of HUD elements got never initialized at the beginning, only on value changes. The reason for this was that the HUD updates got called only if there was a value change that also got replicated. I am manually calling each of these update functions at startup now.
  • Balancing, balancing, and more balancing… As I knew exactly where to change all values, Rebecca told me what she wanted and I changed the values.

Drone Upgrades

The Defender still missed one of the most important interaction: Upgrading his drones. I had a huge list of upgrades and not enough time to implement them all, so Rebecca and I sat down to prioritize each of the features. She gave them an importance value measured on the impact it will have on the gameplay and I added my cost estimations. Retrospectively viewed, we could have subtracted them from each other and sort it by the result, but I went more or less with my gut feeling.

The first thing, I added to the project, was the Upgrade Menu itself and the Drone Upgrade Component. There are four Skill-Tree-Branches: Durability, Offense, Defense and Agility, each with three different upgrades. The component stores most of the dynamic texts and the current level in each branch. The menu holds one button per upgrade. Each of them consumes a settable amount of upgrade points and to unlock a higher ranked upgrade, the Defender needs to unlock the previous upgrades first.

The next step was to implement each of the upgrades themselves. Some of them were quite easy, like increasing the drones health points or damage. Others were more difficult because most of our components and blueprints were not designed to be altered while playing.
One example is again the health component. Durability Upgrade Level 2 sets the health component to use two health bars instead of one and activates regeneration for each of these bars. I skip the details of that component, as Daniel had probably written about that. Initially, the health bars or segments are generated at that moment the component gets initialized. I had to add code to reinitialize all of these little things while maintaining the original data and apply it to the new status.
The most difficult ones were new features at all, like increasing the detection range. This one was not implemented by Epic. You cannot change the AI Perception Range at runtime in Blueprints. So, I wrote that function in C++ and exposed it to the Blueprints myself. Another example was to give the Sentry Drone an additional melee attack. The attack was really simple, but I had to change the Behavior Tree to be able to unlock different actions, too.
At last, there were some upgrades that would need too much time and were removed from the scope: Adding a homing projectile to the drones, adding a charge/dash that would allow the drone to close the distance for the melee attack, and the “Call Drone” upgrade that would enable another ability for the Generators which allow them to call for help, basically.

Animations

Gina “finished” her animations (is there anything ever finishes when it comes to art?!) and I dedicated some time to implement them. From the programming point of view that would be a task where I can ease myself and relax while working if there weren’t all these “export from modeling software & import to engine” issues. There is this huge list of import options in the engine where I really have no clue what I am doing, not to speak from the ones of Blender but David took care of them. Most of them are not at all self-explanatory. And having to work through all that just destroys my work-flow each time. Sometimes there is a problem with the frame count, with the play rate, with the scaling, with the rotation, with mirroring on different axes, incompatible assets (like the skeleton has changed and therefore the new and old animations aren’t compatible anymore), flipped normals, missing material, frame-skipping, and so on. Does it read like a rant? Well, it is a rant! It cannot be that complicated to align a modeling piece of software with an engine, and I am not talking about the usual “which axis is up” and “is it left or right handed”… and somehow, I am too far away from Blender, Maya and the like, and the modeling terminology to have a clue what is going wrong. 

Besides adding these animations, we wanted to have the grapple always pointing at the magnet. I started to change the animation blueprint to rotate the root bone of the animation always towards the magnet with a “look at” node. That worked fine for the loop-animation but created other issues with the transitions. Due to time constraints, we removed this feature from the scope, again.

The Threat of Plugins

Ozan presented us the final level this week. And the whole team needed to add their specific needs to it: the artists added lighting and such, the designers balanced some distances in the level, etc. For Daniel and me, it was to ensure that the player spawns at the right place, the drones get not stuck, the grapple works at every corner… simply, we went through every aspect of the game.

This new level is bigger than my own test map and by a lot, and it is more vertically oriented than horizontal. At first, I discovered that all of my Environment Querrys weren’t ready to compensate this height difference, but I could work on that. It also demonstrated the problems of 2D EQS running in three dimensions. As the system is projecting all possible nodes onto the ground, the drones were not that likely to use the vertical space.

But one system caught me off-guard at the day before the final presentation: DoN’s 3D Pathfinding Plugin. The whole game got tremendously unstable: the frame rate got spiked regularly and the game crashed nearly every two minutes. Adding more drones to the scene increased the problems, removing them at all removed all the problems. Take a look at the maximum values in milliseconds. Both functions slowed down the game at the same time and adding them up almost equals to one entire second where the engine only perform these two operations.

Fly-To Node

Pathfinding Query

With the profiler’s help, I was able to visualize the amount of the freezes (best to view in fullscreen):

Obviously, I discovered that I hadn’t fixed the issues with the “fly-to” node, I mentioned in Creative Hub. It was still accessing wrong memory addresses. Even after working for many hours, there was no fix to the problem. I rewrote my fail-safe code around the fly-to node several times, but it had no influence at all. The plugin delivers functions which check if a given vector is in the navigatable area and another one that validates if the current agent can navigate to that point. And only if both were true, I hand this vector over to the fly-to node. But still, the engine crashed. I came to the conclusion that both functions may not operate the way I thought they would. Of course, there is no documentation.

The final presentation passed by without a fix and so we went into the showcase, well known that our product will not deliver. The audience that showed up was pretty impressed even with the number of crashes they had to get through, to understand the gameplay, and the team seemed more or less fine. But for me, it became a disappointment, and from there it turned over into frustration. I never spent less time at my own game at a showcase than this time.

As I couldn’t just let it go and ignore the issues, I continued working even after the deadline. Finally yesterday, I was able to improve the stability by much:
– One fact, I could spot was the relationship between the requested path length of a drone and the frequency of frame freezes. Reducing the maximum allowed path length of a drone to 4500 Unreal Units reduced the frame freezes.
– Another breakthrough was the “validate vector” Behavior Tree Task. This task was my fail-safe code, the one that should ensure that it is a correct moving location. It was a child of a sequence and it shared this sequence with the “fly-to” node. Only if this task was successful (meaning it is a valid location) the “fly-to” node gots executed. I converted that task into a Decorator. A Decorator is a requirement or a condition that must be met to allow the attached task to be executed. So I attached this one to the “fly-to” node. I was sure it will result in the same outcome, cause where should be the difference, right?
– The last step was to exchange the navigation mesh with another one provided by the plugin. That one has no boundaries and is not pre-backed, instead, it generates a navigation mesh for every path dynamically.

All three things reduced the probability of frame freezing and negate every engine crash. I did three test runs with twenty active agents and a runtime of more than one hour without a crash.

Summary

  • I always had a bad feeling of using Plugins, especially the ones that are for free and aren’t developed by an experienced person. And this story will definitely not convince me from the opposite.
  • I really like the Unreal Engine. It is closely developed to C++ standards and you can nicely see it by almost every feature of the engine, things like creating a value in a Blueprint and being able to specify it is a private or a public one.
  • Creating a whole game in Blueprints is possible, but there are some exceptions that need to be done in bare C++. Nonetheless, working in Blueprints was fun to do and it felt more like a creative process than working in VisualStudio. Creating code is aiming towards my logical mind, creating a Blueprint is additionally addressing my image processing mind. Every Blueprint has its unique visual appeal and I could remember those quicker than regular code. To me, It looks more like a detailed map with many points of interest to navigate in.
  • The next time I work with this engine, I will definitely go with C++ only, to see how far I can go and to be able to compare development time.
  • Working with AI was just lovely. Sometimes they were behaving wrongly but were so cute while doing so. I had to laugh so often about my own creation.
  • SCRUM, well… I think we will aim for a Post-Mortem-Meeting with Professor Limpach to see where we had our problems and why.