using System; using System.Collections.Generic; using System.Linq; namespace Otter { /// /// Class used to manage Entities. The active Game should update the active Scene, which then updates /// all of the contained Entities. /// public class Scene { #region Private Fields List entitiesToAdd = new List(); List entitiesToRemove = new List(); List entitiesToRemoveNextFrame = new List(); List entitiesToChangeLayer = new List(); List entitiesToChangeOrder = new List(); List groupsToPause = new List(); List groupsToUnpause = new List(); List pausedGroups = new List(); List graphics = new List(); SortedDictionary> orders = new SortedDictionary>(); SortedDictionary> layers = new SortedDictionary>(); internal Dictionary> Colliders = new Dictionary>(); List entities = new List(); Dictionary entitiesById = new Dictionary(); int nextEntityId = 0; int entityCount = 0; #endregion #region Public Fields /// /// The Glide instance for this Scene to control all tweens. /// public Tweener Tweener = new Tweener(); /// /// The current time since this Scene has started. /// public float Timer; /// /// An action that triggers during Update(). /// public Action OnUpdate = delegate { }; /// /// An action that triggers during UpdateFirst(). /// public Action OnUpdateFirst = delegate { }; /// /// An action that triggers during UpdateLast(). /// public Action OnUpdateLast = delegate { }; /// /// An action that triggers during Render(), after all entities have been rendered. /// public Action OnRender = delegate { }; /// /// An action that triggers during Begin(). /// public Action OnBegin = delegate { }; /// /// An action that triggers during End(). /// public Action OnEnd = delegate { }; /// /// An action that triggers when an entity is Added. /// public Action OnAdd = delegate { }; /// /// An action that triggers when an entity is removed. /// public Action OnRemove = delegate { }; /// /// An action that triggers when the Scene is paused because a Scene is stacked on top of it. /// public Action OnPause = delegate { }; /// /// An action that triggers when the Scene is resumed because the active Scene on top of it was popped. /// public Action OnResume = delegate { }; /// /// An action that triggers after the Scene has updated the camera positions for the Game's Surfaces. /// public Action OnCameraUpdate = delegate { }; /// /// The angle of the camera. /// public float CameraAngle; /// /// The zoom of the camera. /// public float CameraZoom = 1f; /// /// The width of the scene. /// public int Width; /// /// The height of the scene. /// public int Height; /// /// Determines if the scene will control the game surface's camera. /// public bool ApplyCamera = true; /// /// A reference back to the current scene being run by the game. /// public static Scene Instance; /// /// Determines if scenes below this scene on the stack are allowed to render. /// public bool DrawScenesBelow = true; /// /// The bounds that the camera should be clamped inside. /// public Rectangle CameraBounds; /// /// Determines if the camera will be clamped inside the CameraBounds rectangle. /// public bool UseCameraBounds = false; /// /// The Entity that the Scene's camera will follow. /// public Entity CameraFocus; /// /// Determines if the scene will render its graphics or not. /// public bool Visible = true; #endregion #region Public Properties /// /// A reference to the Game that owns this Scene. /// public Game Game { get; internal set; } /// /// The default surface to render the scene's graphics to. If null then render /// to the default game surface. /// public Surface Surface { get { if (Surfaces == null) return null; if (Surfaces.Count == 0) return null; return Surfaces[Surfaces.Count - 1]; } set { Surfaces.Clear(); Surfaces.Add(value); } } /// /// The list of surfaces the Scene should render to. /// public List Surfaces { get; private set; } /// /// Half of the scene's width. /// public float HalfWidth { private set { } get { return Width / 2; } } /// /// Half of the scene's height. /// public float HalfHeight { private set { } get { return Height / 2; } } public Vector2 Center { get { return new Vector2(HalfWidth, HalfHeight); } } /// /// A reference to the Input from the Game controlling this scene. /// public Input Input { get { return Game.Input; } } /// /// The current number of entities in the scene. /// public int EntityCount { get { return entityCount; } } /// /// The current mouse X position in relation to the scene space. /// public float MouseX { get { return Input.MouseX + CameraX; } } /// /// The current mouse Y position in relation to the scene space. /// public float MouseY { get { return Input.MouseY + CameraY; } } /// /// The current raw mouse X position in relation to the scene space. /// public float MouseRawX { get { return Input.MouseRawX + CameraX; } } /// /// The current raw mouse Y position in relation to the scene space. /// public float MouseRawY { get { return Input.MouseRawY + CameraY; } } /// /// The X position of the camera in the scene. /// public float CameraX { get { return cameraX; } set { cameraX = value; if (UseCameraBounds) { cameraX = Util.Clamp(cameraX, CameraBounds.Left, CameraBounds.Right - CameraWidth); } } } /// /// The X position of the center of the camera. /// public float CameraCenterX { get { return cameraX + Game.HalfWidth; } } /// /// The Y position of the center of the camera. /// public float CameraCenterY { get { return cameraY + Game.HalfHeight; } } /// /// The Y position of the camera in the scene. /// public float CameraY { get { return cameraY; } set { cameraY = value; if (UseCameraBounds) { cameraY = Util.Clamp(cameraY, CameraBounds.Top, CameraBounds.Bottom - CameraHeight); } } } /// /// The width in pixels that the camera is showing with the current zoom. /// public float CameraWidth { get { return Game.Width / CameraZoom; } } /// /// The height in pixels that the camera is showing with the current zoom. /// public float CameraHeight { get { return Game.Height / CameraZoom; } } /// /// The bounds of the Scene as a Rectangle. /// public Rectangle Bounds { get { return new Rectangle(0, 0, Width, Height); } } /// /// A reference to the debugger object from the game that owns this scene. /// public Debugger Debugger { get { return Game.Debugger; } } #endregion #region Constructors /// /// Create a Scene with a specified width and height. If the width and height are not defined they /// will be inferred by the Game class that uses the Scene. /// /// The width of the scene. /// The height of the scene. public Scene(int width = 0, int height = 0) { Width = width; Height = height; Surfaces = new List(); CameraBounds = new Rectangle(0, 0, (int)width, (int)height); } #endregion #region Private Methods void RenderScene() { if (Visible) { foreach (var g in graphics) { g.Render(); } OnRender(); } } #endregion #region Public Indexers public Entity this[int id] { get { if (entitiesById.ContainsKey(id)) return entitiesById[id]; return null; } } #endregion #region Public Methods /// /// A handy shortcut for casting the Scene as a specific scene type. /// For some reason I just like this better than doing (Scene as Type).Whatever(); /// /// The type of scene. /// The scene as that type. public T As() where T : Scene { return (T)this; } /// /// Centers the camera of the scene. /// /// The x coordinate to be the center of the scene. /// The y coordinate to be the center of the scene. public void CenterCamera(float x, float y) { CameraX = x - Game.HalfWidth; CameraY = y - Game.HalfHeight; } /// /// Add an entity to the scene. /// /// Adds a new entity /// The added Entity. public T Add(T e) where T : Entity { if (e == null) throw new ArgumentNullException("Entity cannot be null."); if (e.Scene != null) return e; entitiesToAdd.Add(e); e.Scene = this; e.MarkedForRemoval = false; e.MarkedForAdd = true; return e; } /// /// Create and add a new Entity to the Scene. /// /// The Type of entity to add. /// The constructor arguments for creating the Entity. /// The created Entity. public T Add(params object[] constructorArgs) where T : Entity { return Add((T)Activator.CreateInstance(typeof(T), constructorArgs)); } /// /// Add a list of Entities to the scene. /// /// The type of Entity. /// The list of Entities. /// The list of Entities. public List Add(List entities) where T : Entity { foreach (var e in entities) { Add(e); } return entities; } /// /// Adds an Entity only if no other Entities of that type exist in the Scene already. /// /// The type of Entity. /// The Entity to add. /// The added Entity, or the Entity of type T that exists in the Scene already. public T AddUnique(T e) where T : Entity { if (GetEntity() == null) { if (entitiesToAdd.Count(en => en is T) == 0) { return Add(e); } else { return (T)entitiesToAdd.Find(en => en is T); } } return GetEntity(); } /// /// Creates an adds an Entity to the Scene if there is no Entity of that type in the Scene already. /// /// The type of Entity to create and Add. /// The constructor arguments for creating the Entity. /// The added Entity, or the Entity of type T that exists in the Scene already. public T AddUnique(params object[] constructorArgs) where T : Entity { return AddUnique((T)Activator.CreateInstance(typeof(T), constructorArgs)); } /// /// Adds a list of Entities to the Scene if there is no Entity of that type added already. /// /// The type of Entity /// The list of Entities to AddUnique. /// A list of the Entities that were successfully added. public List AddUnique(List entities) where T : Entity { var added = new List(); entities.ForEach(e => { if (AddUnique(e) != null) { added.Add(e); } }); return added; } /// /// Add multiple entities to the scene. /// /// The entities to add. /// A list of the entities. public List AddMultiple(params Entity[] entities) { var r = new List(); foreach (var e in entities) { r.Add(Add(e)); } return r; } /// /// Set the only graphic of the scene. /// /// The graphic. /// The graphic. public T SetGraphic(T g) where T : Graphic { graphics.Clear(); graphics.Add(g); return g; } /// /// Adds a Graphic to the scene. /// /// The Graphic. /// The Graphic. public T AddGraphic(T g) where T : Graphic { graphics.Add(g); return g; } /// /// Adds a Graphic to the Scene. /// /// /// The Graphic to add. /// The X position to place the Graphic. /// The Y position to add the Graphic. /// The added Graphic. public T AddGraphic(T g, float x, float y) where T : Graphic { graphics.Add(g); g.SetPosition(x, y); return g; } /// /// Add multiple graphics to the scene. /// /// The graphics. /// A list of the graphics added. public List AddGraphics(params Graphic[] graphics) { var r = new List(); foreach (var g in graphics) { r.Add(AddGraphic(g)); } return r; } /// /// Removes a Graphic from the scene. /// /// The type (inferred from the parameter.) /// The Graphic to remove. /// The Graphic. public T RemoveGraphic(T g) where T : Graphic { graphics.Remove(g); return g; } /// /// Removes all Graphics from the scene. /// public void ClearGraphics() { graphics.Clear(); } /// /// Adds a Graphic to the Scene and sets its Scroll value to 0. /// /// /// The Graphic to add. /// The added Graphic. public T AddGraphicGUI(T g) where T : Graphic { g.Scroll = 0; return AddGraphic(g); } /// /// Adds a Graphic to the Scene and sets its Scroll value to 0. /// /// /// The Graphic to add. /// The X position to place the Graphic. /// The Y position to add the Graphic. /// The added Graphic. public T AddGraphicGUI(T g, float x, float y) where T : Graphic { g.Scroll = 0; g.SetPosition(x, y); return AddGraphic(g); } /// /// Adds graphics to the Scene and sets their Scroll values to 0. /// /// /// The graphics to add. /// The added graphics. public List AddGraphicsGUI(params Graphic[] graphics) { var r = new List(); foreach (var g in graphics) { r.Add(AddGraphicGUI(g)); } return r; } /// /// Removes an entity from the scene. /// /// The type (inferred from the parameter.) /// The entity to remove. /// The entity. public T Remove(T e) where T : Entity { if (e == null) throw new ArgumentNullException("Entity to remove cannot be null."); if (e.MarkedForRemoval) return e; if (e.Scene == null) return e; if (!entitiesToAdd.Contains(e)) { entitiesToRemove.Add(e); // Only add to entities to remove if it has been added already. } e.MarkedForRemoval = true; e.MarkedForAdd = false; return e; } /// /// Removes the first Entity of type T from the Scene. /// /// The type of Entity to remove. /// The removed Entity. public T Remove() where T : Entity { return Remove(GetEntity()); } public void Remove(List entities) where T : Entity { foreach (var e in entities) Remove(e); } /// /// Remove all entities from the scene. /// public void RemoveAll() { foreach (var e in entities) { Remove(e); } } public List RemoveMultiple(params Entity[] entities) { var r = new List(); foreach (var e in entities) { r.Add(Remove(e)); } return r; } public T RemoveNextFrame(T e) where T : Entity { if (e == null) throw new ArgumentNullException("Entity to remove cannot be null."); if (e.MarkedForRemoval) return e; if (e.Scene == null) return e; if (!entitiesToAdd.Contains(e)) { entitiesToRemoveNextFrame.Add(e); } //e.MarkedForRemoval = true; e.MarkedForAdd = false; return e; } /// /// Add a surface to the list of surfaces that the scene should render to. /// This only applies to the Scene's graphics, NOT the entities in the scene. /// /// public void AddSurface(Surface target) { if (Surfaces == null) Surfaces = new List(); Surfaces.Add(target); } /// /// Remove a surface from the list of targets that the scene should render to. /// /// public void RemoveSurface(Surface target) { if (Surfaces == null) Surfaces = new List(); Surfaces.Remove(target); } /// /// Remove all surface targets and revert back to the default game surface. /// public void ClearSurfaces() { if (Surfaces == null) Surfaces = new List(); Surfaces.Clear(); } /// /// Sends an Entity to the back of its layer. Probably don't use this and change the Entity's layer in the same update. /// /// The Entity to modify. public void SendToBack(Entity e) { if (!layers.ContainsKey(e.Layer)) return; if (!layers[e.Layer].Contains(e)) return; layers[e.Layer].Remove(e); layers[e.Layer].Insert(0, e); } /// /// Sends an Entity further back in its layer. Probably don't use this and change the Entity's layer in the same update. /// /// The Entity to modify. public void SendBackward(Entity e) { if (!layers.ContainsKey(e.Layer)) return; if (!layers[e.Layer].Contains(e)) return; var oldIndex = layers[e.Layer].IndexOf(e); if (oldIndex == 0) return; layers[e.Layer].Remove(e); layers[e.Layer].InsertOrAdd(oldIndex - 1, e); } /// /// Brings an Entity further forward in its layer. Probably don't use this and change the Entity's layer in the same update. /// /// The Entity to modify. public void BringForward(Entity e) { if (!layers.ContainsKey(e.Layer)) return; if (!layers[e.Layer].Contains(e)) return; var oldIndex = layers[e.Layer].IndexOf(e); if (oldIndex == layers[e.Layer].Count - 1) return; layers[e.Layer].Remove(e); layers[e.Layer].InsertOrAdd(oldIndex + 1, e); } /// /// Brings an Entity to the front of its layer. Probably don't use this and change the Entity's layer in the same update. /// /// The Entity to modify. public void BringToFront(Entity e) { if (!layers.ContainsKey(e.Layer)) return; if (!layers[e.Layer].Contains(e)) return; layers[e.Layer].Remove(e); layers[e.Layer].Add(e); } /// /// Called when the scene begins after being switched to, or added to the stack. /// public virtual void Begin() { } /// /// Called when the scene ends after being switched away from, or removed from the stack. /// public virtual void End() { } /// /// Called when the scene is paused because a new scene is stacked on it. /// public virtual void Pause() { } /// /// Called when the scene resumes after a scene is added above it. /// public virtual void Resume() { } /// /// The first update of the scene. /// public virtual void UpdateFirst() { } /// /// The last update of the scene. /// public virtual void UpdateLast() { } /// /// The main update loop of the scene. /// public virtual void Update() { } /// /// Renders the scene. Graphics added to the scene render first. /// Graphics drawn in Render() will render on top of all entities. /// public virtual void Render() { } /// /// Update the internal lists stored by the scene. The engine will usually take care of this! /// public void UpdateLists() { while (entitiesToAdd.Count > 0) { var adding = new List(entitiesToAdd); entitiesToAdd.Clear(); foreach (var e in adding) { if (e.MarkedForRemoval) continue; if (!orders.ContainsKey(e.Order)) { orders.Add(e.Order, new List()); } orders[e.Order].Add(e); if (!layers.ContainsKey(e.Layer)) { layers.Add(e.Layer, new List()); } layers[e.Layer].Add(e); entities.Add(e); var id = GetNextEntityId(); entitiesById.Add(id, e); e.InstanceId = id; e.MarkedForAdd = false; foreach (var c in e.Colliders) { AddColliderInternal(c); } entityCount++; } foreach (var e in adding) { // Invoke these methods after *all* entities in the queue are actually in the scene. e.UpdateComponentLists(); // trying this twice? this might break everything. e.Added(); e.UpdateComponentLists(); // Add components after e.Added, so that Entity.Scene is not null for components. e.OnAdded(); // Moved OnAdded after UpdateComponentLists so components can hook into OnAdded } } foreach (var e in entitiesToChangeOrder) { orders[e.oldOrder].Remove(e); if (orders[e.oldOrder].Count == 0) { orders.Remove(e.oldOrder); } if (!orders.ContainsKey(e.Order)) { orders.Add(e.Order, new List()); } orders[e.Order].Add(e); } entitiesToChangeOrder.Clear(); foreach (var e in entitiesToChangeLayer) { layers[e.oldLayer].Remove(e); if (layers[e.oldLayer].Count == 0) { layers.Remove(e.oldLayer); } if (!layers.ContainsKey(e.Layer)) { layers.Add(e.Layer, new List()); } layers[e.Layer].Add(e); } entitiesToChangeLayer.Clear(); while (entitiesToRemove.Count > 0) { var removing = new List(entitiesToRemove); entitiesToRemove.Clear(); foreach (var e in removing) { orders[e.Order].Remove(e); if (orders[e.Order].Count == 0) { orders.Remove(e.Order); } layers[e.Layer].Remove(e); if (layers[e.Layer].Count == 0) { layers.Remove(e.Layer); } entities.Remove(e); entitiesById.Remove(e.InstanceId); e.InstanceId = -1; foreach (var c in e.Colliders) { RemoveColliderInternal(c); } entityCount--; } foreach (var e in removing) { e.Removed(); e.OnRemoved(); e.Scene = null; } } foreach (var e in entitiesToRemoveNextFrame) { Remove(e); } entitiesToRemoveNextFrame.Clear(); foreach (var group in groupsToPause) { if (!pausedGroups.Contains(group)) { foreach (var order in orders) { foreach (var e in order.Value) { if (e.Group == group) { e.Paused(); } } } pausedGroups.Add(group); } } groupsToPause.Clear(); foreach (var group in groupsToUnpause) { if (IsGroupPaused(group)) { foreach (var order in orders) { foreach (var e in order.Value) { if (e.Group == group) { e.Resumed(); } } } pausedGroups.Remove(group); } } groupsToUnpause.Clear(); } /// /// Tweens a set of numeric properties on an object. /// /// The object to tween. /// The values to tween to, in an anonymous type ( new { prop1 = 100, prop2 = 0} ). /// Duration of the tween in seconds. /// Delay before the tween starts, in seconds. /// The tween created, for setting properties on. public Tween Tween(object target, object values, float duration, float delay = 0) { return Tweener.Tween(target, values, duration, delay); } /// /// Pause a group of entities. /// /// The group to pause. public void PauseGroup(int group) { if (groupsToUnpause.Contains(group)) { groupsToUnpause.Remove(group); } else { groupsToPause.Add(group); } } /// /// Resume a paused group of entities. /// /// The group to resume. public void ResumeGroup(int group) { if (!IsGroupPaused(group)) return; if (groupsToPause.Contains(group)) { groupsToPause.Remove(group); } else { groupsToUnpause.Add(group); } } /// /// Pause or resume a group of entities. If paused, resume. If running, pause. /// /// The group to toggle. public void PauseGroupToggle(int group) { if (IsGroupPaused(group)) { ResumeGroup(group); } else { PauseGroup(group); } } /// /// If a group of entities is currently paused. Note that pausing wont happen until the next update /// aftering calling pause. /// /// The group to check. /// True if the group is paused. public bool IsGroupPaused(int group) { if (groupsToPause.Contains(group)) { return true; } return pausedGroups.Contains(group); } /// /// Returns a list of all the entities in the given group. /// /// The group to get. /// All of the entities in the group. public List GetEntitiesInGroup(int group) { return entities.Where(e => e.Group == group).ToList(); } /// /// Returns a list of all the Entities in the given layer. /// /// The layer to get. /// All of the entities in the group. public List GetEntitiesInLayer(int layer) { if (layers.ContainsKey(layer)) { return layers[layer]; } return new List(); } /// /// Get a list of entities of type T from the Scene. /// /// The type of entity to collect. /// A list of entities of type T. public List GetEntities() where T : Entity { if (typeof(T) == typeof(Entity)) { return entities.Cast().ToList(); } var list = new List(); foreach (var e in entities) { if (e is T) { list.Add(e as T); } } return list; } public List GetEntitiesAll() { return entities.ToList(); } /// /// Get a list of Entities of a type from the Scene. /// /// The type of Entity to list. /// A list of Entities of type t. public List GetEntities(Type t) { return entities.Where(e => e.GetType() == t).ToList(); } /// /// Get the first instance of an Entity of type T. /// /// The entity type to search for. /// The first entity of that type in the scene. public T GetEntity() where T : Entity { foreach (var e in entities) { if (e is T) { return (e as T); } } return null; } /// /// Get a list of Entities that have a Collider that matches a specified tag. /// /// The tag to search for. /// Entities that have a Collider with that tag. public List GetEntities(int colliderTag) { var list = new List(); GetColliders(colliderTag).ForEach(c => list.Add(c.Entity)); return list; } /// /// Get a list of Entities that have a Collider that matches a specified tag. /// /// The tag to search for. /// Entities that have a Collider with that tag. public List GetEntities(Enum colliderTag) { return GetEntities(Convert.ToInt32(colliderTag)); } public List GetEntitiesWith() where T1 : Component { return entities .Where(e => e.GetComponent() != null) .ToList(); } public List GetEntitiesWith() where T1 : Component where T2 : Component{ return entities .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .ToList(); } public List GetEntitiesWith() where T1 : Component where T2 : Component where T3 : Component{ return entities .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .ToList(); } public List GetEntitiesWith() where T1 : Component where T2 : Component where T3 : Component where T4 : Component { return entities .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .ToList(); } public List GetEntitiesWith() where T1 : Component where T2 : Component where T3 : Component where T4 : Component where T5 : Component { return entities .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .ToList(); } public List GetEntitiesWith() where T1 : Component where T2 : Component where T3 : Component where T4 : Component where T5 : Component where T6 : Component { return entities .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .Where(e => e.GetComponent() != null) .ToList(); } /// /// Get a list of Colliders that match a specified tag. /// /// The tag to search for. /// Colliders that have the specified tag. public List GetColliders(int tag) { return Colliders[tag].ToList(); } /// /// Get a list of Colliders that match a specified tag. /// /// The tag to search for. /// Colliders that have the specified tag. public List GetColliders(Enum tag) { return GetColliders(Convert.ToInt32(tag)); } /// /// Get the top most Entity in the rendering order from a set of Entities. /// /// The set of Entities to evaluate. /// The top most Entity in the set. public Entity GetTopEntity(params Entity[] entities) { if (entities.Length == 0) return null; if (entities.Length == 1) return entities[0]; var validEntities = entities.Where(e => e.Scene == this); if (validEntities.Count() == 0) return null; var min = validEntities.Min(e => e.Layer); var minIndex = validEntities.Where(e => e.Layer == min).Max(e => layers[min].IndexOf(e)); return layers[min][minIndex]; } /// /// Get the bottom most Entity in the rendering order from a set of Entities. /// /// The set of Entities to evaluate. /// The bottom most Entity in the set. public Entity GetBottomEntity(params Entity[] entities) { if (entities.Length == 0) return null; if (entities.Length == 1) return entities[0]; var validEntities = entities.Where(e => e.Scene == this); if (validEntities.Count() == 0) return null; var max = validEntities.Max(e => e.Layer); var maxIndex = validEntities.Where(e => e.Layer == max).Min(e => layers[max].IndexOf(e)); return layers[max][maxIndex]; } /// /// Count how many entities of type T are in this Scene. /// /// The type of entity to count. /// The number of entities of type T. public int GetCount() where T : Entity { var count = 0; foreach (var e in entities) { if (e is T) { count++; } } return count; } #endregion #region Internal internal float cameraX, cameraY; internal int GetNextEntityId() { var id = nextEntityId; nextEntityId++; return id; } internal void AddColliderInternal(Collider c) { foreach (var tag in c.Tags) { if (Colliders.ContainsKey(tag)) { if (!Colliders[tag].Contains(c)) { // Quick fix to prevent double adding. Colliders[tag].Add(c); } } else { Colliders[tag] = new List(); Colliders[tag].Add(c); } } } internal void RemoveColliderInternal(Collider c) { foreach (var tag in c.Tags) { if (Colliders.ContainsKey(tag)) { Colliders[tag].Remove(c); if (Colliders[tag].Count == 0) { Colliders.Remove(tag); } } } } internal void BeginInternal() { Instance = this; foreach (var e in entitiesToAdd) { e.SceneBegin(); } Game.OnSceneBegin(); OnBegin(); if (Width == 0 || Height == 0) { Width = Game.Width; Height = Game.Height; } Begin(); } internal void EndInternal() { foreach (var order in orders) { foreach (var e in order.Value) { e.SceneEnd(); } } Game.OnSceneEnd(); OnEnd(); End(); UpdateLists(); // Testing this } internal void PauseInternal() { foreach (var order in orders) { foreach (var e in order.Value) { e.ScenePause(); } } OnPause(); Pause(); } internal void ResumeInternal() { Instance = this; foreach (var order in orders) { foreach (var e in order.Value) { e.SceneResume(); } } OnResume(); Resume(); } internal void UpdateFirstInternal() { OnUpdateFirst(); UpdateFirst(); foreach (var order in orders) { foreach (var e in order.Value) { if (e.AutoUpdate) { if (!IsGroupPaused(e.Group)) { e.UpdateFirstInternal(); } } } } } internal void UpdateLastInternal() { OnUpdateLast(); UpdateLast(); foreach (var order in orders) { foreach (var e in order.Value) { if (e.AutoUpdate) { if (!IsGroupPaused(e.Group)) { e.UpdateLastInternal(); } } if (e.Order != order.Key) { entitiesToChangeOrder.Add(e); e.oldOrder = order.Key; } } } foreach (var layer in layers.Reverse()) { foreach (var e in layer.Value) { if (e.Layer != layer.Key) { entitiesToChangeLayer.Add(e); e.oldLayer = layer.Key; } } } foreach (Graphic g in graphics) { g.Update(); } if (UseCameraBounds) { CameraX = Util.Clamp(CameraX, CameraBounds.Left, CameraBounds.Right - Game.Width); CameraY = Util.Clamp(CameraY, CameraBounds.Top, CameraBounds.Bottom - Game.Height); } foreach (var g in graphics) { g.Update(); } UpdateCamera(); Timer += Game.DeltaTime; } internal void UpdateCamera() { if (CameraFocus != null) { CameraX = CameraFocus.X - Game.HalfWidth; CameraY = CameraFocus.Y - Game.HalfHeight; } var cx = CameraX; var cy = CameraY; if (Debugger.Instance != null) { if (Debugger.IsOpen) { cx += Debugger.DebugCameraX; cy += Debugger.DebugCameraY; } } if (ApplyCamera) { Game.Surfaces.FindAll(s => s.UseSceneCamera).ForEach(s => s.SetView(Util.Round(cx), Util.Round(cy), CameraAngle, CameraZoom)); Game.Surface.SetView(Util.Round(cx), Util.Round(cy), CameraAngle, CameraZoom); } OnCameraUpdate(); } internal void UpdateInternal() { OnUpdate(); Tweener.Update(Game.DeltaTime); Update(); foreach (var order in orders) { foreach (var e in order.Value) { if (e.AutoUpdate) { if (!IsGroupPaused(e.Group)) { e.UpdateInternal(); } } } } } internal void RenderInternal() { //Render scene graphics behind everything (Scenery!) if (Surface == null) { RenderScene(); } else { Surface temp = Draw.Target; foreach (var surface in Surfaces) { Draw.SetTarget(surface); RenderScene(); } Draw.SetTarget(temp); } foreach (var layer in layers.Reverse()) { foreach (var e in layer.Value) { if (e.AutoRender && e.Visible) { e.RenderInternal(); } } } if (Surface == null) { Render(); } else { Surface temp = Draw.Target; foreach (var surface in Surfaces) { Draw.SetTarget(surface); Render(); } Draw.SetTarget(temp); } } #endregion } }