我正在制作一个迷宫游戏,在这里,我有一个简单的地图...
直到没有问题,但我的问题是碰撞
这是我的地图
在这里,我使用以下代码自己构建了地图:
package maze;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
public class Maze1 extends GameObject{
public Maze1(int x, int y, ID id) {
super(x, y, id);
}
public void tick() {
}
public void render(Graphics g){
Font fnt = new Font("arial", 1, 25);
g.setFont(fnt);
g.drawString("Level : 1",165 , 433);
//x, y, WIDTH, HEIGHT
g.setColor(Color.darkGray);
g.fillRect(65, 65, 130 ,15);
g.fillRect(0, 130, 145 ,15);
g.fillRect(195, 195, 400 ,15);
g.fillRect(65, 195, 80 ,15);
g.fillRect(130, 260, 80 ,15);
g.fillRect(65, 325, 195 ,15);
g.fillRect(325, 325, 80 ,15);
// x, y, WIDTH, HEIGHT
g.fillRect(195, 130, 80 ,80);
g.fillRect(260, 0, 145 ,80);
//x, y, HEIGHT, WIDTH
g.fillRect(65, 145, 15 ,130);
g.fillRect(195, 65, 15 ,195);
g.fillRect(260, 260, 15 ,130);
g.fillRect(325, 130, 15 ,80);
g.fillRect(325, 260, 15 ,65);
g.setColor(Color.black);
g.fillRect(0, -20, 500 ,32); //x, y, WIDTH, HEIGHT
g.fillRect(0, 390, 500 ,15);
g.fillRect(0, Game.HEIGHT - 41, 500 ,30);
g.fillRect(-20, 0, 32 ,500);
g.fillRect(Game.WIDTH -18, 0, 32 ,340);
g.fillRect(Game.WIDTH -18, 400, 32 ,100);
}
}
此碰撞代码用于右上角矩形
我尝试了两种不同类型的碰撞代码,但没有一种会起作用
冲突代码:
public void collision() {
if(this.getX() >=229 && this.getY() <= 79) {
if(this.getX() >=229) {
this.setVelX(0);
this.setVelY(0);
this.setX(this.getX() -1);
}
if(this.getY() <= 79){
this.setVelX(0);
this.setVelY(0);
this.setY(this.getY() +1);
}
}
这里,当玩家从左侧击中矩形时,玩家将向下移动;当玩家从底部击中矩形时,玩家将向左侧移动。
我已经用if,else if语句尝试了相同的代码,但仍然无法正常工作。当玩家击打左侧时,效果很好,但是当玩家从底部击打矩形时,它会传送到矩形的边缘。
希望我的描述足够清楚,以便您了解我的情况。
提前谢谢!
答案 0 :(得分:1)
对于碰撞检测,我建议将地图数据保留在矩形列表中。像这样:
public class Rect {
public int topLeftX;
public int topLeftY;
public int width;
public int height;
public Rect(int x, int y, int w, int h){
topLeftX = x;
topLeftY = y;
width = w;
height = h;
}
//Ignore the code below here for now
public boolean collidingWith(int x, int y, int width, int height){
Rect r = new Rect(x, y, width, height);
boolean rLeftInWidth = r.topLeftX > topLeftX && r.topLeftX < topLeftX + width;
boolean rRightInWidth = r.topLeftX + r.width > topLeftX && r.topLeftX + width < topLeftX + width;
boolean rTopInHeight = r.topLeftY > topLeftY && r.topLeftY < topLeftY + width;
boolean rBottomInHeight = r.topLeftY + r.width > topLeftY && r.topLeftY + width < topLeftY + width;
if(rLeftInWidth || rRightInWidth){
//If there is horizantal overlap between the other rectangle and this one
if(rTopInHeight || rBottomInHeight){
//If there is also vertical overlap then we must be colliding
return true;
}
}
return false;
}
}
然后将矩形保存在数组或某种类型的集合中,ArrayList可能最简单。
ArrayList<Rect> wallData = new ArrayList<Rect>();
然后您可以添加地图数据。这是从您的矩形画中提取的:
g.fillRect(65, 65, 130 ,15);
它变成具有相同参数的矩形。您甚至可以在填充矩形并重复使用之前执行此操作。
wallData.add(new Rect(65, 65, 130, 15));
Rect r = wallData.get(0);
g.fillRect(r.topLeftX, r.topLeftY, r.width, r.height);
那么,既然您已经有了这些数据,您将如何使用它?当您要检查碰撞时,只需遍历矩形列表并检查玩家是否在碰撞。
for(Rect rectangle: wallData){
if(rectangle.collidingWith(<playerX>, <playerY>, <playerWidth>, <playerHeight>)){
//Your player is colliding with a rectangle!
}
}
还记得我之前告诉您忽略的那一部分吗?让我们现在来看一下。 我发誓,它比看起来简单!
public boolean collidingWith(int x, int y, int width, int height){
Rect r = new Rect(x, y, width, height);
boolean rLeftInWidth = r.topLeftX > topLeftX && r.topLeftX < topLeftX + width;
boolean rRightInWidth = r.topLeftX + r.width > topLeftX && r.topLeftX + width < topLeftX + width;
boolean rTopInHeight = r.topLeftY > topLeftY && r.topLeftY < topLeftY + width;
boolean rBottomInHeight = r.topLeftY + r.width > topLeftY && r.topLeftY + width < topLeftY + width;
if(rLeftInWidth || rRightInWidth){
//If there is horizantal overlap between the other rectangle and this one
if(rTopInHeight || rBottomInHeight){
//If there is also vertical overlap then we must be colliding
return true;
}
}
return false;
}
}
我们首先确定是否存在水平重叠。例如,以下内容是水平重叠的,但不是垂直重叠的。
=-----=
- -
- -
-------
+------
- -
- -
-------
您可以知道,因为带有加号的角位于带有等号的角之间。四个布尔值仅用于确定我们的拐角是否位于另一个对象的拐角之间。
boolean rLeftInWidth = r.topLeftX > topLeftX && r.topLeftX < topLeftX + width;
如果我们的左上角位于其他矩形的左上角和右上角之间,则这变为true。然后,我们也会在右下角执行该操作。如果其中任何一个是正确的,那我们就水平重叠了!
从那里,我们仅检查它是否在水平和垂直方向上重叠。如果是这样,它就会像这样碰撞!
-------
- -
- ------
----- -
- -
------
现在,当您意识到播放器正在碰撞时,您会怎么做?这需要一些工作,但没什么特别的。在通过将播放器的速度添加到位置来移动播放器之前,只需保存其位置即可。
private int playerX;
private int playerY;
<method where you change it>{
playerX = <playerX>;
playerY = <playerY>;
<change their location according to velocity>
}
现在,如果玩家与墙壁碰撞,只需将其位置设置回刚才保存的值,并将其速度设置为0!
设置起来有点复杂,但是一旦完成,这是一个不错的解决方案。
在这个答案中,我在<>之间放了一堆东西。那只是意味着您需要该值,或者这就是它所说的。
希望对您有所帮助!如果您有任何疑问,请随时提出,我很乐意提供更多帮助。碰撞检测是一个复杂的主题,有很多方法。通常,这是我发现最简单的应用程序之一。
与您的原始方法相比,这种方法的优点:
如果创建了矩形列表,则可以使用循环将其绘制:
for(Rect r: wallData){
g.fillRect(r.topLeftX, r.topLeftY, r.width, r.height);
}
易于编辑:如果您决定更改地图,则只需更改一些矩形的宽度,高度和位置,而不必经过一堆if语句来尝试确定是否合适。更改。 (我之前已经讲过)
容易出错:为每个墙设置一些矩形要比设置一堆if语句容易得多。
这种方法与您的原始方法的缺点
这是效率较低的-有更多操作可以检查播放器是否与矩形碰撞,而不是2 ifs。另外,可能会有玩家无法与之碰撞的矩形。但是,效率损失非常小,尤其是在地图中的矩形数量较少的情况下。
这个比较复杂。最好了解您使用的代码,而不是盲目地复制粘贴。如果您需要进行更改,那么如果您不了解,就会更加困难。 (不是您不知道,这可能会有点难。)