JavaFX中的塔防(2)
在上一部分中,我們創建了一個簡單的編輯器,讓我們放置炮塔。 現在,我們將在敵人起源的地方添加一個生成點,并為其定義攻擊目標。 首先,我將通過對象層向地圖添加更多信息。 這是標準的TMX,因此我們可以在TileMap編輯器中實現:
為了計算敵人的攻擊路徑,我們將使用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()); } } } }結果看起來像這樣:
您會看到紅色的最短路徑。 由于該算法沒有“看到”背景圖像的結構,因此會相應地計算路徑,而敵人只會忽略船的結構(背景被認為是宇宙飛船的一部分)。 要解決此問題,我們稍后將添加一些不可見的圖塊。 對于較大型的游戲,最好使用不可見的碰撞層,這樣可以為您提供更好的性能,并提供更多方式來實現鎖定段落等功能。 對我們而言,transparent-tile-approach更好,因為我們不需要額外的圖層,并且用戶可以編輯布局更容易。
現在,我們需要將敵人送往這條路。 為了給Sprite制作動畫,我將動畫階段合并為一個圖像:
現在,我們可以使用Tiled編輯器從中創建TileSet:
我還使用Tiled向派生點添加了兩個附加屬性:
第一個定義了每種類型我想要產生多少個敵人,第二個定義了它們產生之間的停頓時間。 我懷疑他們能否經受住時間的考驗,但現在讓我們與他們合作。 在用于讀取對象組的代碼內,我們可以訪問屬性:
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非常方便。 在下一部分中,我們將注意敵人指向正確的方向,并向炮塔添加一些行為。
翻譯自: https://www.javacodegeeks.com/2013/10/tower-defense-in-javafx-2.html
總結
以上是生活随笔為你收集整理的JavaFX中的塔防(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 醨怎么读 醨字具体怎么读
- 下一篇: Java中的堆栈和队列