You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1482 lines
49 KiB
C#
1482 lines
49 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Otter {
|
|
/// <summary>
|
|
/// Class used to manage Entities. The active Game should update the active Scene, which then updates
|
|
/// all of the contained Entities.
|
|
/// </summary>
|
|
public class Scene {
|
|
|
|
#region Private Fields
|
|
|
|
List<Entity> entitiesToAdd = new List<Entity>();
|
|
List<Entity> entitiesToRemove = new List<Entity>();
|
|
List<Entity> entitiesToRemoveNextFrame = new List<Entity>();
|
|
List<Entity> entitiesToChangeLayer = new List<Entity>();
|
|
List<Entity> entitiesToChangeOrder = new List<Entity>();
|
|
|
|
List<int> groupsToPause = new List<int>();
|
|
List<int> groupsToUnpause = new List<int>();
|
|
|
|
List<int> pausedGroups = new List<int>();
|
|
|
|
List<Graphic> graphics = new List<Graphic>();
|
|
|
|
SortedDictionary<int, List<Entity>> orders = new SortedDictionary<int, List<Entity>>();
|
|
SortedDictionary<int, List<Entity>> layers = new SortedDictionary<int, List<Entity>>();
|
|
|
|
internal Dictionary<int, List<Collider>> Colliders = new Dictionary<int, List<Collider>>();
|
|
|
|
List<Entity> entities = new List<Entity>();
|
|
Dictionary<int, Entity> entitiesById = new Dictionary<int, Entity>();
|
|
int nextEntityId = 0;
|
|
|
|
int entityCount = 0;
|
|
|
|
#endregion
|
|
|
|
#region Public Fields
|
|
|
|
/// <summary>
|
|
/// The Glide instance for this Scene to control all tweens.
|
|
/// </summary>
|
|
public Tweener Tweener = new Tweener();
|
|
|
|
/// <summary>
|
|
/// The current time since this Scene has started.
|
|
/// </summary>
|
|
public float Timer;
|
|
|
|
/// <summary>
|
|
/// An action that triggers during Update().
|
|
/// </summary>
|
|
public Action OnUpdate = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers during UpdateFirst().
|
|
/// </summary>
|
|
public Action OnUpdateFirst = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers during UpdateLast().
|
|
/// </summary>
|
|
public Action OnUpdateLast = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers during Render(), after all entities have been rendered.
|
|
/// </summary>
|
|
public Action OnRender = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers during Begin().
|
|
/// </summary>
|
|
public Action OnBegin = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers during End().
|
|
/// </summary>
|
|
public Action OnEnd = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers when an entity is Added.
|
|
/// </summary>
|
|
public Action OnAdd = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers when an entity is removed.
|
|
/// </summary>
|
|
public Action OnRemove = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers when the Scene is paused because a Scene is stacked on top of it.
|
|
/// </summary>
|
|
public Action OnPause = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers when the Scene is resumed because the active Scene on top of it was popped.
|
|
/// </summary>
|
|
public Action OnResume = delegate { };
|
|
|
|
/// <summary>
|
|
/// An action that triggers after the Scene has updated the camera positions for the Game's Surfaces.
|
|
/// </summary>
|
|
public Action OnCameraUpdate = delegate { };
|
|
|
|
/// <summary>
|
|
/// The angle of the camera.
|
|
/// </summary>
|
|
public float CameraAngle;
|
|
|
|
/// <summary>
|
|
/// The zoom of the camera.
|
|
/// </summary>
|
|
public float CameraZoom = 1f;
|
|
|
|
/// <summary>
|
|
/// The width of the scene.
|
|
/// </summary>
|
|
public int Width;
|
|
|
|
/// <summary>
|
|
/// The height of the scene.
|
|
/// </summary>
|
|
public int Height;
|
|
|
|
/// <summary>
|
|
/// Determines if the scene will control the game surface's camera.
|
|
/// </summary>
|
|
public bool ApplyCamera = true;
|
|
|
|
/// <summary>
|
|
/// A reference back to the current scene being run by the game.
|
|
/// </summary>
|
|
public static Scene Instance;
|
|
|
|
/// <summary>
|
|
/// Determines if scenes below this scene on the stack are allowed to render.
|
|
/// </summary>
|
|
public bool DrawScenesBelow = true;
|
|
|
|
/// <summary>
|
|
/// The bounds that the camera should be clamped inside.
|
|
/// </summary>
|
|
public Rectangle CameraBounds;
|
|
|
|
/// <summary>
|
|
/// Determines if the camera will be clamped inside the CameraBounds rectangle.
|
|
/// </summary>
|
|
public bool UseCameraBounds = false;
|
|
|
|
/// <summary>
|
|
/// The Entity that the Scene's camera will follow.
|
|
/// </summary>
|
|
public Entity CameraFocus;
|
|
|
|
/// <summary>
|
|
/// Determines if the scene will render its graphics or not.
|
|
/// </summary>
|
|
public bool Visible = true;
|
|
|
|
#endregion
|
|
|
|
#region Public Properties
|
|
|
|
/// <summary>
|
|
/// A reference to the Game that owns this Scene.
|
|
/// </summary>
|
|
public Game Game { get; internal set; }
|
|
|
|
/// <summary>
|
|
/// The default surface to render the scene's graphics to. If null then render
|
|
/// to the default game surface.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The list of surfaces the Scene should render to.
|
|
/// </summary>
|
|
public List<Surface> Surfaces { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Half of the scene's width.
|
|
/// </summary>
|
|
public float HalfWidth {
|
|
private set { }
|
|
get { return Width / 2; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Half of the scene's height.
|
|
/// </summary>
|
|
public float HalfHeight {
|
|
private set { }
|
|
get { return Height / 2; }
|
|
}
|
|
|
|
public Vector2 Center {
|
|
get {
|
|
return new Vector2(HalfWidth, HalfHeight);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A reference to the Input from the Game controlling this scene.
|
|
/// </summary>
|
|
public Input Input {
|
|
get { return Game.Input; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The current number of entities in the scene.
|
|
/// </summary>
|
|
public int EntityCount {
|
|
get { return entityCount; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The current mouse X position in relation to the scene space.
|
|
/// </summary>
|
|
public float MouseX {
|
|
get { return Input.MouseX + CameraX; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The current mouse Y position in relation to the scene space.
|
|
/// </summary>
|
|
public float MouseY {
|
|
get { return Input.MouseY + CameraY; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The current raw mouse X position in relation to the scene space.
|
|
/// </summary>
|
|
public float MouseRawX {
|
|
get { return Input.MouseRawX + CameraX; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The current raw mouse Y position in relation to the scene space.
|
|
/// </summary>
|
|
public float MouseRawY {
|
|
get { return Input.MouseRawY + CameraY; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The X position of the camera in the scene.
|
|
/// </summary>
|
|
public float CameraX {
|
|
get {
|
|
return cameraX;
|
|
}
|
|
set {
|
|
cameraX = value;
|
|
if (UseCameraBounds) {
|
|
cameraX = Util.Clamp(cameraX, CameraBounds.Left, CameraBounds.Right - CameraWidth);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The X position of the center of the camera.
|
|
/// </summary>
|
|
public float CameraCenterX {
|
|
get { return cameraX + Game.HalfWidth; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Y position of the center of the camera.
|
|
/// </summary>
|
|
public float CameraCenterY {
|
|
get { return cameraY + Game.HalfHeight; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Y position of the camera in the scene.
|
|
/// </summary>
|
|
public float CameraY {
|
|
get {
|
|
return cameraY;
|
|
}
|
|
set {
|
|
cameraY = value;
|
|
if (UseCameraBounds) {
|
|
cameraY = Util.Clamp(cameraY, CameraBounds.Top, CameraBounds.Bottom - CameraHeight);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The width in pixels that the camera is showing with the current zoom.
|
|
/// </summary>
|
|
public float CameraWidth {
|
|
get {
|
|
return Game.Width / CameraZoom;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The height in pixels that the camera is showing with the current zoom.
|
|
/// </summary>
|
|
public float CameraHeight {
|
|
get {
|
|
return Game.Height / CameraZoom;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The bounds of the Scene as a Rectangle.
|
|
/// </summary>
|
|
public Rectangle Bounds {
|
|
get {
|
|
return new Rectangle(0, 0, Width, Height);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A reference to the debugger object from the game that owns this scene.
|
|
/// </summary>
|
|
public Debugger Debugger {
|
|
get { return Game.Debugger; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="width">The width of the scene.</param>
|
|
/// <param name="height">The height of the scene.</param>
|
|
public Scene(int width = 0, int height = 0) {
|
|
Width = width;
|
|
Height = height;
|
|
Surfaces = new List<Surface>();
|
|
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
|
|
|
|
/// <summary>
|
|
/// 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();
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of scene.</typeparam>
|
|
/// <returns>The scene as that type.</returns>
|
|
public T As<T>() where T : Scene {
|
|
return (T)this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Centers the camera of the scene.
|
|
/// </summary>
|
|
/// <param name="x">The x coordinate to be the center of the scene.</param>
|
|
/// <param name="y">The y coordinate to be the center of the scene.</param>
|
|
public void CenterCamera(float x, float y) {
|
|
CameraX = x - Game.HalfWidth;
|
|
CameraY = y - Game.HalfHeight;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add an entity to the scene.
|
|
/// </summary>
|
|
/// <param name="e">Adds a new entity</param>
|
|
/// <returns>The added Entity.</returns>
|
|
public T Add<T>(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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create and add a new Entity to the Scene.
|
|
/// </summary>
|
|
/// <typeparam name="T">The Type of entity to add.</typeparam>
|
|
/// <param name="constructorArgs">The constructor arguments for creating the Entity.</param>
|
|
/// <returns>The created Entity.</returns>
|
|
public T Add<T>(params object[] constructorArgs) where T : Entity {
|
|
return Add((T)Activator.CreateInstance(typeof(T), constructorArgs));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a list of Entities to the scene.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of Entity.</typeparam>
|
|
/// <param name="entities">The list of Entities.</param>
|
|
/// <returns>The list of Entities.</returns>
|
|
public List<T> Add<T>(List<T> entities) where T : Entity {
|
|
foreach (var e in entities) {
|
|
Add(e);
|
|
}
|
|
return entities;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds an Entity only if no other Entities of that type exist in the Scene already.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of Entity.</typeparam>
|
|
/// <param name="e">The Entity to add.</param>
|
|
/// <returns>The added Entity, or the Entity of type T that exists in the Scene already.</returns>
|
|
public T AddUnique<T>(T e) where T : Entity {
|
|
if (GetEntity<T>() == null) {
|
|
if (entitiesToAdd.Count(en => en is T) == 0) {
|
|
return Add(e);
|
|
}
|
|
else {
|
|
return (T)entitiesToAdd.Find(en => en is T);
|
|
}
|
|
}
|
|
return GetEntity<T>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an adds an Entity to the Scene if there is no Entity of that type in the Scene already.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of Entity to create and Add.</typeparam>
|
|
/// <param name="constructorArgs">The constructor arguments for creating the Entity.</param>
|
|
/// <returns>The added Entity, or the Entity of type T that exists in the Scene already.</returns>
|
|
public T AddUnique<T>(params object[] constructorArgs) where T : Entity {
|
|
return AddUnique((T)Activator.CreateInstance(typeof(T), constructorArgs));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a list of Entities to the Scene if there is no Entity of that type added already.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of Entity</typeparam>
|
|
/// <param name="entities">The list of Entities to AddUnique.</param>
|
|
/// <returns>A list of the Entities that were successfully added.</returns>
|
|
public List<T> AddUnique<T>(List<T> entities) where T : Entity {
|
|
var added = new List<T>();
|
|
entities.ForEach(e => {
|
|
if (AddUnique(e) != null) {
|
|
added.Add(e);
|
|
}
|
|
});
|
|
return added;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add multiple entities to the scene.
|
|
/// </summary>
|
|
/// <param name="entities">The entities to add.</param>
|
|
/// <returns>A list of the entities.</returns>
|
|
public List<Entity> AddMultiple(params Entity[] entities) {
|
|
var r = new List<Entity>();
|
|
foreach (var e in entities) {
|
|
r.Add(Add(e));
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the only graphic of the scene.
|
|
/// </summary>
|
|
/// <param name="g">The graphic.</param>
|
|
/// <returns>The graphic.</returns>
|
|
public T SetGraphic<T>(T g) where T : Graphic {
|
|
graphics.Clear();
|
|
graphics.Add(g);
|
|
return g;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a Graphic to the scene.
|
|
/// </summary>
|
|
/// <param name="g">The Graphic.</param>
|
|
/// <returns>The Graphic.</returns>
|
|
public T AddGraphic<T>(T g) where T : Graphic {
|
|
graphics.Add(g);
|
|
return g;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a Graphic to the Scene.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="g">The Graphic to add.</param>
|
|
/// <param name="x">The X position to place the Graphic.</param>
|
|
/// <param name="y">The Y position to add the Graphic.</param>
|
|
/// <returns>The added Graphic.</returns>
|
|
public T AddGraphic<T>(T g, float x, float y) where T : Graphic {
|
|
graphics.Add(g);
|
|
g.SetPosition(x, y);
|
|
return g;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add multiple graphics to the scene.
|
|
/// </summary>
|
|
/// <param name="graphics">The graphics.</param>
|
|
/// <returns>A list of the graphics added.</returns>
|
|
public List<Graphic> AddGraphics(params Graphic[] graphics) {
|
|
var r = new List<Graphic>();
|
|
foreach (var g in graphics) {
|
|
r.Add(AddGraphic(g));
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a Graphic from the scene.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type (inferred from the parameter.)</typeparam>
|
|
/// <param name="g">The Graphic to remove.</param>
|
|
/// <returns>The Graphic.</returns>
|
|
public T RemoveGraphic<T>(T g) where T : Graphic {
|
|
graphics.Remove(g);
|
|
return g;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all Graphics from the scene.
|
|
/// </summary>
|
|
public void ClearGraphics() {
|
|
graphics.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a Graphic to the Scene and sets its Scroll value to 0.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="g">The Graphic to add.</param>
|
|
/// <returns>The added Graphic.</returns>
|
|
public T AddGraphicGUI<T>(T g) where T : Graphic {
|
|
g.Scroll = 0;
|
|
return AddGraphic(g);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a Graphic to the Scene and sets its Scroll value to 0.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="g">The Graphic to add.</param>
|
|
/// <param name="x">The X position to place the Graphic.</param>
|
|
/// <param name="y">The Y position to add the Graphic.</param>
|
|
/// <returns>The added Graphic.</returns>
|
|
public T AddGraphicGUI<T>(T g, float x, float y) where T : Graphic {
|
|
g.Scroll = 0;
|
|
g.SetPosition(x, y);
|
|
return AddGraphic(g);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds graphics to the Scene and sets their Scroll values to 0.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="graphics">The graphics to add.</param>
|
|
/// <returns>The added graphics.</returns>
|
|
public List<Graphic> AddGraphicsGUI(params Graphic[] graphics) {
|
|
var r = new List<Graphic>();
|
|
foreach (var g in graphics) {
|
|
r.Add(AddGraphicGUI(g));
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes an entity from the scene.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type (inferred from the parameter.)</typeparam>
|
|
/// <param name="e">The entity to remove.</param>
|
|
/// <returns>The entity.</returns>
|
|
public T Remove<T>(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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes the first Entity of type T from the Scene.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of Entity to remove.</typeparam>
|
|
/// <returns>The removed Entity.</returns>
|
|
public T Remove<T>() where T : Entity {
|
|
return Remove(GetEntity<T>());
|
|
}
|
|
|
|
public void Remove<T>(List<T> entities) where T : Entity {
|
|
foreach (var e in entities) Remove(e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove all entities from the scene.
|
|
/// </summary>
|
|
public void RemoveAll() {
|
|
foreach (var e in entities) {
|
|
Remove(e);
|
|
}
|
|
}
|
|
|
|
public List<Entity> RemoveMultiple(params Entity[] entities) {
|
|
var r = new List<Entity>();
|
|
foreach (var e in entities) {
|
|
r.Add(Remove(e));
|
|
}
|
|
return r;
|
|
}
|
|
|
|
public T RemoveNextFrame<T>(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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="target"></param>
|
|
public void AddSurface(Surface target) {
|
|
if (Surfaces == null) Surfaces = new List<Surface>();
|
|
Surfaces.Add(target);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove a surface from the list of targets that the scene should render to.
|
|
/// </summary>
|
|
/// <param name="target"></param>
|
|
public void RemoveSurface(Surface target) {
|
|
if (Surfaces == null) Surfaces = new List<Surface>();
|
|
Surfaces.Remove(target);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove all surface targets and revert back to the default game surface.
|
|
/// </summary>
|
|
public void ClearSurfaces() {
|
|
if (Surfaces == null) Surfaces = new List<Surface>();
|
|
Surfaces.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends an Entity to the back of its layer. Probably don't use this and change the Entity's layer in the same update.
|
|
/// </summary>
|
|
/// <param name="e">The Entity to modify.</param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends an Entity further back in its layer. Probably don't use this and change the Entity's layer in the same update.
|
|
/// </summary>
|
|
/// <param name="e">The Entity to modify.</param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Brings an Entity further forward in its layer. Probably don't use this and change the Entity's layer in the same update.
|
|
/// </summary>
|
|
/// <param name="e">The Entity to modify.</param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Brings an Entity to the front of its layer. Probably don't use this and change the Entity's layer in the same update.
|
|
/// </summary>
|
|
/// <param name="e">The Entity to modify.</param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the scene begins after being switched to, or added to the stack.
|
|
/// </summary>
|
|
public virtual void Begin() {
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the scene ends after being switched away from, or removed from the stack.
|
|
/// </summary>
|
|
public virtual void End() {
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the scene is paused because a new scene is stacked on it.
|
|
/// </summary>
|
|
public virtual void Pause() {
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the scene resumes after a scene is added above it.
|
|
/// </summary>
|
|
public virtual void Resume() {
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// The first update of the scene.
|
|
/// </summary>
|
|
public virtual void UpdateFirst() {
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// The last update of the scene.
|
|
/// </summary>
|
|
public virtual void UpdateLast() {
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// The main update loop of the scene.
|
|
/// </summary>
|
|
public virtual void Update() {
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renders the scene. Graphics added to the scene render first.
|
|
/// Graphics drawn in Render() will render on top of all entities.
|
|
/// </summary>
|
|
public virtual void Render() {
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the internal lists stored by the scene. The engine will usually take care of this!
|
|
/// </summary>
|
|
public void UpdateLists() {
|
|
while (entitiesToAdd.Count > 0) {
|
|
var adding = new List<Entity>(entitiesToAdd);
|
|
entitiesToAdd.Clear();
|
|
|
|
foreach (var e in adding) {
|
|
if (e.MarkedForRemoval) continue;
|
|
|
|
if (!orders.ContainsKey(e.Order)) {
|
|
orders.Add(e.Order, new List<Entity>());
|
|
}
|
|
orders[e.Order].Add(e);
|
|
|
|
if (!layers.ContainsKey(e.Layer)) {
|
|
layers.Add(e.Layer, new List<Entity>());
|
|
}
|
|
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<Entity>());
|
|
}
|
|
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<Entity>());
|
|
}
|
|
layers[e.Layer].Add(e);
|
|
}
|
|
entitiesToChangeLayer.Clear();
|
|
|
|
while (entitiesToRemove.Count > 0) {
|
|
var removing = new List<Entity>(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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tweens a set of numeric properties on an object.
|
|
/// </summary>
|
|
/// <param name="target">The object to tween.</param>
|
|
/// <param name="values">The values to tween to, in an anonymous type ( new { prop1 = 100, prop2 = 0} ).</param>
|
|
/// <param name="duration">Duration of the tween in seconds.</param>
|
|
/// <param name="delay">Delay before the tween starts, in seconds.</param>
|
|
/// <returns>The tween created, for setting properties on.</returns>
|
|
public Tween Tween(object target, object values, float duration, float delay = 0) {
|
|
return Tweener.Tween(target, values, duration, delay);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pause a group of entities.
|
|
/// </summary>
|
|
/// <param name="group">The group to pause.</param>
|
|
public void PauseGroup(int group) {
|
|
if (groupsToUnpause.Contains(group)) {
|
|
groupsToUnpause.Remove(group);
|
|
}
|
|
else {
|
|
groupsToPause.Add(group);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resume a paused group of entities.
|
|
/// </summary>
|
|
/// <param name="group">The group to resume.</param>
|
|
public void ResumeGroup(int group) {
|
|
if (!IsGroupPaused(group)) return;
|
|
|
|
if (groupsToPause.Contains(group)) {
|
|
groupsToPause.Remove(group);
|
|
}
|
|
else {
|
|
groupsToUnpause.Add(group);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pause or resume a group of entities. If paused, resume. If running, pause.
|
|
/// </summary>
|
|
/// <param name="group">The group to toggle.</param>
|
|
public void PauseGroupToggle(int group) {
|
|
if (IsGroupPaused(group)) {
|
|
ResumeGroup(group);
|
|
}
|
|
else {
|
|
PauseGroup(group);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// If a group of entities is currently paused. Note that pausing wont happen until the next update
|
|
/// aftering calling pause.
|
|
/// </summary>
|
|
/// <param name="group">The group to check.</param>
|
|
/// <returns>True if the group is paused.</returns>
|
|
public bool IsGroupPaused(int group) {
|
|
if (groupsToPause.Contains(group)) {
|
|
return true;
|
|
}
|
|
return pausedGroups.Contains(group);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a list of all the entities in the given group.
|
|
/// </summary>
|
|
/// <param name="group">The group to get.</param>
|
|
/// <returns>All of the entities in the group.</returns>
|
|
public List<Entity> GetEntitiesInGroup(int group) {
|
|
return entities.Where(e => e.Group == group).ToList<Entity>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a list of all the Entities in the given layer.
|
|
/// </summary>
|
|
/// <param name="layer">The layer to get.</param>
|
|
/// <returns>All of the entities in the group.</returns>
|
|
public List<Entity> GetEntitiesInLayer(int layer) {
|
|
if (layers.ContainsKey(layer)) {
|
|
return layers[layer];
|
|
}
|
|
return new List<Entity>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a list of entities of type T from the Scene.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of entity to collect.</typeparam>
|
|
/// <returns>A list of entities of type T.</returns>
|
|
public List<T> GetEntities<T>() where T : Entity {
|
|
if (typeof(T) == typeof(Entity)) {
|
|
return entities.Cast<T>().ToList<T>();
|
|
}
|
|
|
|
var list = new List<T>();
|
|
foreach (var e in entities) {
|
|
if (e is T) {
|
|
list.Add(e as T);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public List<Entity> GetEntitiesAll() {
|
|
return entities.ToList<Entity>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a list of Entities of a type from the Scene.
|
|
/// </summary>
|
|
/// <param name="t">The type of Entity to list.</param>
|
|
/// <returns>A list of Entities of type t.</returns>
|
|
public List<Entity> GetEntities(Type t) {
|
|
return entities.Where(e => e.GetType() == t).ToList<Entity>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the first instance of an Entity of type T.
|
|
/// </summary>
|
|
/// <typeparam name="T">The entity type to search for.</typeparam>
|
|
/// <returns>The first entity of that type in the scene.</returns>
|
|
public T GetEntity<T>() where T : Entity {
|
|
foreach (var e in entities) {
|
|
if (e is T) {
|
|
return (e as T);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a list of Entities that have a Collider that matches a specified tag.
|
|
/// </summary>
|
|
/// <param name="colliderTag">The tag to search for.</param>
|
|
/// <returns>Entities that have a Collider with that tag.</returns>
|
|
public List<Entity> GetEntities(int colliderTag) {
|
|
var list = new List<Entity>();
|
|
GetColliders(colliderTag).ForEach(c => list.Add(c.Entity));
|
|
return list;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a list of Entities that have a Collider that matches a specified tag.
|
|
/// </summary>
|
|
/// <param name="colliderTag">The tag to search for.</param>
|
|
/// <returns>Entities that have a Collider with that tag.</returns>
|
|
public List<Entity> GetEntities(Enum colliderTag) {
|
|
return GetEntities(Convert.ToInt32(colliderTag));
|
|
}
|
|
|
|
public List<Entity> GetEntitiesWith<T1>()
|
|
where T1 : Component {
|
|
return entities
|
|
.Where(e => e.GetComponent<T1>() != null)
|
|
.ToList<Entity>();
|
|
}
|
|
|
|
public List<Entity> GetEntitiesWith<T1, T2>()
|
|
where T1 : Component
|
|
where T2 : Component{
|
|
return entities
|
|
.Where(e => e.GetComponent<T1>() != null)
|
|
.Where(e => e.GetComponent<T2>() != null)
|
|
.ToList<Entity>();
|
|
}
|
|
|
|
public List<Entity> GetEntitiesWith<T1, T2, T3>()
|
|
where T1 : Component
|
|
where T2 : Component
|
|
where T3 : Component{
|
|
return entities
|
|
.Where(e => e.GetComponent<T1>() != null)
|
|
.Where(e => e.GetComponent<T2>() != null)
|
|
.Where(e => e.GetComponent<T3>() != null)
|
|
.ToList<Entity>();
|
|
}
|
|
|
|
public List<Entity> GetEntitiesWith<T1, T2, T3, T4>()
|
|
where T1 : Component
|
|
where T2 : Component
|
|
where T3 : Component
|
|
where T4 : Component {
|
|
return entities
|
|
.Where(e => e.GetComponent<T1>() != null)
|
|
.Where(e => e.GetComponent<T2>() != null)
|
|
.Where(e => e.GetComponent<T3>() != null)
|
|
.Where(e => e.GetComponent<T4>() != null)
|
|
.ToList<Entity>();
|
|
}
|
|
|
|
public List<Entity> GetEntitiesWith<T1, T2, T3, T4, T5>()
|
|
where T1 : Component
|
|
where T2 : Component
|
|
where T3 : Component
|
|
where T4 : Component
|
|
where T5 : Component {
|
|
return entities
|
|
.Where(e => e.GetComponent<T1>() != null)
|
|
.Where(e => e.GetComponent<T2>() != null)
|
|
.Where(e => e.GetComponent<T3>() != null)
|
|
.Where(e => e.GetComponent<T4>() != null)
|
|
.Where(e => e.GetComponent<T5>() != null)
|
|
.ToList<Entity>();
|
|
}
|
|
|
|
public List<Entity> GetEntitiesWith<T1, T2, T3, T4, T5, T6>()
|
|
where T1 : Component
|
|
where T2 : Component
|
|
where T3 : Component
|
|
where T4 : Component
|
|
where T5 : Component
|
|
where T6 : Component {
|
|
return entities
|
|
.Where(e => e.GetComponent<T1>() != null)
|
|
.Where(e => e.GetComponent<T2>() != null)
|
|
.Where(e => e.GetComponent<T3>() != null)
|
|
.Where(e => e.GetComponent<T4>() != null)
|
|
.Where(e => e.GetComponent<T5>() != null)
|
|
.Where(e => e.GetComponent<T6>() != null)
|
|
.ToList<Entity>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a list of Colliders that match a specified tag.
|
|
/// </summary>
|
|
/// <param name="tag">The tag to search for.</param>
|
|
/// <returns>Colliders that have the specified tag.</returns>
|
|
public List<Collider> GetColliders(int tag) {
|
|
return Colliders[tag].ToList<Collider>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a list of Colliders that match a specified tag.
|
|
/// </summary>
|
|
/// <param name="tag">The tag to search for.</param>
|
|
/// <returns>Colliders that have the specified tag.</returns>
|
|
public List<Collider> GetColliders(Enum tag) {
|
|
return GetColliders(Convert.ToInt32(tag));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the top most Entity in the rendering order from a set of Entities.
|
|
/// </summary>
|
|
/// <param name="entities">The set of Entities to evaluate.</param>
|
|
/// <returns>The top most Entity in the set.</returns>
|
|
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];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the bottom most Entity in the rendering order from a set of Entities.
|
|
/// </summary>
|
|
/// <param name="entities">The set of Entities to evaluate.</param>
|
|
/// <returns>The bottom most Entity in the set.</returns>
|
|
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];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Count how many entities of type T are in this Scene.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of entity to count.</typeparam>
|
|
/// <returns>The number of entities of type T.</returns>
|
|
public int GetCount<T>() 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<Collider>();
|
|
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
|
|
|
|
}
|
|
}
|