Compare commits
	
		
			6 Commits
		
	
	
		
			7a3202a053
			...
			8d49fb467c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8d49fb467c | |||
| 2caa042317 | |||
| fe8bde855d | |||
| ac620264b1 | |||
| f31b84f519 | |||
| efb7cc7452 | 
@@ -1,12 +1,7 @@
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public abstract class Behaviour : BehaviourBase, IFirstFrameUpdate,
 | 
			
		||||
    IPreUpdate, IUpdate, IPostUpdate,
 | 
			
		||||
    IPreDraw, IDraw, IPostDraw
 | 
			
		||||
public abstract class Behaviour : BehaviourBase
 | 
			
		||||
{
 | 
			
		||||
    protected IUniverse Universe => BehaviourController.UniverseObject.Universe;
 | 
			
		||||
    protected IUniverseObject UniverseObject => BehaviourController.UniverseObject;
 | 
			
		||||
 | 
			
		||||
    private readonly Event<IUniverseObject, IUniverseObject.EnteredUniverseArguments>.EventHandler delegateEnteredUniverse = null!;
 | 
			
		||||
    private readonly Event<IUniverseObject, IUniverseObject.ExitedUniverseArguments>.EventHandler delegateExitedUniverse = null!;
 | 
			
		||||
 | 
			
		||||
@@ -21,10 +16,10 @@ public abstract class Behaviour : BehaviourBase, IFirstFrameUpdate,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnUnassign() { }
 | 
			
		||||
    protected virtual void OnUnassign(IAssignable assignable) => OnUnassign();
 | 
			
		||||
    protected void OnUnassign(IAssignable assignable) => OnUnassign();
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnInitialize() { }
 | 
			
		||||
    protected virtual void OnInitialize(IInitializable _)
 | 
			
		||||
    protected void OnInitialize(IInitializable _)
 | 
			
		||||
    {
 | 
			
		||||
        BehaviourController.UniverseObject.OnEnteredUniverse.AddListener(delegateEnteredUniverse);
 | 
			
		||||
        BehaviourController.UniverseObject.OnExitedUniverse.AddListener(delegateExitedUniverse);
 | 
			
		||||
@@ -36,7 +31,7 @@ public abstract class Behaviour : BehaviourBase, IFirstFrameUpdate,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnFinalize() { }
 | 
			
		||||
    protected virtual void OnFinalize(IInitializable _)
 | 
			
		||||
    protected void OnFinalize(IInitializable _)
 | 
			
		||||
    {
 | 
			
		||||
        BehaviourController.UniverseObject.OnEnteredUniverse.RemoveListener(delegateEnteredUniverse);
 | 
			
		||||
        BehaviourController.UniverseObject.OnExitedUniverse.RemoveListener(delegateExitedUniverse);
 | 
			
		||||
@@ -47,100 +42,9 @@ public abstract class Behaviour : BehaviourBase, IFirstFrameUpdate,
 | 
			
		||||
            ExitedUniverse(UniverseObject, new(Universe));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnFirstActiveFrame() { }
 | 
			
		||||
    void IFirstFrameUpdate.FirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
        OnFirstActiveFrame();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnPreUpdatePreActiveCheck() { }
 | 
			
		||||
    protected virtual void OnPreUpdate() { }
 | 
			
		||||
    void IPreUpdate.PreUpdate()
 | 
			
		||||
    {
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        OnPreUpdatePreActiveCheck();
 | 
			
		||||
 | 
			
		||||
        if (!IsActive)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnPreUpdate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnUpdatePreActiveCheck() { }
 | 
			
		||||
    protected virtual void OnUpdate() { }
 | 
			
		||||
    void IUpdate.Update()
 | 
			
		||||
    {
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        OnUpdatePreActiveCheck();
 | 
			
		||||
 | 
			
		||||
        if (!IsActive)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnUpdate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnPostUpdatePreActiveCheck() { }
 | 
			
		||||
    protected virtual void OnPostUpdate() { }
 | 
			
		||||
    void IPostUpdate.PostUpdate()
 | 
			
		||||
    {
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        OnPostUpdatePreActiveCheck();
 | 
			
		||||
 | 
			
		||||
        if (!StateEnable.Enabled)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnPostUpdate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnPreDrawPreActiveCheck() { }
 | 
			
		||||
    protected virtual void OnPreDraw() { }
 | 
			
		||||
    void IPreDraw.PreDraw()
 | 
			
		||||
    {
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        OnPreDrawPreActiveCheck();
 | 
			
		||||
 | 
			
		||||
        if (!StateEnable.Enabled)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnPreDraw();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnDrawPreActiveCheck() { }
 | 
			
		||||
    protected virtual void OnDraw() { }
 | 
			
		||||
    void IDraw.Draw()
 | 
			
		||||
    {
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        OnDrawPreActiveCheck();
 | 
			
		||||
 | 
			
		||||
        if (!StateEnable.Enabled)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnDraw();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnPostDrawPreActiveCheck() { }
 | 
			
		||||
    protected virtual void OnPostDraw() { }
 | 
			
		||||
    void IPostDraw.PostDraw()
 | 
			
		||||
    {
 | 
			
		||||
        Debug.Assert.AssertInitialized(this);
 | 
			
		||||
 | 
			
		||||
        OnPostDrawPreActiveCheck();
 | 
			
		||||
 | 
			
		||||
        if (!StateEnable.Enabled)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        OnPostDraw();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnEnteredUniverse(IUniverse universe) { }
 | 
			
		||||
    protected virtual void EnteredUniverse(IUniverseObject sender, IUniverseObject.EnteredUniverseArguments args) => OnEnteredUniverse(args.Universe);
 | 
			
		||||
    protected void EnteredUniverse(IUniverseObject sender, IUniverseObject.EnteredUniverseArguments args) => OnEnteredUniverse(args.Universe);
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnExitedUniverse(IUniverse universe) { }
 | 
			
		||||
    protected virtual void ExitedUniverse(IUniverseObject sender, IUniverseObject.ExitedUniverseArguments args) => OnExitedUniverse(args.Universe);
 | 
			
		||||
    protected void ExitedUniverse(IUniverseObject sender, IUniverseObject.ExitedUniverseArguments args) => OnExitedUniverse(args.Universe);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,19 +4,6 @@ public abstract class Behaviour2D : Behaviour, IBehaviour2D
 | 
			
		||||
{
 | 
			
		||||
    public ITransform2D Transform { get; private set; } = null!;
 | 
			
		||||
 | 
			
		||||
    protected sealed override void OnInitialize(IInitializable _)
 | 
			
		||||
    {
 | 
			
		||||
        Transform = BehaviourController.GetRequiredBehaviour<ITransform2D>();
 | 
			
		||||
        base.OnInitialize(_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected sealed override void OnFinalize(IInitializable _)
 | 
			
		||||
    {
 | 
			
		||||
        Transform = null!;
 | 
			
		||||
        base.OnFinalize(_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected sealed override void OnUnassign(IAssignable assignable) => base.OnUnassign(assignable);
 | 
			
		||||
    protected sealed override void EnteredUniverse(IUniverseObject sender, IUniverseObject.EnteredUniverseArguments args) => base.EnteredUniverse(sender, args);
 | 
			
		||||
    protected sealed override void ExitedUniverse(IUniverseObject sender, IUniverseObject.ExitedUniverseArguments args) => base.ExitedUniverse(sender, args);
 | 
			
		||||
    protected override void OnInitialize() => Transform = BehaviourController.GetRequiredBehaviour<ITransform2D>();
 | 
			
		||||
    protected override void OnFinalize() => Transform = null!;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,9 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
 | 
			
		||||
    private readonly Event<IActive, IActive.ActiveChangedArguments>.EventHandler delegateOnUniverseObjectActiveChanged = null!;
 | 
			
		||||
    private readonly Event<IStateEnable, IStateEnable.EnabledChangedArguments>.EventHandler delegateOnStateEnabledChanged = null!;
 | 
			
		||||
 | 
			
		||||
    public IUniverse Universe => BehaviourController.UniverseObject.Universe;
 | 
			
		||||
    public IUniverseObject UniverseObject => BehaviourController.UniverseObject;
 | 
			
		||||
 | 
			
		||||
    private IBehaviourController _behaviourController = null!;
 | 
			
		||||
    public IBehaviourController BehaviourController => _behaviourController;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,11 +4,12 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class DrawManager : UniverseObject
 | 
			
		||||
{
 | 
			
		||||
    private static Comparer<IBehaviour> SortByPriority() => Comparer<IBehaviour>.Create((x, y) => y.Priority.CompareTo(x.Priority));
 | 
			
		||||
    // We use Descending order because draw calls are running from last to first
 | 
			
		||||
    private static Comparer<IBehaviour> SortByDescendingPriority() => Comparer<IBehaviour>.Create((x, y) => y.Priority.CompareTo(x.Priority));
 | 
			
		||||
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IPreDraw> preDrawEntities = new() { SortBy = SortByPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IDraw> drawEntities = new() { SortBy = SortByPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IPostDraw> postDrawEntities = new() { SortBy = SortByPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IPreDraw> preDrawEntities = new() { SortBy = SortByDescendingPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IDraw> drawEntities = new() { SortBy = SortByDescendingPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IPostDraw> postDrawEntities = new() { SortBy = SortByDescendingPriority() };
 | 
			
		||||
 | 
			
		||||
    private void OnPreDraw(IUniverse sender)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,13 @@ namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class UpdateManager : UniverseObject
 | 
			
		||||
{
 | 
			
		||||
    private static Comparer<IBehaviour> SortByPriority() => Comparer<IBehaviour>.Create((x, y) => y.Priority.CompareTo(x.Priority));
 | 
			
		||||
    // We use Ascending order because draw calls are running from last to first
 | 
			
		||||
    private static Comparer<IBehaviour> SortByAscendingPriority() => Comparer<IBehaviour>.Create((x, y) => x.Priority.CompareTo(y.Priority));
 | 
			
		||||
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IFirstFrameUpdate> firstFrameUpdates = new() { SortBy = SortByPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IPreUpdate> preUpdateEntities = new() { SortBy = SortByPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IUpdate> updateEntities = new() { SortBy = SortByPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IPostUpdate> postUpdateEntities = new() { SortBy = SortByPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IFirstFrameUpdate> firstFrameUpdates = new() { SortBy = SortByAscendingPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IPreUpdate> preUpdateEntities = new() { SortBy = SortByAscendingPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IUpdate> updateEntities = new() { SortBy = SortByAscendingPriority() };
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IPostUpdate> postUpdateEntities = new() { SortBy = SortByAscendingPriority() };
 | 
			
		||||
 | 
			
		||||
    private readonly List<IFirstFrameUpdate> toCallFirstFrameUpdates = new(32);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public interface IDrawableSprite : IBehaviour
 | 
			
		||||
{
 | 
			
		||||
    void Draw(SpriteBatch spriteBatch);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public interface IDrawableTriangle : IBehaviour
 | 
			
		||||
{
 | 
			
		||||
    void Draw(ITriangleBatch triangleBatch);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public interface ITriangleBatch
 | 
			
		||||
{
 | 
			
		||||
    void Begin(Matrix? view = null, Matrix? projection = null);
 | 
			
		||||
    void Draw(Triangle triangle, ColorRGBA colorRGBA);
 | 
			
		||||
    void End();
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public class DrawableShapeBehaviour : Behaviour2D, IDrawableTriangle, IPreDraw
 | 
			
		||||
{
 | 
			
		||||
    private readonly Shape2D shape = new([]);
 | 
			
		||||
    private readonly List<Triangle> worldTriangles = [];
 | 
			
		||||
    private readonly Shape2D worldShape = new([]);
 | 
			
		||||
    protected ColorRGB color = new(255, 255, 255);
 | 
			
		||||
 | 
			
		||||
    public void PreDraw() => UpdateWorldShape();
 | 
			
		||||
 | 
			
		||||
    public void Draw(ITriangleBatch triangleBatch)
 | 
			
		||||
    {
 | 
			
		||||
        worldShape.ToTrianglesConvex(worldTriangles);
 | 
			
		||||
 | 
			
		||||
        foreach (Triangle triangle in worldTriangles)
 | 
			
		||||
            triangleBatch.Draw(new(triangle.C, triangle.B, triangle.A), color);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void UpdateWorldShape() => shape.Transform(Transform, worldShape);
 | 
			
		||||
 | 
			
		||||
    public DrawableShapeBehaviour() => shape = Shape2D.Triangle;
 | 
			
		||||
    public DrawableShapeBehaviour(Shape2D shape) => this.shape = shape;
 | 
			
		||||
    public DrawableShapeBehaviour(Shape2D shape, ColorRGB color) { this.shape = shape; this.color = color; }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,110 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Systems.Input;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public class KeyboardInputsBehaviour : Behaviour, IButtonInputs<Keys>, IUpdate
 | 
			
		||||
{
 | 
			
		||||
    public Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments> OnAnyButtonPressed { get; } = new();
 | 
			
		||||
    public Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments> OnAnyButtonReleased { get; } = new();
 | 
			
		||||
 | 
			
		||||
    private readonly Dictionary<Keys, Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>> OnPressed = new(256);
 | 
			
		||||
    private readonly Dictionary<Keys, Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>> OnReleased = new(256);
 | 
			
		||||
 | 
			
		||||
    private int cachePressedCurrentlyCount = 0;
 | 
			
		||||
    private readonly Keys[] cachePressedCurrently = new Keys[256];
 | 
			
		||||
 | 
			
		||||
    private int cachePressedPreviouslyCount = 0;
 | 
			
		||||
    private readonly Keys[] cachePressedPreviously = new Keys[256];
 | 
			
		||||
 | 
			
		||||
    public void RegisterOnPress(Keys key, Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>.EventHandler callback)
 | 
			
		||||
    {
 | 
			
		||||
        if (!OnPressed.TryGetValue(key, out Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>? delegateCallback))
 | 
			
		||||
        {
 | 
			
		||||
            delegateCallback = new();
 | 
			
		||||
            OnPressed.Add(key, delegateCallback);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        delegateCallback.AddListener(callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void UnregisterOnPress(Keys key, Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>.EventHandler callback)
 | 
			
		||||
    {
 | 
			
		||||
        if (OnPressed.TryGetValue(key, out Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>? delegateCallback))
 | 
			
		||||
            delegateCallback.RemoveListener(callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void RegisterOnRelease(Keys key, Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>.EventHandler callback)
 | 
			
		||||
    {
 | 
			
		||||
        if (!OnReleased.TryGetValue(key, out Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>? delegateCallback))
 | 
			
		||||
        {
 | 
			
		||||
            delegateCallback = new();
 | 
			
		||||
            OnReleased.Add(key, delegateCallback);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        delegateCallback.AddListener(callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void UnregisterOnRelease(Keys key, Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>.EventHandler callback)
 | 
			
		||||
    {
 | 
			
		||||
        if (OnReleased.TryGetValue(key, out Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>? delegateCallback))
 | 
			
		||||
            delegateCallback.RemoveListener(callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Update()
 | 
			
		||||
    {
 | 
			
		||||
        KeyboardState keyboardState = Keyboard.GetState();
 | 
			
		||||
        keyboardState.GetPressedKeys(cachePressedCurrently);
 | 
			
		||||
        cachePressedCurrentlyCount = keyboardState.GetPressedKeyCount();
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < cachePressedCurrentlyCount; i++)
 | 
			
		||||
        {
 | 
			
		||||
            Keys currentlyPressedKey = cachePressedCurrently[i];
 | 
			
		||||
 | 
			
		||||
            if (WasPressed(currentlyPressedKey))
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (OnPressed.TryGetValue(currentlyPressedKey, out Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>? callback))
 | 
			
		||||
                callback?.Invoke(this, new(currentlyPressedKey));
 | 
			
		||||
 | 
			
		||||
            OnAnyButtonPressed?.Invoke(this, new(currentlyPressedKey));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < cachePressedPreviouslyCount; i++)
 | 
			
		||||
        {
 | 
			
		||||
            Keys previouslyPressedKey = cachePressedPreviously[i];
 | 
			
		||||
 | 
			
		||||
            if (IsPressed(previouslyPressedKey))
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (OnReleased.TryGetValue(previouslyPressedKey, out Event<IButtonInputs<Keys>, IButtonInputs<Keys>.ButtonCallbackArguments>? callback))
 | 
			
		||||
                callback?.Invoke(this, new(previouslyPressedKey));
 | 
			
		||||
 | 
			
		||||
            OnAnyButtonReleased?.Invoke(this, new(previouslyPressedKey));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount);
 | 
			
		||||
        cachePressedPreviouslyCount = cachePressedCurrentlyCount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool IsPressed(Keys key)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < cachePressedCurrentlyCount; i++)
 | 
			
		||||
            if (cachePressedCurrently[i] == key)
 | 
			
		||||
                return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private bool WasPressed(Keys key)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < cachePressedPreviouslyCount; i++)
 | 
			
		||||
            if (cachePressedPreviously[i] == key)
 | 
			
		||||
                return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,109 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public class MonoGameCamera2DBehaviour : BehaviourBase, ICamera2D, IFirstFrameUpdate, IPreDraw
 | 
			
		||||
{
 | 
			
		||||
    public event MatrixTransformChangedArguments? OnMatrixTransformChanged = null;
 | 
			
		||||
    public event ViewportChangedArguments? OnViewportChanged = null;
 | 
			
		||||
    public event ZoomChangedArguments? OnZoomChanged = null;
 | 
			
		||||
 | 
			
		||||
    private Matrix _matrixTransform = Matrix.Identity;
 | 
			
		||||
 | 
			
		||||
    private Viewport _viewport = default;
 | 
			
		||||
    private float _zoom = 1f;
 | 
			
		||||
 | 
			
		||||
    public GraphicsDeviceManager Graphics { get; private set; } = null!;
 | 
			
		||||
    public ITransform2D Transform { get; private set; } = null!;
 | 
			
		||||
 | 
			
		||||
    public Matrix MatrixTransform
 | 
			
		||||
    {
 | 
			
		||||
        get => _matrixTransform;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_matrixTransform == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _matrixTransform = value;
 | 
			
		||||
            OnMatrixTransformChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2D Position
 | 
			
		||||
    {
 | 
			
		||||
        get => Transform.Position;
 | 
			
		||||
        set => Transform.Position = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Viewport Viewport
 | 
			
		||||
    {
 | 
			
		||||
        get => _viewport;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_viewport.Equals(value))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _viewport = value;
 | 
			
		||||
            OnViewportChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Zoom
 | 
			
		||||
    {
 | 
			
		||||
        get => _zoom;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            float newValue = Syntriax.Engine.Core.Math.Max(0.1f, value);
 | 
			
		||||
 | 
			
		||||
            if (_zoom == newValue)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _zoom = newValue;
 | 
			
		||||
            OnZoomChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Rotation
 | 
			
		||||
    {
 | 
			
		||||
        get => Transform.Rotation;
 | 
			
		||||
        set => Transform.Rotation = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO This causes delay since OnPreDraw calls assuming this is called in in Update 
 | 
			
		||||
    public Vector2D ScreenToWorldPosition(Vector2D screenPosition)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D worldPosition = Vector2.Transform(screenPosition.ToVector2(), Matrix.Invert(MatrixTransform)).ToVector2D();
 | 
			
		||||
        return worldPosition.Scale(EngineConverterExtensions.screenScale);
 | 
			
		||||
    }
 | 
			
		||||
    public Vector2D WorldToScreenPosition(Vector2D worldPosition)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D screenPosition = Vector2.Transform(worldPosition.ToVector2(), MatrixTransform).ToVector2D();
 | 
			
		||||
        return screenPosition.Scale(EngineConverterExtensions.screenScale);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void FirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        Graphics = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour<MonoGameWindowContainer>().Window.Graphics;
 | 
			
		||||
        Viewport = Graphics.GraphicsDevice.Viewport;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void PreDraw()
 | 
			
		||||
    {
 | 
			
		||||
        MatrixTransform =
 | 
			
		||||
            Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 0f)) *
 | 
			
		||||
            Matrix.CreateRotationZ(Rotation * Syntriax.Engine.Core.Math.DegreeToRadian) *
 | 
			
		||||
            Matrix.CreateScale(Transform.Scale.X.Max(Transform.Scale.Y)) *
 | 
			
		||||
            Matrix.CreateScale(Zoom) *
 | 
			
		||||
            Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected sealed override void InitializeInternal() => Transform = BehaviourController.GetRequiredBehaviour<ITransform2D>();
 | 
			
		||||
    protected sealed override void FinalizeInternal() => Transform = null!;
 | 
			
		||||
 | 
			
		||||
    public delegate void MatrixTransformChangedArguments(MonoGameCamera2DBehaviour sender);
 | 
			
		||||
    public delegate void ViewportChangedArguments(MonoGameCamera2DBehaviour sender);
 | 
			
		||||
    public delegate void ZoomChangedArguments(MonoGameCamera2DBehaviour sender);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public class SpriteBatcher : BehaviourBase, IFirstFrameUpdate, IDraw
 | 
			
		||||
{
 | 
			
		||||
    private static Comparer<IBehaviour> SortByPriority() => Comparer<IBehaviour>.Create((x, y) => y.Priority.CompareTo(x.Priority));
 | 
			
		||||
    private SpriteBatch spriteBatch = null!;
 | 
			
		||||
    private MonoGameCamera2DBehaviour camera2D = null!;
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IDrawableSprite> drawableSprites = new() { SortBy = SortByPriority() };
 | 
			
		||||
 | 
			
		||||
    public void FirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        MonoGameWindowContainer windowContainer = Universe.FindRequiredBehaviour<MonoGameWindowContainer>();
 | 
			
		||||
        camera2D = Universe.FindRequiredBehaviour<MonoGameCamera2DBehaviour>();
 | 
			
		||||
 | 
			
		||||
        spriteBatch = new(windowContainer.Window.GraphicsDevice);
 | 
			
		||||
        drawableSprites.Unassign();
 | 
			
		||||
        drawableSprites.Assign(Universe);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Draw()
 | 
			
		||||
    {
 | 
			
		||||
        spriteBatch.Begin(transformMatrix: camera2D.MatrixTransform);
 | 
			
		||||
        for (int i = 0; i < drawableSprites.Count; i++)
 | 
			
		||||
            drawableSprites[i].Draw(spriteBatch);
 | 
			
		||||
        spriteBatch.End();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public class TriangleBatcher : BehaviourBase, ITriangleBatch, IFirstFrameUpdate, IDraw
 | 
			
		||||
{
 | 
			
		||||
    private static Comparer<IBehaviour> SortByAscendingPriority() => Comparer<IBehaviour>.Create((x, y) => x.Priority.CompareTo(y.Priority));
 | 
			
		||||
 | 
			
		||||
    private TriangleBatch triangleBatch = null!;
 | 
			
		||||
    private MonoGameCamera2DBehaviour camera2D = null!;
 | 
			
		||||
    private readonly ActiveBehaviourCollectorSorted<IDrawableTriangle> drawableShapes = new() { SortBy = SortByAscendingPriority() };
 | 
			
		||||
 | 
			
		||||
    public void FirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        MonoGameWindowContainer windowContainer = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour<MonoGameWindowContainer>();
 | 
			
		||||
        camera2D = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour<MonoGameCamera2DBehaviour>();
 | 
			
		||||
 | 
			
		||||
        triangleBatch = new(windowContainer.Window.GraphicsDevice);
 | 
			
		||||
        drawableShapes.Unassign();
 | 
			
		||||
        drawableShapes.Assign(BehaviourController.UniverseObject.Universe);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Draw()
 | 
			
		||||
    {
 | 
			
		||||
        triangleBatch.Begin(camera2D.MatrixTransform);
 | 
			
		||||
        for (int i = 0; i < drawableShapes.Count; i++)
 | 
			
		||||
            drawableShapes[i].Draw(triangleBatch);
 | 
			
		||||
        triangleBatch.End();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Begin(Matrix? view = null, Matrix? projection = null) => triangleBatch.Begin(view, projection);
 | 
			
		||||
    public void Draw(Triangle triangle, ColorRGBA colorRGBA) => triangleBatch.Draw(triangle, colorRGBA);
 | 
			
		||||
    public void End() => triangleBatch.End();
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net9.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>disable</ImplicitUsings>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <RootNamespace>Syntriax.Engine.Integration.MonoGame</RootNamespace>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105">
 | 
			
		||||
      <PrivateAssets>All</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\Engine\Engine.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
using System.Runtime.CompilerServices;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public static class EngineConverterExtensions
 | 
			
		||||
{
 | 
			
		||||
    public readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right;
 | 
			
		||||
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static UniverseTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Color ToColor(this ColorRGBA rgba) => new(rgba.R, rgba.G, rgba.B, rgba.A);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2D ToVector2D(this Point point) => new(point.X, point.Y);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2();
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Vector2D ApplyDisplayScale(this Vector2D vector) => vector.Scale(screenScale);
 | 
			
		||||
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
    public static Rectangle ToDisplayRectangle(this Rectangle rectangle, DisplayMode displayMode) => new()
 | 
			
		||||
    {
 | 
			
		||||
        X = rectangle.X,
 | 
			
		||||
        Y = displayMode.Height - rectangle.Y - rectangle.Height,
 | 
			
		||||
        Width = rectangle.Width,
 | 
			
		||||
        Height = rectangle.Height
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public abstract class MonoGameWindow : Game
 | 
			
		||||
{
 | 
			
		||||
    public GraphicsDeviceManager Graphics { get; protected set; } = null!;
 | 
			
		||||
    public IUniverse Universe { get; protected set; } = null!;
 | 
			
		||||
    public ColorRGB BackgroundColor { get; set; } = new ColorRGB(35, 20, 35);
 | 
			
		||||
 | 
			
		||||
    public MonoGameWindow()
 | 
			
		||||
    {
 | 
			
		||||
        Preserver.Preserve();
 | 
			
		||||
        Graphics = new GraphicsDeviceManager(this);
 | 
			
		||||
        Content.RootDirectory = "Content";
 | 
			
		||||
        IsMouseVisible = true;
 | 
			
		||||
        Universe = new Universe();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract void PopulateUniverse(IUniverse universe);
 | 
			
		||||
    protected override void Initialize()
 | 
			
		||||
    {
 | 
			
		||||
        Universe.Initialize();
 | 
			
		||||
        Universe.InstantiateUniverseObject().SetUniverseObject("Window Container")
 | 
			
		||||
            .BehaviourController.AddBehaviour<MonoGameWindowContainer>(this);
 | 
			
		||||
 | 
			
		||||
        PopulateUniverse(Universe);
 | 
			
		||||
 | 
			
		||||
        base.Initialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void LoadContent()
 | 
			
		||||
    {
 | 
			
		||||
        // TODO: use this.Content to load your game content here
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Update(GameTime gameTime)
 | 
			
		||||
    {
 | 
			
		||||
        Universe.Update(gameTime.ToEngineTime());
 | 
			
		||||
 | 
			
		||||
        base.Update(gameTime);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Draw(GameTime gameTime)
 | 
			
		||||
    {
 | 
			
		||||
        GraphicsDevice.Clear(((ColorRGBA)BackgroundColor).ToColor());
 | 
			
		||||
 | 
			
		||||
        Universe.Draw();
 | 
			
		||||
 | 
			
		||||
        base.Draw(gameTime);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,74 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
public class TriangleBatch : ITriangleBatch
 | 
			
		||||
{
 | 
			
		||||
    private readonly GraphicsDevice graphicsDevice;
 | 
			
		||||
    private VertexBuffer vertexBuffer = default!;
 | 
			
		||||
    private readonly VertexPositionColor[] vertices = new VertexPositionColor[1024];
 | 
			
		||||
    private int verticesIndex = 0;
 | 
			
		||||
    private Matrix _view;
 | 
			
		||||
    private Matrix _projection;
 | 
			
		||||
    private readonly BasicEffect basicEffect;
 | 
			
		||||
 | 
			
		||||
    public TriangleBatch(GraphicsDevice graphicsDevice)
 | 
			
		||||
    {
 | 
			
		||||
        this.graphicsDevice = graphicsDevice;
 | 
			
		||||
        this.graphicsDevice.RasterizerState = new RasterizerState() { CullMode = CullMode.None };
 | 
			
		||||
        basicEffect = new(graphicsDevice);
 | 
			
		||||
        basicEffect.VertexColorEnabled = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Draw(Triangle triangle, ColorRGBA colorRGBA)
 | 
			
		||||
    {
 | 
			
		||||
        if (verticesIndex + 3 >= vertices.Length)
 | 
			
		||||
            Flush();
 | 
			
		||||
 | 
			
		||||
        Vector2 A = triangle.A.ToDisplayVector2();
 | 
			
		||||
        Vector2 B = triangle.B.ToDisplayVector2();
 | 
			
		||||
        Vector2 C = triangle.C.ToDisplayVector2();
 | 
			
		||||
        Color color = colorRGBA.ToColor();
 | 
			
		||||
 | 
			
		||||
        vertices[verticesIndex++] = new(new(A.X, A.Y, 0f), color);
 | 
			
		||||
        vertices[verticesIndex++] = new(new(B.X, B.Y, 0f), color);
 | 
			
		||||
        vertices[verticesIndex++] = new(new(C.X, C.Y, 0f), color);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Begin(Matrix? view = null, Matrix? projection = null)
 | 
			
		||||
    {
 | 
			
		||||
        if (view != null)
 | 
			
		||||
            _view = view.Value;
 | 
			
		||||
        else
 | 
			
		||||
            _view = Matrix.Identity;
 | 
			
		||||
 | 
			
		||||
        if (projection != null)
 | 
			
		||||
            _projection = projection.Value;
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            Viewport viewport = graphicsDevice.Viewport;
 | 
			
		||||
            _projection = Matrix.CreateOrthographicOffCenter(viewport.X, viewport.Width, viewport.Height, viewport.Y, 0, 1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void End() => Flush();
 | 
			
		||||
 | 
			
		||||
    private void Flush()
 | 
			
		||||
    {
 | 
			
		||||
        basicEffect.Projection = _projection;
 | 
			
		||||
        basicEffect.View = _view;
 | 
			
		||||
        vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionColor), 1024, BufferUsage.WriteOnly);
 | 
			
		||||
        vertexBuffer.SetData(vertices);
 | 
			
		||||
 | 
			
		||||
        graphicsDevice.SetVertexBuffer(vertexBuffer);
 | 
			
		||||
 | 
			
		||||
        foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
 | 
			
		||||
            pass.Apply();
 | 
			
		||||
        graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, verticesIndex / 3);
 | 
			
		||||
 | 
			
		||||
        verticesIndex = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
[IgnoreSerialization]
 | 
			
		||||
public class MonoGameWindowContainer(MonoGameWindow GameWindow) : BehaviourBase
 | 
			
		||||
{
 | 
			
		||||
    public MonoGameWindow Window { get; } = GameWindow;
 | 
			
		||||
}
 | 
			
		||||
@@ -44,6 +44,8 @@ public abstract class Collider2DBehaviourBase : Behaviour2D, ICollider2D
 | 
			
		||||
 | 
			
		||||
    protected override void OnInitialize()
 | 
			
		||||
    {
 | 
			
		||||
        base.OnInitialize();
 | 
			
		||||
 | 
			
		||||
        BehaviourController.TryGetBehaviourInParent(out _rigidBody2D);
 | 
			
		||||
 | 
			
		||||
        BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAddedToController);
 | 
			
		||||
@@ -78,6 +80,8 @@ public abstract class Collider2DBehaviourBase : Behaviour2D, ICollider2D
 | 
			
		||||
 | 
			
		||||
    protected override void OnFinalize()
 | 
			
		||||
    {
 | 
			
		||||
        base.OnFinalize();
 | 
			
		||||
 | 
			
		||||
        BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAddedToController);
 | 
			
		||||
        BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemovedFromController);
 | 
			
		||||
        Transform.OnScaleChanged.RemoveListener(delegateSetNeedsRecalculationFromScale);
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.StateMachine;
 | 
			
		||||
 | 
			
		||||
public class StateMachine : Behaviour
 | 
			
		||||
public class StateMachine : Behaviour, IUpdate
 | 
			
		||||
{
 | 
			
		||||
    public Event<StateMachine, StateChangedArguments> OnStateChanged { get; } = new();
 | 
			
		||||
 | 
			
		||||
@@ -44,7 +44,7 @@ public class StateMachine : Behaviour
 | 
			
		||||
            State = nextState;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    public void Update()
 | 
			
		||||
    {
 | 
			
		||||
        if (State is null)
 | 
			
		||||
            return;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Time;
 | 
			
		||||
 | 
			
		||||
public class StopwatchBehaviour : Behaviour, IStopwatch
 | 
			
		||||
public class StopwatchBehaviour : Behaviour, IUpdate, IStopwatch
 | 
			
		||||
{
 | 
			
		||||
    public Event<IReadOnlyStopwatch> OnStarted { get; } = new();
 | 
			
		||||
    public Event<IReadOnlyStopwatch, IReadOnlyStopwatch.StopwatchDeltaArguments> OnDelta { get; } = new();
 | 
			
		||||
@@ -38,7 +38,7 @@ public class StopwatchBehaviour : Behaviour, IStopwatch
 | 
			
		||||
        OnStopped?.Invoke(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    public virtual void Update()
 | 
			
		||||
    {
 | 
			
		||||
        if (State is not TimerState.Ticking)
 | 
			
		||||
            return;
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,9 @@ public class TickerBehaviour : StopwatchBehaviour, ITicker
 | 
			
		||||
        nextTick = Time + Period;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    public override void Update()
 | 
			
		||||
    {
 | 
			
		||||
        base.OnUpdate();
 | 
			
		||||
        base.Update();
 | 
			
		||||
 | 
			
		||||
        while (Time > nextTick)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Systems.Time;
 | 
			
		||||
 | 
			
		||||
public class TimerBehaviour : Behaviour, ITimer
 | 
			
		||||
public class TimerBehaviour : Behaviour, IUpdate, ITimer
 | 
			
		||||
{
 | 
			
		||||
    public Event<IReadOnlyTimer> OnStarted { get; } = new();
 | 
			
		||||
    public Event<IReadOnlyTimer, IReadOnlyTimer.TimerDeltaArguments> OnDelta { get; } = new();
 | 
			
		||||
@@ -53,7 +53,7 @@ public class TimerBehaviour : Behaviour, ITimer
 | 
			
		||||
        OnStopped?.Invoke(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    public void Update()
 | 
			
		||||
    {
 | 
			
		||||
        if (State is not TimerState.Ticking)
 | 
			
		||||
            return;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										69
									
								
								Engine.sln
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								Engine.sln
									
									
									
									
									
								
							@@ -17,36 +17,104 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Serializers.Yaml", "
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet", "Engine.Serializers\YamlDotNet\YamlDotNet\YamlDotNet.csproj", "{3D852C92-BC14-4893-AEF2-50612DAFCD8F}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Integration", "Integration", "{823D4020-332D-2C13-F261-6F510F11A57E}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame", "Engine.Integration\Engine.Integration.MonoGame\Engine.Integration.MonoGame.csproj", "{C3438D33-0879-44E4-9DF0-D29F5621C44C}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
		Debug|Any CPU = Debug|Any CPU
 | 
			
		||||
		Debug|x64 = Debug|x64
 | 
			
		||||
		Debug|x86 = Debug|x86
 | 
			
		||||
		Release|Any CPU = Release|Any CPU
 | 
			
		||||
		Release|x64 = Release|x64
 | 
			
		||||
		Release|x86 = Release|x86
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{8452323D-99EF-43B1-8E7B-123E02279674}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
@@ -54,5 +122,6 @@ Global
 | 
			
		||||
	GlobalSection(NestedProjects) = preSolution
 | 
			
		||||
		{E9D1CDC3-5BFF-4C87-AFEB-6CE372709176} = {F88E129A-9A47-4D27-96EE-6EC02F79594B}
 | 
			
		||||
		{3D852C92-BC14-4893-AEF2-50612DAFCD8F} = {F88E129A-9A47-4D27-96EE-6EC02F79594B}
 | 
			
		||||
		{C3438D33-0879-44E4-9DF0-D29F5621C44C} = {823D4020-332D-2C13-F261-6F510F11A57E}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user