(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