All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jbox2d.dynamics.contacts.Contact Maven / Gradle / Ivy

The newest version!
/*
 * The MIT License (MIT)
 *
 * FXGL - JavaFX Game Library
 *
 * Copyright (c) 2015-2017 AlmasB ([email protected])
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.jbox2d.dynamics.contacts;


import org.jbox2d.callbacks.ContactListener;
import org.jbox2d.collision.ContactID;
import org.jbox2d.collision.Manifold;
import org.jbox2d.collision.ManifoldPoint;
import org.jbox2d.collision.WorldManifold;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.JBoxUtils;
import org.jbox2d.common.Transform;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.Fixture;
import org.jbox2d.pooling.IWorldPool;

/**
 * The class manages contact between two shapes. A contact exists for each overlapping AABB in the
 * broad-phase (except if filtered). Therefore a contact object may exist that has no contact
 * points.
 *
 * @author daniel
 */
public abstract class Contact {

    // Flags stored in m_flags
    // Used when crawling contact graph when forming islands.
    public static final int ISLAND_FLAG = 0x0001;
    // Set when the shapes are touching.
    public static final int TOUCHING_FLAG = 0x0002;
    // This contact can be disabled (by user)
    public static final int ENABLED_FLAG = 0x0004;
    // This contact needs filtering because a fixture filter was changed.
    public static final int FILTER_FLAG = 0x0008;
    // This bullet contact had a TOI event
    public static final int BULLET_HIT_FLAG = 0x0010;

    public static final int TOI_FLAG = 0x0020;

    public int m_flags;

    // World pool and list pointers.
    public Contact m_prev;
    public Contact m_next;

    // Nodes for connecting bodies.
    public ContactEdge m_nodeA = null;
    public ContactEdge m_nodeB = null;

    public Fixture m_fixtureA;
    public Fixture m_fixtureB;

    public int m_indexA;
    public int m_indexB;

    public final Manifold m_manifold;

    public float m_toiCount;
    public float m_toi;

    public float m_friction;
    public float m_restitution;

    public float m_tangentSpeed;

    protected final IWorldPool pool;

    protected Contact(IWorldPool argPool) {
        m_fixtureA = null;
        m_fixtureB = null;
        m_nodeA = new ContactEdge();
        m_nodeB = new ContactEdge();
        m_manifold = new Manifold();
        pool = argPool;
    }

    /** initialization for pooling */
    public void init(Fixture fA, int indexA, Fixture fB, int indexB) {
        m_flags = ENABLED_FLAG;

        m_fixtureA = fA;
        m_fixtureB = fB;

        m_indexA = indexA;
        m_indexB = indexB;

        m_manifold.pointCount = 0;

        m_prev = null;
        m_next = null;

        m_nodeA.contact = null;
        m_nodeA.prev = null;
        m_nodeA.next = null;
        m_nodeA.other = null;

        m_nodeB.contact = null;
        m_nodeB.prev = null;
        m_nodeB.next = null;
        m_nodeB.other = null;

        m_toiCount = 0;
        m_friction = Contact.mixFriction(fA.getFriction(), fB.getFriction());
        m_restitution = Contact.mixRestitution(fA.getRestitution(), fB.getRestitution());

        m_tangentSpeed = 0;
    }

    /**
     * Get the contact manifold. Do not set the point count to zero. Instead call Disable.
     */
    public Manifold getManifold() {
        return m_manifold;
    }

    /**
     * Get the world manifold.
     */
    public void getWorldManifold(WorldManifold worldManifold) {
        final Body bodyA = m_fixtureA.getBody();
        final Body bodyB = m_fixtureB.getBody();
        final Shape shapeA = m_fixtureA.getShape();
        final Shape shapeB = m_fixtureB.getShape();

        worldManifold.initialize(m_manifold, bodyA.getTransform(), shapeA.getRadius(),
                bodyB.getTransform(), shapeB.getRadius());
    }

    /**
     * Is this contact touching
     *
     * @return
     */
    public boolean isTouching() {
        return (m_flags & TOUCHING_FLAG) == TOUCHING_FLAG;
    }

    /**
     * Enable/disable this contact. This can be used inside the pre-solve contact listener. The
     * contact is only disabled for the current time step (or sub-step in continuous collisions).
     *
     * @param flag
     */
    public void setEnabled(boolean flag) {
        if (flag) {
            m_flags |= ENABLED_FLAG;
        } else {
            m_flags &= ~ENABLED_FLAG;
        }
    }

    /**
     * Has this contact been disabled?
     *
     * @return
     */
    public boolean isEnabled() {
        return (m_flags & ENABLED_FLAG) == ENABLED_FLAG;
    }

    /**
     * Get the next contact in the world's contact list.
     *
     * @return
     */
    public Contact getNext() {
        return m_next;
    }

    /**
     * Get the first fixture in this contact.
     *
     * @return
     */
    public Fixture getFixtureA() {
        return m_fixtureA;
    }

    public int getChildIndexA() {
        return m_indexA;
    }

    /**
     * Get the second fixture in this contact.
     *
     * @return
     */
    public Fixture getFixtureB() {
        return m_fixtureB;
    }

    public int getChildIndexB() {
        return m_indexB;
    }

    public void setFriction(float friction) {
        m_friction = friction;
    }

    public float getFriction() {
        return m_friction;
    }

    public void resetFriction() {
        m_friction = Contact.mixFriction(m_fixtureA.getFriction(), m_fixtureB.getFriction());
    }

    public void setRestitution(float restitution) {
        m_restitution = restitution;
    }

    public float getRestitution() {
        return m_restitution;
    }

    public void resetRestitution() {
        m_restitution = Contact.mixRestitution(m_fixtureA.getRestitution(), m_fixtureB.getRestitution());
    }

    public void setTangentSpeed(float speed) {
        m_tangentSpeed = speed;
    }

    public float getTangentSpeed() {
        return m_tangentSpeed;
    }

    public abstract void evaluate(Manifold manifold, Transform xfA, Transform xfB);

    /**
     * Flag this contact for filtering. Filtering will occur the next time step.
     */
    public void flagForFiltering() {
        m_flags |= FILTER_FLAG;
    }

    // djm pooling
    private final Manifold oldManifold = new Manifold();

    public void update(ContactListener listener) {

        oldManifold.set(m_manifold);

        // Re-enable this contact.
        m_flags |= ENABLED_FLAG;

        boolean touching = false;
        boolean wasTouching = (m_flags & TOUCHING_FLAG) == TOUCHING_FLAG;

        boolean sensorA = m_fixtureA.isSensor();
        boolean sensorB = m_fixtureB.isSensor();
        boolean sensor = sensorA || sensorB;

        Body bodyA = m_fixtureA.getBody();
        Body bodyB = m_fixtureB.getBody();
        Transform xfA = bodyA.getTransform();
        Transform xfB = bodyB.getTransform();
        // log.debug("TransformA: "+xfA);
        // log.debug("TransformB: "+xfB);

        if (sensor) {
            Shape shapeA = m_fixtureA.getShape();
            Shape shapeB = m_fixtureB.getShape();
            touching = pool.getCollision().testOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB);

            // Sensors don't generate manifolds.
            m_manifold.pointCount = 0;
        } else {
            evaluate(m_manifold, xfA, xfB);
            touching = m_manifold.pointCount > 0;

            // Match old contact ids to new contact ids and copy the
            // stored impulses to warm start the solver.
            for (int i = 0; i < m_manifold.pointCount; ++i) {
                ManifoldPoint mp2 = m_manifold.points[i];
                mp2.normalImpulse = 0.0f;
                mp2.tangentImpulse = 0.0f;
                ContactID id2 = mp2.id;

                for (int j = 0; j < oldManifold.pointCount; ++j) {
                    ManifoldPoint mp1 = oldManifold.points[j];

                    if (mp1.id.isEqual(id2)) {
                        mp2.normalImpulse = mp1.normalImpulse;
                        mp2.tangentImpulse = mp1.tangentImpulse;
                        break;
                    }
                }
            }

            if (touching != wasTouching) {
                bodyA.setAwake(true);
                bodyB.setAwake(true);
            }
        }

        if (touching) {
            m_flags |= TOUCHING_FLAG;
        } else {
            m_flags &= ~TOUCHING_FLAG;
        }

        if (listener == null) {
            return;
        }

        if (!wasTouching && touching) {
            listener.beginContact(this);
        }

        if (wasTouching && !touching) {
            listener.endContact(this);
        }

        if (!sensor && touching) {
            listener.preSolve(this, oldManifold);
        }
    }

    /**
     * Friction mixing law. The idea is to allow either fixture to drive the restitution to zero. For
     * example, anything slides on ice.
     *
     * @param friction1
     * @param friction2
     * @return
     */
    public static final float mixFriction(float friction1, float friction2) {
        return JBoxUtils.sqrt(friction1 * friction2);
    }

    /**
     * Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface. For
     * example, a superball bounces on anything.
     *
     * @param restitution1
     * @param restitution2
     * @return
     */
    public static final float mixRestitution(float restitution1, float restitution2) {
        return restitution1 > restitution2 ? restitution1 : restitution2;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy