Most of the interactions between entities in an RTS revolve around trading resources between the player, environment, and enemy. If we consider unit hitpoints to be a resource, which causes death when depleted (much like trees when exhausting wood or mines when exhausting gold), implementing HP in the same system as other resources looks like a reasonable thing to do. However, in reality, this turns out to greatly complicate the content pipeline.
There are a number of subtle differences between the default configuration for health, and for other resources an RTS might have. By default:
- When an entity damages another entity, it should not gain the damaged health for itself
- Health should not be transferrable between entities
- There is no global player health (ie. player stockpile for Food/Wood/Gold)
- Armour types dont make sense for other resources
Many of these should be optionally possible, and there are many other behaviours that are shared between the two (animation timing, buffs, range, depletion events). I am not sure of the best approach when dealing with these two similar systems; for this project I am choosing to use polymorphism to expose similar capabilities with different defaults. A base class InteractionAction will provide logic for interacting with a target entity (offering range, action interval, and sub-action logic), with two specialisations for AttackAction and GatherAction, which provide inspector variables and the missing logic.
Eventually I would like to support something like an entity that generates 1 gold for every 2 hitpoints that it deals to an enemy. This will need to be implemented with a 3rd specialisation, CustomAction, which allows arbitrary resource exchanges on various events (perhaps also a boomerang that damages whatever it hits, and heals when it returns?)
Most of the logic for this system takes place in InteractionAction. This class handles moving toward a target, and then repeating an interaction at a set interval (ie. move toward a tree, then “chop” to gather some wood every second). The class internally holds a SubRequest, which is used for the current “stage” (this would first be targeting the tree, but once enough wood is collected, it would then target a resource drop site). It is up to the subclass to override BeginStage to determine the best target for the action (ie. if the unit is already holding its full capacity, look for a drop site, if not, try to mine resources) and call EndStage where appropriate (ie. after the resources were dropped, or after capacity was reached).
The component does not yet support projectile interactions, a nice way to implement them would be to create a new InteractionProjectile component and hold a reference to it in InteractionAction; creating new instances on each NotifyInterval() call, and having it call back to InteractionAction on specific events (hitting enemy, returning to source unit).
As usual, heres a webbuild, and the project files.
The light-blue boxes are resources, dark-blue is a resource drop point, and the other sphere is an enemy that can be attacked.
Things are getting hard to debug without a UI, so I may skip pathfinding and do UI next instead.