I’m going to start a series on building the major components of an RTS in Unity, starting with how to develop a typical framework. RTS games remain one of the most complex and difficult game types to create, dont expect to have anything fancy working for quite a long time.
Most developers looking to build an RTS will be looking to include a multiplayer component. I wont go into a lot of detail, but supporting multiplayer in a game with hundreds of active units constantly doing things in the world is quite difficult; 1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond does a much better job of explaining the typical approach used (though some other approaches also exist). A well designed RTS should have a layer which all input “Commands” pass before interacting with the world; this layer synchronises actions through to the various clients to ensure the world simulates correctly for each client.
An RTS framework will likely involve the following components (and more):
- Entity: Represents the base data that each object within the scene contains (Name, Player, Health)
- Action: Contains logic for an action that an entity can perform
- MoveAction: Take a target location and walk the best path to reach that location
- BuildAction: Invoke MoveAction; when in range, begin construction on a Buildable component
- GatherAction: Invoke MoveAction; when in range, gather resources from a ResourceSite component
- AttackAction: Invoke MoveAction; when in range, reduce the target Entitys Health
- Components: Optional items that augment the way an entity acts
- Sight: Cause this object to reveal the surrounding area
- Buildable: Accept build actions from other entities; when complete, swap for another entity
- ResourceSite: Hold an amount of resource that can be gathered
- Pathfinder: Store terrain information required for pathfinding and provide pathfind query results
- Player: Store information about a player (Name, Colour, Alliances)
- Command: A target and action to be applied to a set of entities
- SceneManager: Handle executing commands in the correct order and at the correct time, and querying for entities
- LOSManager: Hide objects that are out of sight of the player
- SelectionManager: Store and allow interactions of the currently selected entities
- CameraManager: Handle camera movements
- BuildManager: Allows the player to interactively place buildings when a building type is selected
- InputManager: Receive mouse and keyboard inputs and send them to the appropriate manager
To ensure the game simulates correctly on all clients, no gameplay-altering information should ever leak into the entities or their actions/components except through generating Commands. Unfortunately, Unity makes this constraint very difficult to enforce; at any point a script can change the state of an entity or an action can query the Input class and cause a client desync. It is entirely up to the programmer to make sure that never happens.
I’ve created a very basic framework, you can view it online here, or download the project file here:
Its very simple, dont expect much.
This project contains a working Action system, though has only a partially implemented Move action. Entities can be selected by clicking or box-selecting them, they can then be ordered to move by right-clicking the terrain or another entity. Right-clicking another entity will cause the target position to continually update, and cause the entities to follow.
New actions can be implemented in a similar way, and then dragged onto the object via the inspector. An AttackAction may subclass the MoveAction and only run base.Step() when the object is too far away to attack. Once the objects are in range, it can then begin the attack logic. The action with the highest score for a given request is used, thus an attack action returning a score of 2 when targeted at an enemy entity would be used instead of the MoveAction returning a score of 1.