Files
doom-dm/Engine/src/Scene/GameObject.cs
2024-12-16 04:28:45 +03:00

158 lines
3.4 KiB
C#

using System.Reflection;
using Engine.Scene.Component;
using Engine.Scene.Component.BuiltIn;
namespace Engine.Scene;
public sealed class GameObject : IUpdate, IRender
{
public Guid Id { get; } = Guid.NewGuid();
public Transform Transform { get; }
internal Scene? Scene { get; set; }
private readonly Queue<Action> _componentActions = new();
private readonly List<Component.Component> _components = [];
private readonly HashSet<Type> _addedComponentTypes = [];
public GameObject()
{
AddComponent<Transform>();
ProcessChanges();
Transform = GetComponent<Transform>()!;
}
public GameObject(Transform parTransform)
{
AddComponent(parTransform.Clone());
ProcessChanges();
Transform = GetComponent<Transform>()!;
}
public void Awake()
{
foreach (var component in _components)
{
component.Awake();
}
}
public void Start()
{
foreach (var component in _components)
{
component.Start();
}
}
public void Update(double parDeltaTime)
{
foreach (var component in _components)
{
component.Update(parDeltaTime);
}
}
public void Render()
{
foreach (var component in _components)
{
component.Render();
}
}
public void Destroy()
{
foreach (var component in _components)
{
component.Destroy();
}
}
public T? GetComponent<T>() where T : Component.Component
{
return !HasComponent<T>() ? null : _components.OfType<T>().First();
}
public void AddComponent<T>() where T : Component.Component, new()
{
var component = new T();
AddComponent(component);
}
public void AddComponent<T>(params object?[] parArgs) where T : Component.Component
{
var component = (T?)Activator.CreateInstance(
typeof(T),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance |
BindingFlags.OptionalParamBinding,
null,
parArgs,
null
);
if (component == null)
{
throw new InvalidOperationException($"Failed to create component of type {typeof(T)}");
}
AddComponent(component);
}
public void AddComponent<T>(T parComponent) where T : Component.Component
{
_componentActions.Enqueue(() =>
{
if (HasComponent<T>())
{
throw new ArgumentException($"GameObject already has component of type {typeof(T)}");
}
parComponent.GameObject = this;
_components.Add(parComponent);
_addedComponentTypes.Add(typeof(T).GetComponentBaseType());
});
}
public void RemoveComponent<T>() where T : Component.Component
{
if (typeof(T) == typeof(Transform))
{
throw new ArgumentException("GameObject cannot remove Transform component");
}
_componentActions.Enqueue(() =>
{
if (!HasComponent<T>())
{
throw new ArgumentException($"GameObject does not have component of type {typeof(T)}");
}
var component = GetComponent<T>();
if (component == null)
{
return;
}
_components.Remove(component);
_addedComponentTypes.Remove(typeof(T));
});
}
public bool HasComponent<T>() where T : Component.Component
{
var baseType = typeof(T).GetComponentBaseType();
return _addedComponentTypes.Contains(baseType);
}
internal void ProcessChanges()
{
while (_componentActions.TryDequeue(out var action))
{
action();
}
}
}