| /*␊ |
| * Farseer Physics Engine based on Box2D.XNA port:␊ |
| * Copyright (c) 2010 Ian Qvist␊ |
| * ␊ |
| * Box2D.XNA port of Box2D:␊ |
| * Copyright (c) 2009 Brandon Furtwangler, Nathan Furtwangler␊ |
| *␊ |
| * Original source Box2D:␊ |
| * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com ␊ |
| * ␊ |
| * This software is provided 'as-is', without any express or implied ␊ |
| * warranty. In no event will the authors be held liable for any damages ␊ |
| * arising from the use of this software. ␊ |
| * Permission is granted to anyone to use this software for any purpose, ␊ |
| * including commercial applications, and to alter it and redistribute it ␊ |
| * freely, subject to the following restrictions: ␊ |
| * 1. The origin of this software must not be misrepresented; you must not ␊ |
| * claim that you wrote the original software. If you use this software ␊ |
| * in a product, an acknowledgment in the product documentation would be ␊ |
| * appreciated but is not required. ␊ |
| * 2. Altered source versions must be plainly marked as such, and must not be ␊ |
| * misrepresented as being the original software. ␊ |
| * 3. This notice may not be removed or altered from any source distribution. ␊ |
| */␊ |
| ␊ |
| using System;␊ |
| using System.Collections.Generic;␊ |
| using System.Diagnostics;␊ |
| using FarseerPhysics.Collision;␊ |
| using FarseerPhysics.Common;␊ |
| using FarseerPhysics.Controllers;␊ |
| using FarseerPhysics.Dynamics.Contacts;␊ |
| using FarseerPhysics.Dynamics.Joints;␊ |
| using Microsoft.Xna.Framework;␊ |
| ␊ |
| namespace FarseerPhysics.Dynamics␊ |
| {␊ |
| /// <summary>␊ |
| /// Contains filter data that can determine whether an object should be processed or not.␊ |
| /// </summary>␊ |
| public abstract class FilterData␊ |
| {␊ |
| public Category DisabledOnCategories = Category.None;␊ |
| ␊ |
| public int DisabledOnGroup;␊ |
| public Category EnabledOnCategories = Category.All;␊ |
| public int EnabledOnGroup;␊ |
| ␊ |
| public virtual bool IsActiveOn(Body body)␊ |
| {␊ |
| if (body == null || !body.Enabled || body.IsStatic)␊ |
| return false;␊ |
| ␊ |
| if (body.FixtureList == null)␊ |
| return false;␊ |
| ␊ |
| foreach (Fixture fixture in body.FixtureList)␊ |
| {␊ |
| //Disable␊ |
| if ((fixture.CollisionGroup == DisabledOnGroup) &&␊ |
| fixture.CollisionGroup != 0 && DisabledOnGroup != 0)␊ |
| return false;␊ |
| ␊ |
| if ((fixture.CollisionCategories & DisabledOnCategories) != Category.None)␊ |
| return false;␊ |
| ␊ |
| if (EnabledOnGroup != 0 || EnabledOnCategories != Category.All)␊ |
| {␊ |
| //Enable␊ |
| if ((fixture.CollisionGroup == EnabledOnGroup) &&␊ |
| fixture.CollisionGroup != 0 && EnabledOnGroup != 0)␊ |
| return true;␊ |
| ␊ |
| if ((fixture.CollisionCategories & EnabledOnCategories) != Category.None &&␊ |
| EnabledOnCategories != Category.All)␊ |
| return true;␊ |
| }␊ |
| else␊ |
| {␊ |
| return true;␊ |
| }␊ |
| }␊ |
| ␊ |
| return false;␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Adds the category.␊ |
| /// </summary>␊ |
| /// <param name="category">The category.</param>␊ |
| public void AddDisabledCategory(Category category)␊ |
| {␊ |
| DisabledOnCategories |= category;␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Removes the category.␊ |
| /// </summary>␊ |
| /// <param name="category">The category.</param>␊ |
| public void RemoveDisabledCategory(Category category)␊ |
| {␊ |
| DisabledOnCategories &= ~category;␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Determines whether this body ignores the the specified controller.␊ |
| /// </summary>␊ |
| /// <param name="category">The category.</param>␊ |
| /// <returns>␊ |
| /// ␉<c>true</c> if the object has the specified category; otherwise, <c>false</c>.␊ |
| /// </returns>␊ |
| public bool IsInDisabledCategory(Category category)␊ |
| {␊ |
| return (DisabledOnCategories & category) == category;␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Adds the category.␊ |
| /// </summary>␊ |
| /// <param name="category">The category.</param>␊ |
| public void AddEnabledCategory(Category category)␊ |
| {␊ |
| EnabledOnCategories |= category;␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Removes the category.␊ |
| /// </summary>␊ |
| /// <param name="category">The category.</param>␊ |
| public void RemoveEnabledCategory(Category category)␊ |
| {␊ |
| EnabledOnCategories &= ~category;␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Determines whether this body ignores the the specified controller.␊ |
| /// </summary>␊ |
| /// <param name="category">The category.</param>␊ |
| /// <returns>␊ |
| /// ␉<c>true</c> if the object has the specified category; otherwise, <c>false</c>.␊ |
| /// </returns>␊ |
| public bool IsInEnabledCategory(Category category)␊ |
| {␊ |
| return (EnabledOnCategories & category) == category;␊ |
| }␊ |
| }␊ |
| ␊ |
| [Flags]␊ |
| public enum WorldFlags␊ |
| {␊ |
| /// <summary>␊ |
| /// Flag that indicates a new fixture has been added to the world.␊ |
| /// </summary>␊ |
| NewFixture = (1 << 0),␊ |
| ␊ |
| /// <summary>␊ |
| /// Flag that clear the forces after each time step.␊ |
| /// </summary>␊ |
| ClearForces = (1 << 2),␊ |
| ␊ |
| SubStepping = (1 << 4),␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// The world class manages all physics entities, dynamic simulation,␊ |
| /// and asynchronous queries.␊ |
| /// </summary>␊ |
| public class World␊ |
| {␊ |
| /// <summary>␊ |
| /// Fires whenever a body has been added␊ |
| /// </summary>␊ |
| public BodyDelegate BodyAdded;␊ |
| ␊ |
| /// <summary>␊ |
| /// Fires whenever a body has been removed␊ |
| /// </summary>␊ |
| public BodyDelegate BodyRemoved;␊ |
| ␊ |
| internal Queue<Contact> ContactPool = new Queue<Contact>(256);␊ |
| ␊ |
| /// <summary>␊ |
| /// Fires whenever a fixture has been added␊ |
| /// </summary>␊ |
| public FixtureDelegate FixtureAdded;␊ |
| ␊ |
| /// <summary>␊ |
| /// Fires whenever a fixture has been removed␊ |
| /// </summary>␊ |
| public FixtureDelegate FixtureRemoved;␊ |
| ␊ |
| internal WorldFlags Flags;␊ |
| ␊ |
| /// <summary>␊ |
| /// Fires whenever a joint has been added␊ |
| /// </summary>␊ |
| public JointDelegate JointAdded;␊ |
| ␊ |
| /// <summary>␊ |
| /// Fires whenever a joint has been removed␊ |
| /// </summary>␊ |
| public JointDelegate JointRemoved;␊ |
| ␊ |
| public ControllerDelegate ControllerAdded;␊ |
| ␊ |
| public ControllerDelegate ControllerRemoved;␊ |
| ␊ |
| private float _invDt0;␊ |
| public Island Island = new Island();␊ |
| private Body[] _stack = new Body[64];␊ |
| private bool _stepComplete;␊ |
| private HashSet<Body> _bodyAddList = new HashSet<Body>();␊ |
| private HashSet<Body> _bodyRemoveList = new HashSet<Body>();␊ |
| private HashSet<Joint> _jointAddList = new HashSet<Joint>();␊ |
| private HashSet<Joint> _jointRemoveList = new HashSet<Joint>();␊ |
| private TOIInput _input = new TOIInput();␊ |
| ␊ |
| /// <summary>␊ |
| /// If false, the whole simulation stops. It still processes added and removed geometries.␊ |
| /// </summary>␊ |
| public bool Enabled = true;␊ |
| ␊ |
| #if (!SILVERLIGHT)␊ |
| private Stopwatch _watch = new Stopwatch();␊ |
| #endif␊ |
| ␊ |
| /// <summary>␊ |
| /// Initializes a new instance of the <see cref="World"/> class.␊ |
| /// </summary>␊ |
| private World()␊ |
| {␊ |
| Flags = WorldFlags.ClearForces;␊ |
| ␊ |
| ControllerList = new List<Controller>();␊ |
| BreakableBodyList = new List<BreakableBody>();␊ |
| BodyList = new List<Body>(32);␊ |
| JointList = new List<Joint>(32);␊ |
| }␊ |
| ␊ |
| public World(Vector2 gravity, AABB span)␊ |
| : this()␊ |
| {␊ |
| Gravity = gravity;␊ |
| ContactManager = new ContactManager(new QuadTreeBroadPhase(span));␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Initializes a new instance of the <see cref="World"/> class.␊ |
| /// </summary>␊ |
| /// <param name="gravity">The gravity.</param>␊ |
| public World(Vector2 gravity)␊ |
| : this()␊ |
| {␊ |
| ContactManager = new ContactManager(new DynamicTreeBroadPhase());␊ |
| Gravity = gravity;␊ |
| }␊ |
| ␊ |
| public List<Controller> ControllerList { get; private set; }␊ |
| ␊ |
| public List<BreakableBody> BreakableBodyList { get; private set; }␊ |
| ␊ |
| public float UpdateTime { get; private set; }␊ |
| ␊ |
| public float ContinuousPhysicsTime { get; private set; }␊ |
| ␊ |
| public float ControllersUpdateTime { get; private set; }␊ |
| ␊ |
| public float AddRemoveTime { get; private set; }␊ |
| ␊ |
| public float ContactsUpdateTime { get; private set; }␊ |
| ␊ |
| public float SolveUpdateTime { get; private set; }␊ |
| ␊ |
| /// <summary>␊ |
| /// Get the number of broad-phase proxies.␊ |
| /// </summary>␊ |
| /// <value>The proxy count.</value>␊ |
| public int ProxyCount␊ |
| {␊ |
| get { return ContactManager.BroadPhase.ProxyCount; }␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Change the global gravity vector.␊ |
| /// </summary>␊ |
| /// <value>The gravity.</value>␊ |
| public Vector2 Gravity;␊ |
| ␊ |
| /// <summary>␊ |
| /// Set flag to control automatic clearing of forces after each time step.␊ |
| /// </summary>␊ |
| /// <value><c>true</c> if it should auto clear forces; otherwise, <c>false</c>.</value>␊ |
| public bool AutoClearForces␊ |
| {␊ |
| set␊ |
| {␊ |
| if (value)␊ |
| {␊ |
| Flags |= WorldFlags.ClearForces;␊ |
| }␊ |
| else␊ |
| {␊ |
| Flags &= ~WorldFlags.ClearForces;␊ |
| }␊ |
| }␊ |
| get { return (Flags & WorldFlags.ClearForces) == WorldFlags.ClearForces; }␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Get the contact manager for testing.␊ |
| /// </summary>␊ |
| /// <value>The contact manager.</value>␊ |
| public ContactManager ContactManager { get; private set; }␊ |
| ␊ |
| /// <summary>␊ |
| /// Get the world body list.␊ |
| /// </summary>␊ |
| /// <value>Thehead of the world body list.</value>␊ |
| public List<Body> BodyList { get; private set; }␊ |
| ␊ |
| /// <summary>␊ |
| /// Get the world joint list. ␊ |
| /// </summary>␊ |
| /// <value>The joint list.</value>␊ |
| public List<Joint> JointList { get; private set; }␊ |
| ␊ |
| /// <summary>␊ |
| /// Get the world contact list. With the returned contact, use Contact.GetNext to get␊ |
| /// the next contact in the world list. A null contact indicates the end of the list.␊ |
| /// </summary>␊ |
| /// <value>The head of the world contact list.</value>␊ |
| public List<Contact> ContactList␊ |
| {␊ |
| get { return ContactManager.ContactList; }␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Enable/disable single stepped continuous physics. For testing.␊ |
| /// </summary>␊ |
| public bool EnableSubStepping␊ |
| {␊ |
| set␊ |
| {␊ |
| if (value)␊ |
| {␊ |
| Flags |= WorldFlags.SubStepping;␊ |
| }␊ |
| else␊ |
| {␊ |
| Flags &= ~WorldFlags.SubStepping;␊ |
| }␊ |
| }␊ |
| get { return (Flags & WorldFlags.SubStepping) == WorldFlags.SubStepping; }␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Add a rigid body.␊ |
| /// </summary>␊ |
| /// <returns></returns>␊ |
| internal void AddBody(Body body)␊ |
| {␊ |
| Debug.Assert(!_bodyAddList.Contains(body), "You are adding the same body more than once.");␊ |
| ␊ |
| if (!_bodyAddList.Contains(body))␊ |
| _bodyAddList.Add(body);␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Destroy a rigid body.␊ |
| /// Warning: This automatically deletes all associated shapes and joints.␊ |
| /// </summary>␊ |
| /// <param name="body">The body.</param>␊ |
| public void RemoveBody(Body body)␊ |
| {␊ |
| Debug.Assert(!_bodyRemoveList.Contains(body),␊ |
| "The body is already marked for removal. You are removing the body more than once.");␊ |
| ␊ |
| if (!_bodyRemoveList.Contains(body))␊ |
| _bodyRemoveList.Add(body);␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Create a joint to constrain bodies together. This may cause the connected bodies to cease colliding.␊ |
| /// </summary>␊ |
| /// <param name="joint">The joint.</param>␊ |
| public void AddJoint(Joint joint)␊ |
| {␊ |
| Debug.Assert(!_jointAddList.Contains(joint), "You are adding the same joint more than once.");␊ |
| ␊ |
| if (!_jointAddList.Contains(joint))␊ |
| _jointAddList.Add(joint);␊ |
| }␊ |
| ␊ |
| private void RemoveJoint(Joint joint, bool doCheck)␊ |
| {␊ |
| if (doCheck)␊ |
| {␊ |
| Debug.Assert(!_jointRemoveList.Contains(joint),␊ |
| "The joint is already marked for removal. You are removing the joint more than once.");␊ |
| }␊ |
| ␊ |
| if (!_jointRemoveList.Contains(joint))␊ |
| _jointRemoveList.Add(joint);␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Destroy a joint. This may cause the connected bodies to begin colliding.␊ |
| /// </summary>␊ |
| /// <param name="joint">The joint.</param>␊ |
| public void RemoveJoint(Joint joint)␊ |
| {␊ |
| RemoveJoint(joint, true);␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// All adds and removes are cached by the World duing a World step.␊ |
| /// To process the changes before the world updates again, call this method.␊ |
| /// </summary>␊ |
| public void ProcessChanges()␊ |
| {␊ |
| ProcessAddedBodies();␊ |
| ProcessAddedJoints();␊ |
| ␊ |
| ProcessRemovedBodies();␊ |
| ProcessRemovedJoints();␊ |
| }␊ |
| ␊ |
| private void ProcessRemovedJoints()␊ |
| {␊ |
| if (_jointRemoveList.Count > 0)␊ |
| {␊ |
| foreach (Joint joint in _jointRemoveList)␊ |
| {␊ |
| bool collideConnected = joint.CollideConnected;␊ |
| ␊ |
| // Remove from the world list.␊ |
| JointList.Remove(joint);␊ |
| ␊ |
| // Disconnect from island graph.␊ |
| Body bodyA = joint.BodyA;␊ |
| Body bodyB = joint.BodyB;␊ |
| ␊ |
| // Wake up connected bodies.␊ |
| bodyA.Awake = true;␊ |
| ␊ |
| // WIP David␊ |
| if (!joint.IsFixedType())␊ |
| {␊ |
| bodyB.Awake = true;␊ |
| }␊ |
| ␊ |
| // Remove from body 1.␊ |
| if (joint.EdgeA.Prev != null)␊ |
| {␊ |
| joint.EdgeA.Prev.Next = joint.EdgeA.Next;␊ |
| }␊ |
| ␊ |
| if (joint.EdgeA.Next != null)␊ |
| {␊ |
| joint.EdgeA.Next.Prev = joint.EdgeA.Prev;␊ |
| }␊ |
| ␊ |
| if (joint.EdgeA == bodyA.JointList)␊ |
| {␊ |
| bodyA.JointList = joint.EdgeA.Next;␊ |
| }␊ |
| ␊ |
| joint.EdgeA.Prev = null;␊ |
| joint.EdgeA.Next = null;␊ |
| ␊ |
| // WIP David␊ |
| if (!joint.IsFixedType())␊ |
| {␊ |
| // Remove from body 2␊ |
| if (joint.EdgeB.Prev != null)␊ |
| {␊ |
| joint.EdgeB.Prev.Next = joint.EdgeB.Next;␊ |
| }␊ |
| ␊ |
| if (joint.EdgeB.Next != null)␊ |
| {␊ |
| joint.EdgeB.Next.Prev = joint.EdgeB.Prev;␊ |
| }␊ |
| ␊ |
| if (joint.EdgeB == bodyB.JointList)␊ |
| {␊ |
| bodyB.JointList = joint.EdgeB.Next;␊ |
| }␊ |
| ␊ |
| joint.EdgeB.Prev = null;␊ |
| joint.EdgeB.Next = null;␊ |
| }␊ |
| ␊ |
| // WIP David␊ |
| if (!joint.IsFixedType())␊ |
| {␊ |
| // If the joint prevents collisions, then flag any contacts for filtering.␊ |
| if (collideConnected == false)␊ |
| {␊ |
| ContactEdge edge = bodyB.ContactList;␊ |
| while (edge != null)␊ |
| {␊ |
| if (edge.Other == bodyA)␊ |
| {␊ |
| // Flag the contact for filtering at the next time step (where either␊ |
| // body is awake).␊ |
| edge.Contact.FlagForFiltering();␊ |
| }␊ |
| ␊ |
| edge = edge.Next;␊ |
| }␊ |
| }␊ |
| }␊ |
| ␊ |
| if (JointRemoved != null)␊ |
| {␊ |
| JointRemoved(joint);␊ |
| }␊ |
| }␊ |
| ␊ |
| _jointRemoveList.Clear();␊ |
| }␊ |
| }␊ |
| ␊ |
| private void ProcessAddedJoints()␊ |
| {␊ |
| if (_jointAddList.Count > 0)␊ |
| {␊ |
| foreach (Joint joint in _jointAddList)␊ |
| {␊ |
| // Connect to the world list.␊ |
| JointList.Add(joint);␊ |
| ␊ |
| // Connect to the bodies' doubly linked lists.␊ |
| joint.EdgeA.Joint = joint;␊ |
| joint.EdgeA.Other = joint.BodyB;␊ |
| joint.EdgeA.Prev = null;␊ |
| joint.EdgeA.Next = joint.BodyA.JointList;␊ |
| ␊ |
| if (joint.BodyA.JointList != null)␊ |
| joint.BodyA.JointList.Prev = joint.EdgeA;␊ |
| ␊ |
| joint.BodyA.JointList = joint.EdgeA;␊ |
| ␊ |
| // WIP David␊ |
| if (!joint.IsFixedType())␊ |
| {␊ |
| joint.EdgeB.Joint = joint;␊ |
| joint.EdgeB.Other = joint.BodyA;␊ |
| joint.EdgeB.Prev = null;␊ |
| joint.EdgeB.Next = joint.BodyB.JointList;␊ |
| ␊ |
| if (joint.BodyB.JointList != null)␊ |
| joint.BodyB.JointList.Prev = joint.EdgeB;␊ |
| ␊ |
| joint.BodyB.JointList = joint.EdgeB;␊ |
| ␊ |
| Body bodyA = joint.BodyA;␊ |
| Body bodyB = joint.BodyB;␊ |
| ␊ |
| // If the joint prevents collisions, then flag any contacts for filtering.␊ |
| if (joint.CollideConnected == false)␊ |
| {␊ |
| ContactEdge edge = bodyB.ContactList;␊ |
| while (edge != null)␊ |
| {␊ |
| if (edge.Other == bodyA)␊ |
| {␊ |
| // Flag the contact for filtering at the next time step (where either␊ |
| // body is awake).␊ |
| edge.Contact.FlagForFiltering();␊ |
| }␊ |
| ␊ |
| edge = edge.Next;␊ |
| }␊ |
| }␊ |
| }␊ |
| ␊ |
| if (JointAdded != null)␊ |
| JointAdded(joint);␊ |
| ␊ |
| // Note: creating a joint doesn't wake the bodies.␊ |
| }␊ |
| ␊ |
| _jointAddList.Clear();␊ |
| }␊ |
| }␊ |
| ␊ |
| private void ProcessAddedBodies()␊ |
| {␊ |
| if (_bodyAddList.Count > 0)␊ |
| {␊ |
| foreach (Body body in _bodyAddList)␊ |
| {␊ |
| // Add to world list.␊ |
| BodyList.Add(body);␊ |
| ␊ |
| if (BodyAdded != null)␊ |
| BodyAdded(body);␊ |
| }␊ |
| ␊ |
| _bodyAddList.Clear();␊ |
| }␊ |
| }␊ |
| ␊ |
| private void ProcessRemovedBodies()␊ |
| {␊ |
| if (_bodyRemoveList.Count > 0)␊ |
| {␊ |
| foreach (Body body in _bodyRemoveList)␊ |
| {␊ |
| Debug.Assert(BodyList.Count > 0);␊ |
| ␊ |
| // You tried to remove a body that is not contained in the BodyList.␊ |
| // Are you removing the body more than once?␊ |
| Debug.Assert(BodyList.Contains(body));␊ |
| ␊ |
| // Delete the attached joints.␊ |
| JointEdge je = body.JointList;␊ |
| while (je != null)␊ |
| {␊ |
| JointEdge je0 = je;␊ |
| je = je.Next;␊ |
| ␊ |
| RemoveJoint(je0.Joint, false);␊ |
| }␊ |
| body.JointList = null;␊ |
| ␊ |
| // Delete the attached contacts.␊ |
| ContactEdge ce = body.ContactList;␊ |
| while (ce != null)␊ |
| {␊ |
| ContactEdge ce0 = ce;␊ |
| ce = ce.Next;␊ |
| ContactManager.Destroy(ce0.Contact);␊ |
| }␊ |
| body.ContactList = null;␊ |
| ␊ |
| // Delete the attached fixtures. This destroys broad-phase proxies.␊ |
| for (int i = 0; i < body.FixtureList.Count; i++)␊ |
| {␊ |
| body.FixtureList[i].DestroyProxies(ContactManager.BroadPhase);␊ |
| body.FixtureList[i].Destroy();␊ |
| }␊ |
| ␊ |
| body.FixtureList = null;␊ |
| ␊ |
| // Remove world body list.␊ |
| BodyList.Remove(body);␊ |
| ␊ |
| if (BodyRemoved != null)␊ |
| BodyRemoved(body);␊ |
| }␊ |
| ␊ |
| _bodyRemoveList.Clear();␊ |
| }␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Take a time step. This performs collision detection, integration,␊ |
| /// and consraint solution.␊ |
| /// </summary>␊ |
| /// <param name="dt">The amount of time to simulate, this should not vary.</param>␊ |
| public void Step(float dt)␊ |
| {␊ |
| #if (!SILVERLIGHT)␊ |
| if (Settings.EnableDiagnostics)␊ |
| _watch.Start();␊ |
| #endif␊ |
| ␊ |
| ProcessChanges();␊ |
| ␊ |
| #if (!SILVERLIGHT)␊ |
| if (Settings.EnableDiagnostics)␊ |
| AddRemoveTime = _watch.ElapsedTicks;␊ |
| #endif␊ |
| //If there is no change in time, no need to calculate anything.␊ |
| if (dt == 0 || !Enabled)␊ |
| {␊ |
| #if (!SILVERLIGHT)␊ |
| if (Settings.EnableDiagnostics)␊ |
| {␊ |
| _watch.Stop();␊ |
| _watch.Reset();␊ |
| }␊ |
| #endif␊ |
| return;␊ |
| }␊ |
| ␊ |
| // If new fixtures were added, we need to find the new contacts.␊ |
| if ((Flags & WorldFlags.NewFixture) == WorldFlags.NewFixture)␊ |
| {␊ |
| ContactManager.FindNewContacts();␊ |
| Flags &= ~WorldFlags.NewFixture;␊ |
| }␊ |
| ␊ |
| TimeStep step;␊ |
| step.inv_dt = 1.0f / dt;␊ |
| step.dt = dt;␊ |
| step.dtRatio = _invDt0 * dt;␊ |
| ␊ |
| //Update controllers␊ |
| for (int i = 0; i < ControllerList.Count; i++)␊ |
| {␊ |
| ControllerList[i].Update(dt);␊ |
| }␊ |
| ␊ |
| #if (!SILVERLIGHT)␊ |
| if (Settings.EnableDiagnostics)␊ |
| ControllersUpdateTime = _watch.ElapsedTicks - AddRemoveTime;␊ |
| #endif␊ |
| ␊ |
| // Update contacts. This is where some contacts are destroyed.␊ |
| ContactManager.Collide();␊ |
| ␊ |
| #if (!SILVERLIGHT)␊ |
| if (Settings.EnableDiagnostics)␊ |
| ContactsUpdateTime = _watch.ElapsedTicks - (AddRemoveTime + ControllersUpdateTime);␊ |
| #endif␊ |
| // Integrate velocities, solve velocity raints, and integrate positions.␊ |
| Solve(ref step);␊ |
| ␊ |
| #if (!SILVERLIGHT)␊ |
| if (Settings.EnableDiagnostics)␊ |
| SolveUpdateTime = _watch.ElapsedTicks - (AddRemoveTime + ControllersUpdateTime + ContactsUpdateTime);␊ |
| #endif␊ |
| ␊ |
| // Handle TOI events.␊ |
| if (Settings.ContinuousPhysics)␊ |
| {␊ |
| SolveTOI(ref step);␊ |
| }␊ |
| ␊ |
| #if (!SILVERLIGHT)␊ |
| if (Settings.EnableDiagnostics)␊ |
| ContinuousPhysicsTime = _watch.ElapsedTicks -␊ |
| (AddRemoveTime + ControllersUpdateTime + ContactsUpdateTime + SolveUpdateTime);␊ |
| #endif␊ |
| _invDt0 = step.inv_dt;␊ |
| ␊ |
| if ((Flags & WorldFlags.ClearForces) != 0)␊ |
| {␊ |
| ClearForces();␊ |
| }␊ |
| ␊ |
| for (int i = 0; i < BreakableBodyList.Count; i++)␊ |
| {␊ |
| BreakableBodyList[i].Update();␊ |
| }␊ |
| ␊ |
| #if (!SILVERLIGHT)␊ |
| if (Settings.EnableDiagnostics)␊ |
| {␊ |
| _watch.Stop();␊ |
| //AddRemoveTime = 1000 * AddRemoveTime / Stopwatch.Frequency;␊ |
| ␊ |
| UpdateTime = _watch.ElapsedTicks;␊ |
| _watch.Reset();␊ |
| }␊ |
| #endif␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Call this after you are done with time steps to clear the forces. You normally␊ |
| /// call this after each call to Step, unless you are performing sub-steps. By default,␊ |
| /// forces will be automatically cleared, so you don't need to call this function.␊ |
| /// </summary>␊ |
| public void ClearForces()␊ |
| {␊ |
| for (int i = 0; i < BodyList.Count; i++)␊ |
| {␊ |
| Body body = BodyList[i];␊ |
| body.Force = Vector2.Zero;␊ |
| body.Torque = 0.0f;␊ |
| }␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Query the world for all fixtures that potentially overlap the␊ |
| /// provided AABB.␊ |
| /// ␊ |
| /// Inside the callback:␊ |
| /// Return true: Continues the query␊ |
| /// Return false: Terminate the query␊ |
| /// </summary>␊ |
| /// <param name="callback">A user implemented callback class.</param>␊ |
| /// <param name="aabb">The aabb query box.</param>␊ |
| public void QueryAABB(Func<Fixture, bool> callback, ref AABB aabb)␊ |
| {␊ |
| ContactManager.BroadPhase.Query(proxyId =>␊ |
| {␊ |
| FixtureProxy proxy = ContactManager.BroadPhase.GetProxy(proxyId);␊ |
| return callback(proxy.Fixture);␊ |
| }, ref aabb);␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Ray-cast the world for all fixtures in the path of the ray. Your callback␊ |
| /// controls whether you get the closest point, any point, or n-points.␊ |
| /// The ray-cast ignores shapes that contain the starting point.␊ |
| /// ␊ |
| /// Inside the callback:␊ |
| /// return -1: ignore this fixture and continue␊ |
| /// return 0: terminate the ray cast␊ |
| /// return fraction: clip the ray to this point␊ |
| /// return 1: don't clip the ray and continue␊ |
| /// </summary>␊ |
| /// <param name="callback">A user implemented callback class.</param>␊ |
| /// <param name="point1">The ray starting point.</param>␊ |
| /// <param name="point2">The ray ending point.</param>␊ |
| public void RayCast(RayCastCallback callback, Vector2 point1, Vector2 point2)␊ |
| {␊ |
| RayCastInput input = new RayCastInput();␊ |
| input.MaxFraction = 1.0f;␊ |
| input.Point1 = point1;␊ |
| input.Point2 = point2;␊ |
| ␊ |
| ContactManager.BroadPhase.RayCast((rayCastInput, proxyId) =>␊ |
| {␊ |
| FixtureProxy proxy = ContactManager.BroadPhase.GetProxy(proxyId);␊ |
| Fixture fixture = proxy.Fixture;␊ |
| int index = proxy.ChildIndex;␊ |
| RayCastOutput output;␊ |
| bool hit = fixture.RayCast(out output, ref rayCastInput, index);␊ |
| ␊ |
| if (hit)␊ |
| {␊ |
| float fraction = output.Fraction;␊ |
| Vector2 point = (1.0f - fraction) * input.Point1 +␊ |
| fraction * input.Point2;␊ |
| return callback(fixture, point, output.Normal, fraction);␊ |
| }␊ |
| ␊ |
| return input.MaxFraction;␊ |
| }, ref input);␊ |
| }␊ |
| ␊ |
| private void Solve(ref TimeStep step)␊ |
| {␊ |
| // Size the island for the worst case.␊ |
| Island.Reset(BodyList.Count,␊ |
| ContactManager.ContactList.Count,␊ |
| JointList.Count,␊ |
| ContactManager);␊ |
| ␊ |
| // Clear all the island flags.␊ |
| foreach (Body b in BodyList)␊ |
| {␊ |
| b.Flags &= ~BodyFlags.Island;␊ |
| }␊ |
| ␊ |
| for (int i = 0; i < ContactManager.ContactList.Count; i++)␊ |
| {␊ |
| Contact c = ContactManager.ContactList[i];␊ |
| c.Flags &= ~ContactFlags.Island;␊ |
| }␊ |
| foreach (Joint j in JointList)␊ |
| {␊ |
| j.IslandFlag = false;␊ |
| }␊ |
| ␊ |
| // Build and simulate all awake islands.␊ |
| int stackSize = BodyList.Count;␊ |
| if (stackSize > _stack.Length)␊ |
| _stack = new Body[Math.Max(_stack.Length * 2, stackSize)];␊ |
| ␊ |
| for (int index = BodyList.Count - 1; index >= 0; index--)␊ |
| {␊ |
| Body seed = BodyList[index];␊ |
| if ((seed.Flags & (BodyFlags.Island)) != BodyFlags.None)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| if (seed.Awake == false || seed.Enabled == false)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // The seed can be dynamic or kinematic.␊ |
| if (seed.BodyType == BodyType.Static)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Reset island and stack.␊ |
| Island.Clear();␊ |
| int stackCount = 0;␊ |
| _stack[stackCount++] = seed;␊ |
| seed.Flags |= BodyFlags.Island;␊ |
| ␊ |
| // Perform a depth first search (DFS) on the constraint graph.␊ |
| while (stackCount > 0)␊ |
| {␊ |
| // Grab the next body off the stack and add it to the island.␊ |
| Body b = _stack[--stackCount];␊ |
| Debug.Assert(b.Enabled);␊ |
| Island.Add(b);␊ |
| ␊ |
| // Make sure the body is awake.␊ |
| b.Awake = true;␊ |
| ␊ |
| // To keep islands as small as possible, we don't␊ |
| // propagate islands across static bodies.␊ |
| if (b.BodyType == BodyType.Static)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Search all contacts connected to this body.␊ |
| for (ContactEdge ce = b.ContactList; ce != null; ce = ce.Next)␊ |
| {␊ |
| Contact contact = ce.Contact;␊ |
| ␊ |
| // Has this contact already been added to an island?␊ |
| if ((contact.Flags & ContactFlags.Island) != ContactFlags.None)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Is this contact solid and touching?␊ |
| if (!ce.Contact.Enabled || !ce.Contact.IsTouching())␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Skip sensors.␊ |
| bool sensorA = contact.FixtureA.IsSensor;␊ |
| bool sensorB = contact.FixtureB.IsSensor;␊ |
| if (sensorA || sensorB)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| Island.Add(contact);␊ |
| contact.Flags |= ContactFlags.Island;␊ |
| ␊ |
| Body other = ce.Other;␊ |
| ␊ |
| // Was the other body already added to this island?␊ |
| if ((other.Flags & BodyFlags.Island) != BodyFlags.None)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| Debug.Assert(stackCount < stackSize);␊ |
| _stack[stackCount++] = other;␊ |
| other.Flags |= BodyFlags.Island;␊ |
| }␊ |
| ␊ |
| // Search all joints connect to this body.␊ |
| for (JointEdge je = b.JointList; je != null; je = je.Next)␊ |
| {␊ |
| if (je.Joint.IslandFlag)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| Body other = je.Other;␊ |
| ␊ |
| // WIP David␊ |
| //Enter here when it's a non-fixed joint. Non-fixed joints have a other body.␊ |
| if (other != null)␊ |
| {␊ |
| // Don't simulate joints connected to inactive bodies.␊ |
| if (other.Enabled == false)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| Island.Add(je.Joint);␊ |
| je.Joint.IslandFlag = true;␊ |
| ␊ |
| if ((other.Flags & BodyFlags.Island) != BodyFlags.None)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| Debug.Assert(stackCount < stackSize);␊ |
| _stack[stackCount++] = other;␊ |
| other.Flags |= BodyFlags.Island;␊ |
| }␊ |
| else␊ |
| {␊ |
| Island.Add(je.Joint);␊ |
| je.Joint.IslandFlag = true;␊ |
| }␊ |
| }␊ |
| }␊ |
| ␊ |
| Island.Solve(ref step, ref Gravity);␊ |
| ␊ |
| // Post solve cleanup.␊ |
| for (int i = 0; i < Island.BodyCount; ++i)␊ |
| {␊ |
| // Allow static bodies to participate in other islands.␊ |
| Body b = Island.Bodies[i];␊ |
| if (b.BodyType == BodyType.Static)␊ |
| {␊ |
| b.Flags &= ~BodyFlags.Island;␊ |
| }␊ |
| }␊ |
| }␊ |
| ␊ |
| // Synchronize fixtures, check for out of range bodies.␊ |
| foreach (Body b in BodyList)␊ |
| {␊ |
| // If a body was not in an island then it did not move.␊ |
| if ((b.Flags & BodyFlags.Island) != BodyFlags.Island)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| if (b.BodyType == BodyType.Static)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Update fixtures (for broad-phase).␊ |
| b.SynchronizeFixtures();␊ |
| }␊ |
| ␊ |
| // Look for new contacts.␊ |
| ContactManager.FindNewContacts();␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Find TOI contacts and solve them.␊ |
| /// </summary>␊ |
| /// <param name="step">The step.</param>␊ |
| private void SolveTOI(ref TimeStep step)␊ |
| {␊ |
| Island.Reset(2 * Settings.MaxTOIContacts, Settings.MaxTOIContacts, 0, ContactManager);␊ |
| ␊ |
| if (_stepComplete)␊ |
| {␊ |
| for (int i = 0; i < BodyList.Count; i++)␊ |
| {␊ |
| BodyList[i].Flags &= ~BodyFlags.Island;␊ |
| BodyList[i].Sweep.Alpha0 = 0.0f;␊ |
| }␊ |
| ␊ |
| for (int i = 0; i < ContactManager.ContactList.Count; i++)␊ |
| {␊ |
| Contact c = ContactManager.ContactList[i];␊ |
| ␊ |
| // Invalidate TOI␊ |
| c.Flags &= ~(ContactFlags.TOI | ContactFlags.Island);␊ |
| c.TOICount = 0;␊ |
| c.TOI = 1.0f;␊ |
| }␊ |
| }␊ |
| ␊ |
| // Find TOI events and solve them.␊ |
| for (; ; )␊ |
| {␊ |
| // Find the first TOI.␊ |
| Contact minContact = null;␊ |
| float minAlpha = 1.0f;␊ |
| ␊ |
| for (int i = 0; i < ContactManager.ContactList.Count; i++)␊ |
| {␊ |
| Contact c = ContactManager.ContactList[i];␊ |
| ␊ |
| // Is this contact disabled?␊ |
| if (c.Enabled == false)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Prevent excessive sub-stepping.␊ |
| if (c.TOICount > Settings.MaxSubSteps)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| float alpha;␊ |
| if ((c.Flags & ContactFlags.TOI) == ContactFlags.TOI)␊ |
| {␊ |
| // This contact has a valid cached TOI.␊ |
| alpha = c.TOI;␊ |
| }␊ |
| else␊ |
| {␊ |
| Fixture fA = c.FixtureA;␊ |
| Fixture fB = c.FixtureB;␊ |
| ␊ |
| // Is there a sensor?␊ |
| if (fA.IsSensor || fB.IsSensor)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| Body bA = fA.Body;␊ |
| Body bB = fB.Body;␊ |
| ␊ |
| BodyType typeA = bA.BodyType;␊ |
| BodyType typeB = bB.BodyType;␊ |
| //Debug.Assert(typeA == BodyType.Dynamic || typeB == BodyType.Dynamic);␊ |
| ␊ |
| bool awakeA = bA.Awake && typeA != BodyType.Static;␊ |
| bool awakeB = bB.Awake && typeB != BodyType.Static;␊ |
| ␊ |
| // Is at least one body awake?␊ |
| if (awakeA == false && awakeB == false)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| bool collideA = (bA.IsBullet || typeA != BodyType.Dynamic) && !bA.IgnoreCCD;␊ |
| bool collideB = (bB.IsBullet || typeB != BodyType.Dynamic) && !bB.IgnoreCCD;␊ |
| ␊ |
| // Are these two non-bullet dynamic bodies?␊ |
| if (collideA == false && collideB == false)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Compute the TOI for this contact.␊ |
| // Put the sweeps onto the same time interval.␊ |
| float alpha0 = bA.Sweep.Alpha0;␊ |
| ␊ |
| if (bA.Sweep.Alpha0 < bB.Sweep.Alpha0)␊ |
| {␊ |
| alpha0 = bB.Sweep.Alpha0;␊ |
| bA.Sweep.Advance(alpha0);␊ |
| }␊ |
| else if (bB.Sweep.Alpha0 < bA.Sweep.Alpha0)␊ |
| {␊ |
| alpha0 = bA.Sweep.Alpha0;␊ |
| bB.Sweep.Advance(alpha0);␊ |
| }␊ |
| ␊ |
| Debug.Assert(alpha0 < 1.0f);␊ |
| ␊ |
| // Compute the time of impact in interval [0, minTOI]␊ |
| _input.ProxyA.Set(fA.Shape, c.ChildIndexA);␊ |
| _input.ProxyB.Set(fB.Shape, c.ChildIndexB);␊ |
| _input.SweepA = bA.Sweep;␊ |
| _input.SweepB = bB.Sweep;␊ |
| _input.TMax = 1.0f;␊ |
| ␊ |
| TOIOutput output;␊ |
| TimeOfImpact.CalculateTimeOfImpact(out output, _input);␊ |
| ␊ |
| // Beta is the fraction of the remaining portion of the .␊ |
| float beta = output.T;␊ |
| if (output.State == TOIOutputState.Touching)␊ |
| {␊ |
| alpha = Math.Min(alpha0 + (1.0f - alpha0) * beta, 1.0f);␊ |
| }␊ |
| else␊ |
| {␊ |
| alpha = 1.0f;␊ |
| }␊ |
| ␊ |
| c.TOI = alpha;␊ |
| c.Flags |= ContactFlags.TOI;␊ |
| }␊ |
| ␊ |
| if (alpha < minAlpha)␊ |
| {␊ |
| // This is the minimum TOI found so far.␊ |
| minContact = c;␊ |
| minAlpha = alpha;␊ |
| }␊ |
| }␊ |
| ␊ |
| if (minContact == null || 1.0f - 10.0f * Settings.Epsilon < minAlpha)␊ |
| {␊ |
| // No more TOI events. Done!␊ |
| _stepComplete = true;␊ |
| break;␊ |
| }␊ |
| ␊ |
| // Advance the bodies to the TOI.␊ |
| Fixture fA1 = minContact.FixtureA;␊ |
| Fixture fB1 = minContact.FixtureB;␊ |
| Body bA1 = fA1.Body;␊ |
| Body bB1 = fB1.Body;␊ |
| ␊ |
| Sweep backup1 = bA1.Sweep;␊ |
| Sweep backup2 = bB1.Sweep;␊ |
| ␊ |
| bA1.Advance(minAlpha);␊ |
| bB1.Advance(minAlpha);␊ |
| ␊ |
| // The TOI contact likely has some new contact points.␊ |
| minContact.Update(ContactManager);␊ |
| minContact.Flags &= ~ContactFlags.TOI;␊ |
| ++minContact.TOICount;␊ |
| ␊ |
| // Is the contact solid?␊ |
| if (minContact.Enabled == false || minContact.IsTouching() == false)␊ |
| {␊ |
| // Restore the sweeps.␊ |
| minContact.Enabled = false;␊ |
| bA1.Sweep = backup1;␊ |
| bB1.Sweep = backup2;␊ |
| bA1.SynchronizeTransform();␊ |
| bB1.SynchronizeTransform();␊ |
| continue;␊ |
| }␊ |
| ␊ |
| bA1.Awake = true;␊ |
| bB1.Awake = true;␊ |
| ␊ |
| // Build the island␊ |
| Island.Clear();␊ |
| Island.Add(bA1);␊ |
| Island.Add(bB1);␊ |
| Island.Add(minContact);␊ |
| ␊ |
| bA1.Flags |= BodyFlags.Island;␊ |
| bB1.Flags |= BodyFlags.Island;␊ |
| minContact.Flags |= ContactFlags.Island;␊ |
| ␊ |
| // Get contacts on bodyA and bodyB.␊ |
| Body[] bodies = { bA1, bB1 };␊ |
| for (int i = 0; i < 2; ++i)␊ |
| {␊ |
| Body body = bodies[i];␊ |
| if (body.BodyType == BodyType.Dynamic)␊ |
| {␊ |
| // for (ContactEdge ce = body.ContactList; ce && Island.BodyCount < Settings.MaxTOIContacts; ce = ce.Next)␊ |
| for (ContactEdge ce = body.ContactList; ce != null; ce = ce.Next)␊ |
| {␊ |
| Contact contact = ce.Contact;␊ |
| ␊ |
| // Has this contact already been added to the island?␊ |
| if ((contact.Flags & ContactFlags.Island) == ContactFlags.Island)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Only add static, kinematic, or bullet bodies.␊ |
| Body other = ce.Other;␊ |
| if (other.BodyType == BodyType.Dynamic &&␊ |
| body.IsBullet == false && other.IsBullet == false)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Skip sensors.␊ |
| if (contact.FixtureA.IsSensor || contact.FixtureB.IsSensor)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Tentatively advance the body to the TOI.␊ |
| Sweep backup = other.Sweep;␊ |
| if ((other.Flags & BodyFlags.Island) == 0)␊ |
| {␊ |
| other.Advance(minAlpha);␊ |
| }␊ |
| ␊ |
| // Update the contact points␊ |
| contact.Update(ContactManager);␊ |
| ␊ |
| // Was the contact disabled by the user?␊ |
| if (contact.Enabled == false)␊ |
| {␊ |
| other.Sweep = backup;␊ |
| other.SynchronizeTransform();␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Are there contact points?␊ |
| if (contact.IsTouching() == false)␊ |
| {␊ |
| other.Sweep = backup;␊ |
| other.SynchronizeTransform();␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Add the contact to the island␊ |
| contact.Flags |= ContactFlags.Island;␊ |
| Island.Add(contact);␊ |
| ␊ |
| // Has the other body already been added to the island?␊ |
| if ((other.Flags & BodyFlags.Island) == BodyFlags.Island)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| // Add the other body to the island.␊ |
| other.Flags |= BodyFlags.Island;␊ |
| ␊ |
| if (other.BodyType != BodyType.Static)␊ |
| {␊ |
| other.Awake = true;␊ |
| }␊ |
| ␊ |
| Island.Add(other);␊ |
| }␊ |
| }␊ |
| }␊ |
| ␊ |
| TimeStep subStep;␊ |
| subStep.dt = (1.0f - minAlpha) * step.dt;␊ |
| subStep.inv_dt = 1.0f / subStep.dt;␊ |
| subStep.dtRatio = 1.0f;␊ |
| //subStep.positionIterations = 20;␊ |
| //subStep.velocityIterations = step.velocityIterations;␊ |
| //subStep.warmStarting = false;␊ |
| Island.SolveTOI(ref subStep);␊ |
| ␊ |
| // Reset island flags and synchronize broad-phase proxies.␊ |
| for (int i = 0; i < Island.BodyCount; ++i)␊ |
| {␊ |
| Body body = Island.Bodies[i];␊ |
| body.Flags &= ~BodyFlags.Island;␊ |
| ␊ |
| if (body.BodyType != BodyType.Dynamic)␊ |
| {␊ |
| continue;␊ |
| }␊ |
| ␊ |
| body.SynchronizeFixtures();␊ |
| ␊ |
| // Invalidate all contact TOIs on this displaced body.␊ |
| for (ContactEdge ce = body.ContactList; ce != null; ce = ce.Next)␊ |
| {␊ |
| ce.Contact.Flags &= ~(ContactFlags.TOI | ContactFlags.Island);␊ |
| }␊ |
| }␊ |
| ␊ |
| // Commit fixture proxy movements to the broad-phase so that new contacts are created.␊ |
| // Also, some contacts can be destroyed.␊ |
| ContactManager.FindNewContacts();␊ |
| ␊ |
| if (EnableSubStepping)␊ |
| {␊ |
| _stepComplete = false;␊ |
| break;␊ |
| }␊ |
| }␊ |
| }␊ |
| ␊ |
| public void AddController(Controller controller)␊ |
| {␊ |
| Debug.Assert(!ControllerList.Contains(controller), "You are adding the same controller more than once.");␊ |
| ␊ |
| controller.World = this;␊ |
| ControllerList.Add(controller);␊ |
| ␊ |
| if (ControllerAdded != null)␊ |
| ControllerAdded(controller);␊ |
| }␊ |
| ␊ |
| public void RemoveController(Controller controller)␊ |
| {␊ |
| Debug.Assert(ControllerList.Contains(controller),␊ |
| "You are removing a controller that is not in the simulation.");␊ |
| ␊ |
| if (ControllerList.Contains(controller))␊ |
| {␊ |
| ControllerList.Remove(controller);␊ |
| ␊ |
| if (ControllerRemoved != null)␊ |
| ControllerRemoved(controller);␊ |
| }␊ |
| }␊ |
| ␊ |
| public void AddBreakableBody(BreakableBody breakableBody)␊ |
| {␊ |
| BreakableBodyList.Add(breakableBody);␊ |
| }␊ |
| ␊ |
| public void RemoveBreakableBody(BreakableBody breakableBody)␊ |
| {␊ |
| //The breakable body list does not contain the body you tried to remove.␊ |
| Debug.Assert(BreakableBodyList.Contains(breakableBody));␊ |
| ␊ |
| BreakableBodyList.Remove(breakableBody);␊ |
| }␊ |
| ␊ |
| public Fixture TestPoint(Vector2 point)␊ |
| {␊ |
| AABB aabb;␊ |
| Vector2 d = new Vector2(Settings.Epsilon, Settings.Epsilon);␊ |
| aabb.LowerBound = point - d;␊ |
| aabb.UpperBound = point + d;␊ |
| ␊ |
| Fixture myFixture = null;␊ |
| ␊ |
| // Query the world for overlapping shapes.␊ |
| QueryAABB(␊ |
| fixture =>␊ |
| {␊ |
| bool inside = fixture.TestPoint(ref point);␊ |
| if (inside)␊ |
| {␊ |
| myFixture = fixture;␊ |
| return false;␊ |
| }␊ |
| ␊ |
| // Continue the query.␊ |
| return true;␊ |
| }, ref aabb);␊ |
| ␊ |
| return myFixture;␊ |
| }␊ |
| ␊ |
| /// <summary>␊ |
| /// Returns a list of fixtures that are at the specified point.␊ |
| /// </summary>␊ |
| /// <param name="point">The point.</param>␊ |
| /// <returns></returns>␊ |
| public List<Fixture> TestPointAll(Vector2 point)␊ |
| {␊ |
| AABB aabb;␊ |
| Vector2 d = new Vector2(Settings.Epsilon, Settings.Epsilon);␊ |
| aabb.LowerBound = point - d;␊ |
| aabb.UpperBound = point + d;␊ |
| ␊ |
| List<Fixture> fixtures = new List<Fixture>();␊ |
| ␊ |
| // Query the world for overlapping shapes.␊ |
| QueryAABB(␊ |
| fixture =>␊ |
| {␊ |
| bool inside = fixture.TestPoint(ref point);␊ |
| if (inside)␊ |
| fixtures.Add(fixture);␊ |
| ␊ |
| // Continue the query.␊ |
| return true;␊ |
| }, ref aabb);␊ |
| ␊ |
| return fixtures;␊ |
| }␊ |
| ␊ |
| public void Clear()␊ |
| {␊ |
| ProcessChanges();␊ |
| ␊ |
| for (int i = BodyList.Count - 1; i >= 0; i--)␊ |
| {␊ |
| RemoveBody(BodyList[i]);␊ |
| }␊ |
| ␊ |
| for (int i = ControllerList.Count - 1; i >= 0; i--)␊ |
| {␊ |
| RemoveController(ControllerList[i]);␊ |
| }␊ |
| ␊ |
| for (int i = BreakableBodyList.Count - 1; i >= 0; i--)␊ |
| {␊ |
| RemoveBreakableBody(BreakableBodyList[i]);␊ |
| }␊ |
| ␊ |
| ProcessChanges();␊ |
| }␊ |
| }␊ |
| } |