151 lines
3.3 KiB
C#
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();
|
|
}
|
|
}
|
|
} |