1using System.Collections;
2using System.Collections.ObjectModel;
32[JsonObject(IsReference =
true)]
33public class Scene : IEnumerable<SceneLayer>, IDisposable
35 [Newtonsoft.Json.JsonIgnore]
36 internal DefinitionProvenance? DefinitionProvenance {
get;
set; }
38 [JsonProperty(
"SceneLayers")]
39 private readonly List<SceneLayer> _sceneLayers = [];
43#pragma warning disable IDE0051
44 [JsonProperty(
"_sceneLayers")]
45 private List<SceneLayer>? LegacySceneLayers
49 if (value is
null || _sceneLayers.Count != 0)
52 foreach (var sceneLayer
in value)
54 _sceneLayers.Add(sceneLayer);
60#pragma warning restore IDE0051
63 private readonly
object _renderSurfaceHostSync =
new();
100 #endregion Scene events
102 #region constructors / finalizer
114 _sceneLayers =
new List<SceneLayer>();
126 protected Scene(List<SceneLayer>? sceneLayers,
131 _sceneLayers = sceneLayers ??
new List<SceneLayer>();
132 ID =
string.IsNullOrWhiteSpace(
id) ? Guid.NewGuid().ToString() : id;
156 SetSceneLayerEventDelegates();
158 foreach (var sceneLayer
in _sceneLayers)
164 if (
this is not EmptyScene)
165 _allScenes.Add(
this);
168 #endregion constructors / finalizer
170 #region public properties
196 public string ID {
get;
protected internal set; } = Guid.NewGuid().ToString();
207 public int Count => _sceneLayers?.Count ?? 0;
221 lock (_renderSurfaceHostSync)
222 return _boundRenderSurfaceHost;
231 internal bool UsesDirtyRegionRendering => BoundRenderSurfaceHost?.
Backbuffer.IsGlThreadRendered !=
true;
267 public ReadOnlyCollection<SceneLayer>
SceneLayers => _sceneLayers.AsReadOnly();
269 private ReadOnlyCollection<SceneLayer>? _visibleSortedCache;
270 private bool _visibleSortedDirty =
true;
296 if (_visibleSortedDirty || _visibleSortedCache ==
null)
298 _visibleSortedCache = _sceneLayers
299 .Where(sl => sl.Visible)
300 .OrderBy(sl => sl.ZOrder)
303 _visibleSortedDirty =
false;
305 return _visibleSortedCache;
337 #endregion public properties
339 #region internal properties and methods
350 ArgumentNullException.ThrowIfNull(host);
354 if (ReferenceEquals(
this,
Empty))
357 lock (_renderSurfaceHostSync)
359 if (_boundRenderSurfaceHost is not
null &&
360 !ReferenceEquals(_boundRenderSurfaceHost, host))
362 throw new InvalidOperationException(
363 $
"Scene '{ID}' is already bound to another RenderSurfaceHost.");
366 _boundRenderSurfaceHost = host;
372 if (!UsesDirtyRegionRendering)
374 foreach (var layer
in _sceneLayers)
375 layer.RefreshQueue.ClearRefreshQueue();
384 internal void UnbindRenderSurfaceHost(RenderSurfaceHostBase host)
386 ArgumentNullException.ThrowIfNull(host);
388 if (ReferenceEquals(
this,
Empty))
391 lock (_renderSurfaceHostSync)
393 if (ReferenceEquals(_boundRenderSurfaceHost, host))
394 _boundRenderSurfaceHost =
null;
410 internal bool IsDirty
424 #endregion internal properties and methods
426 #region public methods
474 var sceneLayer =
new SceneLayer(columnCount, rowCount, width, height, parallax, coordinateSystem);
475 sceneLayer.ZOrder = zOrder;
477 _sceneLayers.Add(sceneLayer);
498 _sceneLayers.Add(sceneLayer);
524 _sceneLayers.Clear();
545 _sceneLayers.Remove(sceneLayer);
565 foreach (var sceneLayer
in _sceneLayers)
567 if (sceneLayer.
ID ==
id)
588 if (_sceneLayers.Count == 0)
589 return RectangleF.Empty;
591 RectangleF result = RectangleF.Empty;
592 bool hasBounds =
false;
594 foreach (var layer
in _sceneLayers)
596 var lb = layer.GetLayerBoundsPx();
607 result = RectangleF.Union(result, lb);
614 #endregion public methods
616 #region raise Scene events
640 sceneLayer.Scene =
this;
641 sceneLayer.ApplyDefaultTileCollisionProfile();
644 sceneLayer.Disposing += sceneLayerDisposing;
645 sceneLayer.VisibleChanged += visChgDel;
646 sceneLayer.SceneLayerTileSizeChanged += sceneLayerTileSizeDel;
647 sceneLayer.WrappingChanged += wrappingDel;
648 sceneLayer.ShowGridLinesChanged += gridLinesShowChanged;
649 sceneLayer.ShowCollisionBoxesChanged += showCollisionBoxesChanged;
650 sceneLayer.ZOrderChanged += zOrderChangedDel;
651 sceneLayer.ParallaxChanged += parallaxChangedDel;
652 sceneLayer.OriginPxChanged += originPxChangedDel;
654 _visibleSortedDirty =
true;
680 sceneLayer.Scene =
null;
682 sceneLayer.Disposing -= sceneLayerDisposing;
683 sceneLayer.VisibleChanged -= visChgDel;
684 sceneLayer.SceneLayerTileSizeChanged -= sceneLayerTileSizeDel;
685 sceneLayer.WrappingChanged -= wrappingDel;
686 sceneLayer.ShowGridLinesChanged -= gridLinesShowChanged;
687 sceneLayer.ShowCollisionBoxesChanged -= showCollisionBoxesChanged;
688 sceneLayer.ZOrderChanged -= zOrderChangedDel;
689 sceneLayer.ParallaxChanged -= parallaxChangedDel;
690 sceneLayer.OriginPxChanged -= originPxChangedDel;
692 _visibleSortedDirty =
true;
706 #endregion raise handle Scene events
708 #region handle SceneLayer events
710 private Action<SceneLayer> sceneLayerDisposing;
711 private Action<SceneLayer> visChgDel;
712 private Action<SceneLayer> sceneLayerTileSizeDel;
713 private Action<SceneLayer> wrappingDel;
714 private Action<SceneLayer> gridLinesShowChanged;
715 private Action<SceneLayer> showCollisionBoxesChanged;
716 private Action<SceneLayer> zOrderChangedDel;
717 private Action<SceneLayer> parallaxChangedDel;
718 private Action<SceneLayer> originPxChangedDel;
720 private void SetSceneLayerEventDelegates()
722 sceneLayerDisposing = (sceneLayer) =>
RemoveLayer(sceneLayer);
723 visChgDel = (sceneLayer) => _SceneLayerVisibleChanged();
724 sceneLayerTileSizeDel = (sceneLayer) => _SceneLayerTileSizeChanged();
725 wrappingDel = (sceneLayer) => _SceneLayerWrappingChanged();
726 gridLinesShowChanged = (sceneLayer) => _SceneLayerGridLinesShowChanged();
727 showCollisionBoxesChanged = (sceneLayer) => _SceneLayerShowCollisionBoxChanged();
728 zOrderChangedDel = (sceneLayer) => _SceneLayerZOrderChanged();
729 parallaxChangedDel = (sceneLayer) => _SceneLayerParallaxChanged();
730 originPxChangedDel = (sceneLayer) => _SceneLayerZeroPixelChanged();
733 private void _SceneLayerVisibleChanged()
735 _visibleSortedDirty =
true;
753 #endregion handle SceneLayer events
769 public SceneLayer?
this[
int i] => (i >= 0 && i < _sceneLayers.Count) ? _sceneLayers[i] : null;
786 #region enumerable code
810 IEnumerator<SceneLayer> IEnumerable<SceneLayer>.GetEnumerator()
812 for (
int i = 0; i < _sceneLayers.Count; i++)
814 yield
return _sceneLayers[i];
818 #endregion enumerable code
820 #region IDisposable Members
847 GC.SuppressFinalize(
this);
853 _allScenes.Remove(
this);
861 #endregion IDisposable Members
863 #region static helpers
865 internal readonly
static List<Scene> _allScenes = [];
888 public static List<string>
GetAllSceneIDs() => _allScenes.FindAll(s => s !=
null).ConvertAll(s => s.ID);
902 public static ReadOnlyCollection<Scene>
GetAllScenes() => _allScenes.AsReadOnly();
920 var tmp =
new List<Scene>(_allScenes);
921 foreach (var scene
in tmp)
925 #endregion static helpers
950 private sealed class EmptyScene :
Scene
952 internal EmptyScene()
954 _sceneLayers.Clear();
958 SceneLayer.Empty.Scene =
this;
967 protected override void OnSceneLayerAdded(SceneLayer sceneLayer)
968 =>
throw new InvalidOperationException(
"Cannot add layers to Scene.Empty");
974 protected override void OnSceneLayerRemoved(SceneLayer sceneLayer)
988 #endregion empty Scene
Manages the lifecycle, lookup, and per-frame updates of all active Sprite instances.
static SpriteManager Instance
Gets the singleton instance of the sprite manager.
Manages collision group definitions and provides bitwise mask values for collision filtering....
Stores named collision-filtering profiles for a scene. Profiles resolve their group names through the...
Represents a base class for hosting a render surface, providing functionality for managing rendering ...
BackbufferBase Backbuffer
Gets the in-memory BackbufferBase associated with the current rendering context.
Represents a single layer within a Scene, containing a grid of tiles and supporting various coordinat...
string ID
Gets or sets the unique identifier for this layer.
static SceneLayer Empty
Gets the singleton empty scene layer instance.
Represents a game scene containing multiple layers of tiles, sprites, and game objects....
SceneLayer? GetSceneLayerByID(string id)
Retrieves a layer from this scene by its unique identifier.
virtual void OnSceneLayerAdded(SceneLayer sceneLayer)
Raises the SceneLayerAdded event and performs internal setup when a layer is added to the scene.
Scene()
Initializes a new instance of the Scene class with an empty layer collection.
Action< SceneLayer >? SceneLayerRemoved
Occurs when a SceneLayer is removed from this scene.
SceneLayer AddLayer(SceneLayer sceneLayer)
Adds an existing SceneLayer to this scene.
CollisionGroupRegistry CollisionGroups
Gets the registry of collision groups used to organize and manage collision detection within the scen...
static ? Scene GetSceneByID(string id)
Retrieves a scene from the global scene collection by its unique identifier.
TypedValueBag ValueBag
Gets the extensible value bag for storing arbitrary scene-specific metadata.
bool FullRefreshNeeded
Gets or sets a value indicating whether the entire scene needs to be refreshed on the next render.
static List< string > GetAllSceneIDs()
Gets a list of unique identifiers for all active scenes in the global scene collection.
Action< SceneLayer >? SceneLayerAdded
Occurs when a SceneLayer is added to this scene.
ReadOnlyCollection< SceneLayer > SceneLayers
Gets a read-only collection of all layers in this scene, in their current order.
ReadOnlyCollection< SceneLayer > VisibleSceneLayers
Gets a read-only collection of visible layers sorted by z-order for rendering.
virtual void OnSceneLayerRemoved(SceneLayer sceneLayer)
Raises the SceneLayerRemoved event and performs internal cleanup when a layer is removed from the sce...
static void ClearAllScenes()
Disposes all active scenes in the global scene collection, releasing all resources.
string ID
Gets or sets the unique identifier for this scene.
virtual void Dispose()
Releases all resources used by the Scene and removes it from the global scene collection.
static ReadOnlyCollection< Scene > GetAllScenes()
Gets a read-only collection of all active scenes in the global scene collection.
int CountOfVisibleLayers
Gets the number of currently visible layers in this scene.
static Scene Empty
Gets the singleton empty scene instance.
virtual void OnSceneDisposing()
Raises the SceneDisposing event when the scene is being disposed.
Scene(List< SceneLayer >? sceneLayers, string? id, CollisionGroupRegistry? collisionGroups, CollisionProfileRegistry? collisionProfiles)
Initializes a new instance of the Scene class from serialized state.
CollisionProfileRegistry CollisionProfiles
Gets the named collision-filtering profiles used by layers and sprites in this scene....
SceneLayer AddLayer(int columnCount, int rowCount, int width=32, int height=32, int zOrder=0, float parallax=1f, CoordinateSystemTypes coordinateSystem=CoordinateSystemTypes.Orthogonal)
Creates and adds a new SceneLayer to this scene with the specified properties.
void RemoveLayer(SceneLayer sceneLayer)
Removes the specified layer from this scene.
Action< Scene >? SceneDisposing
Occurs when this scene is being disposed.
IEnumerator GetEnumerator()
Returns an enumerator that iterates through the scene's layers.
RectangleF GetWorldBoundsPx()
Computes a world-space pixel bounding rectangle that encloses all layers in the scene.
void RemoveAllLayers()
Removes all layers from this scene.
int Count
Gets the total number of layers in this scene, including hidden layers.
A flexible, strongly-typed value container intended for runtime-attached metadata and ephemeral engin...
CoordinateSystemTypes
Identifies the layout and math rules used to map tiles to world pixels and world pixels back to grid ...