我正在用slick2d+java编写一个碰撞检测算法,我最终将在我将要制作的platformer游戏中使用该算法该算法的工作原理是检测播放器与矩形重叠的程度,然后通过重叠将播放器移出矩形问题是,算法有很多问题,我无法解决首先,有时球员移动太远的矩形,所以它看起来是反弹了。第二,有时玩家能够在矩形内移动一个很小但很明显的量最后,如果我提高速度,有时玩家可以通过矩形的所有方式这是一个相当模糊的问题,但我真的需要一些帮助,找出什么是错的任何想法都将非常感谢。如果安装了Slick2D,那么源代码应该可以编译而不会有任何问题。
算法:
public void Collision(Polygon player, Polygon poly, Vector2f translation){
Vector2f magnitude = new Vector2f();
//Find the vectre of each object
Vector2f p1Centre = new Vector2f(player.getX() + (player.getWidth()/2), player.getY() + (player.getHeight()/2));
Vector2f p2Centre = new Vector2f(poly.getX() + (poly.getWidth()/2), poly.getY() + (poly.getHeight()/2));
//Calculate the distance between the two
Vector2f distance = new Vector2f(p1Centre);
distance.sub(p2Centre);
//Get the absolute distance
Vector2f absDistance = new Vector2f(distance.x<0 ? -distance.x : distance.x, distance.y<0 ? -distance.y : distance.y);
//Get the combined half widths and heights of each object
Vector2f halvedBounds = new Vector2f((player.getWidth() + poly.getWidth())/2.0f, (player.getHeight() + poly.getHeight())/2.0f);
//If the absolute distance is less thate the halved widths heights then there is a collision
if((absDistance.x < halvedBounds.x) && (absDistance.y < halvedBounds.y)){
//Set the magnitude vector to the halved bounds minus the absolute distance
magnitude.x = halvedBounds.x - absDistance.x;
magnitude.y = halvedBounds.y - absDistance.y;
//Only react to the lesser overlap;
if(magnitude.x < magnitude.y){
magnitude.x = (distance.x > 0) ? magnitude.x : -magnitude.x;
magnitude.y = 0;
}
else{
magnitude.y = (distance.y > 0) ? magnitude.y : -magnitude.y;
magnitude.x = 0;
}
//Debug
System.out.println(magnitude.x+" "+magnitude.y);
System.out.println(translation.x+" "+translation.y+"\n");
//Add the magnitude to the player position
position.add(magnitude);
}
}
完整来源:
import java.util.ArrayList;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Polygon;
import org.newdawn.slick.geom.Vector2f;
public class TestCode extends BasicGame {
private Vector2f position = new Vector2f(300, 300);
private ArrayList<Polygon> solids;
private Polygon player;
public TestCode(String title) {
super(title);
}
public static void main(String[] args) throws SlickException{
AppGameContainer game = new AppGameContainer(new TestCode("test"));
game.setDisplayMode(800, 600, false);
game.start();
}
@Override
public void render(GameContainer gc, Graphics g) throws SlickException {
if(gc.isPaused()){
g.setColor(Color.red);
g.drawString("Paused", 90, 10);
}else{
g.setColor(Color.green);
g.drawString("Playing", 90, 10);
}
g.setColor(Color.red);
for(Polygon p : solids)
g.fill(p);
g.setColor(Color.cyan);
g.fill(player);
}
@Override
public void init(GameContainer gc) throws SlickException {
gc.setVSync(true);
solids = new ArrayList<Polygon>();
player = new Polygon(new float[]{
50, 50, // upper left point
70, 50, // upper right
70, 90, // lower right
50, 90 // lower left
});
for(int i=0, x=200, y=200; i<10; i++, x+=40){
solids.add(new Polygon(new float[]{
x, y, // upper left point
x+40, y, // upper right
x+40, y+40, // lower right
x, y+40 // lower left
}));
}
}
@Override
public void update(GameContainer gc, int delta) throws SlickException {
Input input = gc. getInput();
Vector2f translation = new Vector2f(0, 0);
if(input.isKeyDown(Input.KEY_UP))
translation.y = -1f;
if(input.isKeyDown(Input.KEY_DOWN))
translation.y = 1f;
if(input.isKeyDown(Input.KEY_LEFT))
translation.x = -1f;
if(input.isKeyDown(Input.KEY_RIGHT))
translation.x = 1f;
translation.normalise();
translation.x*=2;
translation.y*=2;
position.add(translation);
for(Polygon p : solids)
Collision(player, p, translation);
player.setLocation(position);
}
public void Collision(Polygon player, Polygon poly, Vector2f translation){
Vector2f magnitude = new Vector2f();
//Find the vectre of each object
Vector2f p1Centre = new Vector2f(player.getX() + (player.getWidth()/2), player.getY() + (player.getHeight()/2));
Vector2f p2Centre = new Vector2f(poly.getX() + (poly.getWidth()/2), poly.getY() + (poly.getHeight()/2));
//Calculate the distance between the two
Vector2f distance = new Vector2f(p1Centre);
distance.sub(p2Centre);
//Get the absolute distance
Vector2f absDistance = new Vector2f(distance.x<0 ? -distance.x : distance.x, distance.y<0 ? -distance.y : distance.y);
//Get the combined half widths and heights of each object
Vector2f halvedBounds = new Vector2f((player.getWidth() + poly.getWidth())/2.0f, (player.getHeight() + poly.getHeight())/2.0f);
//If the absolute distance is less thate the halved widths heights then there is a collision
if((absDistance.x < halvedBounds.x) && (absDistance.y < halvedBounds.y)){
//Set the magnitude vector to the halved bounds minus the absolute distance
magnitude.x = halvedBounds.x - absDistance.x;
magnitude.y = halvedBounds.y - absDistance.y;
//Only react to the lesser overlap;
if(magnitude.x < magnitude.y){
magnitude.x = (distance.x > 0) ? magnitude.x : -magnitude.x;
magnitude.y = 0;
}
else{
magnitude.y = (distance.y > 0) ? magnitude.y : -magnitude.y;
magnitude.x = 0;
}
//Debug
System.out.println(magnitude.x+" "+magnitude.y);
System.out.println(translation.x+" "+translation.y+"\n");
//Add the magnitude to the player position
position.add(magnitude);
}
}
}
最佳答案
高速和播放器通过矩形的问题与采样碰撞数据的频率有关。
假设我真的很笨,我只检查一次碰撞如果一个物体以每秒15米的速度移动,并且有一个1平方米的方向如果我检查物体在离广场7米的地方是否有碰撞,一秒钟后,我会完全忽略物体穿过广场的情况。
许多碰撞检测库处理此问题的方法是,它们比常规对象更经常检查快速移动的对象。当这种情况发生时,你的玩家移动的速度有多快?
关于java - 矩形碰撞检测算法半工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10302276/