Coding isn’t that hard actually. The hard part is to write code that makes sense, is readable and understandable. So I want to get a better developer and create some solid architecture.
So I want to do create an architecture for NPCs in a video-game. It is a Realtime Strategy game like Starcraft, Age of Empires, Command & Conquers, etc etc.. So I’ll have different kinds of NPCs. A NPC can have one to many abilities (methods) of these: Build()
, Farm()
and Attack()
.
Examples:
Worker can Build()
and Farm()
Warrior can Attack()
Citizen can Build()
, Farm()
and Attack()
Fisherman can Farm()
and Attack()
I hope everything is clear so far.
So now I do have my NPC Types and their abilities. But lets come to the technical / programmatical aspect.
What would be a good programmatic architecture for my different kinds of NPCs?
Okay I could have a base class. Actually I think this is a good way to stick with the DRY principle. So I can have methods like WalkTo(x,y)
in my base class since every NPC will be able to move. But now lets come to the real problem. Where do I implement my abilities? (remember: Build()
, Farm()
and Attack()
)
Since the abilities will consists of the same logic it would be annoying / break DRY principle to implement them for each NPC (Worker,Warrior, ..).
Okay I could implement the abilities within the base class. This would require some kind of logic that verifies if a NPC can use ability X. IsBuilder
, CanBuild
, .. I think it is clear what I want to express.
But I don’t feel very well with this idea. This sounds like a bloated base class with too much functionality.
I do use C# as programming language. So multiple inheritance isn’t an option here. Means: Having extra base classes like Fisherman : Farmer, Attacker
won’t work.
2
Composition and Interface Inheritance are the usual alternatives to classical multiple inheritance.
Everything that you described above that starts with the word “can” is a capability that can be represented with an interface, as in ICanBuild
, or ICanFarm
. You can inherit as many of those interfaces as you think you need.
public class Worker: ICanBuild, ICanFarm
{
#region ICanBuild Implementation
// Build
#endregion
#region ICanFarm Implementation
// Farm
#endregion
}
You can pass in “generic” building and farming objects through the constructor of your class. That’s where composition comes in.
7
As other posters have mentioned a component architecture could be the solution to this problem.
class component // Some generic base component structure
{
void update() {} // With an empty update function
}
In this case extend the update function to implement whatever functionality the NPC should have.
class build : component
{
override void update()
{
// Check if the right object is selected, resources, etc
}
}
Iterating a component container and updating each component allows the specific functionality of each component to be applied.
class npc
{
void update()
{
foreach(component c in components)
c.update();
}
list<component> components;
}
As each type of object is wanted you could use some form of the factory pattern to construct the individual types you wanted.
npc worker;
worker.add_component<build>();
worker.add_component<walk>();
worker.add_component<attack>();
I have always run into problems as the components get more and more complex. Keeping component complexity low (one responsibility) can help alleviate that problem.
If you define interfaces like ICanBuild
then your game system has to inspect every NPC by type, which is typically frowned upon in OOP. For example: if (npc is ICanBuild)
.
You’re better off with:
interface INPC
{
bool CanBuild { get; }
void Build(...);
bool CanFarm { get; }
void Farm(...);
... etc.
}
Then:
class Worker : INPC
{
private readonly IBuildStrategy buildStrategy;
public Worker(IBuildStrategy buildStrategy)
{
this.buildStrategy = buildStrategy;
}
public bool CanBuild { get { return true; } }
public void Build(...)
{
this.buildStrategy.Build(...);
}
}
…or of course you could use a number of different architectures, like some kind of domain specific language in the form of a fluent interface for defining different types of NPCs, etc., where you build NPC types by combining different behaviors:
var workerType = NPC.Builder
.Builds(new WorkerBuildBehavior())
.Farms(new WorkerFarmBehavior())
.Build();
var workerFactory = new NPCFactory(workerType);
var worker = workerFactory.Build();
The NPC builder could implement a DefaultWalkBehavior
that could be overridden in the case of an NPC that flies but can’t walk, etc.
2
I’d put all the abilities in separate classes that inherit from Ability. Then in the unit type class have a list of abilities and other stuff like attack, defence, max health etc. Also have a unit class that has current health, location, etc. and has unit type as a member variable.
Define all unit types in a config file or a database, rather than hard coding it.
Then the level designer can easily adjust the abilities and stats of unit types without recompiling the game, and also people can write mods for the game.