我正在用java制作一个2d rpg游戏,但我遇到了一个问题。我可以让玩家在舞台上移动,我也在舞台上拥有岩石,树木,墙壁等。我不知道如何检测碰撞并使其到达玩家无法穿过物体的位置。读取地图文件并在画布上绘制图像的代码如下:
public void loadLevel(BufferedImage levelImage){
tiles = new int[levelImage.getWidth()][levelImage.getHeight()];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Color c = new Color(levelImage.getRGB(x, y));
String h = String.format("%02x%02x%02x", c.getRed(),c.getGreen(),c.getBlue());
switch(h){
case "00ff00"://GRASS Tile - 1
tiles[x][y] = 1;
break;
case "808080"://Stone -2
tiles[x][y] = 2;
break;
case "894627"://Dirt -3
tiles[x][y] = 3;
break;
case "404040"://Rock on Grass -4
tiles[x][y] = 4;
break;
case "00b700"://Tree -5
tiles[x][y] = 5;
break;
case"000000"://Wall -6
tiles[x][y] = 6;
break;
case "cccccc"://Rock on stone -7
tiles[x][y] = 7;
break;
default:
tiles[x][y] = 1;
System.out.println(h);
break;
}
}
}
}
播放器类如下:
public class Player {
private int x,y;
public int locx,locy;
private Rectangle playerR;
private ImageManager im;
public boolean up =false,dn = false,lt=false,rt=false,moving = false,canMove = true;
private final int SPEED =2;
public Player(int x, int y, ImageManager im){
this.x = x;
this.y = y;
this.im = im;
locx = x;
locy = y;
playerR = new Rectangle(x,y,16,16);
}
public void tick(){
if (up) {
if(canMove){
y -= SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
moving = true;
}
else{
y += 1;
canMove=true;
}
}
if (dn) {
y +=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if (lt) {
x -= SPEED;
locx = x;
locy = y;
moving = true;
}
if (rt) {
x+=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if(moving){
System.out.println("PLAYER\tX:"+locx+" Y:"+locy);
moving = false;
}
}
public void render(Graphics g){
g.drawImage(im.player, x, y, Game.TILESIZE*Game.SCALE, Game.TILESIZE*Game.SCALE, null);
}
}
我真的不知道怎么做碰撞,但是我用谷歌搜索了它,人们说要为玩家制作一个矩形和玩家应该碰撞的所有物体,每次玩家移动时,移动玩家的矩形。这是正确的方法吗?
编辑编辑编辑
碰撞为真时的代码:
if (rt) {
x+=SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
for(int i = 0;i<Level.collisions.size();i++){
if(intersects(playerR,Level.collisions.get(i))==true){
x-=SPEED;
locx = x;
playerR.setLocation(locx, locy);
}
}
moving = true;
}
交叉方法如下:
private boolean intersects(Rectangle r1, Rectangle r2){
return r1.intersects(r2);
}
答案 0 :(得分:1)
我将专注于你的tick方法,因为这是大多数逻辑的发展方向。这里有一些变化。最值得注意的是,我们只在检查碰撞之前移动矩形。然后循环遍历关卡中的所有可碰撞对象。一旦找到一个,我们重置我们的x和y并突破循环(看看任何其他对象没有意义,因为我们已经找到了我们碰撞的那个)。然后我们更新我们的球员位置。通过这种方式,我集中了代码,因此不会重复。如果你看到自己重复编码,很有可能将它拉到一个公共场所或一个方法。
public void tick() {
if (up) {
y -= SPEED;
} else if (dn) {
y += SPEED;
} else if (lt) {
x -= SPEED;
} else if (rt) {
x += SPEED;
}
playerR.setLocation(x, y);
for (Rectangle collideable : Level.collisions) {
if (intersects(playerR, collideable)) {
x = locx;
y = locy;
playerR.setLocation(x, y);
break;
}
}
locx = x;
locy = y;
}
答案 1 :(得分:0)
有不同的方法可以做到这一点。当你谈到一个“RPG”时,我认为你的观点是等距的(45°自上而下) 我会在纯90°自上而下进行碰撞检测,因为它更容易,而且更真实 我们有两种可能性:
Player
移至下一个位置。如果发生碰撞,请重置其位置。如果您想要进行“滑行”碰撞响应,则必须检查碰撞将发生在哪个轴上,并且仅停止/重置此轴的移动。
要进行更有效的碰撞检测,只需检查可能发生碰撞的物体附近。 通过将平方“dangerRadius”与玩家与物体之间的平方距离进行比较来做到这一点:
if ((player.x - object.x)² + (player.y - object.y)² <= dangerRadius²)
// Check for intersection
这将通过使用简单的计算来解决大多数对象:
在你的游戏中你应该把逻辑和视图分开。所以基本上你不会检测,如果两个图像重叠,但你检查,你的逻辑中的对象是否重叠。然后在正确的位置绘制图像。
希望这有帮助。
编辑重要提示:如果您更新角色,则根据最后一帧与此帧之间的时间(1 / FPS),您必须限制最长时间步长。为什么?因为如果由于某种原因(可能是慢速设备?)FPS真的很低,那么角色可能会在2帧之间移动很远,因此他可以在1帧内通过一个物体。
此外,如果你只是简单地重置碰撞运动或只是不移动你和物体之间的距离可能很大,低FPS。对于正常的FPS而不是高速运动速度,这不会发生/明显。
答案 2 :(得分:0)
我个人对Java很新,尽管我过去曾使用过C#。我正在制作类似的游戏,对于碰撞检测,我只需检查玩家和物体的位置:
if (z.gettileX() == p.gettileX()){
if (z.gettileY() == p.gettileY()){
System.out.println("Collision!");
}
}
如果玩家(p)具有相等的X坐标且Y坐标为z(坏人),它将发送此消息并确认两者实际上已发生碰撞。如果你可以在z后面的实际类中固有来检查坐标是否相等,你可以创建无限数量的游戏内对象来检测碰撞并以相同的方式作出反应,即墙壁。
答案 3 :(得分:0)
这可能就是你要找的东西。我为了多个物体的碰撞和个别的侧面碰撞而特意制作了这个类。
abstract class Entity {
private Line2D topLine;
private Line2D bottomLine;
private Line2D leftLine;
private Line2D rightLine;
private Rectangle rectangle;
private Entity entity;
protected boolean top;
protected boolean bottom;
protected boolean left;
protected boolean right;
protected int x;
protected int y;
protected int width;
protected int height;
public Entity(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
updateLinesAndRects();
}
public void updateLinesAndRects() {
topLine = new Line(x + 1, y, width - 2, 0);
bottomLine = new Line(x + 1, y + height, width - 2, height);
leftLine = new Line(x, y + 1, 0, height - 2);
rightLine = new Line(x + width, y + 1, 0, height - 2);
rectangle = new Rectangle(x, y, width, height)
}
public void setCollision(Entity entity) {
this.entity = entity;
top = isColliding(new Line2D[]{topLine, bottomLine, leftLine, rightLine});
bottom = isColliding(new Line2D[]{bottomLine, topLine, leftLine, rightLine});
left = isColliding(new Line2D[]{leftLine, topLine, bottomLine, rightLine});
right = isColliding(new Line2D[]{rightLine, topLine, bottomLine, leftLine});
}
public void updateBounds() {
if(top) y = entity.y + entity.height;
if(bottom) y = entity.y - height;
if(left) x = entity.x + entity.width;
if(right) x = entity.x - width;
}
public boolean isColliding() {
return rectangle.intersects(entity.rect);
}
private boolean isLinesColliding(Line2D[] lines) {
Rectangle rect = entity.getRectangle();
return lines[0].intersects(rect) && !lines[1].intersects(rect) && !lines[2].intersects(rect) && !lines[3].intersects(rect);
}
private Line2D line(float x, float y, float width, float height) {
return new Line2D(new Point2D.Float(x, y), new Point2D.Float(x + width, x + height));
}
public Rectangle getRectangle() {
return rectangle;
}
}
示例:
class Player extends Entity{
Entity[] entities;
public Player(int x, int y, int width, int height) {
super(x, y, width, height);
}
public void update() {
updateLinesAndRects();
for(Entity entity : entities) {
setCollision(entity);
if(top) system.out.println("player is colliding from the top!");
if(isColliding()) system.out.println("player is colliding!");
updateBounds(); // updates the collision bounds for the player from the entities when colliding.
}
}
public void setEntities(Entity[] entities) {
this.entities = entities;
}
}