我刚开始通过libgdx框架学习游戏编程,我正处于开发的碰撞检测阶段。我制作了一个非常简单的游戏,它有一些基本的边界框碰撞检测系统。但是,我想实现像素完美碰撞以保证准确性。
我将展示我认为对帮助您了解正在发生的事情非常重要的代码片段。
创建一个二维数组来定义屏幕上瓷砖的位置:
int[][] map = {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,1,1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,1,1,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
};
我的主游戏类中的这个create()
方法将一个玩家和三个实体添加到ArrayList
类型Entity
。
@Override
public void create () {
batch = new SpriteBatch();
tileTexture = new Texture("block.png");
screenWidth = Gdx.graphics.getWidth();
screenHeight = Gdx.graphics.getHeight();
// add some entities including a player
entities.add(new Player(this, 100, 150, 20, 20, 120.0f, new Texture("player.png")));
entities.add(new Entity(this, 50, 150, 20, 20, 120.0f, new Texture("enemy.png")));
entities.add(new Entity(this, 200, 200, 20, 20, 120.0f, new Texture("enemy.png")));
entities.add(new Entity(this, 180, 50, 20, 20, 120.0f, new Texture("enemy.png")));
}
render() method
在游戏运行时绘制平铺贴图和实体。另一个名为Entity
的类包含特定实体的数据(可以是块/播放器)。数据可以是该实体的x
和y
位置。
// draw tile map
// go over each row bottom to top
for(int y = 0; y < mapHeight; y++) {
// go over each column left to right
for(int x = 0; x < mapWidth; x++) {
// tile
if(map[x][y] == 1) {
batch.draw(tileTexture, x * tileSize, y * tileSize);
}
}
}
// draw all entities
for(int i = entities.size() - 1; i >= 0; i--) {
Entity e = entities.get(i);
batch.draw(e.texture, e.x, e.y);
}
要在玩家(绿色区块)移动时检查碰撞,我有两种方法可以检查玩家是否与实体或图块发生碰撞。
tileCollision()
方法:
public boolean tileCollision(Entity e, Direction direction, float newX, float newY) {
boolean collision = false;
// determine affected tiles
int x1 = (int) Math.floor(Math.min(e.x, newX) / tileSize);
int y1 = (int) Math.floor(Math.min(e.y, newY) / tileSize);
int x2 = (int) Math.floor((Math.max(e.x, newX) + e.width - 0.1f) / tileSize);
int y2 = (int) Math.floor((Math.max(e.y, newY) + e.height - 0.1f) / tileSize);
// tile checks
for(int x = x1; x <= x2; x++) {
for(int y = y1; y <= y2; y++) {
if(map[x][y] == 1) {
collision = true;
e.tileCollision(map[x][y], x, y, newX, newY, direction);
}
}
}
return collision;
}
此方法中的代码行e.tileCollision(map[x][y], x, y, newX, newY, direction);
调用Entity类中的tileCollision()
方法,该方法打印块与tile碰撞的位置。
要检查实体之间的冲突,我们有这个方法:
public boolean entityCollision(Entity e1, Direction direction, float newX, float newY) {
boolean collision = false;
for(int i = 0; i < entities.size(); i++) {
Entity e2 = entities.get(i);
// we don't want to check for collisions between the same entity
if(e1 != e2) {
// axis aligned rectangle rectangle collision detection
if(newX < e2.x + e2.width && e2.x < newX + e1.width &&
newY < e2.y + e2.height && e2.y < newY + e1.height) {
collision = true;
e1.entityCollision(e2, newX, newY, direction);
}
}
}
return collision;
}
注意:绿色块可以在实体中移动,但无法通过切片。这是因为行e1.entityCollision(e2, newX, newY, direction);
调用类entityCollision()
中允许绿色块移动的Entity
方法。
这种类型的碰撞检测似乎是基本且低效的(时间复杂度为O(n^2)
)。
如何在此上下文中实现像素完美碰撞?
其他问题:如果我想提高效率,我可以使用什么碰撞检测系统来消除不必要的检查?