Why Changes Needed to be Made to Project Hermes


Improving the Base Game

After some testing of the 1st version of the game, I walked away with many different goals. I narrowed them down to a few most important ones:

  • Reduce Abstractions
  • Add a Moving Camera
  • Improve UI
  • Improve Car Movement
  • Improve Enemy Spawning
  • Do some Rebalancing

Goals

Reduce Abstractions

One of the biggest issues with the first build was that many systems were abstracted.

The Problem with Resource Meters. How the player received resources and how the forward base used resources was only represented by meters. The player’s meter increased, while the forward base meter decreased.

The Problem with Control Meters. “Control” of a region was also abstracted. When the forward base had at least 75% of its capacity of supplies, control increased. When below 25%, control decreased. This system didn’t create a direct connection between the player’s actions and winning the game.

Adding a front line. The first thing that needed to change was the connection between delivering supplies to the forward base and winning. To do so, I created a front line, where the forward base would send tanks. The enemy also had a base, and they would send their own tanks to the front line as well.

The forward base can only spawn tanks if they had enough resources for one.

Adding a rear “base.” The next abstraction was how the player earned supplies. This was a fairly simple solution: a convoy delivers supplies to the player. On a regular schedule, a convoy drops off supplies at the main base, and the player can then use those resources to spawn their own convoys.

Changing Win and Loss. The last change was adding towers at the forward base and the enemy base. If the allies on the front line destroy the enemy towers, then you win! If the enemy destroys the ally towers, then you lose.

Moving Camera

The static camera in the original game greatly limited the size of levels. I added a basic RTS-style camera to allow levels to grow.

I Used a Tutorial. I used a video from GameDevGuide (one of my favorite Unity Tutorial YouTubers) to get started. I added a few additional features, but it basically appears in game as from the video.

Building a Camera Controller for a Strategy Game

Improve Car Movement

I took this too far. This won’t likely last beyond this iteration.

The Problem With Car Movement

My Vehicles Moved Like People, Not Vehicles. This shouldn’t have bothered me, and I should have studied other RTS games. This game isn’t a simulation, so vehicles turning more like people than vehicles isn’t an issue, especially if it allows them to have simple and free movement.

Vehicles Used to Get Stuck On Each Other. I wanted to fix an issue I kept seeing in v0.1 where vehicles would regularly collide head on and then stop moving in the proper direction.

A Waypoint System Would Have Fixed these Issues. And I built one. And it’s great. And yes, it does fix these problems. I just wish I built it first.

How I "Fixed" Car Movement

Every Vehicle In the Game is Now Driven by Physics. This is why I took it too far. I wanted to continue using the built in NavMesh system (to avoid obstacles), but wanted the vehicles to move like vehicles. To do so, I set up an invisible NavMesh Agent object that would move ahead of each vehicle towards the next waypoint. The vehicle would then drive towards the NavMesh Agent using each wheel as a driving force.


They Now Have Collision Avoidance. To keep them from getting stuck on each other, I needed them to avoid colliding with each other. If they did, they would send each other off course and would no be able to correct themselves.

I had to create a system where they looked out ahead of themselves for vehicles, and they would slam on the brakes if they got too close. This doesn’t work all the time, but it works better.

These Vehicles Can Merge. In a desire to allow traffic to merge into the same connection, I wanted them to yield to traffic.

For example, in the forward base, when vehicles arrive, originally vehicles from all destinations would enter a rotary (roundabout for those of you not in New England), drop off their supplies, and exit through the same road they came from.

This required a “right of way” system, checking each vehicle's speed. It later checked how long they had been stopped as well, so vehicles wouldn’t get stuck waiting for a long line of vehicles to pass. I then prioritized specific roads, so those in the rotary would have right of way no matter their speed.

You can see demonstration of the system that I built to allow vehicles driven by physics and the NavMesh will merge into a rotary here: Getting Physics-Based Vehicles to Merge (Unity Game Engine)

As you can see, it works. For the most part.


My Fixes Made it Worse

This is a Sunk Cost Feature. If this system worked with just those features, the fixes would be great. However, it didn’t and required a lot more work.

Vehicles Still Got Stuck. And they still do - although a bit less now.

If vehicles ever hit anything that won’t move, then the vehicle is stuck forever. Play the game for a short period of time, and you’ll likely run into this issue yourself, especially with the tanks that get sent to the front line.


They Also Need to Be Able to Correct Themselves. Even with collision avoidance, there will be times that avoiding a collision isn’t possible or easy. In that case, they need to acknowledge that they are stuck, then reverse, make the necessary turn to avoid whatever got in their way, and move around it.

This Must Be Removed. In order to make this system work reliably, it needs a lot more work. And the system doesn’t add much to the gameplay. If anything, it gets in the way of fun gameplay. Working on it any longer would be a waste of time.

I’m incredibly proud of the work I’ve done on it, but even when I started it I never expected it to get as far as it did. I was shocked that I was able to get it working as well as it did.

That said, I’ll need to remove this system. The system causes more issues than it solves, takes more processing power than the base navigation system, and is too challenging to debug. Cut it!

Waypoints

As mentioned, I created a Waypoint system to guide these vehicles around.

Previous Versions Used A Single Waypoint. In the past, spawned units would drive towards a waypoint halfway along their chosen path. Once arriving, they would then be given a new waypoint at the forward base. After that, they would reverse the process to return to the main base.

This was acceptable for the first iteration, but as roads got more complex the system needed expanding.


I Started with a Tutorial. I once again used GameDevGuide to get started, but went much further beyond his video this time.

Building a Traffic System in Unity

I then expanded the editor tool to rapidly build new complex roads.


A Waypoint Route Tool to Rapidly Build Roads

This is Vital for Future Development. Creating roads quickly has already allowed me to experiment with different road layouts without much effort.

Level design will be much simpler in the future!

Improve Enemy Spawning

Enemy Spawning was Random. The original system was simple: If a player’s unit entered a trigger area, there was a random chance an enemy would spawn.

This Discouraged Players From Favoring One Route. If players split their forces, they would be facing more enemy units, but it would be more manageable than splitting them unevenly. A 75/25 split was often worse than a 50/50, because the 75 would hit so many enemies it would be a challenge, and the 25 would be so weak they could be destroyed by any small number of enemies.

But it Encouraged Players to Use Overwhelming Force On One Route. If players focused solely on one route, completely ignoring the other, then they would be much more likely to succeed - even more so than a 50/50 split.

Rethinking Enemy Spawning

The Enemy Needed to React to the Player’s Route Choices. In order to encourage players to not focus too much on one route, the enemy needed divert forces to the player’s favored route. This would encourage the player to reevaluate their route choices regularly.

Enemies Needed Set Spawn Points. Without set spawn points, the locations they spawned at seemed completely random.

To remedy this, I added Enemy Outposts, which would spawn enemy units and be assigned specific roads they could attack. Spawned enemies would then travel to Ambush Points along their designated route.


I Needed an Enemy Director to Split Resources. The Enemy director would earn resources, and then split those resources among each route. If there were multiple outposts assigned to a route, the outposts would equally split the resources for those routes.


Creating a Formula to React to the Player

I Needed a Formula To Calculate Where to Send Units. This formula needed to account for several things:

  • d =The default percentage of resources that route should get. 
    • Certain roads might be more dangerous for convoys than others, i.e., a mountain path vs. a highway.
  • m = The multiplier that the default percentage should be weighted
  • s = The share (%) of units that have been sent along this particular road
  • t = The total units that the player has spawned
  • L = The maximum number of units we’re tracking to determine which route the player is favoring
    • t and L are to ensure that at the beginning of a level, the enemy split doesn’t shift widely when the player sends out their first unit.
  • a = The result of the formula (the actual percentage of resources this road will receive)

The Formula Looks Like This.

a=(d(m/(t/L)) + s(t/L)) / (m/(t/L)+t/L)

Hopefully, writing it out in code makes it a little easier to digest:

//Determine split by weighing the default split with the player's recent route choices
percentOfSpawnListFull = (totalUnits / maxSpawnedUnitListSize);        // t/L
calculatedPercent = percentOfSpawnListFull == 0 ? 1 : percentOfSpawnListFull;
adjustedModifier = defaultSplitMultiplier / calculatedPercent;       //Get inverse of % to more heavily weight default when less cars
weightedDefault = defaultPercShareOfTotalResources * adjustedModifier;
//Adjust unit share based on the number of units that have been spawned so far
percentShare = totalUnits == 0 ? 0 : unitsTravelledOnThisRoad / totalUnits;
adjustedUnitShare = percentShare * percentOfSpawnListFull;
 
//Normalizer turns everything back into a percentage
normalizer = adjustedModifier + percentOfSpawnListFull;
adjustedSplit = (weightedDefault + adjustedUnitShare) / normalizer;  

Note: I’ve cut out code that is unnecessary for this demonstration.

The Formula Allows Us to Balance Easier. It includes a bunch of variables that we can tweak to create a more dynamic experience. I’m very excited to use this in the future to better control pacing and difficulty.

I plan on expanding this devlog soon with details on improving the UI and creating more dev tools. I also want to discuss the future of the project. I'll update as soon as I can!

Files

project-hermes-v0.2.1.zip 46 MB
Nov 23, 2022

Get Project Hermes

Leave a comment

Log in with itch.io to leave a comment.