在上一部分中,我们创建了一个简单的编辑器,让我们放置炮塔。 现在,我们将在敌人起源的地方添加一个生成点,并为其定义攻击目标。 首先,我将通过对象层向地图添加更多信息。 这是标准的TMX,因此我们可以在TileMap编辑器中实现:








JavaFX中的塔防(2)

为了计算敌人的攻击路径,我们将使用A *算法,该算法是tilengine模块的一部分:

因此,让我们获取派生点和目标并将其存储为我们的算法:

ArrayList objectGroups = tileMap.getObjectGroups();
for (ObjectGroup objectGroup : objectGroups) {
for (final TObject tObject : objectGroup.getObjectLIst()) {
if (tObject.getName().equals("spawnpoint")) {

spawnpointX = tObject.getX() / turrets.getTilewidth();
spawnpointY = tObject.getY() / turrets.getTileheight();

}

if (tObject.getName().equals("target")) {

targetX = tObject.getX() / turrets.getTilewidth();
targetY = tObject.getY() / turrets.getTileheight();

}
}
}

使用这些值,我们可以初始化A *算法,该算法计算敌人的最短路径:

AStar.AStarTile start = new AStar.AStarTile((int) spawnpointX, (int) spawnpointY);
AStar.AStarTile end = new AStar.AStarTile((int) targetX, (int) targetY);
attackPath = AStar.getPath(tileMap, platformLayer, start, end);

为了查看结果,我们将向GameCanvas添加一个调试层:

private class AStarLayer extends Layer {
public AStarLayer() {
}
Color pathColor = Color.rgb(255, 100, 100, .2);

@Override
public void draw(GraphicsContext graphicsContext, double x, double y, double width, double height) {
AStar.PathNode start = attackPath;
if (start != null) {
graphicsContext.setFill(pathColor);
graphicsContext.fillRect(start.getX() * tileMap.getTilewidth(), start.getY() * tileMap.getTileheight(), tileMap.getTilewidth(), tileMap.getTileheight());
while (start.getParent() != null) {
start = start.getParent();
graphicsContext.fillRect(start.getX() * tileMap.getTilewidth(), start.getY() * tileMap.getTileheight(), tileMap.getTilewidth(), tileMap.getTileheight());
}
}
}
}

结果看起来像这样:

JavaFX中的塔防(2)

您会看到红色的最短路径。 由于该算法没有“看到”背景图像的结构,因此会相应地计算路径,而敌人只会忽略船的结构(背景被认为是宇宙飞船的一部分)。 要解决此问题,我们稍后将添加一些不可见的图块。 对于较大型的游戏,最好使用不可见的碰撞层,这样可以为您提供更好的性能,并提供更多方式来实现锁定段落等功能。 对我们而言,transparent-tile-approach更好,因为我们不需要额外的图层,并且用户可以编辑布局更容易。

现在,我们需要将敌人送往这条路。 为了给Sprite制作动画,我将动画阶段合并为一个图像:

JavaFX中的塔防(2)

现在,我们可以使用Tiled编辑器从中创建TileSet:

JavaFX中的塔防(2)

我还使用Tiled向派生点添加了两个附加属性:

JavaFX中的塔防(2)

第一个定义了每种类型我想要产生多少个敌人,第二个定义了它们产生之间的停顿时间。 我怀疑他们能否经受住时间的考验,但现在让我们与他们合作。 在用于读取对象组的代码内,我们可以访问属性:

if (tObject.getName().equals("spawnpoint")) {

Properties properties = tObject.getProperties();
evaluationInterval = Long.parseLong(properties.getProperty("delay"));
spawnpointX = tObject.getX() / turrets.getTilewidth();
spawnpointY = tObject.getY() / turrets.getTileheight();

}

现在我们只有一种怪兽,所以我们可以忽略它而只使用延迟。 首先,我们将从TileSet创建一个SpriteAnimation:

final TileSet enemy1 = tileMap.getTileSet("enemy1");
final TileSetAnimation tileSetAnimation = new TileSetAnimation(enemy1, new int[]{0, 1, 2, 3, 4, 5}, 10f);

为了产生怪物,我们将定义一个行为。 那只是一个定时方法调用。 为了支持Lambda表达式,可能会在此处对API进行一些更改:

Behavior monsterSpawnBehavior = new Behavior() {
int enemyCount = 0;

@Override
public boolean perform(GameCanvas canvas, long nanos) {
new Sprite(canvas, tileSetAnimation, "enemy" + (enemyCount++), ((int)spawnpointTileX) * tileMap.getTilewidth(), ((int)spawnpointTileY) * tileMap.getTileheight(), 46, 46, Lookup.EMPTY);
return false;
}
};
monsterSpawnBehavior.setEvaluationInterval(evaluationInterval);
canvas.addBehaviour(monsterSpawnBehavior);

因此,现在每隔十亿分之一秒,一个新的敌人就会被添加到运动场中。 稍后我们可能会创建EnemySprite类来封装Behavior。 但是现在,让我们继续使用此Sprite并向其添加Behavior:

sprite.addBehaviour(new SpriteBehavior() {
AStar.PathNode start = attackPath;

@Override
public boolean perform(Sprite sprite) {
double x = sprite.getX();
double y = sprite.getY();
double pathX = start.getX() * tileMap.getTilewidth();
double pathY = start.getY() * tileMap.getTileheight();
if (Math.abs(pathX- x) 1) {
sprite.setVelocityX(.5);
} else if (pathX- x < -1) { sprite.setVelocityX(-.5); } else { sprite.setVelocityX(0); } if (pathY - y > 1) {
sprite.setVelocityY(.5);
} else if (pathY - y < -1) {
sprite.setVelocityY(-.5);
} else {
sprite.setVelocityY(0);
}
return true;
}
});

结果如下:

现在就这样。 如您所见,通过Behaviors将AI添加到sprite很简单,而AStar非常方便。 在下一部分中,我们将注意敌人指向正确的方向,并向炮塔添加一些行为。

参考:来自我们的JCG合作伙伴 Toni Epple的JavaFX(2)中的塔防技术,来自Eppleton博客。

翻译自: https://www.javacodegeeks.com/2013/10/tower-defense-in-javafx-2.html

相关文章:

  • 2021-12-12
  • 2021-10-17
  • 2022-01-22
  • 2021-09-29
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-01-06
  • 2021-09-16
  • 2021-08-30
  • 2021-09-18
  • 2022-12-23
  • 2021-08-10
相关资源
相似解决方案