Grecs 1.0.7

dotnet add package Grecs --version 1.0.7
NuGet\Install-Package Grecs -Version 1.0.7
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Grecs" Version="1.0.7" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Grecs --version 1.0.7
#r "nuget: Grecs, 1.0.7"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Grecs as a Cake Addin
#addin nuget:?package=Grecs&version=1.0.7

// Install Grecs as a Cake Tool
#tool nuget:?package=Grecs&version=1.0.7

Grecs

What is this?

It's a thing that does stuff.

How do I use it?

  1. Add the nuget package as a dependency
  2. See code example below
  3. Enjoy!

Code Examples

Setup a Context

The EntityContext is the main state container for Grecs. Generally you only need one.

var context = new Grecs.EntityContext();

Create a System or two

There are two popular systems in Grecs, a Grecs.TickSystem and a Grecs.TriggerSystem

TickSystems are processed every tick, TriggerSystem are only processed in response to Add/Edit/Removal of components from an entity during a tick.

Create Some Components

Components are just sacks of data attached to Entitys, there is some philosophy around what should and shouldn't be a component; but you do you.

For Components to be built effectively and plug in smoothly to the various EntityQuery and listeners you gotta do some weird Property hackery, here's an example:

    internal class Health: Grecs.Component
    {
        private int _maxHealth = 4;
        private int _health = 4;

        // I promise I'll fix this weird syntax (no promises)
        public int MaxHP
        {
            get => _maxHealth; set
            {
                if (_maxHealth != value)
                {
                    _maxHealth = value;
                    // this is key  to allow trigger systems to respond to changes
                    Owner?.TriggerComponentChanged(this);
                }
            }
        }

        public int HP
        {
            get => _health; set
            {
                if (_health != value)
                {
                    _health = value;
                    Owner?.TriggerComponentChanged(this);
                }
            }
        }
    }

Create some Entities


var context = new Grecs.EntityContext();
var someEntity = _context.CreateEntity();
someEntity.AddComponent(new Health {
    Health = 18,
    MaxHealth = 32,
});

Setup a SystemCoordinator

The SystemCoordinator is the coordinator of the systems that run against the EntityContext. In essence this setups up the Entity and Component processing pipeline.

var context = new Grecs.EntityContext();
var gameCoordinator = new Grecs.SystemCoordinator();

// Attach YOUR systems to the coordinator
gameCoordinator
    .Add(new AnimatorSystem())
    .Add(new InputTickSystem())
    .Add(new SlimeSystem())
    .Add(new AttackTickSystem())
    .Add(new MovementSystem(context))
    .Add(new DeathSystem(context))
    .Add(new SkeletonSystem(context))
    .Add(new GraphicsSystem(context));

Run the Systems

Now that Grecs is configured, simple tick the coordinator to process the systems.

var context = new Grecs.EntityContext();
var gameCoordinator = new Grecs.SystemCoordinator();

// ...

// in your update function
gameCoordinator.Execute(deltaTime, context);

Quick word on EntityQuery's

Queries support basic And and Or based on the Component Types, this is most easily explained by example

var query = new Grecs.EntityQuery();
query.And(typeof(Health), typeof(Player));

var context = new Grecs.EntityContext();
// use the query to pull entities
var healthAndPlayerEntities = context.GetEntities(query);

An additional word on Listeners

These are mostly used for trigger systems.

var query = new Grecs.EntityQuery();
query.And(typeof(Health), typeof(Player));

var context = new Grecs.EntityContext();

// create a listener that will react to added or changed Health and Player components (these work due to the funky Component property syntax shown way above)
var healthAndPlayerListener = context.CreateListener(query);
healthAndPlayerListener.ListenToAdded = true;
healthAndPlayerListener.ListenToChanged = true;
healthAndPlayerListener.ListenToRemoved = false;

// ... run Systems, or add, remove, update compoents on entities ...

var addedOrChangedEntities = healthAndPlayerListener.Gather();

Example Tick System

internal class HiTickSystem : Grecs.TickSystem
{
    // Implemented interface function
    public override void Execute(float deltaTime, EntityContext context)
    {
        Console.WriteLine("Hi");
    }
}

Example Trigger System

internal class HiTriggerSystem : Gercs.TriggerSystem
{
    // Constructor required
    public HiTriggerSystem(EntityContext context):base(context) { }

    // Implemented from interface
    public override void Execute(EntityContext context, Entity[] entities)
    {
        foreach(var entity in entities)
        {
            Console.WriteLine($"Hi {entity.id}");
        }
    }

    // Implement from interface
    protected override bool Filter(Entity entity)
    {
        // can do additional filtering against specific entities that are pulled from the listeners
        return true;
    }

    protected override QueryListener GetListener(EntityContext context)
    {
        var hiQuery = new EntityQuery();
        hiQuery.And(typeof(HiComponent));
        var listener = context.CreateListener(hiQuery);
        listener.ListenToAdded = true;
        listener.ListenToChanged = true;
        listener.ListenToRemoved = true;

        return listener;
    }
}

A Full Executable Example

using Grecs;

namespace GrecsExample
{
    internal class Program
    {
        /**
         * A Program that:
         *  - Creates 5 entities
         *  - Updates their Component every frame till it is at or above 5
         *  - Prints the number of components updated every frame
         *  
         * Observations:
         *  - TickSystems run every frame
         *  - TriggerSystems only run when triggered
         */
        static void Main(string[] args)
        {
            // Setup Context and Systems
            var context = new Grecs.EntityContext();
            var gameCoordinator = new Grecs.SystemCoordinator();
            gameCoordinator
                .Add(new HiTickSystem())
                .Add(new HiTriggerSystem(context));

            // create 5 entities with different SomeNumbers
            for(var  i = 0; i < 5; i++)
            {
                var entity = context.CreateEntity();
                entity.AddComponent(new HiComponent { SomeNumber = i });
            }

            // generally you'd get the time between frames, but for simplicty this is hardcoded
            var deltaTime = .016f;

            Console.WriteLine("Let us get this party started.");
            for(var i = 0; i < 15; i++)
            {
                Console.WriteLine($"Tick {i}");
                gameCoordinator.Execute(deltaTime, context);
            }
        }
    }

    internal class HiComponent : Grecs.Component
    {
        private int _someNumber;
        public int SomeNumber
        {
            get => _someNumber; set
            {
                if (_someNumber != value)
                {
                    _someNumber = value;
                    Owner?.TriggerComponentChanged(this);
                }
            }
        }
    }

    internal class HiTickSystem : Grecs.TickSystem
    {
        public override void Execute(float deltaTime, EntityContext context)
        {
            var hiQuery = new EntityQuery();
            hiQuery.And(typeof(HiComponent));

            // get all entities with HiComponents and increase SomeNumber until it reaches 5
            var hiEntities = context.GetEntities(hiQuery);
            foreach (var hiEntity in hiEntities)
            {
                var hiComponent = hiEntity.GetComponent<HiComponent>();
                if (hiComponent.SomeNumber < 5)
                {
                    hiComponent.SomeNumber++;
                }
            }
        }
    }

    internal class HiTriggerSystem : Grecs.TriggerSystem
    {
        // pass associated context to bad Grecs.TriggerSystem
        public HiTriggerSystem(EntityContext context) : base(context){}

        public override void Execute(EntityContext context, Entity[] entities)
        {
            Console.WriteLine($"# of Entites Changed: {entities.Length}");
        }

        protected override bool Filter(Entity entity)
        {
            return true;
        }

        protected override QueryListener GetListener(EntityContext context)
        {
            var hiQuery = new EntityQuery();
            hiQuery.And(typeof(HiComponent));

            // Listent to changes to HiComponents
            var listener = context.CreateListener(hiQuery);
            listener.ListenToAdded = false;
            listener.ListenToChanged = true;
            listener.ListenToRemoved = false;

            return listener;
        }
    }
}

Regular Component vs PooledComponent

Use the Grecs.PooledComponent for any component that is constantly created and destroyed, otherwise extend the regular Grecs.Component

The only functional difference between the two is your options for instantiation. For regular ol Grecs.Component you can new them up, or call CreateComponent on a Grecs.Entity For the Grecs.PooledComponent you MUST use [Your New PooledComponent sub class].GetInstance() for the entity CreateComponent.

Enjoy this small snippet

internal class MyRegularOldComponent: Component
{
    private bool _isDone;
    public bool IsDone
    {
        get => _isDone; set
        {
            if (_isDone != value)
            {
                _isDone = value;
                Owner?.TriggerComponentChanged(this);
            }
        }
    }
}

internal class MyFancyPooledVersion: PooledComponent<PooledIntention>
{
    private bool _isDone;
    public bool IsDone
    {
        get => _isDone; set
        {
            if (_isDone != value)
            {
                _isDone = value;
                Owner?.TriggerComponentChanged(this);
            }
        }
    }
}

/// ... in your instantiation function

var context = new Grecs.EntityContext();

var entity = context.CreateEntity();

// create a regular old component
entity.AddComponent(new MyRegularOldComponent { IsDone = false });

// creating a fancy pooled one, no fancy Object Intializer syntax :(
var c = MyFancyPooledVersion.GetInstace();
c.IsDone = true;
entity.AddComponent(c);


Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.7 105 2/24/2024
1.0.6 82 2/24/2024
1.0.5 84 2/23/2024
1.0.4 89 2/22/2024
1.0.3 89 2/22/2024
1.0.2 90 2/22/2024
1.0.0 108 2/22/2024