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

com.flowpowered.react.collision.CollisionDetection Maven / Gradle / Ivy

Go to download

Real-time 3D physics library for Java, based on the ReactPhysics3D library.

The newest version!
/*
 * This file is part of React, licensed under the MIT License (MIT).
 *
 * Copyright (c) 2013 Flow Powered 
 * Original ReactPhysics3D C++ library by Daniel Chappuis 
 * React is re-licensed with permission from ReactPhysics3D author.
 *
 * 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.
 */
/*
 * This file is part of React.
 *
 * Copyright (c) 2013 Spout LLC 
 * React is licensed under the Spout License Version 1.
 *
 * React is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * In addition, 180 days after any changes are published, you can use the
 * software, incorporating those changes, under the terms of the MIT license,
 * as described in the Spout License Version 1.
 *
 * React is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License,
 * the MIT license and the Spout License Version 1 along with this program.
 * If not, see  for the GNU Lesser General Public
 * License and see  for the full license, including
 * the MIT license.
 */
package com.flowpowered.react.collision;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.flowpowered.react.Utilities.IntPair;
import com.flowpowered.react.body.CollisionBody;
import com.flowpowered.react.body.RigidBody;
import com.flowpowered.react.collision.broadphase.BroadPhaseAlgorithm;
import com.flowpowered.react.collision.broadphase.PairManager.BodyPair;
import com.flowpowered.react.collision.broadphase.SweepAndPruneAlgorithm;
import com.flowpowered.react.collision.linkedphase.LinkedPhase;
import com.flowpowered.react.collision.narrowphase.GJK.GJKAlgorithm;
import com.flowpowered.react.collision.narrowphase.NarrowPhaseAlgorithm;
import com.flowpowered.react.collision.narrowphase.SphereVsSphereAlgorithm;
import com.flowpowered.react.collision.shape.CollisionShape;
import com.flowpowered.react.collision.shape.CollisionShape.CollisionShapeType;
import com.flowpowered.react.constraint.ContactPoint.ContactPointInfo;
import com.flowpowered.react.engine.CollisionWorld;
import com.flowpowered.react.engine.linked.LinkedDynamicsWorld;

/**
 * This class computes the collision detection algorithms. We first perform a broad-phase algorithm to know which pairs of bodies can collide and then we run a narrow-phase algorithm to compute the
 * collision contacts between the bodies.
 */
public class CollisionDetection {
    private final CollisionWorld mWorld;
    private final Map mOverlappingPairs = new HashMap<>();
    private final BroadPhaseAlgorithm mBroadPhaseAlgorithm;
    private final GJKAlgorithm mNarrowPhaseGJKAlgorithm = new GJKAlgorithm();
    private final SphereVsSphereAlgorithm mNarrowPhaseSphereVsSphereAlgorithm = new SphereVsSphereAlgorithm();
    private final Set mNoCollisionPairs = new HashSet<>();
    private final LinkedPhase mLinkedPhase;

    /**
     * Constructs a new collision detection from the collision world.
     *
     * @param world The world
     */
    public CollisionDetection(CollisionWorld world) {
        mWorld = world;
        mBroadPhaseAlgorithm = new SweepAndPruneAlgorithm(this);
        if (world instanceof LinkedDynamicsWorld) {
            mLinkedPhase = new LinkedPhase((LinkedDynamicsWorld) mWorld);
        } else {
            mLinkedPhase = null;
        }
    }

    /**
     * Adds a body to the collision detection.
     *
     * @param body The body to add
     */
    public void addBody(CollisionBody body) {
        mBroadPhaseAlgorithm.addObject(body, body.getAABB());
    }

    /**
     * Removes a body from the collision detection.
     *
     * @param body The body to remove
     */
    public void removeBody(CollisionBody body) {
        mBroadPhaseAlgorithm.removeObject(body);
    }

    /**
     * Add a pair of bodies that cannot collide with each other.
     *
     * @param body1 The first body
     * @param body2 The second body
     */
    public void addNoCollisionPair(CollisionBody body1, CollisionBody body2) {
        mNoCollisionPairs.add(BroadPhasePair.computeBodiesIndexPair(body1, body2));
    }

    /**
     * Removes a pair of bodies that cannot collide with each other.
     *
     * @param body1 The first body
     * @param body2 The second body
     */
    public void removeNoCollisionPair(CollisionBody body1, CollisionBody body2) {
        mNoCollisionPairs.remove(BroadPhasePair.computeBodiesIndexPair(body1, body2));
    }

    /**
     * Computes the collision detection.
     */
    public void computeCollisionDetection() {
        if (mLinkedPhase != null) {
            computeLinkedPhase();
        }
        computeBroadPhase();
        computeNarrowPhase();
    }

    // Computes the linked-phase collision detection.
    private void computeLinkedPhase() {
        final List bodies = new ArrayList<>(mWorld.getBodies());
        final List foundBodies = new ArrayList<>();
        for (CollisionBody body : bodies) {
            if (!(body instanceof RigidBody)) {
                continue;
            }
            for (RigidBody rigidBody : mLinkedPhase.getBodiesInRange((RigidBody) body)) {
                foundBodies.add(rigidBody);
            }
        }
        ((LinkedDynamicsWorld) mWorld).addLinkedBodies(foundBodies);
    }

    // Computes the broad-phase collision detection.
    private void computeBroadPhase() {
        for (CollisionBody body : mWorld.getBodies()) {
            if (body.getHasMoved()) {
                mBroadPhaseAlgorithm.updateObject(body, body.getAABB());
            }
        }
    }

    // Computes the narrow-phase collision detection.
    private void computeNarrowPhase() {
        for (Entry entry : mOverlappingPairs.entrySet()) {
            final ContactPointInfo contactInfo = new ContactPointInfo();
            final BroadPhasePair pair = entry.getValue();
            if (pair == null) {
                throw new IllegalStateException("pair cannot be null");
            }
            final CollisionBody body1 = pair.getFirstBody();
            final CollisionBody body2 = pair.getSecondBody();
            mWorld.updateOverlappingPair(pair);
            if (mNoCollisionPairs.contains(pair.getBodiesIndexPair())) {
                continue;
            }
            if (body1.isSleeping() && body2.isSleeping()) {
                continue;
            }
            final NarrowPhaseAlgorithm narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm(body1.getCollisionShape(), body2.getCollisionShape());
            narrowPhaseAlgorithm.setCurrentOverlappingPair(pair);
            if (narrowPhaseAlgorithm.testCollision(body1.getCollisionShape(), body1.getTransform(), body2.getCollisionShape(), body2.getTransform(), contactInfo)) {
                contactInfo.setFirstBody((RigidBody) body1);
                contactInfo.setSecondBody((RigidBody) body2);
                mWorld.notifyNewContact(pair, contactInfo);
            }
        }
    }

    /**
     * Allows the broad phase to notify the collision detection about an overlapping pair. This method is called by a broad-phase collision detection algorithm.
     *
     * @param addedPair The pair that was added
     */
    public void broadPhaseNotifyAddedOverlappingPair(BodyPair addedPair) {
        final IntPair indexPair = addedPair.getBodiesIndexPair();
        final BroadPhasePair broadPhasePair = new BroadPhasePair(addedPair.getFirstBody(), addedPair.getSecondBody());
        final BroadPhasePair old = mOverlappingPairs.put(indexPair, broadPhasePair);
        if (old != null) {
            throw new IllegalStateException("the pair already existed in the overlapping pairs map");
        }
        mWorld.notifyAddedOverlappingPair(broadPhasePair);
    }

    /**
     * Allows the broad phase to notify the collision detection about a removed overlapping pair.
     *
     * @param removedPair The pair that was removed
     */
    public void broadPhaseNotifyRemovedOverlappingPair(BodyPair removedPair) {
        final IntPair indexPair = removedPair.getBodiesIndexPair();
        final BroadPhasePair broadPhasePair = mOverlappingPairs.get(indexPair);
        if (broadPhasePair == null) {
            throw new IllegalStateException("the removed pair must be in the map");
        }
        mWorld.notifyRemovedOverlappingPair(broadPhasePair);
        mOverlappingPairs.remove(indexPair);
    }

    // Selects the narrow-phase collision algorithm to use given two collision shapes.
    private NarrowPhaseAlgorithm selectNarrowPhaseAlgorithm(CollisionShape collisionShape1, CollisionShape collisionShape2) {
        if (collisionShape1.getType() == CollisionShapeType.SPHERE && collisionShape2.getType() == CollisionShapeType.SPHERE) {
            return mNarrowPhaseSphereVsSphereAlgorithm;
        } else {
            return mNarrowPhaseGJKAlgorithm;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy