Skip to content

A lightweight Entity Component System in a portable library.

License

Notifications You must be signed in to change notification settings

robert-wallis/ECSLight

Repository files navigation

Chat at https://gitter.im/ECSLight/Lobby Build Status

ECS Light

ECS Light is a lightweight Entity Component System (ECS).

The main design principles of this library should allow users to:

  • Favor Composition over Inheritance
  • Seperate Behavior and State
  • Easy to Test, and Refactor your code
  • Enable Clean-Code such as IoC

To that end, ECS Light does not do any code generation. We found that ECS code generators add very little and make developers fear refactoring code.

ECS Light is a portable library so it can be used easily in Unity, MonoGame (XNA), or on a headless server.

We try to avoid forcing the user to use a certain paradigm. Other than the ECS paradigm of course! For example, Contexts are not in a Singleton, therefore a headless server can run multiple seperate contexts. Or two players can play splitscreen with different contexts for each player. The user is of course free to put a Context into a singleton themself. (We think singletons often allow code to violate dependency inversion, making it harder to test.)

We don't claim ECS Light is the prime example of Clean-Code. Surely it violates some SOLID principles.

Please submit a pull-request if you would like to refactor ECS Light into a cleaner, faster, and lighter, library for everyone.

Getting Started

Installing

  1. Download the latest release from https://github.com/robert-wallis/ECSLight/releases.
    • Unity: Place the ECSLight.dll somewhere inside the Assets folder. I put mine in a Assets/ECSLight/ folder.
    • MonoGame: Just add the ECSLight.dll to your References in Visual Studio or Xamarin Studio.

Quick Start

A context is a helper to manage a set of entities, components, and entity sets.

	var context = new Context();

Our example context represents anything in our game world.

You can have multiple contexts, like two game boards in a multiplayer game.

Entities

An entity is just id for some thing in your app.

In ECSLight entities are light objects with easy to access APIs for components.

An entity marks an id of a thing. Like a rock, character, tile, or puzzle piece.

a hero's id

We'll make an entity for a character.

	var hero = context.CreateEntity("The Hero");

You want to use Context.CreateEntity instead of newing up an Entity because the component manager and the set manager need to know when an Entity is destroyed to send the appropriate events and subscribe entities to the appropriate sets.

Components

Entities are made of Components

Our 'hero' needs to be placed in the world somewhere, so he needs a position in the world. Any piece of information, data, about an object is a component in ECS. So let's make a Position component.

class Position {
	public int X;
	public int Y;
}

Notice how Position is just a POD, plain-old-datastructure. And it doesn't contain any logic. Logic belongs in "Systems" in ECS.

Also the X and Y components are integers, this is because our game world has discrete tile locations. If you don't care about this, your game should probably use a Vector2 or Vector3 or whatever makes sense.

Now let's add this Position as a component of the hero.

	hero.Add(new Position {X = 0, Y = 0});

Now the hero is positioned at 0,0. What does that mean?

  • The screen needs to know the position so it can draw the hero.
  • To move the hero we need to know the position.
  • Collision detection needs to know about position changes to see if he triggered a switch.

Those three examples of logic should be seperated from each-other, and they shouldn't be in the Position class. So where do they go?

Systems

Logic is in Systems

Seperating behavior from information helps organize code. In object-oriented programming we are taught to put data in member variables, and logic in functions. In ECS we put data in components and logic in systems. This helps us seperate concerns better while still using OO languages.

ECS Light contains no System specific code, because ECS Light is lightweight.

What if I have a system that needs to act on all entities that have a set of components? Like gravity?

First we'll make a component that tells the gravity system it should use it. Gravity moves floating things, Movable describes the state of things that can be affected by gravity.

class Movable{}

We'll create an EntitySet that is automatically updated with the matching conditions, they must be Movable and have a Position to move.

using ECSLight;
class GravitySystem {
	private readonly EntitySet _movable;
	public GravitySystem(Context context) {
		_movable = context.CreateSet(e => {
			// all entities that are 'movable' with a Position
			e.Contains<Movable>() &&
			e.Contains<Position>()
		});
	}

	// Call this every frame.
	public void Update()
	{
		foreach (var entity in _movable)
			Affect(entity);
	}

	private void Affect(IEntity entity) {
		var position = entity.Get<Position>();
		var newPosition = new Position {
			X = position.X,
			Y = position.Y - 1
		};
		position.Add(newPosition);
	}
}

Why don't we use entity.Get<GameObject>() and update the transform right now? Because other things could update the position too. Like pressing 'up' on the keyboard, an explosion, or a grappling hook. All those things have different 'concerns'. We want to "seperate concerns".

Conclusion

This concludes a quick-start guide on how to use ECS Light.

If you have questions ping me @robert-wallis on gitter.

About

A lightweight Entity Component System in a portable library.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages