Friday, April 13, 2018

Unreal Engine Experiments: Dishonored's Blink Ability

Around a couple of months ago, I finally managed to finish Dishonored. I had tried playing it a couple of times in the past but got turned off both times by the starting section of the game, which I still think is one of the weakest parts of the game. Even though it was very clearly trying to make the player develop an emotional attachment to one of the primary characters, it felt more like a chore to me. The protagonist was obviously close to the said character, but none of that resonated with me as a player who was completely new to this world. I was more interested in exploring the world, with its huge whale hunting ships and a new and original setting, but I had to go through a linear and uninteresting gameplay section. Frankly, I'd rather have the game take me sooner to the scripted story sequences before throwing me into the first real mission. But leaving that aside, after having played the game through to completion, I can definitely say that the experience did get a whole lot better once the world opened up and gave me a chance to explore and study its various intricacies. However, what really made the game stand out for me was its Blink ability and the game does not wait long to present it to the player.

Once you get access to the ability, a whole new array of gameplay possibilities become open to you. It's essentially a single gameplay mechanic tailored towards multiple types of gameplay styles. You can become an explorer, navigating the tallest buildings to the deepest alleyways with the sort of freedom of movement not usually allowed in games (when you factor out the crawling through vents design). Or you can choose to play like a ninja, appearing suddenly from the shadows to strike his opponent, only to disappear again in an instant. If you prefer a more aggressive playstyle, the Blink also provides the player with a tool to quickly close the distance to opponents before plunging a blade into their throats. To be honest, it is the closest I've come to feel like an anime character in a first-person game, moving swiftly across the battlefield, taking down his opponents with finesse. And as is usually the case when I get excited about something like this, I had to learn how it works and recreate it on my own. Fortunately, it didn't just end up as another entry in the backlog of cool experiments to do, and I actually got around to working on it soon.

I first started out with studying the ability to look for any hints of design that could be visible under close inspection. First and quite easy to notice was that it wasn't a teleport ability, The player character was being moved to the targeted destination, while visual effects play out on the screen. With my extremely limited knowledge of materials and VFX, the only effect obvious to me was the field of view modifications. And that would have to do. I was far more interested in the working of its physical movement system.


Upon further inspection, I came across a more obscured design choice. The game was not using a line trace for the targeting system. This can be easily noticeable when using the ability near waist-high walls. If the aiming direction is only slightly above the wall, it will display the target location right in front of the wall. So it seems that a sphere trace (or some other simple 3D shape) is being used to ensure uninterrupted movement to the destination.



So with a basic idea of how things might be working under the hood, I began work on the implementation. The first task was to just move the player towards where the camera was being aimed at. The built-in 'Move Component To' function took care of this requirement. I added a couple of timelines to change and revert the field of view values during the process. Already by this point, I could easily dart around the map using the ability.


Next up on the itinerary was the targeting system. Again my intention here was not to spend time on making effects that looked exactly like its original inspiration. Instead, I was going for something along the lines of a basic cylinder mesh having a gradient material with its transparency increasing along the +z direction. Again my limited experience working on materials became an issue here. Fortunately, after scrounging through a few pages on the net, I came across a solution that did exactly what I wanted. With the gradient material setup, I just needed to move the target display actor based on the results of a sphere trace that ticked at regular intervals.


Now, all that's left was the wall scaling system. I already had a placeholder system that used the 'Launch Character' function to propel the character up the wall when necessary. However, it was too slow and felt out of sync when used in conjunction with the swift Blink movement. And I wasn't really sure how to get it right. Another idea that came to my mind was to use linear interpolation along a parabolic curve to the top of the wall. I wasn't particularly fond of the idea and was hoping it wouldn't come to that. Fortunately, I tried out the 'Move Component To' node again in this scenario and it actually worked out quite well. That was all the confirmation that I needed to go ahead with the implementation.

First, I added a check to see if the obstacles encountered by the targeting system fall into the category of 'walls'. If yes, then I followed it up with a line trace to determine the distance to the top of the wall as well as to confirm that the wall meets the minimum thickness requirement. If both cases return satisfactory results, a further sphere trace is performed from a calculated point just above the top surface of the wall, in the upward (+z) direction to ensure the availability of free space for the player character to stand upright. If this condition is satisfied as well, a direction pointer gets displayed to convey that the character will automatically scale the wall along the said direction after the Blink movement. With the wall scaling mechanism already in place as mentioned earlier, the ability was finally working as intended to the fullest extent.


With all of the required features working in tandem, all that was left was to clean up the code. A new custom actor component was created to house the Blink execution logic. This freed up the player character to handle only the input controls and a few simple interface functions that control the field of view. The use of this component driven design should allow the ability to be linked to new player characters quite easily.

I must say that it felt really good to work on something that can pretty much be classified as finished. It's a huge contrast to my normal work on the toolkits, which I consider to be continuously evolving projects. So I'm excited to keep working on more of these small offshoot projects. Meanwhile, the source code (blueprints) for the Blink ability project has been published on GitHub. Feel free to check it out at:  https://github.com/RohitKotiveetil/UnrealEngine--BlinkAbility

Thursday, April 5, 2018

FPS Tower Defense Toolkit v3.1 Dev Log #3: Performance Optimizations

In the first part of the v3.1 dev log series for FPS Tower Defense Toolkit, I had briefly covered the process of adding support for multiple power cores. While the implementation itself required only minor modifications to the existing systems, it did introduce an additional layer of expensive nav path calculations. This caused a visible dip in performance when using multiple powers cores, and as a result, I had to spend more time focusing on optimizations before releasing the update.

Since the new performance issues arose as a direct result of the additional navmesh updates, it made sense to try and reduce the cost of these operations. While contemplating on what to do in that regard, I remembered an old Unreal Engine live stream session with Mieszko, in which he talked about the various recast navmesh parameters that were exposed to the editor. So I went ahead and checked it out again with the hopes of scavenging something that could be useful in the current scenario. And fortunately, It seems that decreasing the 'Tile Size UU' attribute of the recast nav mesh reduces the amount of nav mesh area that needs to be rebuilt at runtime. Since the tower placement operations essentially modify only a small part of the navmesh at any instant, I reduced the tile size to bring down the number of calculations required. The 'Cell Size' parameter was also increased in order to improve performance at the cost of nav mesh resolution, as was mentioned in the video.


Next up on the list was rendering optimizations. The grid cells used for tower placement were basically planar meshes with a masked grid material applied to them. Since having lots of masked materials across the map can be taxing on the rendering system, I replaced them with a square window frame shaped mesh that uses a basic unlit material.


The next area for cutting costs came in the form of memory optimizations. Static Meshes within Unreal Engine have an attribute 'HasNavigationData' that determines if it is necessary to save collision data for navmesh calculations. But it happens to be the case that most static meshes used within the context of the toolkit do not interfere with the navmesh. Even the tower bases, being one of the few exceptions that impact the underlying nav mesh, use custom nav modifier volumes to create impassable regions. So it made sense to turn it off wherever not required, and thus save memory on collision data.


Now onto the final optimization. While I had some idea about the benefits of all the above three cases, the next one was completely new information to me.

During the tower construction phase before a wave, navigational paths between enemy spawn points and their linked power cores are evaluated in order to ensure that a valid path exists for the AI bots. Since this is a continuous operation, I was looking for ways to make it more efficient. A couple of ideas did cross my mind, but they would require major alterations to the holographic tower display system. Not wanting to delay the update any further unless absolutely necessary, I was searching for other alternatives. And that was when I stumbled upon a thread from the Unreal Engine forums with a potential fix for the issue. As per the instructions posted in the thread, I added the 'Enable Recalculation on Invalidation' node while calculating nav paths and set it's 'Do Recalculation' enum to No. It basically prevents the 'Find Path to Location Synchronously' function from automatically recalculating the path points if the previously calculated path gets invalidated due to changes in the underlying navmesh. And fortunately, coupled with all the other measures, the toolkit was back to its functional state again.


With that, we've reached the end of this dev log. As mentioned earlier, I think there's still room for cost-cutting within the holographic tower display system. But it might require some major changes to the system and hence I'm pushing it onto the next update. Apart from that, there are a couple of bug fixes making it into this update. More details about the same will be posted as part of the v3.1 changelog in the Unreal Engine forum support thread.

As a final note, I'd like to point out that the primary focus of the v3.x series of updates is to bring improvements to the following three facets of the toolkit: the wave spawning systems, AI logic, and visual design. So these areas will keep getting a lot of attention over the course of next few updates. However, the idea of adding support for multiple cores was something that I got from the Unreal Engine community and was not part of the planned features. And I'm really glad to have someone point it out. So if anyone has any feature requests that they think will increase the value of the toolkit, feel free to reach out to me with the same.

Wednesday, April 4, 2018

FPS Tower Defense Toolkit v3.1 Dev Log #2: Improvements to the Weighted Wave Spawning System

The v3.0 update of FPS Tower Defense Toolkit introduced the concept of a weighted wave spawning system. As part of the dev log for the same, I had covered potential methods for improving the system in the future. And one of those plans was to provide designers more control over when different types of AI start making their appearance over the course of a level.

The Weighted Wave Spawn Controller in its native form enabled automated generation of wave spawn patterns based on weighted probability distributions. By controlling the weightings for different AI classes, one could create randomized wave patterns using this system. It employed a system that ensured that only units with a certain threat rating relative to the active wave's threat rating will be allowed to spawn. Coupled with the option to specify if a certain type of unit could be spawned during a mission, it provided some amount of control over the randomness of the system.

However, a limitation still existed in the form of not being able to precisely determine when different types of units would start spawning. In order to negate this issue, I added a new parameter 'SpawnStartingFromWave:'.


If the 'CanBeSpawned?' parameter is set to true, then the spawn controller will now check for the new condition as well, thus providing designers with a tool to control the changes in wave constituency over time. I think this new feature will greatly increase the viability of using the weighted wave spawning system. And with that, we've come to the end of this dev log. The next and final v3.1 dev log will go over optimizations and bug fixes that will make it into the final release.

FPS Tower Defense Toolkit v3.1 Dev Log #1: The Introduction of Multiple Power Cores

[Minor Spoilers ahead: The opening paragraph goes into minor spoiler territory on the story of Sanctum 2]

The ending of the third act of Sanctum 2 marks a pivotal point in its story-driven campaign. Players are finally presented with the reason behind recent waves of coordinated attacks against human settlements and outposts by the planet's native life forms. However, that's not the only thing that makes it interesting. The final mission of the chapter, titled Abandoned Lab is one of the only two maps from the base game where players are tasked with defending multiple cores. The inclusion of an extra core in these maps added a completely new layer of challenge as tower placement needed to be balanced along two paths that couldn't be merged. Having two cores to protect also presented a situation that required the players to split up their team in order to defend multiple paths to the cores, especially during later waves when powerful enemies start advancing against both cores simultaneously. I've found myself returning to this map quite a few times even after I finished the main campaign. Since the FPS Tower Defense Toolkit was inspired by Sanctum 2, adding support for multiple cores was among the features planned for the first round of post-release updates. But due to more pressing feature requests, it got sidelined. And that remained the case for quite some time, until recently, when a customer brought up the idea again.


So that got me thinking again about integrating support for multiple cores into the toolkit. To give people the power to design their own versions of the iconic Abandoned Lab. After going over the rough design plan, I realized that it would barely require any changes at all. The core idea would be centered around creating a link between enemy spawn points and power cores. All AI bots spawned from a specific enemy spawn point will receive directives to set the linked power core as their prime target.

To start with the implementation, I added a new variable to the BP_EnemySpawnPoint class for storing a reference to its linked Power Core. The variable was then publicly exposed so that this link could be easily set up by the designer directly from the editor.


The next thing to consider was to give the AI bots access to this information. This is necessary because the player can pull enemy units from their standard paths. If the bots later lose interest in the player, they should be able to return to the core assigned to them. And that required making some modifications to the Enemy AI Manager class.

The Enemy AI Manager class keeps a dynamically updated list of all entities that can be targeted by the enemy AI bots. Until now, this list included only the power core and the player character. So I made some slight alterations to ensure that references to all the power cores get placed at the top of the array. The underlying reason behind doing so is to have static references to the cores within the list. While the player character can get destroyed during a wave, the indices of the core will remain constant irrespective of changes made to the list at runtime. Due to the static nature of these indices, individual AI units can use the index of their assigned core to fall back to their primary objective whenever required. After making a few more minor changes within the AI blueprints to reflect the aforementioned design alterations, the AI was completely capable of functioning within the updated feature set.



With that, we've come to the end of this dev log. Stay tuned for the next update where I'll go through the process of making improvements to the weighted wave spawning system.

Saturday, March 10, 2018

Playing with Colors: Catalog I

A couple of weeks ago, I posted an article going into an in-depth account on the process of revamping the visual design of FPS Tower Defense Toolkit. As part of the said process, I experimented with various color schemes before finally settling on something that helped establish the theme of a virtual playground.

Perhaps due to this new experience, and partly as a result of a series of problems that pushed my life in various unexpected and adverse directions, I started looking at things from a whole array of new and exciting perspectives. And thus I stumbled upon the beautiful realm of color theory. So it was about a week ago, that I started toying with the idea of experimenting with different color schemes on a daily basis. Today marks the eighth day of this new experimental chapter, and I decided to archive my various forays into the unknown on a sort of weekly basis. I'm not exactly going with the idea of doing it on any specific day of the week, but rather having one catalog for every seven experiments. So today I present to you the first article of the new Playing with Colors series.



Colors: #ff0000 + #ffffff


Colors: #ff0000 + #000000


Colors: #ffff00 + #000000


Colors: #00ff00 + #0da6ff


Colors: #00ffff + #ff2c2c


Colors: #ffff00 + #00ffff


Colors: #6ead3a + #efedef + #254558

That's all there is for this week. As mentioned above, a new catalog will be published after the next seven experiments. Meanwhile, you can follow me on Twitter for a daily dose of color combination shots.

Saturday, March 3, 2018

FPS Tower Defense Toolkit Tutorial: How to create a new level

1. First, ensure that the default Game Mode & Game Instance class parameters in the Project Settings are set to BP_GameMode & BP_GameInstance classes respectively.

2. Now create a new map, open it, & lay down the floor meshes. Add a Nav Mesh Bounds Volume & extend it to encapsulate all the floor meshes. This will enable AI bots to traverse across the level.


3. Add a Lightmass Importance Volume around the core game space.


4. The next step is to add instances of BP_EnemySpawnPoint to act as spawning volumes for the enemy waves. As can be seen in the next screenshot, I've added a couple of spawn points in my level:




5. Now add a BP_PowerCore actor to the level in order to provide the primary target for the enemy AI bots.




6. The toolkit uses modular grid generators to act as platforms for tower placement. But before adding them to the scene, first, add a BP_GridManager actor. The Grid Manager determines the size of individual grid cells across all grid generators in the level through it's publicly exposed variable 'GridCellSize'.




7. With the grid cell size specified, it's now time to add the grid generators. Drag & drop instances of BP_PlanarGridGenerator into the level. The overall size of the generator in the X & Y (local space) directions can be specified through the 'GridCountX' & 'GridCountY' variables as shown below:




8. Now add an instance each of BP_ProjectileManager & BP_ObjectPoolManager into the level. If you plan to use the pooling system, just set 'PoolPlasmaProjectiles?' to true through the details section of the actor. Since this system uses a fixed size pooling system, also make sure to specify the pool size through the 'PoolSizePlasmaProjectile' variable.




9. The next step is to add an instance of BP_EnemyAIManager. It will tackle the responsibility of keeping track of potential targets for the enemy AI bots. While the target acquisition and response logic are handled directly by the bots themselves, the Enemy AI Manager aims to provide them with all the necessary information in that regard.


10. Now comes two of the most important classes required for the functioning of the toolkit: the Tower Manager and Wave Spawn Controller. Add the BP_TowerManager actor first. There's no need to make any changes to its default parameters, but if you're interested in knowing more about the class, check out the concept overview post for the same at: https://forums.unrealengine.com/unreal-engine/marketplace/50583-fps-tower-defense-toolkit?p=647339#post647339

Next, add an instance of either BP_BatchedWaveSpawnController or BP_WeightedWaveSpawnController to the level. While most of the default parameters will work right out of the box without any need for customizations, you will have to add references to the enemy spawn points within the publicly exposed array 'BatchedWaveSpawnDataArray', if you're going for the former model. Just make sure to specify the 'SpawnPoint' parameter for each wave by linking it to one of the spawn points added to the level in Step 4.


For further reading about the wave spawning systems, see:

11. Now onwards to the final step. All that's left to do is to add level bounds so that actors like projectiles that can move across the level gets destroyed once they cross a certain threshold. Add six BP_LevelBounds actors along the outer periphery of the level, making sure that they form a cuboid shape to encapsulate the entire level.



With that, you should have a fully functional level at your disposal. If you have any queries regarding the workflow, feel free to let me know in the comments section.

If you're interested in the toolkit, you can purchase it through the Unreal Engine Marketplace: https://www.unrealengine.com/marketplace/fps-tower-defense-toolkit

Friday, March 2, 2018

FPS Tower Defense Toolkit Basics: Weighted Wave Spawn Controller

The FPS Tower Defense Toolkit comes equipped with two different types of wave spawning models: one centered around user-defined wave patterns, and another geared towards generating waves based on weighted probability distributions. I covered the former of the two in an earlier article. You can read more about it here: FPS Tower Defense Toolkit Basics: Batched Wave Spawn Controller. Today I'm going over the design of the second model: the Weighted Wave Spawning System.

The WeightedWaveSpawnController is intended to provide the designers with a tool capable of generating waves of AI bots in an automated manner. Unlike its contemporary, which requires the designer to explicitly specify each and every aspect of the wave, we have a system here that spawns units based on a weighted probability distribution. This approach essentially allows us to control the spawn probabilities of different AI classes based on the weights associated with them.

Another factor that helps with the automation process is the threat rating attribute, which keeps increasing with each subsequent wave. As the threat rating goes up, it opens the door for spawning high tier enemies. Meanwhile, the number of low tier enemies may go up as well. Both of these factors together increase the overall difficulty of the game over time.

To aid in the functioning of these systems are a host of variables that can be customized directly from the editor. I will go through each of those attributes one by one and briefly explain their individual functionalities:


1. WeightedWaveSpawnData: Controls the shifting dynamics of waves through the following parameters:
  • NumberOfWaves: Determines the total number of waves.
  • TowerBaseResourceAllocation_BaseValue: The number of towers bases to be distributed to the player per wave.
  • TowerBaseResourceAllocation_StartingBonus: Bonus tower bases to be provided to the player at the start of a level.
  • TowerPointResourceAllocation_BaseValue: Tower points to be distributed to the player prior to the first wave.
  • TowerPointAllocation_LinearGrowthMultiplier: The number of tower points to be distributed to the player keeps changing based on a linear function. This parameter controls the growth rate of tower point allocation with each new wave.
  • WaveThreatRating_BaseValue: Threat Rating of the first wave. Determines the starting difficulty of the level.
  • WaveThreatRating_LinearGrowthMultiplier: The wave threat rating increases with each new wave based on a linear function. This parameter controls its growth rate and thus provides an estimate of how fast the difficulty rises up as the player progresses through the level.
  • SpawnInterval_MinValue: Minimum duration between spawning of individual bots.
  • SpawnInterval_MaxValue: Maximum duration between spawning of individual bots.
  • MaxUnitToWaveThreatRatio: Restricts the types of units that can be spawned in a wave based on the ratio of their threat rating to the wave threat rating. Only AI classes with these ratios less than or equal to this parameter will be spawned. As a result, this feature can be used to prevent high tier units from being spawned during the initial waves.
2. AISpawnWeightingDataArray: Enables setting of the spawn weights, with each element of the array used to represent the spawn probability data about an individual AI class. Each element of the array contains the following attributes:
  • AIType: An enum that defines the AI model.
  • BaseWeighting: Controls the spawn weight of this AI class. Higher values relative to other classes increase the spawn chances, while lower values reduce it.
  • CanBeSpawned?: Determines if this AI type can be spawned. Can be used to control/restrict the types of enemies present in different levels.
  • DataTableRowName: Connects the AI class with the associated row in the DT_EnemyAIStats data table. [No need to explicitly specify this as it will be set automatically by the wave spawn controller]
3. NumberOfWaveCycles: Not applicable to this model. Used by Batched Wave Spawn Controllers to repeat wave patterns.

4. TimedWaveStarts?: Determines if new waves will start automatically after a designated amount of time. If turned off, the player will have to manually trigger new waves.

5. WaveTimerInterval: If TimedWaveStarts? is set to true, then this parameter controls the time interval between waves.