Files
doom-dm/Engine/src/Scene/Scene.cs
2025-01-06 00:45:28 +03:00

151 lines
3.3 KiB
C#

using Engine.Graphics.Camera;
using Engine.Graphics.Pipeline;
using Engine.Scene.Component.BuiltIn;
namespace Engine.Scene;
public class Scene : IUpdate, IRender
{
public bool IsPlaying { get; private set; }
public IReadOnlyDictionary<RenderLayer, ICamera> Cameras => _cameras;
public float TimeScale { get; set; } = 1.0f;
private readonly Dictionary<RenderLayer, ICamera> _cameras = new();
internal Hierarchy<GameObject> Hierarchy { get; } = new();
private readonly Queue<Action> _sceneActions = [];
internal void Enter()
{
if (IsPlaying)
{
throw new InvalidOperationException("Scene is already playing");
}
ProcessChanges();
var allCameras = FindAllComponents<Camera>();
foreach (var camera in allCameras)
{
_cameras.Add(camera.RenderLayer, camera);
}
IsPlaying = true;
}
public List<T> FindAllComponents<T>(bool parOnlyEnabled = true) where T : Component.Component
{
return Hierarchy.Objects
.Where(parGameObject => !parOnlyEnabled || parGameObject.IsEnabled)
.Select(parGameObject => parGameObject.GetComponent<T>())
.Where(parComponent => parComponent != null).ToList()!;
}
public T? FindFirstComponent<T>() where T : Component.Component
{
return Hierarchy.Objects.Select(parGameObject => parGameObject.GetComponent<T>())
.FirstOrDefault(parComponent => parComponent != null);
}
public void Update(double parDeltaTime)
{
if (!IsPlaying)
{
throw new InvalidOperationException("Scene is not playing");
}
ProcessChanges();
var hierarchyObjects = Hierarchy.Objects;
foreach (var gameObject in hierarchyObjects)
{
gameObject.PreUpdate();
}
foreach (var gameObject in hierarchyObjects)
{
gameObject.Update(parDeltaTime * TimeScale);
}
}
public void Render()
{
if (!IsPlaying)
{
throw new InvalidOperationException("Scene is not playing");
}
foreach (var gameObject in Hierarchy.Objects)
{
gameObject.Render();
}
}
internal void Exit()
{
if (!IsPlaying)
{
throw new InvalidOperationException("Scene is not playing");
}
foreach (var gameObject in Hierarchy.Objects)
{
gameObject.Destroy();
}
IsPlaying = false;
}
public void Add(GameObject parGameObject)
{
parGameObject.Scene = this;
Hierarchy.Add(parGameObject);
}
public void AddChild(GameObject parParent, GameObject parChild)
{
Add(parChild);
Hierarchy.AddChild(parParent, parChild);
}
public void Remove(GameObject parGameObject)
{
var children = Hierarchy.GetAllChildren(parGameObject).ToList();
Hierarchy.Remove(parGameObject);
_sceneActions.Enqueue(() =>
{
foreach (var child in children)
{
child.Destroy();
child.Scene = null;
}
parGameObject.Destroy();
parGameObject.Scene = null;
});
}
public IEnumerable<GameObject> GetChildren(GameObject parParent, bool parRecursive = false)
{
return parRecursive ? Hierarchy.GetAllChildren(parParent) : Hierarchy.GetChildren(parParent);
}
private void ProcessChanges()
{
Hierarchy.ProcessChanges();
foreach (var gameObject in Hierarchy.Objects)
{
gameObject.ProcessChanges();
}
while (_sceneActions.TryDequeue(out var action))
{
action();
}
}
}