/// <summary> /// Updates the Scene. /// </summary> public void Update() { if (!this.active) { throw new InvalidOperationException("Cannot update a scene that is not active. Call Activate first."); } if (this.isUpdating) { throw new InvalidOperationException("Can't update a Scene while it is already being updated."); } this.isUpdating = true; try { // Remove disposed objects from managers this.CleanupDisposedObjects(); // Update physics this.physicsWorld.Simulate(Time.DeltaTime); // Update all GameObjects Profile.TimeUpdateScene.BeginMeasure(); DualityApp.EditorGuard(() => { this.UpdateComponents <ICmpUpdatable>(cmp => cmp.OnUpdate()); this.visibilityStrategy.Update(); }); Profile.TimeUpdateScene.EndMeasure(); } finally { this.isUpdating = false; } }
private static void OnLeaving() { switchLock++; if (Leaving != null) { Leaving(current, null); } isSwitching = true; if (current.ResWeak != null) { // Deactivate GameObjects DualityApp.EditorGuard(() => { GameObject[] activeObj = current.ResWeak.ActiveObjects.ToArray(); foreach (GameObject o in activeObj) { o.OnDeactivate(); } }); // Clear the physics world of all contents physicsWorld.Clear(); ResetPhysics(); } switchLock--; }
/// <summary> /// Transitions the <see cref="Scene"/> into an inactive state, where it can no /// longer be updated or rendered. This is the state of a <see cref="Scene"/> /// after it was loaded. /// </summary> public void Deactivate() { if (!this.active) { throw new InvalidOperationException("Cannot deactivate a scene that is not active."); } // Deactivate GameObjects DualityApp.EditorGuard(() => { // Create a list of components to deactivate List <ICmpInitializable> shutdownList = new List <ICmpInitializable>(); foreach (Component component in this.FindComponents <ICmpInitializable>()) { if (!component.Active) { continue; } shutdownList.Add(component as ICmpInitializable); } // Deactivate all the listed components. Note that they may create or destroy // objects, so it's important that we're iterating a copy of the scene objects // here, and not the real thing. for (int i = shutdownList.Count - 1; i >= 0; i--) { shutdownList[i].OnDeactivate(); } }); // Clear physics world as we're ending simulation this.physicsWorld.Native.Clear(); this.physicsWorld.ResetSimulation(); this.active = false; }
/// <summary> /// Transitions the <see cref="Scene"/> into an active state, where it can be /// updated and rendered. This is the state of a <see cref="Scene"/> while it /// is <see cref="Current"/>. /// </summary> public void Activate() { if (this.active) { throw new InvalidOperationException("Cannot activate a scene that is already active."); } // Set state to active immediately, so the scene will be treated as // such when reacting to added objects and similar events. this.active = true; // Apply physical properties this.physicsWorld.ResetSimulation(); this.physicsWorld.Gravity = this.globalGravity; // When in the editor, apply prefab links if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor) { this.ApplyPrefabLinks(); } // When running the game, break prefab links if (DualityApp.ExecContext == DualityApp.ExecutionContext.Game) { this.BreakPrefabLinks(); } // Activate GameObjects DualityApp.EditorGuard(() => { // Create a list of components to activate List <ICmpInitializable> initList = new List <ICmpInitializable>(); foreach (Component component in this.FindComponents <ICmpInitializable>()) { if (!component.Active) { continue; } initList.Add(component as ICmpInitializable); } // Activate all the listed components. Note that they may create or destroy // objects, so it's important that we're iterating a copy of the scene objects // here, and not the real thing. for (int i = 0; i < initList.Count; i++) { initList[i].OnActivate(); } }); // Update object visibility / culling info, so a scheduled switch at the // end of a frame will get up-to-date culling for rendering DualityApp.EditorGuard(() => { this.visibilityStrategy.Update(); }); }
private static void OnEntered() { switchLock++; if (current.ResWeak != null) { // Apply physical properties ResetPhysics(); physicsWorld.Gravity = PhysicsUnit.ForceToPhysical * current.ResWeak.GlobalGravity; // When in the editor, apply prefab links if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor) { current.ResWeak.ApplyPrefabLinks(); } // When running the game, break prefab links if (DualityApp.ExecContext == DualityApp.ExecutionContext.Game) { current.ResWeak.BreakPrefabLinks(); } // Activate GameObjects DualityApp.EditorGuard(() => { // Create a list of components to activate List <ICmpInitializable> initList = new List <ICmpInitializable>(); foreach (Component component in current.ResWeak.FindComponents <ICmpInitializable>()) { if (!component.Active) { continue; } initList.Add(component as ICmpInitializable); } // Activate all the listed components. Note that they may create or destroy // objects, so it's important that we're iterating a copy of the scene objects // here, and not the real thing. for (int i = 0; i < initList.Count; i++) { initList[i].OnInit(Component.InitContext.Activate); } }); } isSwitching = false; if (Entered != null) { Entered(current, null); } switchLock--; }
/// <summary> /// Updates the Scene in the editor. /// </summary> internal void EditorUpdate() { if (!this.IsCurrent) { throw new InvalidOperationException("Can't update non-current Scene!"); } switchLock++; Profile.TimeUpdateScene.BeginMeasure(); DualityApp.EditorGuard(() => { this.UpdateComponents <ICmpEditorUpdatable>(cmp => cmp.OnUpdate()); this.visibilityStrategy.Update(); }); Profile.TimeUpdateScene.EndMeasure(); switchLock--; }
/// <summary> /// Updates the Scene in the editor. /// </summary> internal void EditorUpdate() { if (this.isUpdating) { throw new InvalidOperationException("Can't update a Scene while it is already being updated."); } this.isUpdating = true; try { Profile.TimeUpdateScene.BeginMeasure(); DualityApp.EditorGuard(() => { this.UpdateComponents <ICmpEditorUpdatable>(cmp => cmp.OnUpdate()); }); Profile.TimeUpdateScene.EndMeasure(); } finally { this.isUpdating = false; } }
/// <summary> /// Updates the Scene in the editor. /// </summary> internal void EditorUpdate() { if (!this.IsCurrent) { throw new InvalidOperationException("Can't update non-current Scene!"); } switchLock++; Profile.TimeUpdateScene.BeginMeasure(); DualityApp.EditorGuard(() => { // Update all GameObjects GameObject[] activeObj = this.objectManager.ActiveObjects.ToArray(); foreach (GameObject obj in activeObj) { obj.EditorUpdate(); } }); Profile.TimeUpdateScene.EndMeasure(); switchLock--; }
private static void OnEntered() { switchLock++; if (current.ResWeak != null) { // Apply physical properties ResetPhysics(); physicsWorld.Gravity = PhysicsUnit.ForceToPhysical * current.ResWeak.GlobalGravity; // When in the editor, apply prefab links if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor) { current.ResWeak.ApplyPrefabLinks(); } // When running the game, break prefab links if (DualityApp.ExecContext == DualityApp.ExecutionContext.Game) { current.ResWeak.BreakPrefabLinks(); } // Activate GameObjects DualityApp.EditorGuard(() => { GameObject[] activeObj = current.ResWeak.ActiveObjects.ToArray(); foreach (GameObject o in activeObj) { o.OnActivate(); } }); } isSwitching = false; if (Entered != null) { Entered(current, null); } switchLock--; }
private static void OnLeaving() { switchLock++; if (Leaving != null) { Leaving(current, null); } isSwitching = true; if (current.ResWeak != null) { // Deactivate GameObjects DualityApp.EditorGuard(() => { // Create a list of components to deactivate List <ICmpInitializable> shutdownList = new List <ICmpInitializable>(); foreach (Component component in current.ResWeak.FindComponents <ICmpInitializable>()) { if (!component.Active) { continue; } shutdownList.Add(component as ICmpInitializable); } // Deactivate all the listed components. Note that they may create or destroy // objects, so it's important that we're iterating a copy of the scene objects // here, and not the real thing. for (int i = shutdownList.Count - 1; i >= 0; i--) { shutdownList[i].OnShutdown(Component.ShutdownContext.Deactivate); } }); // Clear the physics world of all contents physicsWorld.Clear(); ResetPhysics(); } switchLock--; }
/// <summary> /// Updates the Scene /// </summary> internal void Update() { if (!this.IsCurrent) { throw new InvalidOperationException("Can't update non-current Scene!"); } switchLock++; // Update physics bool physUpdate = false; double physBegin = Time.MainTimer.TotalMilliseconds; if (Scene.PhysicsFixedTime) { physicsAcc += Time.MsPFMult * Time.TimeMult; int iterations = 0; if (physicsAcc >= Time.MsPFMult) { Profile.TimeUpdatePhysics.BeginMeasure(); DualityApp.EditorGuard(() => { double timeUpdateBegin = Time.MainTimer.TotalMilliseconds; while (physicsAcc >= Time.MsPFMult) { // Catch up on updating progress FarseerPhysics.Settings.VelocityThreshold = PhysicsUnit.VelocityToPhysical * DualityApp.AppData.PhysicsVelocityThreshold; physicsWorld.Step(Time.SPFMult); physicsAcc -= Time.MsPFMult; iterations++; double timeSpent = Time.MainTimer.TotalMilliseconds - timeUpdateBegin; if (timeSpent >= Time.MsPFMult * 10.0f) { break; // Emergency exit } } }); physUpdate = true; Profile.TimeUpdatePhysics.EndMeasure(); } } else { Profile.TimeUpdatePhysics.BeginMeasure(); DualityApp.EditorGuard(() => { FarseerPhysics.Settings.VelocityThreshold = PhysicsUnit.VelocityToPhysical * Time.TimeMult * DualityApp.AppData.PhysicsVelocityThreshold; physicsWorld.Step(Time.TimeMult * Time.SPFMult); if (Time.TimeMult == 0.0f) { physicsWorld.ClearForces(); // Complete freeze? Clear forces, so they don't accumulate. } physicsAcc = PhysicsAccStart; }); physUpdate = true; Profile.TimeUpdatePhysics.EndMeasure(); } double physTime = Time.MainTimer.TotalMilliseconds - physBegin; // Apply Farseers internal measurements to Duality if (physUpdate) { Profile.TimeUpdatePhysicsAddRemove.Set(1000.0f * physicsWorld.AddRemoveTime / System.Diagnostics.Stopwatch.Frequency); Profile.TimeUpdatePhysicsContacts.Set(1000.0f * physicsWorld.ContactsUpdateTime / System.Diagnostics.Stopwatch.Frequency); Profile.TimeUpdatePhysicsContinous.Set(1000.0f * physicsWorld.ContinuousPhysicsTime / System.Diagnostics.Stopwatch.Frequency); Profile.TimeUpdatePhysicsController.Set(1000.0f * physicsWorld.ControllersUpdateTime / System.Diagnostics.Stopwatch.Frequency); Profile.TimeUpdatePhysicsSolve.Set(1000.0f * physicsWorld.SolveUpdateTime / System.Diagnostics.Stopwatch.Frequency); } // Update low fps physics state if (!physicsLowFps) { physicsLowFps = Time.LastDelta > Time.MsPFMult && physTime > Time.LastDelta * 0.85f; } else { physicsLowFps = !(Time.LastDelta < Time.MsPFMult * 0.9f || physTime < Time.LastDelta * 0.6f); } // Update all GameObjects Profile.TimeUpdateScene.BeginMeasure(); DualityApp.EditorGuard(() => { this.UpdateComponents <ICmpUpdatable>(cmp => cmp.OnUpdate()); this.visibilityStrategy.Update(); }); Profile.TimeUpdateScene.EndMeasure(); // Perform a cleanup step to catch all DisposeLater calls from within the Scene update DualityApp.RunCleanup(); // Perform a scheduled Scene switch PerformScheduledSwitch(); switchLock--; }
/// <summary> /// Advances this physics world simulation by <paramref name="timestep"/> seconds. /// /// If <see cref="IsFixedTimestep"/> is true, this may actually simulate multiple smaller /// steps, or none at all while accumulating the internal fixed step timer. Otherwise, /// it will perform exactly one physics stept with the specified <paramref name="timestep"/>. /// </summary> /// <param name="timestep"></param> public void Simulate(float timestep) { bool physUpdate = false; double physBegin = Time.MainTimer.TotalSeconds; if (this.IsFixedTimestep) { this.fixedStepTimer += timestep; int iterations = 0; if (this.fixedStepTimer >= this.fixedStepPeriod) { Profile.TimeUpdatePhysics.BeginMeasure(); DualityApp.EditorGuard(() => { double timeUpdateBegin = Time.MainTimer.TotalSeconds; while (this.fixedStepTimer >= this.fixedStepPeriod) { // Catch up on updating progress this.UpdateNativeSettings(); this.native.Step(this.fixedStepPeriod); this.fixedStepTimer -= this.fixedStepPeriod; iterations++; double timeSpent = Time.MainTimer.TotalSeconds - timeUpdateBegin; if (timeSpent >= Time.SecondsPerFrame * 10.0f) { break; // Emergency exit } } }); physUpdate = true; Profile.TimeUpdatePhysics.EndMeasure(); } } else { Profile.TimeUpdatePhysics.BeginMeasure(); DualityApp.EditorGuard(() => { this.UpdateNativeSettings(); this.native.Step(timestep); if (timestep == 0.0f) { this.native.ClearForces(); // Complete freeze? Clear forces, so they don't accumulate. } this.fixedStepTimer = this.fixedStepPeriod; }); physUpdate = true; Profile.TimeUpdatePhysics.EndMeasure(); } double physTime = Time.MainTimer.TotalSeconds - physBegin; // Apply Farseers internal measurements to Duality if (physUpdate) { Profile.TimeUpdatePhysicsAddRemove.Set(1000.0f * this.native.AddRemoveTime / Stopwatch.Frequency); Profile.TimeUpdatePhysicsContacts.Set(1000.0f * this.native.ContactsUpdateTime / Stopwatch.Frequency); Profile.TimeUpdatePhysicsContinous.Set(1000.0f * this.native.ContinuousPhysicsTime / Stopwatch.Frequency); Profile.TimeUpdatePhysicsController.Set(1000.0f * this.native.ControllersUpdateTime / Stopwatch.Frequency); Profile.TimeUpdatePhysicsSolve.Set(1000.0f * this.native.SolveUpdateTime / Stopwatch.Frequency); } // Update low fps physics state if (!this.lowFramerateMode) { this.lowFramerateMode = Time.UnscaledDeltaTime > Time.SecondsPerFrame && physTime > Time.UnscaledDeltaTime * 0.85f; } else { this.lowFramerateMode = !(Time.UnscaledDeltaTime < Time.SecondsPerFrame * 0.9f || physTime < Time.UnscaledDeltaTime * 0.6f); } }