// Copyright (c) 2017 Kastellanos Nikolaos /* Original source Farseer Physics Engine: * Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com * Microsoft Permissive License (Ms-PL) v1.1 */ /* * Farseer Physics Engine: * Copyright (c) 2012 Ian Qvist * * Original source Box2D: * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * 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.Collision.Shapes; using FarseerPhysics.Common; using FarseerPhysics.Dynamics.Contacts; using Microsoft.Xna.Framework; namespace FarseerPhysics.Dynamics { /// /// A fixture is used to attach a Shape to a body for collision detection. A fixture /// inherits its transform from its parent. Fixtures hold additional non-geometric data /// such as friction, collision filters, etc. /// Fixtures are created via Body.CreateFixture. /// Warning: You cannot reuse fixtures. /// public class Fixture { private bool _isSensor; private float _friction; private float _restitution; internal Category _collidesWith; internal Category _collisionCategories; internal short _collisionGroup; public FixtureProxy[] Proxies { get; private set; } public int ProxyCount { get; private set; } /// /// Fires after two shapes has collided and are solved. This gives you a chance to get the impact force. /// public AfterCollisionEventHandler AfterCollision; /// /// Fires when two fixtures are close to each other. /// Due to how the broadphase works, this can be quite inaccurate as shapes are approximated using AABBs. /// public BeforeCollisionEventHandler BeforeCollision; /// /// Fires when two shapes collide and a contact is created between them. /// Note that the first fixture argument is always the fixture that the delegate is subscribed to. /// public OnCollisionEventHandler OnCollision; /// /// Fires when two shapes separate and a contact is removed between them. /// Note: This can in some cases be called multiple times, as a fixture can have multiple contacts. /// Note The first fixture argument is always the fixture that the delegate is subscribed to. /// public OnSeparationEventHandler OnSeparation; internal Fixture(Category collisionCategory, Category collidesWith) // Note: This is internal because it's used by Deserialization. { _collisionCategories = collisionCategory; _collidesWith = collidesWith; _collisionGroup = 0; //Fixture defaults Friction = 0.2f; Restitution = 0f; } public Fixture(Shape shape, Category collisionCategory, Category collidesWith) : this(collisionCategory, collidesWith) { Shape = shape.Clone(); // Reserve proxy space Proxies = new FixtureProxy[Shape.ChildCount]; ProxyCount = 0; } /// /// Defaults to 0 /// /// Collision groups allow a certain group of objects to never collide (negative) /// or always collide (positive). Zero means no collision group. Non-zero group /// filtering always wins against the mask bits. /// public short CollisionGroup { set { if (_collisionGroup == value) return; _collisionGroup = value; Refilter(); } get { return _collisionGroup; } } /// /// Defaults to Category.All /// /// The collision mask bits. This states the categories that this /// fixture would accept for collision. /// public Category CollidesWith { get { return _collidesWith; } set { if (_collidesWith == value) return; _collidesWith = value; Refilter(); } } /// /// The collision categories this fixture is a part of. /// /// Defaults to Category.Cat1 /// public Category CollisionCategories { get { return _collisionCategories; } set { if (_collisionCategories == value) return; _collisionCategories = value; Refilter(); } } /// /// Get the child Shape. /// /// The shape. public Shape Shape { get; private set; } /// /// Gets or sets a value indicating whether this fixture is a sensor. /// /// true if this instance is a sensor; otherwise, false. public bool IsSensor { get { return _isSensor; } set { if (Body != null) Body.Awake = true; _isSensor = value; } } /// /// Get the parent body of this fixture. This is null if the fixture is not attached. /// /// The body. public Body Body { get; internal set; } /// /// Set the user data. Use this to store your application specific data. /// /// The user data. public object UserData; /// /// Set the coefficient of friction. This will _not_ change the friction of /// existing contacts. /// /// The friction. public float Friction { get { return _friction; } set { Debug.Assert(!float.IsNaN(value)); _friction = value; } } /// /// Set the coefficient of restitution. This will not change the restitution of /// existing contacts. /// /// The restitution. public float Restitution { get { return _restitution; } set { Debug.Assert(!float.IsNaN(value)); _restitution = value; } } /// /// Contacts are persistant and will keep being persistant unless they are /// flagged for filtering. /// This methods flags all contacts associated with the body for filtering. /// private void Refilter() { // Flag associated contacts for filtering. ContactEdge edge = Body.ContactList; while (edge != null) { Contact contact = edge.Contact; Fixture fixtureA = contact.FixtureA; Fixture fixtureB = contact.FixtureB; if (fixtureA == this || fixtureB == this) { contact.FilterFlag = true; } edge = edge.Next; } World world = Body.World; if (world == null) return; // Touch each proxy so that new pairs may be created IBroadPhase broadPhase = world.ContactManager.BroadPhase; TouchProxies(broadPhase); } /// /// Touch each proxy so that new pairs may be created /// /// internal void TouchProxies(IBroadPhase broadPhase) { for (int i = 0; i < ProxyCount; ++i) broadPhase.TouchProxy(Proxies[i].ProxyId); } /// /// Test a point for containment in this fixture. /// /// A point in world coordinates. /// public bool TestPoint(ref Vector2 point) { return Shape.TestPoint(ref Body._xf, ref point); } /// /// Cast a ray against this Shape. /// /// The ray-cast results. /// The ray-cast input parameters. /// Index of the child. /// public bool RayCast(out RayCastOutput output, ref RayCastInput input, int childIndex) { return Shape.RayCast(out output, ref input, ref Body._xf, childIndex); } /// /// Get the fixture's AABB. This AABB may be enlarge and/or stale. /// If you need a more accurate AABB, compute it using the Shape and /// the body transform. /// /// The aabb. /// Index of the child. public void GetAABB(out AABB aabb, int childIndex) { Debug.Assert(0 <= childIndex && childIndex < ProxyCount); aabb = Proxies[childIndex].AABB; } // These support body activation/deactivation. internal void CreateProxies(IBroadPhase broadPhase, ref Transform xf) { if (ProxyCount != 0) throw new InvalidOperationException("Proxies already created for this Fixture."); // Create proxies in the broad-phase. ProxyCount = Shape.ChildCount; for (int i = 0; i < ProxyCount; ++i) { FixtureProxy proxy = new FixtureProxy(); proxy.Fixture = this; proxy.ChildIndex = i; proxy.Body = this.Body; Shape.ComputeAABB(out proxy.AABB, ref xf, i); proxy.ProxyId = broadPhase.AddProxy(ref proxy.AABB); broadPhase.SetProxy(proxy.ProxyId, ref proxy); Proxies[i] = proxy; } } internal void DestroyProxies(IBroadPhase broadPhase) { // Destroy proxies in the broad-phase. for (int i = 0; i < ProxyCount; ++i) { broadPhase.RemoveProxy(Proxies[i].ProxyId); Proxies[i].ProxyId = -1; } ProxyCount = 0; } internal void Synchronize(IBroadPhase broadPhase, ref Transform transform1, ref Transform transform2) { for (int i = 0; i < ProxyCount; ++i) { FixtureProxy proxy = Proxies[i]; // Compute an AABB that covers the swept Shape (may miss some rotation effect). AABB aabb1, aabb2; Shape.ComputeAABB(out aabb1, ref transform1, proxy.ChildIndex); Shape.ComputeAABB(out aabb2, ref transform2, proxy.ChildIndex); proxy.AABB.Combine(ref aabb1, ref aabb2); Vector2 displacement = transform2.p - transform1.p; broadPhase.MoveProxy(proxy.ProxyId, ref proxy.AABB, displacement); } } /// /// Clones the fixture onto the specified body. /// /// The body you wish to clone the fixture onto. /// The cloned fixture. public Fixture CloneOnto(Body body) { return CloneOnto(body, this.Shape); } /// /// Clones the fixture and attached shape onto the specified body. /// Note: This is used only by Deserialization. /// /// The body you wish to clone the fixture onto. /// The cloned fixture. internal Fixture CloneOnto(Body body, Shape shape) { Fixture fixture = new Fixture(shape.Clone(), _collisionCategories, _collidesWith) { UserData = UserData, Restitution = Restitution, Friction = Friction, IsSensor = IsSensor, _collisionGroup = _collisionGroup }; body.Add(fixture); return fixture; } } }