GithubHelp home page GithubHelp logo

morpeh's Introduction

Morpeh

ECS Framework for Unity Game Engine.

  • Simple Syntax.
  • Simple Integration with Unity Engine.
  • No code generation and any C# Reflection in Runtime.
  • Structure-based and Cache-friendly.
  • Reactive and Fast Filters based on bitsets.
  • Built-in Events and Reactive Variables.
  • Single-threaded.

Table of Contents

Introduction

Base concept of ECS pattern

Entity

Container of components.
Has a set of methods for add, get, set, remove components.

var entity = this.World.CreateEntity();

ref var addedHealthComponent  = ref entity.AddComponent<HealthComponent>();
ref var gottenHealthComponent = ref entity.GetComponent<HealthComponent>();

bool removed = entity.RemoveComponent<HealthComponent>();
entity.SetComponent(new HealthComponent {healthPoints = 100});

bool hasHealthComponent = entity.Has<HealthComponent>();

Component

Components are types which include only data.
In Morpeh components are value types for performance purposes.

public struct HealthComponent : IComponent {
    public int healthPoints;
}

System

Types that process entities with a specific set of components.
Entities are selected using a filter.

public class HealthSystem : ISystem {
    public World World { get; set; }

    private Filter filter;

    public void OnAwake() {
        this.filter = this.World.Filter.With<HealthComponent>();
    }

    public void OnUpdate(float deltaTime) {
        foreach (var entity in this.filter) {
            ref var healthComponent = ref entity.GetComponent<HealthComponent>();
            healthComponent.healthPoints += 1;
        }
    }

    public void Dispose() {
    }
}

World

A type that contains entities, components caches, systems and root filter.

var newWorld = World.Create();

var newEntity = newWorld.CreateEntity();
newWorld.RemoveEntity(newEntity);

var systemsGroup = newWorld.CreateSystemsGroup();
systemsGroup.AddSystem(new HealthSystem());

newWorld.AddSystemsGroup(order: 0, systemsGroup);
newWorld.RemoveSystemsGroup(systemsGroup);

var filter = newWorld.Filter.With<HealthComponent>();

Simple Start

Important
For a better user experience, we strongly recommend having Odin Inspector and FindReferences2 in the project.
All GIFs are hidden under spoilers.

After installation import ScriptTemplates and Restart Unity.

import_script_templates.gif

Let's create our first component and open it.

Right click in project window and select Create/ECS/Component.

create_component.gif

After it, you will see something like this.

using Morpeh;
using UnityEngine;
using Unity.IL2CPP.CompilerServices;

[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
[System.Serializable]
public struct HealthComponent : IComponent {
}

Don't care about attributes.
Il2CppSetOption attribute can give you better performance.

Add health points field to the component.

public struct HealthComponent : IComponent {
    public int healthPoints;
}

It is okay.

Now let's create first system.

Right click in project window and select Create/ECS/System.

create_system.gif

Icon U means UpdateSystem. Also you can create FixedUpdateSystem and LateUpdateSystem.
They are similar as MonoBehaviour's Update, FixedUpdate, LateUpdate.

System looks like this.

using Morpeh;
using UnityEngine;
using Unity.IL2CPP.CompilerServices;

[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
[CreateAssetMenu(menuName = "ECS/Systems/" + nameof(HealthSystem))]
public sealed class HealthSystem : UpdateSystem {
    public override void OnAwake() {
    }

    public override void OnUpdate(float deltaTime) {
    }
}

We have to add a filter to find all the entities with HealthComponent.

public sealed class HealthSystem : UpdateSystem {
    private Filter filter;
    
    public override void OnAwake() {
        this.filter = this.World.Filter.With<HealthComponent>();
    }

    public override void OnUpdate(float deltaTime) {
    }
}

You can chain filters by two operators With<> and Without<>.
For example this.World.Filter.With<FooComponent>().With<BarComponent>().Without<BeeComponent>();

Now we can iterate all needed entities.

public sealed class HealthSystem : UpdateSystem {
    private Filter filter;
    
    public override void OnAwake() {
        this.filter = this.World.Filter.With<HealthComponent>();
    }

    public override void OnUpdate(float deltaTime) {
        foreach (var entity in this.filter) {
            ref var healthComponent = ref entity.GetComponent<HealthComponent>();
            Debug.Log(healthComponent.healthPoints);
        }
    }
}

Don't forget about ref operator.
Components are struct and if you wanna change them directly, then you must use reference operator.

For high performance, you can do cached sampling.
No need to do GetComponent from entity every time.
But we will focus on a simplified version, because even in this version GetComponent is very fast.

public sealed class HealthSystem : UpdateSystem {
    private Filter filter;
    
    public override void OnAwake() {
        this.filter = this.World.Filter.With<HealthComponent>();
    }

    public override void OnUpdate(float deltaTime) {
        var healthBag = this.filter.Select<HealthComponent>();

        for (int i = 0, length = this.filter.Length; i < length; i++) {
            ref var healthComponent = ref healthBag.GetComponent(i);
            Debug.Log(healthComponent.healthPoints);
        }
    }
}

Let's create ScriptableObject for HealthSystem.
This will allow the system to have its inspector and we can refer to it in the scene.

Right click in project window and select Create/ECS/Systems/HealthSystem.

create_system_scriptableobject.gif

Next step: create Installer on the scene.
This will help us choose which systems should work and in which order.

Right click in hierarchy window and select ECS/Installer.

create_installer.gif

Add system to the installer and run project.

add_system_to_installer.gif

Nothing happened because we did not create our entities.
I will show the creation of entities directly related to GameObject, because to create them from the code it is enough to write world.CreateEntity().
To do this, we need a provider that associates GameObject with an entity.

Create a new provider.

Right click in project window and select Create/ECS/Provider.

create_provider.gif

using Morpeh;
using Unity.IL2CPP.CompilerServices;

[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
public sealed class HealthProvider : MonoProvider<{YOUR_COMPONENT}> {
}

We need to specify a component for the provider.

public sealed class HealthProvider : MonoProvider<HealthComponent> {
}
Create new GameObject and add HealthProvider.

add_provider.gif

Now press the play button, and you will see Debug.Log with healthPoints.
Nice!

Advanced

TODO

How To Install

Unity Package Installation

  • Add to your project manifiest by path UnityProject/Packages/manifiest.json these lines:
{
  "dependencies": {
  },
  "scopedRegistries": [
    {
      "name": "XCrew",
      "url": "http://xcrew.dev",
      "scopes": [
        "com.xcrew"
      ]
    }
  ]
}
  • Open window Package Manager in Unity and install Morpeh

Git Installation

Add to your project manifiest by path UnityProject/Packages/manifiest.json next line:

{
  "dependencies": {
     "com.xcrew.morpeh": "https://github.com/X-Crew/Morpeh.git"
  }
}

Manual Installation

  • Go to Releases and download latest package.
  • Import Morpeh.

License

MIT License

Contacts

Telegram: benjminmoore
E-Mail: [email protected]

morpeh's People

Contributors

mininaleksandr avatar olegmrzv avatar

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.