使用 Java、Slick2D 和平铺地图编辑器进行碰撞检测
Collision Detection with Java, Slick2D and Tiled Map Editor
很长一段时间以来,我一直在研究碰撞检测以及如何处理它。我需要帮助了解如何使用 Tiled 地图编辑器进行碰撞检测。我用播放器、相机和键盘移动解析并显示了 TMX 文件。我不确定如何处理碰撞。我的地图有 2 层,一层用于您可以在其上行走的草地和瓷砖,另一层是 objectLayer。我见过有人说我应该遍历对象层中的所有图块并为它们分配矩形。我不知道该怎么做,我正在寻找一些见解。
我的主要问题是:如何遍历图层并获取所有图块并为其分配矩形。
游戏Class:
public class Game extends BasicGameState {
Player player;
Camera cam;
Map map = new Map();
public void init(GameContainer container, StateBasedGame sbg) throws SlickException {
map.init();
cam = new Camera(0, 0);
player = new Player(new Image("res/textures/player.png"), container.getWidth() / 2, container.getHeight() / 2, 32, 32);
}
public void update(GameContainer container, StateBasedGame sbg, int delta) throws SlickException {
cam.tick(player);
player.update(container, delta, map);
}
public void render(GameContainer container, StateBasedGame sbg, Graphics g) throws SlickException {
g.translate(-cam.getX(), -cam.getY());
map.render();
player.render(g);
g.translate(cam.getX(), cam.getY());
}
public int getID() {
return 1;
}
}
玩家Class:
public class Player {
float x, y;
int width, height;
double velX = 0.4;
double velY = 0.4;
Image img;
public Player(Image img, float x, float y, int width, int height) {
this.img = img;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void init() throws SlickException {
}
public void update(GameContainer container, int delta, Map map) {
Input input = container.getInput();
if (input.isKeyDown(Input.KEY_D)) x += velX;
if (input.isKeyDown(Input.KEY_A)) x -= velX;
if (input.isKeyDown(Input.KEY_W)) y -= velY;
if (input.isKeyDown(Input.KEY_S)) y += velY;
}
public void render(Graphics g) {
//g.scale(-2, -2);
g.drawImage(img, x, y);
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
地图class:
public class Map {
TiledMap map;
public void init() throws SlickException {
map = new TiledMap("res/map/zenith.tmx");
}
public void render() throws SlickException {
map.render(0, 0);
}
}
我不太熟悉获取磁贴的具体方法,但它肯定在 Javadoc 中。 http://slick.ninjacave.com/javadoc/
为了检查与玩家的碰撞,你需要改变你的动作来检查玩家的新位置是否会发生碰撞,否则你会卡在他们身上。
public void update(GameContainer container, int delta, Map map) {
Input input = container.getInput();
float dx = 0, dy = 0;
// add to dx and dy instead of moving the player straight away.
if (input.isKeyDown(Input.KEY_D)) dx += velX;
if (input.isKeyDown(Input.KEY_A)) dx -= velX;
if (input.isKeyDown(Input.KEY_W)) dy -= velY;
if (input.isKeyDown(Input.KEY_S)) dy += velY;
// here we check the collisions, you can fiddle with this if statement and it'll behave differently.
if(dx != 0 || dy != 0){
if(map.checkCollision(x+dx,y+y){
x+=dx;
y+=dy;
}
}
}
至于检查碰撞本身,您需要在地图 class 中使用一种新方法来为玩家创建一个矩形并检查地图 class 中保存碰撞的二维数组。您可以在地图初始化时填充此数组,方法是在您需要的图层中循环遍历 Tiled 地图,并检查该图块是否与 getTile(x,y) 发生冲突。如果图块具有正确的碰撞属性,您可以在二维数组中的该位置创建一个矩形,如下所示:
collisionArray[x][y] = new Rectangle(x,y,TILEWIDTH,TILEHEIGHT);
您现在可以检查内部碰撞
map.checkCollision(x,y)
并使用
为玩家创建了一个矩形
Rectangle player = new Rectangle(x,y,PLAYERWIDTH,PLAYERHEIGHT);
将它们放在一起,然后您可以使用 .intersect(r) 检查与碰撞数组中任何图块的交集,如前所述,map.collision 可以 return 对玩家来说是正确的停止播放器的移动。
我希望这不是太复杂,javadoc 非常有用,Kevin Glass 写了一篇关于仅使用 2D 数组检查碰撞的文章,碰撞框大小不同。
http://www.cokeandcode.com/main/tutorials/tile-maps/
好的,现在我在我的 checkCollision() 中得到一个空指针异常
public void assignRectangles() {
int objectLayer = map.getLayerIndex("objectLayer");
for (int x = 0; x < map.getWidth(); x++) {
for (int y = 0; y < map.getHeight(); y++) {
if (map.getTileId(x, y, objectLayer) == 1){
collisionArray[x][y] = new Rectangle(x * 32, y * 32, 32, 32);
}
}
}
}
public boolean checkCollision(float x, float y) {
for (int j = 0; j < collisionArray.length; j++) {
for (int i = 0; i < collisionArray[j].length; i++) {
if (collisionArray[j][i].getX() == x || collisionArray[j][i].getY() == y) {
return false;
}
}
}
return true;
}
我在上面写着 if (collisionArray[j][i].getX() == x || collisionArray[j][i].getY() == y)
虽然我不确定为什么会收到它
很长一段时间以来,我一直在研究碰撞检测以及如何处理它。我需要帮助了解如何使用 Tiled 地图编辑器进行碰撞检测。我用播放器、相机和键盘移动解析并显示了 TMX 文件。我不确定如何处理碰撞。我的地图有 2 层,一层用于您可以在其上行走的草地和瓷砖,另一层是 objectLayer。我见过有人说我应该遍历对象层中的所有图块并为它们分配矩形。我不知道该怎么做,我正在寻找一些见解。
我的主要问题是:如何遍历图层并获取所有图块并为其分配矩形。
游戏Class:
public class Game extends BasicGameState {
Player player;
Camera cam;
Map map = new Map();
public void init(GameContainer container, StateBasedGame sbg) throws SlickException {
map.init();
cam = new Camera(0, 0);
player = new Player(new Image("res/textures/player.png"), container.getWidth() / 2, container.getHeight() / 2, 32, 32);
}
public void update(GameContainer container, StateBasedGame sbg, int delta) throws SlickException {
cam.tick(player);
player.update(container, delta, map);
}
public void render(GameContainer container, StateBasedGame sbg, Graphics g) throws SlickException {
g.translate(-cam.getX(), -cam.getY());
map.render();
player.render(g);
g.translate(cam.getX(), cam.getY());
}
public int getID() {
return 1;
}
}
玩家Class:
public class Player {
float x, y;
int width, height;
double velX = 0.4;
double velY = 0.4;
Image img;
public Player(Image img, float x, float y, int width, int height) {
this.img = img;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void init() throws SlickException {
}
public void update(GameContainer container, int delta, Map map) {
Input input = container.getInput();
if (input.isKeyDown(Input.KEY_D)) x += velX;
if (input.isKeyDown(Input.KEY_A)) x -= velX;
if (input.isKeyDown(Input.KEY_W)) y -= velY;
if (input.isKeyDown(Input.KEY_S)) y += velY;
}
public void render(Graphics g) {
//g.scale(-2, -2);
g.drawImage(img, x, y);
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
地图class:
public class Map {
TiledMap map;
public void init() throws SlickException {
map = new TiledMap("res/map/zenith.tmx");
}
public void render() throws SlickException {
map.render(0, 0);
}
}
我不太熟悉获取磁贴的具体方法,但它肯定在 Javadoc 中。 http://slick.ninjacave.com/javadoc/
为了检查与玩家的碰撞,你需要改变你的动作来检查玩家的新位置是否会发生碰撞,否则你会卡在他们身上。
public void update(GameContainer container, int delta, Map map) {
Input input = container.getInput();
float dx = 0, dy = 0;
// add to dx and dy instead of moving the player straight away.
if (input.isKeyDown(Input.KEY_D)) dx += velX;
if (input.isKeyDown(Input.KEY_A)) dx -= velX;
if (input.isKeyDown(Input.KEY_W)) dy -= velY;
if (input.isKeyDown(Input.KEY_S)) dy += velY;
// here we check the collisions, you can fiddle with this if statement and it'll behave differently.
if(dx != 0 || dy != 0){
if(map.checkCollision(x+dx,y+y){
x+=dx;
y+=dy;
}
}
}
至于检查碰撞本身,您需要在地图 class 中使用一种新方法来为玩家创建一个矩形并检查地图 class 中保存碰撞的二维数组。您可以在地图初始化时填充此数组,方法是在您需要的图层中循环遍历 Tiled 地图,并检查该图块是否与 getTile(x,y) 发生冲突。如果图块具有正确的碰撞属性,您可以在二维数组中的该位置创建一个矩形,如下所示:
collisionArray[x][y] = new Rectangle(x,y,TILEWIDTH,TILEHEIGHT);
您现在可以检查内部碰撞
map.checkCollision(x,y)
并使用
为玩家创建了一个矩形Rectangle player = new Rectangle(x,y,PLAYERWIDTH,PLAYERHEIGHT);
将它们放在一起,然后您可以使用 .intersect(r) 检查与碰撞数组中任何图块的交集,如前所述,map.collision 可以 return 对玩家来说是正确的停止播放器的移动。
我希望这不是太复杂,javadoc 非常有用,Kevin Glass 写了一篇关于仅使用 2D 数组检查碰撞的文章,碰撞框大小不同。 http://www.cokeandcode.com/main/tutorials/tile-maps/
好的,现在我在我的 checkCollision() 中得到一个空指针异常
public void assignRectangles() {
int objectLayer = map.getLayerIndex("objectLayer");
for (int x = 0; x < map.getWidth(); x++) {
for (int y = 0; y < map.getHeight(); y++) {
if (map.getTileId(x, y, objectLayer) == 1){
collisionArray[x][y] = new Rectangle(x * 32, y * 32, 32, 32);
}
}
}
}
public boolean checkCollision(float x, float y) {
for (int j = 0; j < collisionArray.length; j++) {
for (int i = 0; i < collisionArray[j].length; i++) {
if (collisionArray[j][i].getX() == x || collisionArray[j][i].getY() == y) {
return false;
}
}
}
return true;
}
我在上面写着 if (collisionArray[j][i].getX() == x || collisionArray[j][i].getY() == y)
虽然我不确定为什么会收到它