我有一个任务来创建2D游戏,该游戏必须使用用于绘制形状的抽象类Shape。我决定制作一个2D平台游戏,但这是我第一次做这样的事情。我试图实现碰撞检测,并决定为播放器对象创建一个偏移量,以查看它是否与我的矩形对象发生碰撞,如果发生偏移,则停止移动。这仅适用于顶部,但是在右侧,左侧和底部,玩家将在矩形中移动,我不明白为什么。我希望碰撞检测对所有方面都适用。我想知道如何更改碰撞检测以使其适用于矩形的所有侧面。
我的应用程序类别:
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);
}
}
答案 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();
}
但是,这种方法的问题是,如果速度足够大,则对象似乎不会发生碰撞,而是会在其之前停下一点,因为变化量大于剩余间隙。
您需要做的是,一旦检测到碰撞,便要计算您要移动的量与可用空间之间的差,而仅将对象移动该量