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 : IGameManager { public Action? OnCameraChanged { get; set; } = null; public Action? OnGameObjectRegistered { get; set; } = null; public Action? OnGameObjectUnRegistered { get; set; } = null; public Action? OnInitialized { get; set; } = null; public Action? OnFinalized { get; set; } = null; public Action? OnUnassigned { get; set; } = null; public Action? OnStateEnableAssigned { get; set; } = null; private readonly List _gameObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); private IStateEnable _stateEnable = null!; private GameObjectFactory _gameObjectFactory = null!; private bool _initialized = false; private ICamera _camera = null!; private GameObjectFactory GameObjectFactory { get { if (_gameObjectFactory is null) _gameObjectFactory = new GameObjectFactory(); return _gameObjectFactory; } } public bool Initialized => _initialized; public IReadOnlyList GameObjects => _gameObjects; public IStateEnable StateEnable { get { if (_stateEnable is null) { Assign(new StateEnableFactory().Instantiate(this)); if (_stateEnable is null) throw NotAssignedException.From(this, _stateEnable); } return _stateEnable; } } public ICamera Camera { get => _camera; set { if (_camera == value) return; _camera = value; OnCameraChanged?.Invoke(this); } } public void RegisterGameObject(IGameObject gameObject) { if (_gameObjects.Contains(gameObject)) throw new Exception($"{nameof(IGameObject)} named {gameObject.Name} is already registered to the {nameof(GameManager)}."); Register(gameObject); } public T InstantiateGameObject(params object?[]? args) where T : class, IGameObject { T gameObject = GameObjectFactory.Instantiate(args); Register(gameObject); return gameObject; } public IGameObject RemoveGameObject(IGameObject gameObject) { if (!_gameObjects.Contains(gameObject)) throw new Exception($"{nameof(IGameObject)} named {gameObject.Name} is not registered to the {nameof(GameManager)}."); Unregister(gameObject); return gameObject; } public bool Initialize() { if (Initialized) return false; NotAssignedException.Check(this, StateEnable); foreach (var gameObject in GameObjects) gameObject.Initialize(); _initialized = true; OnInitialized?.Invoke(this); return true; } public bool Finalize() { if (!Initialized) return false; for (int i = GameObjects.Count; i >= 0; i--) GameObjects[i].Finalize(); OnFinalized?.Invoke(this); _initialized = false; return true; } public bool Assign(IStateEnable stateEnable) { if (Initialized) return false; _stateEnable = stateEnable; OnStateEnableAssigned?.Invoke(this); return true; } public bool Unassign() { if (Initialized) return false; _stateEnable = null!; OnUnassigned?.Invoke(this); return true; } public void Update(EngineTime time) { Time.SetTime(time); foreach (var gameObject in GameObjects) gameObject.BehaviourController.Update(); } public void PreDraw() { foreach (var gameObject in GameObjects) gameObject.BehaviourController.UpdatePreDraw(); } ///////////////////////////////////////////////////////////////// private void Register(IGameObject gameObject) { gameObject.OnFinalized += OnGameObjectFinalize; _gameObjects.Add(gameObject); OnGameObjectRegistered?.Invoke(this, gameObject); } private void Unregister(IGameObject gameObject) { gameObject.OnFinalized -= OnGameObjectFinalize; _gameObjects.Remove(gameObject); OnGameObjectUnRegistered?.Invoke(this, gameObject); } private void OnGameObjectFinalize(IInitialize initialize) { if (initialize is IGameObject gameObject) Unregister(gameObject); } ///////////////////////////////////////////////////////////////// public IEnumerator GetEnumerator() => _gameObjects.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _gameObjects.GetEnumerator(); }