Code Monkey home page Code Monkey logo

relecs's Introduction

RelEcs

A lightweight and easy to use entity component system with an effective feature set for making games.

World

// A world is a container for different kinds of data like entities & components.
World world = new World();

Entity

// Spawn a new entity into the world.
Entity entity = world.Spawn();

// Despawn an entity.
entity.Despawn();

Component

// Components are simple classes.
class Position { public int X, Y; }
class Velocity { public int X, Y; }

// Add new components to an entity.
entity.Add<Position>().Add(new Velocity { X = 1, Y = 0 });

// Get a component from an entity.
var vel = entity.Get<Velocity>();

// Remove a component from an entity.
entity.Remove<Position>();

Element

// Elements are unique class-based components that are attached directly to worlds.
class SavePath { string Value; }

// Add an element to the world.
// You can only have one element per type in a world.
world.AddElement(new SavePath( Value = "user://saves/"));

// Get an element from the world.
var savePath = world.GetElement<SavePath>();
Console.WriteLine(savePath.Value);

// Remove an element from the world.
world.RemoveElement<SavePath>();

Relation

// Like components, relations are classes.
class Likes { }
class Owes { public int Amount; }

class Apples { }

var bob = world.Spawn();
var frank = world.Spawn();

// Relations consist of components, associated with a "target".
// The target can either be another component, or an entity.
bob.Add<Likes>(typeof(Apples));
//   Component ^^^^^^^^^^^^^^

frank.Add(new Owes { Amount = 100 }, bob);
//                            Entity ^^^

// You can test if an entity has a component or a relation.
bool doesBobHaveApples = bob.Has<Apples>();
bool doesBobLikeApples = bob.Has<Likes>(typeof(Apples));

// Or get it directly.
// In this case, we retrieve the amount that Frank owes Bob.
var owes = frank.Get<Owes>(bob);
Console.WriteLine($"Frank owes Bob {owes.Amount} dollars");

Commands

// Commands are a wrapper around World that provide additional helpful functions.
Commands commands = new Commands(world);

// You *do not* need to create your own commands.
// They will be automatically provided for you as the System.Run(Commands) argument.

Query

// With queries, we can get a list of components that we can iterate through.
// A simple query looks like this
var query = commands.Query<Position, Velocity>();

// Now we can loop through these components
foreach(var (pos, vel) in query)
{
    pos.Value += vel.Value;
}
        
// You can create more complex, expressive queries.
// Here, we request every entity that has a Name component, owes money to Bob and does not have the Dead tag.
var appleLovers = commands.Query<Name>().Has<Owes>(bob).Not<Dead>();

// Note that we only get the components inside Query<>.
// Has<T>, Not<T> and Any<T> only filter, but we don't actually get T int he loop.
foreach(var name in query)
{
    Console.WriteLine($"{name.Value} owes bob money and is still alive.")
}

System

// Systems add all the functionality to the Entity Component System.
// Usually, you would run them from within your game loop.
public class MoveSystem : ISystem
{
    public void Run(Commands commands)
    {
        // Query desired components.
        var query = commands.Query<Position, Velocity>(); 
        // Loop over queried of components.
        foreach(var (pos, vel) in query)
        {
            pos.Value += vel.Value;
        }

        // You can also access the entity within the loop.
        var query = commands.Query<Entity, Position, Velocity>();
        foreach (var (entity, pos, vel) in query) =>
        {
            pos.Value += vel.Value;
            // Example: "Tag" a component to show that it has moved.
            entity.Add<Moved>();
        }
    }
}

Running a System

// Create an instance of your system.
var moveSystem = new MoveSystem();

// Run the system.
// The system will match all entities of the world you enter as the parameter.
moveSystem.Run(world);

// You can run a system as many times as you like.
moveSystem.Run(world);
moveSystem.Run(world);
moveSystem.Run(world);

// Usually, systems are run once a frame, inside your game loop.

Triggers

// Triggers are also just structs and very similar to components.
// They act much like a simplified, ECS version of C# events.
class MyTrigger { }

// You can send a bunch of triggers inside of a system.
commands.Send<MyTrigger>();
commands.Send<MyTrigger>();
commands.Send<MyTrigger>();

// In any system, including the origin system, you can now receive these triggers.
commands.Receive((MyTrigger e) =>
{
    Console.WriteLine("It's a trigger!");
});

// Output:
// It's a trigger!
// It's a trigger!
// It's a trigger!

// NOTE: Triggers live until the end of the next frame, to make sure every system receives them.
// Each trigger is always received exactly ONCE per system.

SystemGroup

// You can create system groups, which bundle together multiple systems.
SystemGroup group = new SystemGroup();

// Add any amount of systems to the group.
group.Add(new SomeSystem())
     .Add(new SomeOtherSystem())
     .Add(new AThirdSystem());

// Running a system group will run all of its systems in the order they were added.
group.Run(world);

Example of a Game Loop

// In this example, we are using the Godot Engine.
using Godot;
using RelEcs;
using World = RelEcs.World; // Godot also has a World class, so we need to specify this.

public class GameLoop : Node
{
    World world = new World();

    SystemGroup initSystems = new SystemGroup();
    SystemGroup runSystems = new SystemGroup();
    SystemGroup cleanupSystems = new SystemGroup();

    // Called once on node construction.
    public GameLoop()
    {
        // Add your initialization systems.
        initSystem.Add(new SomeSpawnSystem());

        // Add systems that should run every frame.
        runSystems.Add(new PhysicsSystem())
            .Add(new AnimationSystem())
            .Add(new PlayerControlSystem());
        
        // Add systems that are called once when the Node is removed.
        cleanupSystems.Add(new DespawnSystem());
    }

    // Called every time the node is added to the scene.
    public override void _Ready()
    {
        // Run the init systems.
        initSystems.Run(world);   
    }

    // Called every frame. Delta is time since the last frame.
    public override void _Process(float delta)
    {
        // Run the run systems.
        runSystems.Run(world);

        // IMPORTANT: For RelEcs to work properly, we need to tell the world when a frame is done.
        // For that, we call Tick() on the world, at the end of the function.
        world.Tick();
    }

    // Called when the node is removed from the SceneTree.
    public override void _ExitTree()
    {
        // Run the cleanup systems.
        cleanupSystems.Run(world);
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.