using System; using System.Collections.Generic; using System.Numerics; using System.Runtime.InteropServices; namespace Ougge; [StructLayout(LayoutKind.Sequential)] public struct Transform { Vector2 scale; Vector2 position; float rotation; } public class GameObject { // index in GameObjectPool private ulong _id; private uint _index; private bool _isDestroyed; public ulong Id => _id; public bool IsDestroyed => _isDestroyed; public Transform Transform { get; } public GameObject? Parent; public Dictionary Components; private GameObject(ulong id, uint nativePoolIndex) { _id = id; _index = nativePoolIndex; // Do not move this line or mono runtime will throw SEGFAULT. // Mono runtime can't set values in field declaration, but initializing everything in constructor is OK. Components = new(); } static public GameObject Create() { NativeMethods.createGameObject(out ulong id, out uint index); var o = new GameObject(id, index); return o; } public void Destroy() { if(_isDestroyed) return; _isDestroyed = NativeMethods.destroyGameObject(_index); if(!_isDestroyed) throw new Exception($"Can't destroy GameObject({_id})"); } /// type derived from Component /// true if new component instance was created, false if component of the same tipe is already added to GameObject /// public bool TryCreateComponent(Type t) { if(!t.IsSubclassOf(typeof(Component))) throw new Exception($"type {t.FullName} is not a derived class of {typeof(Component).FullName}"); if(Components.ContainsKey(t)) return false; Components.Add(t, (Component)Activator.CreateInstance(t, this)); return true; } private bool TryCreateComponent_internal(string fullName) { Type t = Type.GetType(fullName) ?? throw new Exception($"type not found '{fullName}'"); return TryCreateComponent(t); } private void InvokeUpdate(double deltaTime) { foreach(var p in Components) { p.Value.Update(deltaTime); } } }