Статьи

Tower Defense в JavaFX (6)

Итак, мы уже в шестой части этого урока, и игра тем временем прошла долгий путь. В этой части мы наконец добавим слой, который показывает счет, количество врагов, которые достигли своей цели, кнопку для запуска следующей волны и оставшиеся деньги для покупки новых турелей. Говоря о деньгах, у нас пока нет логики для этого, поэтому мы должны сначала это исправить. Я не хотел хранить цену в коде приложения, потому что моему воображаемому дизайнеру уровней (который не знает программирования) становится сложнее подстроить переменные. Также я хотел сохранить все в одном месте, поэтому, если мы решим добавить новую башню, не нужно вносить изменения во многих разных местах. К счастью, мы можем хранить свойства в TileSet, поэтому мы сделаем это так.

Формат TMX для Tilemaps — действительно отличный способ отделить дизайн от внутренних элементов программирования (бизнес-логика звучит очень неправильно, когда речь идет об играх). В результате графические дизайнеры могут создавать ресурсы, дизайнеры уровней могут создавать уровни, и даже пользователи могут изменять игру и создавать свои собственные уровни очень легко. До сих пор мы использовали редактор Tiled для создания уровня, а также хранили метаинформацию о появлении врагов и пути атаки в одном из слоев. Теперь мы добавим некоторые свойства к отдельным элементам TileSets. Это работает только с внутренними TileSets, поэтому в Tiled вы должны определить новый Tileset через «Map -> new Tileset». Если вы теперь щелкнете правой кнопкой мыши по плитке, у нее будет действие для определения свойств плитки. Я определил некоторые для моих башенных оснований:

Bildschirmfoto-2013-08-11-эм-08.29.05

Я добавил пару свойств, включая диапазон для оружия, скорость его стрельбы, наносимый им урон, имя и описание, которые будут отображаться позже, и тип, который я хочу использовать, чтобы определить плитки для использования в качестве маркера. , Может быть, появятся также оружие, подобное лазеру, которое должно быть реализовано по-другому. Тогда я могу решить использовать другую логику для этого типа. Я получаю свойства из Tile через Tileset следующим образом:

1
Properties properties = tileSet.getTileList().get(selectedIndex).getProperties();

Внутри CannonSprite я могу использовать их так:

01
02
03
04
05
06
07
08
09
10
11
12
String rangeProperty = properties.getProperty("range");
if (rangeProperty != null) {
range = Integer.parseInt(rangeProperty);
}
String damageProperty = properties.getProperty("damage");
if (damageProperty != null) {
damage = Integer.parseInt(damageProperty);
}
String rateProperty = properties.getProperty("firerate");
if (rateProperty != null) {
rate = Float.parseFloat(rateProperty);
}//....

Мы сделаем то же самое с EnemySprites, чтобы мы могли определить, какие очки вы получите за их уничтожение, их устойчивость к урону, возможно, скорость восстановления и т. Д. Одна из приятных сторон этого подхода состоит в том, что он также очень легко продлить Если позже я решу добавить новую турель, которая создает магнитное поле, чтобы сбить с толку врагов и заставить их лететь медленнее, я могу сделать это, просто добавив новое свойство к этой конкретной турели. Мне не нужно обновлять свои старые дизайны уровней или нарушать пользовательские уровни моих пользователей. Это похоже на один из моих любимых методов программирования, « композиция поверх наследования » в этом аспекте.

Теперь мы можем использовать эти свойства и, например, запускать турели с различной скоростью, изменяя интервал оценки их FireBehavior:

1
2
3
4
 @Override
public long getEvaluationInterval() {
return (long)(2000000000*rate);
}

И мы получаем это в результате:

Вторая турель теперь стреляет с большей скоростью, нанося меньше урона каждой своей пули. Если мы совместим это с разными ценами на турели и ограниченным пространством, доступным для размещения турелей, у нас уже есть некоторые стратегические элементы, которые делают Tower Defense интересной игрой. Теперь наш дизайнер уровней отвечает за разработку уровней, установление цен и других свойств, чтобы сделать игру интересной, а мы продолжаем добавлять новые функции.

Теперь давайте начнем со слоя HUD и просто отобразим счет:

01
02
03
04
05
06
07
08
09
10
    private class HUD extends Layer {
 
@Override
public void draw(GraphicsContext graphicsContext, double x, double y, double width, double height) {
graphicsContext.setFill(Color.RED);
graphicsContext.setFont(Font.font("OricNeo", 12));
graphicsContext.fillText("Score: "+score, 10, 16);
}
 
}

Счет определяется как IntegerProperty в моей игре (это НЕ свойство JavaFX!) И передается EnemySprites:

1
private IntegerProperty score = new IntegerProperty(0);

Таким образом, в методе EnemySprites «die» мы просто увеличиваем это значение:

1
2
3
4
5
6
@Override
public void die() {
super.die();
getParent().addSprite(new Sprite(getParent(), explosionAnimation, "explosion", getX() - 30, getY() - 80, 128, 128, Lookup.EMPTY));
score.set(score.integerValue()+killPoints);
}

Теперь добавьте HUD в качестве верхнего слоя, и вы сможете увидеть результат:

Далее нам нужен какой-то способ запустить волну. Для этого было бы здорово иметь какое-то простое управление, например кнопку. Мы могли бы добавить это по-разному. Возможно, самым простым способом было бы поместить холст в StackPane, добавить AnchorPane сверху и добавить к нему узел JavaFX или элемент управления. Но мы хотим сделать это только с функциями FXGameEngine, поэтому мы будем использовать Sprite в качестве кнопки:

01
02
03
04
05
06
07
08
09
10
final Sprite button = new Sprite(canvas, "button",  tileMap.getWidthInPixels()- 30, 20, 20, 20, Lookup.EMPTY);
button.setOnMouseClicked(new MouseEventHandler() {
 
@Override
public void handle(MouseClick click) {
startWave();
button.die();
}
});
canvas.addSprite(button);

Я уверен, что API для EventHandling все еще немного изменится, но он останется абстракцией, подобной этой. Этот Sprite не имеет средства визуализации, поэтому будет использоваться средство визуализации по умолчанию, которое просто рисует прямоугольник:

Вот и все на сегодня. В следующей части мы добавим деньги в игру, чтобы она стала немного интереснее …

Ссылка: Защита башни в JavaFX (6) от нашего партнера JCG Тони Эппла в блоге Eppleton .