Skip to content

Instantly share code, notes, and snippets.

@Fejuto
Last active November 10, 2018 07:50
Show Gist options
  • Save Fejuto/1dbdcca27a2d25ce3c08bcf2d83d59b7 to your computer and use it in GitHub Desktop.
Save Fejuto/1dbdcca27a2d25ce3c08bcf2d83d59b7 to your computer and use it in GitHub Desktop.
/////////////////////////////////////////////////////////////////////////////////////////////////
// Our team's new way of writing systems using CompositeSystem.cs (attached in this gist) //
// Is functionally the same as the ReactiveSystem below. Keep reading to learn how it works. //
/////////////////////////////////////////////////////////////////////////////////////////////////
public class UpdatePositionSystem : CompositeSystem {
public UpdatePositionSystem(Contexts contexts) : base(contexts){
AddInitialize(() => {
// Do initialization stuff
});
AddReactEach(GameMatcher.Position, true, e => {
// Do stuff with changed entities. e.hasPosition is garuanteed to be true
});
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// How you are used to writing a system. A lot of boilerplate. FeelsBadMan //
//////////////////////////////////////////////////////////////////////////////////////////
public class UpdatePositionSystem : IInitializeSystem, ReactiveSystem<GameEntity> {
Context _context;
public UpdatePositionSystem (Contexts contexts) : base(context.game) {
_context = contexts.game;
}
public void Initialize() {
// Do initialization stuff
}
protected override Collector<GameEntity> GetTrigger(IContext<GameEntity> context) {
return contexts.CreateCollector(GameMatcher.Position)
}
protected override bool Filter(GameEntity entity) {
return entity.hasPosition;
}
protected override void Execute(List<GameEntity> entities) {
foreach (var e in entities) {
// Do stuff with changed entities. e.hasPosition is garuanteed to be true
}
}
}
///////////////////
// Full API demo //
///////////////////
public class DemoSystem : CompositeSystem {
public DemoSystem(Contexts contexts) : base(contexts) {
AddInitialize(() => {
//init
});
AddExecute(() => {
//execute
});
AddCleanup(() => {
//cleanup
});
AddTeardown(() => {
//teardown
});
///////////////////////////////////////////////////////////////////////
// Each AddReact call adds a ReactiveSystem in the backend. //
///////////////////////////////////////////////////////////////////////
//react to GroupEvent.Added.
//true means autoFilter which filters all entities not matching with the matcher. false means all entities pass.
AddReact(GameMatcher.Position, true, entities => {
foreach(var e in entities) {
//react. e.hasPosition is garuanteed to be true
}
});
//custom filter
AddReact(GameMatcher.Position, e => e.hasPosition, entities => {
foreach (var e in entities) {
//react
}
});
AddReact(e => e.hasPosition, entities => {
foreach (var e in entities) {
//react
}
}, GameMatcher.Position.AddedOrRemoved(), GameMatcher.Name.Removed());
//lower level; you are unlikely to need this
AddReact(contexts.game.CreateCollector(GameMatcher.Position), e => e.hasPosition, entities => {
foreach (var e in entities) {
//react
}
});
////////////////////////////////////////////////////////////////////////////////////////////
// Each AddReact has a AddReactEach variation which saves you from writing a foreach loop //
////////////////////////////////////////////////////////////////////////////////////////////
//react to GroupEvent.Added.
//true means autoFilter which filters all entities not matching with the matcher. false means all entities pass.
AddReactEach(GameMatcher.Position, true, e => {
//react. e.hasPosition is garuanteed to be true
});
//custom filter
AddReactEach(GameMatcher.Position, e => e.hasPosition, e => {
//react
});
AddReactEach(e => e.hasPosition, e => {
//react
}, GameMatcher.Position.AddedOrRemoved(), GameMatcher.Name.Removed());
//lower level; you are unlikely to need this
AddReactEach(contexts.game.CreateCollector(GameMatcher.Position), e => e.hasPosition, e => {
//react
});
}
}
using System;
using System.Collections.Generic;
using Entitas;
public class CompositeSystem : Systems {
IContexts contexts;
public CompositeSystem(IContexts contexts) {
this.contexts = contexts;
}
public void AddInitialize(Action initialize) {
Add(new InlineInitializeSystem(initialize));
}
public void AddExecute(Action execute) {
Add(new InlineExecuteSystem(execute));
}
public void AddCleanup(Action cleanup) {
Add(new InlineCleanupSystem(cleanup));
}
public void AddTeardown(Action tearDown) {
Add(new InlineTeardownSystem(tearDown));
}
public void AddReact<TEntity>(IMatcher<TEntity> matcher, bool autoFilter, Action<List<TEntity>> execute) where TEntity : class, IEntity {
AddReact(matcher, e => !autoFilter || matcher.Matches(e), execute);
}
public void AddReact<TEntity>(IMatcher<TEntity> matcher, Func<TEntity, bool> filter, Action<List<TEntity>> execute) where TEntity : class, IEntity {
AddReact(GetContext<TEntity>().CreateCollector(matcher), filter, execute);
}
public void AddReact<TEntity>(Func<TEntity, bool> filter, Action<List<TEntity>> execute, params TriggerOnEvent<TEntity>[] triggers) where TEntity : class, IEntity {
AddReact(GetContext<TEntity>().CreateCollector(triggers), filter, execute);
}
public void AddReact<TEntity>(ICollector<TEntity> collector, Func<TEntity, bool> filter, Action<List<TEntity>> execute) where TEntity : class, IEntity {
Add(new InlineReactiveSystem<TEntity>(collector, filter, execute));
}
public void AddReactEach<TEntity>(IMatcher<TEntity> matcher, bool autoFilter, Action<TEntity> execute) where TEntity : class, IEntity {
AddReact(matcher, autoFilter, entities => entities.ForEach(execute));
}
public void AddReactEach<TEntity>(IMatcher<TEntity> matcher, Func<TEntity, bool> filter, Action<TEntity> execute) where TEntity : class, IEntity {
AddReact(matcher, filter, entities => entities.ForEach(execute));
}
public void AddReactEach<TEntity>(Func<TEntity, bool> filter, Action<TEntity> execute, params TriggerOnEvent<TEntity>[] triggers) where TEntity : class, IEntity {
AddReact(filter, entities => entities.ForEach(execute), triggers);
}
public void AddReactEach<TEntity>(ICollector<TEntity> collector, Func<TEntity, bool> filter, Action<TEntity> execute) where TEntity : class, IEntity {
AddReact(collector, filter, entities => entities.ForEach(execute));
}
IContext<TEntity> GetContext<TEntity>() where TEntity : class, IEntity {
foreach (var c in contexts.allContexts) {
if (c is IContext<TEntity> context) return context;
}
throw new ArgumentException("Context was not valid");
}
class InlineInitializeSystem : IInitializeSystem {
Action initialize;
public InlineInitializeSystem(Action initialize) {
this.initialize = initialize;
}
public void Initialize() {
initialize();
}
}
class InlineExecuteSystem : IExecuteSystem {
Action execute;
public InlineExecuteSystem(Action execute) {
this.execute = execute;
}
public void Execute() {
execute();
}
}
class InlineCleanupSystem : ICleanupSystem {
Action cleanup;
public InlineCleanupSystem(Action cleanup) {
this.cleanup = cleanup;
}
public void Cleanup() {
cleanup();
}
}
class InlineTeardownSystem : ITearDownSystem {
Action tearDown;
public InlineTeardownSystem(Action tearDown) {
this.tearDown = tearDown;
}
public void TearDown() {
tearDown();
}
}
class InlineReactiveSystem<TEntity> : ReactiveSystem<TEntity> where TEntity : class, IEntity {
Func<TEntity, bool> filter;
Action<List<TEntity>> execute;
public InlineReactiveSystem(ICollector<TEntity> collector, Func<TEntity, bool> filter, Action<List<TEntity>> execute) : base(collector) {
this.filter = filter;
this.execute = execute;
}
protected override ICollector<TEntity> GetTrigger(IContext<TEntity> context) {
throw new Exception("should never be called");
}
protected override bool Filter(TEntity entity) {
return filter(entity);
}
protected override void Execute(List<TEntity> entities) {
execute(entities);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment