I'll just leave here some notes about things that have been left out or I know could've been done better:
-
I used kd-trees due to being a proved solution I used before dropping the previous idea of using spatial hashing. this was mostly done because of time constraints when I ditched the initial struct-based architecture. I think spatial hashing would have been a better solution for memory management and would've solved the evading units problem far better. (I used a collider-based approach there)
-
The launch menu I left out due to time constraints and other priorities. Even if an arbitrary number of armies is supported the army initialization should be done dynamically.
-
Armies center looks skewed but I couldn't figure out the problem even if the calculation looked right to me.
-
the Projectile could be improved with some generalization / decoupling.
-
some distance calculations between units and their targets could be cached between the UnitMovementComponent and the UnitCombatComponent.
-
Some animation logic could be decoupled from the unit components, and thinking about it now separating health / damage logic into separate components would have been better and cleaner.
-
I'm sorry if the commits are pretty messy at the beginning, but I ditched the first two architectures completely and I had to re-think it from scratch (more or less).
It was a wild ride, but fun indeed!
In this simulator, armies of varying units and sizes will battle using a set of very simple AI strategies.
This is the simulator entry point, in which the following options can be set per army:
- Warriors amount
- Archers amount
- Strategy type
Then, there's the "launch" button that will put the user on the battle phase.
In this phase, the two armies will fight for victory. The battle will start according to the options selected at the launch menu.
- Units can't overlap other units
- To avoid too much dispersion, units must be at least 80 meters close to the center point of all units
- All units have attack, speed, and defense values. When any unit attacks, the hit formula
is
defender.health -= attacker.attack - defender.defense. - Any unit must not move distances that surpass its own speed on a single frame.
- All units have attack cooldown values. Any unit can't attack if the cooldown value is above zero.
- If health falls under zero, a given unit dies.
- When all the units for a given army dies, a ending menu is instantiated. This menu will have a button that can get the user to the launch menu to start a new simulation.
Armies are composed by the following unit types:
| Attribute | Value |
|---|---|
| Attack range | 2.5 meters |
| Attack cooldown | 1 second |
| Attack amount | 20 pts |
| Health | 50 pts |
| Defense | 5 pts |
| Attribute | Value |
|---|---|
| Attack range | 20 meters |
| Attack cooldown | 5 seconds |
| Post-attack delay | 1 second |
| Attack amount | 10 pts |
| Health | 5 pts |
| Defense | 0 pts |
Special rules: When the archer attacks, it spawns an arrow that flies in a straight direction and impacts the target
from a distance. After the archer attacks, it has a postAttackDelay attribute that prevents further movement for its
given time.
There are only two strategies that are outlined below
Basic
Any Unit will just pick the nearest enemy, and advance to it. It will attack as soon the enemy falls within
its attackRange attribute.
Defensive
Any Unit will just pick the nearest enemy, and advance to it. Warriors will back off when their attackCooldown > 0.
Archers will try to get as far as possible but within their attackRange. If any enemy unit gets too near the Archer,
the Archer will try to move away but at the same time circle its foe.
