This week’s iteration includes improvements to unit routing AI.
As our churn metrics improve, and more website visitors reach the title screen, it behooves us to pivot our investment back into gameplay, where numerous deficiencies (big and small) exist. For example– unit routing and bunching. Play Life’s a Beach for a couple minutes and you will notice some issues with enemies– they tend to bunch up, stand atop one another, and take inefficient routes. Debugging such issues may be complicated, so let’s invest in a…
The previous few weeks of improvements to our landing page and load times were spurred by an improvement in our measurements and analytics in those areas. Likewise, our first step in improving gameplay should be to establish a more formal and rigorous measurement, analysis, and verification approach for gameplay-related problem areas.
Currently, in order to test changes to gameplay, the player must wait through an entire game load, menu navigation, stage navigation, then an intro cutscene– far too slow. We need the ability to launch gameplay within seconds, and spawn in any unit or tower at any time. We need the ability to buff certain units with cheats such as infinite health so we may keep units around long enough to study how our AI, attacks, etc are playing out over a long fight. We need the ability to adjust (and persist changes to) testbeds such that we may test our technologies in diverse environments (and create unit tests out of them to prevent regression). Put differently, we need flexibility when it comes to controlling and experimenting with gameplay
Fighting games, which live-and-die by their gameplay and controls, almost always have a dedicated, customizable testbed (often a training mode or practice room)
In the current iteration of Life’s a Beach, a system called the GameplayManager takes responsibility for spawning enemies in waves defined in the cloud config spreadsheet, running the stage intro cutscene, spawning the player’s posse, spawning initial currency, monitoring victory and defeat conditions, etc.
Note that none of these things are really necessary for testing basic gameplay mechanics (such as routing, teams, attacks, projectiles, etc). While we do need to eventually spawn units to test combat, we certainly don’t need to spawn them in a spreadsheet-defined way. Why can’t we just click a block and say “spawn 5 of unit type X on team “enemy” at this location?
Our new basic gameplay testbed
In our current engine, every block “tile” that forms the ground is its own GameObject. As it turns out, we may re-use our existing “affordance” system that allows us to easily make any GameObject interactible via the mouse, spawning menus and executing arbitrary logic. In the gif below, the new testbed already has a couple nice (if a bit clumsily-accessed) features–
- Every sheet in the config is searchable via the menus automatically, from units to towers to items and more.
- Diving deep into a sheet allows each “entity” (item, unit, tower, etc) within the sheet to be spawned from its ID.
Thanks to a new “Spawn Here” affordance, spawning objects on tiles is mostly easy
While functional and flexible, this isn’t a convenient setup yet due to the amount of menu-diving necessary. It would be much nicer to have these menus be context sensitive, or anchorable to a side of the screen, such that we could change which tile we want to spawn a unit at without closing all of our menus. Convenience / usability improvements like this are critical for the testbed’s future, as the more we enjoy using something, the more it will be used, and the more investment it will receive over time. A mighty level-editor could have many positive impacts down the line, including potential player-usage for custom area creation and modding.
For now, this basic testbed is enough to help us with…
Routing Improvements : Boids Separation
Combat in Life’s a Beach is just about as vanilla as you can get, lacking much of the spice (from abilities to environmental funelling) of popular action RPGs.
Currently, when a fight breaks out there is no value in strategically positioning yourself. In the movie 300 (and in the actual historical event), the tactical value of forcing a chokepoint at the narrow “hot gates” helped mitigate the Spartans’ numerical disadvantage.
In a game like Diablo, a large tactical advantage may often be gained by positioning oneself near chokepoints (hiding behind a single-tile door, standing in a corner, etc) and preventing enemy units from surrounding the player. While this advantage goes out the window a bit when ranged units are present, the idea that enemies cannot stand atop one another to fight you could be a powerful tweak to combat depth.
Any units on the same team will try to move away from one another if close. Poor crab.
While enemies may now be blocked by other enemies (positioning matters), the simplicity of their AI is now more obvious, with units failing to route around blockages.
Boids separation is a very simple rule that produces nice results locally, but may fail globally as seen above. Ideally, units should notice when their progress has been impeded, and should begin attempting other directions to find a new route towards their destination. We may do this by…
- Taking the “separation push” vector that causes our units to stay away from allied units…
- Check how different this “separation push” vector is from the original intended direction of this unit…
- If pushback is negating most of the unit’s desired motion, perform a cross product on the separation push vector and the global up vector to get a “shuffle direction” vector that points us around the blockage.
The result is the following slightly-more-intelligent behavior. While somewhat ugly due to rendering-order issues, units may now shuffle to find an opening of attack. Someone call PETA.
As a result of these changes to combat, it is now practical to hole up in a corner during fights–
A common desperation strategy in games like Diablo is to hole up and limit enemies’ angle of attack.
As we may see above, the player unit is no longer taking damage from all directions at once– only two enemies (two crabs at that) may engage. The dangerous goose enemies are held at bay, where the player’s towers could chisel away at their health and hopefully pick them off. The end result– the environment and stage earns just a bit more consideration than it used to, deepening the moment-to-moment gameplay a tad.
- Routing has been upgraded– units will now run in straighter lines when possible, even when they cannot see their target, rather than sticking to grid-based / “manhattan” movement.
A new routing visualization tool was also produced to help us understand where a unit wants to eventually be (cube), what its planned path is (dots), and where its next straight-line target is (capsule).
As seen in the gif above, the unit will now try to take as many straight lines as possible, sometimes skipping nodes in the planned path. The end result is a small improvement in routing efficiency for units. They come across as slightly more intelligent during gameplay.