(Java)碰撞检测墙

(Java)碰撞检测墙,java,collision-detection,Java,Collision Detection,我一直在尝试使用碰撞检测来阻止物体相互碰撞。但是我不知道怎么做 当物体发生碰撞时,我试着反转它们的速度向量的方向(这样它就会远离碰撞的地方),但有时物体会相互卡住 我试着改变他们的速度,但这只是父母彼此的反对 有没有一种简单的方法来限制对象的移动,使它们不会穿过其他对象?我一直在使用矩形相交进行碰撞,还尝试了圆碰撞检测(使用对象之间的距离) 想法 package objects; import java.awt.Rectangle; import custom.utils.Vector; i

我一直在尝试使用碰撞检测来阻止物体相互碰撞。但是我不知道怎么做

当物体发生碰撞时,我试着反转它们的速度向量的方向(这样它就会远离碰撞的地方),但有时物体会相互卡住

我试着改变他们的速度,但这只是父母彼此的反对

有没有一种简单的方法来限制对象的移动,使它们不会穿过其他对象?我一直在使用矩形相交进行碰撞,还尝试了圆碰撞检测(使用对象之间的距离)

想法

package objects;

import java.awt.Rectangle;

import custom.utils.Vector;
import sprites.Picture;
import render.Window;



// Super class (game objects)
public class Entity implements GameObject{


    private Picture self;
    protected Vector position;
    protected Vector velocity = new Vector(0,0);
    private GameObject[] obj_list = new GameObject[0];

    private boolean init = false;

    // Takes in a "sprite"
    public Entity(Picture i){
        self = i;
        position = new Vector(i.getXY()[0],i.getXY()[1]);
        ObjectUpdater.addObject(this);
    }



    public Object getIdentity() {
        return this;
    }

    // position handles
    public Vector getPosition(){
        return position;
    }

    public void setPosition(double x,double y){
        position.setValues(x,y);
        self.setXY(position);
    }

    public void setPosition(){
        position.setValues((int)Window.getWinSize()[0]/2,(int)Window.getWinSize()[1]/2);
    }

    // velocity handles
    public void setVelocity(double x,double y){ // Use if you're too lazy to make a vector
        velocity.setValues(x, y);
    }
    public void setVelocity(Vector xy){ // Use if your already have a vector
        velocity.setValues(xy.getValues()[0], xy.getValues()[1]);
    }

    public Vector getVelocity(){
        return velocity;
    }


    // inferface for all game objects (so they all update at the same time)

    public boolean checkInit(){
        return init;
    }

    public Rectangle getBounds() {
        double[] corner = position.getValues(); // Get the corner for the bounds
        int[] size = self.getImageSize(); // Get the size of the image

        return new Rectangle((int)Math.round(corner[0]),(int)Math.round(corner[1]),size[0],size[1]); // Make the bound
    }

    // I check for collisions where, this grabs all the objects and checks for collisions on each.

    private void checkCollision(){
        if (obj_list.length > 0){
        for (GameObject i: obj_list){
            if (getBounds().intersects(i.getBounds()) && i != this){
                // What happens here?
            }
        }
        }
    }

    public void updateSelf(){
        checkCollision();
        position = position.add(velocity);
        setPosition(position.getValues()[0],position.getValues()[1]);
        init = true;
    }


    public void pollObjects(GameObject[] o){
        obj_list = o;
    }

}
希望它不太难读

编辑: 所以我一直在使用矩形相交法来计算物体的位置并修改速度。它运行得很好。唯一的问题是一些物体推着其他物体,但这太重要了。碰撞对于我正在制作的迷你游戏来说几乎是一件额外的事情。非常感谢你们的帮助


尽管如此,我仍然非常感谢对上述想法的详细阐述,因为我不完全确定如何将它们实施到我的项目中。

没有看到您的代码,我只能猜测发生了什么。我怀疑你的物体被卡住了,因为它们超出了其他物体的边界,最终进入了内部。确保每个对象的步长不仅是速度*delta_时间,而且步长大小受潜在碰撞的限制。当发生碰撞时,计算碰撞发生的时间(在delta_时间的某个位置),并跟随反弹确定最终对象位置。或者,将物体设置为接触,速度根据动量守恒定律变化

编辑看到您的代码后,我可以展开我的答案。首先,让我澄清一下你提到的一些术语。由于每次调用
updateSelf
都只是将速度向量添加到当前位置,因此实际上是一个单位时间增量(增量时间始终为1)。换句话说,您的“速度”实际上是自上次调用
updateSelf
以来经过的距离(速度*增量时间)。我建议使用显式(浮动)时间增量作为模拟的一部分

其次,跟踪多个运动对象之间碰撞的一般问题非常困难。无论使用什么时间增量,对象都可能在该增量中经历多次碰撞。(想象一个物体被挤压在两个其他物体之间。在任何给定的时间间隔内,物体可能在两个周围物体之间来回反弹的次数没有限制。)此外,一个物体可能(在计算分辨率范围内)同时与多个物体碰撞。如果对象在移动时实际改变大小(正如代码所示),问题就更复杂了

第三,由于要将所有对象位置舍入为整数坐标,因此存在严重的错误源。我建议使用浮点对象来表示对象(
Rectangle2D.Float
而不是
Rectangle
Point2D.Float
而不是
Vector
)。我还建议将
位置
字段替换为捕获位置和大小的矩形
边界
字段。这样,您就不必在每次调用
getBounds()
时创建新对象。如果对象大小不变,这也将简化边界更新

最后,在每个对象内部都有一个重要的冲突检测逻辑问题:当对象a发现它会撞到对象B时,对象B也会撞到对象a!但是,对象B独立于对象A进行自己的计算。如果先更新A,则B可能会错过碰撞,反之亦然。最好将整个碰撞检测和对象移动逻辑移动到一个全局算法,并保持每个游戏对象相对简单

一种方法(我推荐)是编写一个“updateGame”方法,以给定的时间增量推进游戏状态。它将使用一个记录冲突的辅助数据结构,可能如下所示:

public class Collision {
    public int objectIndex1;  // index of first object involved in collision
    public int objectIndex2;  // index of second object
    public int directionCode; // encoding of the direction of the collision
    public float time;        // time of collision
}
void updateGame(float deltaTime) {
    float step = deltaTime;
    do (
        Collision hit = findFirstCollision(step);
        if (hit != null) {
            step = Math.max(hit.time, MIN_STEP);
            updateObjects(step);
            updateVelocities(hit);
        } else {
            updateObjects(step);
        }
        deltaTime -= step;
        step = deltaTime;
    } while (deltaTime > 0);
}

/**
 * Finds the earliest collision that occurs within the given time
 * interval. It uses the current position and velocity of the objects
 * at the start of the interval. If no collisions occur, returns null.
 */
Collision findFirstCollision(float deltaTime) {
    Collision result = null;
    for (int i = 0; i < obj_list.length; ++i) {
        for (int j = i + 1; j < obj_list.length; ++j) {
            Collision hit = findCollision(i, j, deltaTime);
            if (hit != null) {
                if (result == null || hit.time < result.time) {
                    result = hit;
                }
            }
        }
    }
    return result;
}

/**
 * Calculate if there is a collision between obj_list[i1] and
 * obj_list[i2] within deltaTime, given their current positions
 * and velocities. If there is, return a new Collision object
 * that records i1, i2, the direction of the hit, and the time
 * at which the objects collide. Otherwise, return null.
 */
Collision findCollision(int i1, int i2, float deltaTime) {
    // left as an exercise for the reader
}

/**
 * Move every object by its velocity * step
 */
void updateObjects(float step) {
    for (GameObject obj : obj_list) {
        Point2D.Float pos = obj.getPosition();
        Point2D.Float velocity = obj.getVelocity();
        obj.setPosition(
            pos.getX() + step * velocity.getX(),
            pos.getY() + step * velocity.getY()
        );
    }
}

/**
 * Update the velocities of the two objects involved in a
 * collision. Note that this does not always reverse velocities
 * along the direction of collision (one object might be hit
 * from behind by a faster object). The algorithm should assume
 * that the objects are at the exact position of the collision
 * and just update the velocities.
 */
void updateVelocities(Collision collision) {
    // TODO - implement some physics simulation
}
整体算法将游戏从当前时间推进到由参数
deltaTime
定义的新时间。它的结构可能如下所示:

public class Collision {
    public int objectIndex1;  // index of first object involved in collision
    public int objectIndex2;  // index of second object
    public int directionCode; // encoding of the direction of the collision
    public float time;        // time of collision
}
void updateGame(float deltaTime) {
    float step = deltaTime;
    do (
        Collision hit = findFirstCollision(step);
        if (hit != null) {
            step = Math.max(hit.time, MIN_STEP);
            updateObjects(step);
            updateVelocities(hit);
        } else {
            updateObjects(step);
        }
        deltaTime -= step;
        step = deltaTime;
    } while (deltaTime > 0);
}

/**
 * Finds the earliest collision that occurs within the given time
 * interval. It uses the current position and velocity of the objects
 * at the start of the interval. If no collisions occur, returns null.
 */
Collision findFirstCollision(float deltaTime) {
    Collision result = null;
    for (int i = 0; i < obj_list.length; ++i) {
        for (int j = i + 1; j < obj_list.length; ++j) {
            Collision hit = findCollision(i, j, deltaTime);
            if (hit != null) {
                if (result == null || hit.time < result.time) {
                    result = hit;
                }
            }
        }
    }
    return result;
}

/**
 * Calculate if there is a collision between obj_list[i1] and
 * obj_list[i2] within deltaTime, given their current positions
 * and velocities. If there is, return a new Collision object
 * that records i1, i2, the direction of the hit, and the time
 * at which the objects collide. Otherwise, return null.
 */
Collision findCollision(int i1, int i2, float deltaTime) {
    // left as an exercise for the reader
}

/**
 * Move every object by its velocity * step
 */
void updateObjects(float step) {
    for (GameObject obj : obj_list) {
        Point2D.Float pos = obj.getPosition();
        Point2D.Float velocity = obj.getVelocity();
        obj.setPosition(
            pos.getX() + step * velocity.getX(),
            pos.getY() + step * velocity.getY()
        );
    }
}

/**
 * Update the velocities of the two objects involved in a
 * collision. Note that this does not always reverse velocities
 * along the direction of collision (one object might be hit
 * from behind by a faster object). The algorithm should assume
 * that the objects are at the exact position of the collision
 * and just update the velocities.
 */
void updateVelocities(Collision collision) {
    // TODO - implement some physics simulation
}
void updateGame(float deltaTime){
浮动步长=增量时间;
做(
碰撞命中=findFirstCollision(步骤);
如果(命中!=null){
步长=数学最大值(命中时间,最小步长);
更新对象(步骤);
更新速度(hit);
}否则{
更新对象(步骤);
}
deltaTime-=阶跃;
阶跃=deltaTime;
}而(deltaTime>0);
}
/**
*查找给定时间内发生的最早碰撞
*间隔。它使用对象的当前位置和速度
*在间隔的开始处。如果没有发生冲突,则返回null。
*/
碰撞findFirstCollision(浮动增量时间){
碰撞结果=空;
对于(int i=0;i