矩形碰撞检测算法工作一半



我正在用slick2d + java编写一种用于碰撞检测的算法,我最终将在我将制作的平台游戏中使用。该算法的工作原理是检测玩家与矩形的重叠程度,然后通过该重叠将玩家移出矩形。问题是,该算法有很多问题,我不知道如何解决。首先,有时玩家会离开矩形太远,所以看起来它正在从矩形上反弹。其次,有时玩家可以在矩形内移动少量但明显的数量。最后,如果我增加速度,有时玩家可以一直穿过矩形。这是一个相当模糊的问题,但我真的需要一些帮助来找出问题所在。任何想法将不胜感激。如果您安装了 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 米时检查碰撞,然后在一秒钟后,我将完全错过物体穿过正方形。

许多碰撞检测库处理这个问题的方式是,它们比常规对象更频繁地检查快速移动的对象。发生这种情况时,您的玩家移动速度有多快?

所以只要扭转你的问题:在移动之前检查,而不是之后。如果玩家会降落在矩形中,则不允许他。

问题

中更重要的部分来了:"只是接触表面"有多远(实际上取决于你如何进行碰撞检测;如果你正在做边界框碰撞,它会转化为计算,如果你正在做像素完美的碰撞,你可能不得不测试一些假设情况)。

由于这种情况一直在发生,因此请尽量避免不必要的工作(为什么要逐个像素地测试,间隔分割可能是更好的方法;先进行边界框计算,然后进行像素完美;对于"足够矩形"的对象边界框~~像素像素...

欢迎编程世界,它更多的是关于解决问题,而不是一起打一巴掌"画一个尖顶,移动它x像素和转到10"的陈述;-)

相关内容

  • 没有找到相关文章

最新更新