碰撞检测仅在墙的顶部起作用-Java

时间:2018-12-04 22:12:22

标签: java collision-detection graphics2d shapes

我有一个任务来创建2D游戏,该游戏必须使用用于绘制形状的抽象类Shape。我决定制作一个2D平台游戏,但这是我第一次做这样的事情。我试图实现碰撞检测,并决定为播放器对象创建一个偏移量,以查看它是否与我的矩形对象发生碰撞,如果发生偏移,则停止移动。这仅适用于顶部,但是在右侧,左侧和底部,玩家将在矩形中移动,我不明白为什么。我希望碰撞检测对所有方面都适用。我想知道如何更改碰撞检测以使其适用于矩形的所有侧面。

以下是显示所发生情况的gif文件:enter image description here

我的应用程序类别:

package A2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.TreeSet;

import static java.awt.event.KeyEvent.*;

public class App extends JFrame {

    private static final int GRAVITY = 10;
    private static final int MAX_FALL_SPEED = 30;

    public App() {

        final Player player = new Player(200, 300);
        final Rectangle rectangle = new Rectangle(100, 400);
        JPanel mainPanel = new JPanel() {
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                player.draw(g);
                rectangle.draw(g);
            }
        };

        mainPanel.addKeyListener(new controlHandler(this, player, rectangle));
        mainPanel.setFocusable(true);
        add(mainPanel);

        setLayout(new GridLayout());
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(600, 600);
    }


    class controlHandler implements ActionListener, KeyListener {
        int keyCode;
        App app;
        Player player;
        Rectangle rectangle;
        TreeSet<Integer> keys = new TreeSet<>();
        Timer time = new Timer(5, this);
        boolean collision = false;


        public controlHandler(App app, Player player, Rectangle rectangle) {
            this.app = app;
            this.player = player;
            this.rectangle = rectangle;
            time.start();
        }

        public void actionPerformed(ActionEvent e) {
            player.x += player.xVelocity;
            player.y += player.yVelocity;

            Rectangle2D offset = player.getOffsetBounds();

            if(offset.intersects(this.rectangle.wallObj.getBounds2D())){
                collision = true;
                player.xVelocity = 0;
                player.yVelocity = 0;
            }
            else collision = false;

            repaint();
        }

        public void keyPressed(KeyEvent e) {
            keyCode = e.getKeyCode();
            keys.add(keyCode);


            switch (keyCode) {
                case VK_UP:
                    moveUp();
                    break;
                case VK_DOWN:
                    moveDown();
                    break;
                case VK_LEFT:
                    moveLeft();
                    break;
                case VK_RIGHT:
                    moveRight();
                    break;
            }
        }

        public void keyReleased(KeyEvent e) {
            released();
        }
        public void keyTyped(KeyEvent e) { }

        public void moveUp() {
            player.xVelocity = 0;
            player.yVelocity = -2;
        }

        public void moveDown() {
            if(!collision) {
                player.xVelocity = 0;
                player.yVelocity = 2;
            }
        }

        public void moveLeft() {
            player.xVelocity = -2;
            player.yVelocity = 0;
        }

        public void moveRight() {
            player.xVelocity = 2;
            player.yVelocity = 0;
        }

        public void released() {
            player.xVelocity = 0;
            player.yVelocity = 0;
        }
    }

    public static void main(String[] args) {
        App app = new App();
        app.setVisible(true);
    }
}

abstract class Shape {
    public double x;
    public double y;

    public void draw(Graphics g) { }
}

播放器类:

package A2;

import java.awt.*;
import java.awt.geom.Rectangle2D;

public class Player extends Shape {
    public double xVelocity;
    public double yVelocity;
    public double length = 60;
    public double top;
    public double right;
    public double left;
    public double bottom;
    public  Rectangle2D playerObj;


    public Player(double x, double y) {
        this.x = x;
        this.y = y;
        playerObj = new Rectangle2D.Double(x, y, length, length);
    }

    public Rectangle2D getOffsetBounds(){
        return new Rectangle2D.Double(x + xVelocity , y + yVelocity , length, length);
    }

    public void draw(Graphics g) {
        playerObj = new Rectangle2D.Double(x, y, length, length);
        g.setColor(Color.BLACK);
        Graphics2D g2 = (Graphics2D)g;
        g2.fill(playerObj);

    }
}

矩形类(将是一个平台):

package A2;

import java.awt.*;
import java.awt.geom.Rectangle2D;

public class Rectangle extends Shape {
    public double width = 400;
    public double height = 30;
    public double top;
    public double right;
    public double left;
    public double bottom;
    public Rectangle2D wallObj;

    public Rectangle(double x, double y) {
        this.x = x;
        this.y = y;
        wallObj = new Rectangle2D.Double(x, y, width, height);
    }

    public void draw(Graphics g) {
        g.setColor(Color.ORANGE);
        Graphics2D g2 = (Graphics2D)g;
        g2.fill(wallObj);

    }
}

1 个答案:

答案 0 :(得分:1)

因此,根据我的理解,您的碰撞检测过程基本上是创建对象的“虚拟”实例并确定其是否会碰撞。

您的代码实际上是有效的,您可以通过以下事实得知对象碰撞后会“停止”移动,但是您没有执行的操作是重置其后的对象位置。

让我们看一下原始代码...

public void actionPerformed(ActionEvent e) {
  player.x += player.xVelocity;
  player.y += player.yVelocity;

  Rectangle2D offset = player.getOffsetBounds();

  if (offset.intersects(this.rectangle.wallObj.getBounds2D())) {
    collision = true;
    player.xVelocity = 0;
    player.yVelocity = 0;
  } else {
    collision = false;
  }

  repaint();
}
  • 更新对象的位置
  • 创建对象的虚拟实例,将速度再次应用于对象的当前位置...
  • 确定对象是否碰撞
  • 停止运动
  • ...在哪里重置对象的位置,使其不再发生碰撞?!?

例如,在确定是否发生碰撞之后,才应该设置对象的位置。

public void actionPerformed(ActionEvent e) {

  Rectangle2D offset = player.getOffsetBounds();

  if (offset.intersects(this.rectangle.wallObj.getBounds2D())) {
    collision = true;
    player.xVelocity = 0;
    player.yVelocity = 0;
  } else {
    player.x += player.xVelocity;
    player.y += player.yVelocity;
    collision = false;
  }

  repaint();
}

但是,这种方法的问题是,如果速度足够大,则对象似乎不会发生碰撞,而是会在其之前停下一点,因为变化量大于剩余间隙。

您需要做的是,一旦检测到碰撞,便要计算您要移动的量与可用空间之间的差,而仅将对象移动该量