Я давно хотел использовать свой игровой движок для написания игры Tower Defense, но, поскольку была предпринята попытка создать JavaFX Tower Defense Game другой группой, я решил вместо этого создать другую игру. Из списка рассылки я узнал, что другая игра больше не разрабатывается. Поэтому я решил, что должен попробовать.
Tower Defense — игра, которая идеально подходит для подхода, основанного на тайлах, поэтому я начал искать некоторые тайлы. Я нашел некоторые здесь, и художник, Сильвиу Плойстяну, дал мне разрешение использовать их в моей демонстрации. Tower Defense как игра очень похожа на редактор TileMap, поэтому я смогу использовать много кода из редактора, который недавно создал:
Первым делом нужно было объединить отдельные графические изображения в изображения для мозаичного изображения. Я сгруппировал врагов, базы турелей, пушки, местность, а также создал один набор плиток для фона. После этого я использовал TileMap Editor ( http://www.mapeditor.org/ ) для создания TileSets из этих изображений. Вероятно, мне придется выполнить эту часть снова, потому что Gimp изменил цвета в этом процессе, но сейчас я не слишком беспокоюсь о визуальных эффектах.
Затем я добавил 5 слоев снизу вверх на новую карту: «фон», «ландшафт», «турели-базы» и «турели-пушки» и «враги». Также будет слой «пули и взрывы», но позже я добавлю его вручную. Пока что не требуется никакого кодирования, и благодаря подходу, основанному на TileMap, у нас уже есть формат сериализации для игры. Поэтому, когда пользователь редактирует карту, мы можем просто сохранить изменения в TileMap. Вот как карта выглядит сейчас:
Следующим шагом является кодирование. Я просто создал новое приложение JavaFX с BorderPane. В центре у меня будет игровое поле, справа — палитра с пушками.
Вот как вы создаете GameCanvas:
1
2
3
4
5
6
7
|
tileMap = TileMapReader.readMap(fileURL); canvas = new GameCanvas(tileMap.getTilewidth() * tileMap.getWidth(), tileMap.getHeight() * tileMap.getTileheight(), tileMap.getTilewidth() * tileMap.getWidth(), tileMap.getHeight() * tileMap.getTileheight()); // add all the layers ArrayList layers = tileMap.getLayers(); for (TileMapLayer tileMapLayer : layers) { canvas.addLayer(tileMapLayer); } |
Затем я получаю TileSet с пушками и создаю Палитру. Я использую VBox для палитры, так как я хочу сделать ландшафт редактируемым, и я мог бы добавить еще один TileSet для этого позже:
1
2
3
4
5
|
TileSet turrets = tileMap.getTileSet( "turrets" ); TileSetView turretView = new TileSetView(turrets); VBox palette = new VBox(); palette.getChildren().addAll(turretView); |
TileSetView просто отображает базовое изображение и позволяет выбрать плитку щелчком мыши. Возможно, я покажу код чуть позже, когда мы начнем с взаимодействия с пользователем. На данный момент это то, что мы видим после запуска игры:
Уродливая красная область является фоном по умолчанию. К сожалению, размер фонового изображения не кратен размеру плитки, поэтому позже мне придется определить предложение. А пока я проигнорирую это, это просто фон …
Теперь мы хотим, чтобы пользователь мог размещать турели. На данный момент у игрока неограниченное количество денег, поэтому он может разместить столько турелей, сколько захочет. Единственное ограничение заключается в том, что он может размещать их, только если он находится на платформе, и если там еще нет башни. Поэтому мы добавляем EventHandler для событий мыши, который получает выбранную турель из палитры и добавляет ее в базовый слой турели. Для простоты я объединил основание башни и башню в одно изображение:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
canvas.setOnMousePressed( new EventHandler() { @Override public void handle(MouseEvent t) { double x = t.getX(); double y = t.getY(); int idx = ( int ) (( int ) x / tileMap.getTilewidth() + ((( int ) y / tileMap.getTileheight()) * tileMap.getWidth())); if (platformLayer.getGid(idx) != 0 && turretBaseLayer.getGid(idx)== 0 ) { turretBaseLayer.getData().setGid(idx, turretView.getSelectedGid()); } } }); |
В результате теперь мы можем размещать турели там, где есть платформа и еще нет турели:
Я думаю, что первая часть уже показывает, что API действительно хорош для создания простых игр без необходимости писать очень много кода. В следующей части мы добавим точку возрождения и цель и используем A * для расчета пути врага.