using System; using System.Collections; using System.Collections.Generic; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Exceptions; using Syntriax.Engine.Core.Factory; namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("GameObject Count: {_gameObjects.Count}")] public class GameManager : BaseEntity, IGameManager { public event IGameManager.OnUpdateDelegate? OnUpdate = null; public event IGameManager.OnPreDawDelegate? OnPreDraw = null; public event IGameManager.OnGameObjectRegisteredDelegate? OnGameObjectRegistered = null; public event IGameManager.OnGameObjectUnRegisteredDelegate? OnGameObjectUnRegistered = null; public event IGameManager.OnHierarchyObjectRegisteredDelegate? OnHierarchyObjectRegistered = null; public event IGameManager.OnHierarchyObjectUnRegisteredDelegate? OnHierarchyObjectUnRegistered = null; private readonly List _gameObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); private readonly List _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); private GameObjectFactory _gameObjectFactory = null!; private GameObjectFactory GameObjectFactory { get { if (_gameObjectFactory is null) _gameObjectFactory = new GameObjectFactory(); return _gameObjectFactory; } } public IReadOnlyList GameObjects => _gameObjects; public IReadOnlyList HierarchyObjects => _hierarchyObjects; public override IStateEnable StateEnable { get { if (base.StateEnable is null) { Assign(new StateEnableFactory().Instantiate(this)); if (base.StateEnable is null) throw NotAssignedException.From(this, base.StateEnable); } return base.StateEnable; } } public void Register(IHierarchyObject hierarchyObject) { if (_hierarchyObjects.Contains(hierarchyObject)) throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is already registered to the {nameof(GameManager)}."); if (hierarchyObject is IGameObject gameObject) Register(gameObject); else { if (!hierarchyObject.Initialize()) throw new Exception($"{nameof(hierarchyObject)} can't be initialized"); _hierarchyObjects.Add(hierarchyObject); hierarchyObject.EnterHierarchy(this); OnHierarchyObjectRegistered?.Invoke(this, hierarchyObject); } } public T InstantiateGameObject(params object?[]? args) where T : class, IGameObject { T gameObject = GameObjectFactory.Instantiate(args); Register(gameObject); return gameObject; } public void Remove(IHierarchyObject hierarchyObject) { if (!_hierarchyObjects.Contains(hierarchyObject)) throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is not registered to the {nameof(GameManager)}."); if (hierarchyObject is IGameObject gameObject) Unregister(gameObject); else { _hierarchyObjects.Remove(hierarchyObject); hierarchyObject.ExitHierarchy(); if (!hierarchyObject.Finalize()) throw new Exception($"{nameof(hierarchyObject)} can't be finalized"); OnHierarchyObjectUnRegistered?.Invoke(this, hierarchyObject); } } protected override void InitializeInternal() { base.InitializeInternal(); NotAssignedException.Check(this, StateEnable); foreach (var gameObject in GameObjects) gameObject.Initialize(); } protected override void FinalizeInternal() { base.FinalizeInternal(); for (int i = GameObjects.Count; i >= 0; i--) GameObjects[i].Finalize(); } public void Update(EngineTime time) { Time.SetTime(time); for (int i = 0; i < GameObjects.Count; i++) GameObjects[i].BehaviourController.Update(); OnUpdate?.Invoke(this, time); } public void PreDraw() { for (int i = 0; i < GameObjects.Count; i++) GameObjects[i].BehaviourController.UpdatePreDraw(); OnPreDraw?.Invoke(this); } ///////////////////////////////////////////////////////////////// private void Register(IGameObject gameObject) { if (_gameObjects.Contains(gameObject)) throw new Exception($"{nameof(IGameObject)} named {gameObject.Name} is already registered to the {nameof(GameManager)}."); gameObject.OnFinalized += OnGameObjectFinalize; gameObject.OnExitedHierarchy += OnGameObjectExitedHierarchy; foreach (ITransform child in gameObject.Transform.Children) Register(child.GameObject); if (!gameObject.Initialize()) throw new Exception($"{nameof(gameObject)} can't be initialized"); _gameObjects.Add(gameObject); _hierarchyObjects.Add(gameObject); if (!gameObject.EnterHierarchy(this)) throw new Exception($"{nameof(gameObject)} can't enter the hierarchy"); OnHierarchyObjectRegistered?.Invoke(this, gameObject); OnGameObjectRegistered?.Invoke(this, gameObject); } private void Unregister(IGameObject gameObject) { if (!_gameObjects.Contains(gameObject)) throw new Exception($"{nameof(IGameObject)} named {gameObject.Name} is not registered to the {nameof(GameManager)}."); gameObject.OnFinalized -= OnGameObjectFinalize; gameObject.OnExitedHierarchy -= OnGameObjectExitedHierarchy; foreach (ITransform child in gameObject.Transform.Children) Unregister(child.GameObject); _gameObjects.Remove(gameObject); _hierarchyObjects.Remove(gameObject); if (!gameObject.ExitHierarchy()) throw new Exception($"{nameof(gameObject)} can't exit the hierarchy"); if (!gameObject.Finalize()) throw new Exception($"{nameof(gameObject)} can't be finalized"); OnHierarchyObjectUnRegistered?.Invoke(this, gameObject); OnGameObjectUnRegistered?.Invoke(this, gameObject); } private void OnGameObjectFinalize(IInitialize initialize) { if (initialize is IGameObject gameObject) Unregister(gameObject); } private void OnGameObjectExitedHierarchy(IHierarchyObject sender, IGameManager gameManager) { if (sender is IGameObject gameObject) Unregister(gameObject); } ///////////////////////////////////////////////////////////////// public IEnumerator GetEnumerator() => _gameObjects.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _gameObjects.GetEnumerator(); }