8 min read
Making a Survivors-like with Latios Framework Part 6

If by any chance you are reading this article and are currently hiring for a game programmer position, especially with some DOTS and Latios experience, do not hesitate to contact me!

Making a Survivors-like with Latios Framework Part 6

Well, it took me a while to get back to this, but here we are, the final (?) part of the series!

The other articles were like a “Tour of Latios Framework” while I was learning it. This one will be less “code focused” and more “chatty” because a lot of things happened since the last article and I haven’t used other Latios’ features (like Unika, Calligaphics, etc.) in this part.

The Brain is a Weird Organ

After the last article, I had a pretty blurry idea of what I wanted to do next. I knew it had to have an health mechanics that would lead to implementing a “lose condition”.

I started with gathering some SFXs for when the player gets hit, setup some health bar HUD, add a rough attack animation to the skeletons, added a “death” animation and “death SFX” to the player, and then… I kinda felt burnt out.

This kind of feeling is not uncommon for me, especially when working alone on a project. I’m definitely not a solo dev kind of person and I don’t feel like a Game Designer.

Picking between two mutually exclusive features to implement is always a struggle for me. It kinda feels arbitrary despite all the books on game design I read. I guess it is due to not having another team member to bounce ideas off of, or not having a creative vision for the game.

The Sidequests

Without even noticing it, I took a break from the main project and started working on some sidequests.

The first one was that I didn’t like the way my flowfield pathfinding implementation was working. I’m pretty sure there was more efficient ways to do it but, at that time, I was reading blog posts from Recast-Detour’s author Digesting Duck and I was wondering if I could implement a “NavMesh” system powered by Latios Framework.

Building a navigation mesh is a pretty complex task with multiple steps, according to the Recast Navigation documentation.

Here are the steps performed by Recast:

1. Figure out how big the raster voxel grid will be based on the input geometry bounds.
2. Voxelize the input geometry
3. Clean up the voxel data and filter out non-walkable areas
4. Consolidate the voxel data into a more compact representation
4. Further refine the voxel representation
5. Triangulate the navmesh polygons from the voxel data
6. Package the mesh with additional metadata that's useful at runtime.
7. Cleanup

That felt quite a daunting task and I probably didn’t need dynamic obstacles or anything like that in my game. So I investigated the possibility of using a simpler approach : using Unity’s NavMesh.CalculateTriangulation to generate a mesh from the scene geometry and bake the results with Latios’ SmartBlobber.

I’ll skip the details of the implementation, but I ended up with a working navmesh pathfinding solution that I called Navigator. It has been integrated into Latios Framework official Add-ons repository, and that makes me really happy!

As a long term goal, I’d love to have a more complete solution that would allow for baking and updating the navmesh at runtime.

”Stupid Boids”

Since I was already working on a pathfinding solution in a separate sandbox project, I wanted to see if Navigator could handle a big number of agents.

Keeping in mind that this sidequest might end-up into the Survivors game, I started Sidequest nb2: “Stupid Boids”, a simple flocking behavior implementation as a standalone feature. The idea was to have the agents follow a crowd-like behavior.

Navigator + Stupid Boids = Good enough

The Brain is a Weird Organ (Part 2)

The brain is a weird organ but, sometimes, I forget that I know how some things are supposed to work up there.

After a few weeks of working on sidequests, I was afraid I would never get back to the main project. I was mostly afraid that I would have lost the motivation to work on it, or that I would have forgotten how to do it.

I gave it a try anyway, and I was surprised (again) to see that it was even easier to get back to it than I thought. I was even faster than before at implementing features and this break gave me a fresh perspective on the project.

That’s how the learning process works, I guess. It needs time to process the information, digest it and come up with new, fresh perspectives.

Quick Fixes

I realized that something fundamental felt wrong with the game: your average Survivors-like does not have rigid bodies physics. The player is able to move through the enemies at the cost of taking damage. Why?

  • Getting stuck by a horde of enemies is not fun.
  • Getting pushed around by enemies is not fun.
  • It removes the fun of the “reversed bullet hell” aspect of the game: dodging enemies is fun!
  • It makes the game feel more like a “hack and slash” than a “Survivors-like”.

So I removed the rigid bodies from the player and enemies, integrated the Navigator system to handle the enemies’ pathfinding, and added the flocking behavior to the enemies while removing the flowfield pathfinding implementation I had.

Closing the Loop

Health Mechanics

I was finally able to implement the simple health mechanics I had in mind. The player has a health bar that decreases when hit by an enemy, and the game ends when the health reaches zero.

It then displays a “Game Over” screen with the option to restart the game or quit.

Game Over screen

Game Over screen

Experience and Leveling Up

An important aspect of Survivors-like games is the experience and leveling up mechanics.

To gain experience, the player has to kill enemies. When dying, an enemy can drop an “XP Cube” or an “Healing Orb”.

I chose to keep it simple, for now, by not adding new abilities. Instead, when the player levels up, perks are displayed (randomly pick from a pool of perks) and the player can choose one to apply.

I only implemented 3 of them but the system is there, so it can be easily extended later on.

  • A Health Increase perk
  • A Movement Speed Increase perk
  • A Axe Size Increase perk
Level Up screen

Level Up screen

Win Condition

The last thing I wanted to implement was a win condition.

I kept it simple: the player has to survive for a certain amount of time (5 minutes, configurable) to win the game. When the time is up, a “Game Over” screen is displayed with the option to restart the game or quit. It also displays the number of enemies killed.

You Win screen

Win screen

Result

Play

Latios Survivors - Final-ish Result

Where to go from here?

I’d like to call this project “done” for now. Still, there are a lot of things that could be improved or added.

For example:

  • a second type of enemy, a ranged one, would spice things up a bit.
  • a “boss” enemy that would spawn after a certain amount of time.
  • a second skill. I was thinking about a “defensive-attack skill” with a cooldown that would allow the player to cast a shield that would orbit around him and damage enemies that touch it.
  • a better level design… This one is not my cup of tea.
  • bugfixes, performance improvements, more juice, etc.

Conclusion

This project was a great way to learn Latios Framework, its features and chat with the amazingly supportive community around it.

Latios Framework is, in my opinion, one of the greatest open source Unity frameworks out there.

  • It is well documented
  • It has a great community
  • It is constantly being improved by its author, Dreamin I’m Latios.
  • It is packed with features that you would mostly find in paid solutions
  • It’s free and open source!

Using DOTS without Latios Framework, now, feels like a chore: Where’s my explicit system ordering?! How do you even animate a character without Kinemation?! Why Unity’s entities.physics is so slow?!

If you want to try it out or have a look at the code, you can find the 6th part of this project on GitHub Latios Survivors Part 6.

If I had to do it again, I would probably do a lot of things differently, but it was a learning project… and I learned a lot! I had a lot of fun (and tears) doing it!

Bye!