16 октября 2016 г

Отправлено 16 окт. 2016 г., 13:26 пользователем Dimitrijs Fedotovs   [ обновлено 16 окт. 2016 г., 13:51 ]

Пройденный материал

  • Спрайт каретки CaretSprite
    • создание спрайта вручную
    • движение только по горизонтали
  • Новое событие onHalt - вызывается после того, как спрайт "умер"
  • Создание собственных методов
  • Новый спрайт взрыва DirectedBlastSprite

Ход занятия

Шаг 1: Создать новый проект.

Запускаем IntelliJ IDEA и выбираем Create New Project или File -> New Project

Выбираем тип проекта - игра, даем название и в результате у нас есть минимальный код, чтобы начать создавать свою игру.

Шаг 2: создаем каретку "вручную"

В автоматически созданном коде MyGame модифицируем вызов метода load: 
load("/level.txt", this::create);

create подсвечивается красным, т.к. программа ничего не знает о таком методе. Простой способ создать такой - нажать alt+enter и выбрать create method 'create'.

Таким образом сразу после загрузке уровня level.txt программа вызовет метод create. В данный момент этот метод пустой.

Теперь напишем логику создания каретки в методе create:

private void create() {
sprite(CaretSprite::new, getWidth() / 2, getHeight() - 1.5)
.onLoop(ai::followMouseX)
.onInit(c -> c.setSpeed(15))
.onCollision(ai::stopX);
}

Мы используем метод sprite, а не register, потому что нам нужно создать спрайт уже после того как уровень загрузился. Метод register регистрирует символ для спрайта, а спрайт создается позже - во время загрузки уровня.

Новый спрайт каретки появится в координате getWitdh() / 2 по X и getHeight() - 1.5 по Y.

getWidth() - метод возвращающий ширину загруженного уровня. Мы делим его на два, чтобы разместить каретку в середине.

getHeight() - 1.5 дает координату чуть выше нижнего края уровня (на полторы клетки)

onLoop(ai::followMouseX) - заставляет на каждый кадр спрайт смещаться только по координате X, следуя за курсором мышки.

onInit(c -> c.setSpeed(15)) - устанавливает скорость движение каретки перед тем как каретка покажется на экране.

onCollision(ai::stopX) - при столкновении с препятствием (например стенкой) - остановить каретку.

Если запустить игру, то увидем, что каретка движется вслед за мышкой.

Шаг 3: создаем мяч "вручную"

Создание каретки должно влечь за собой создание нового мяча. Поэтому сразу после кода управления кареткой в методе create добавим еще одну строчку - вызов метода createBall(). Этот метод так же нужно создать нажав alt+enter, как и было в предыдущем примере.

private void create() {
sprite(CaretSprite::new, getWidth() / 2, getHeight() - 1.5)
.onLoop(ai::followMouseX)
.onInit(c -> c.setSpeed(15))
.onCollision(ai::stopX);
createBall();
}

private void createBall() {
sprite(BallSprite::new, getWidth() / 2, getHeight() - 3)
.onLoop(ai::followDirection)
.onInit(c -> c.setSpeed(10))
.onCollision(ai::bounce);
}

Метод createBall() создает новый спрайт мяча. Помещает его так же в центре нижней части уровня, только чуть-чуть выше, чем каретка.

onLoop(ai::followDirection) - На каждый кадр игры, мы должны смещать шарик по направлению установленному в свойствах шарика.

onInit(c -> c.setSpeed(10)) - при запуске спрайта установить его скорость в 10 клеток в секунду. Иначе мяч будет стоять на месте.

Если хочешь, что бы шарик сразу летел в заданном направлении необходимо дописать еще один обработчик onInit:

.onInit(c -> c.setDirection(Direction.W))

onCollision(ai::bounce) - заставляет отскакивать мячь от любых спрайтов.

Шаг 4: Ловушка для шарика.

Самостоятельно заполняем нижнюю часть уровня спрайтами ловушек. Как это делать - можно подсмотреть в записках предыдущего урока: 2 октября 2016 г

Добавляем реакцию шара на столкновение с ловушкой:

.onCollision(ai::halt, TrapSprite.class)

Шаг 5: Взрыв шарика

Взрыв это просто еще один спрайт, который после создания можно "запустить" и этот спрайт "умрет" сам, после того как все кадры взрыва воспроизведены.

Взрыв должен появляться на том месте, где только что исчез мяч. Лучшее место, где создавать спрайт взрыва - событие onHalt мяча.

.onHalt(this::explode);

и так же необходимо описать что такое explode.

в общем должно получится так:

private void createBall() {
sprite(BallSprite::new, getWidth() / 2, getHeight() - 3)
.onLoop(ai::followDirection)
.onInit(c -> c.setSpeed(10))
.onCollision(ai::bounce)
.onCollision(ai::halt, TrapSprite.class)
.onHalt(this::explode);
}

private void explode(BallSprite s) {
sprite(DirectedBlastSprite::new, s.getX(), s.getY())
.onInit(b -> b.setDirection(Direction.S))
.onInit(b -> b.explode());
createBall();
}

В метод explode передается сам по себе спрайт мяча, из которого мы можем взять координаты, на которых он находился последний раз.

Так же из метода explode мы вызываем createBall() чтобы создать новый мяч после того как предыдущий уничтожился.

Код игры

В целом у нас должно было получится следующее. Код, создающий спрайт ловушки-огня или лавы специально пропущен для самостоятельной работы.

public class MyGame extends Game {

@Override
public void setup() {
setBackground(new DesertBackground());

register('#', WallSprite::new)
.onInit(w -> w.setColor(WallColor.BLUE));

load("/level.txt", this::create);
}

private void create() {
sprite(CaretSprite::new, getWidth() / 2, getHeight() - 1.5)
.onLoop(ai::followMouseX)
.onInit(c -> c.setSpeed(15))
.onCollision(ai::stopX);
createBall();
}

private void createBall() {
sprite(BallSprite::new, getWidth() / 2, getHeight() - 3)
.onLoop(ai::followDirection)
.onInit(c -> c.setSpeed(10))
.onCollision(ai::bounce)
.onCollision(ai::halt, TrapSprite.class)
.onHalt(this::explode);
}

private void explode(BallSprite s) {
sprite(DirectedBlastSprite::new, s.getX(), s.getY())
.onInit(b -> b.setDirection(Direction.S))
.onInit(b -> b.explode());
createBall();
}

@Override
public void loop() {

}
}

Дополнительно

Варианты DirectedBlastSprite

Создавая DirectedBlastSprite можно выбрать один из трех его вариантов при помощи метода setColor(DirectedBlastColor):
  • YELLOW
  • RED
  • GREEN
Пример:
sprite(DirectedBlastSprite::new, ball.getX(), ball.getY())
.onInit(e -> e.setRotation(Direction.S))
.onInit(e -> e.setColor(DirectedBlastColor.YELLOW))
.onInit(Explosion::explode);

Спрайт RoundBlastSprite

Аналогично DirectedBlastSprite можно использовать RoundBlastSprite. Этот взрыв хорош для блоков.

Так же существует несколько вариантов цвета для такого взрыва setColor(RoundBlastColor.BLUE)

  • YELLOW
  • GREEN
  • BLUE
  • RED

Спрайт CollapseBlastSprite

Еще один спрайт для взрывов:  CollapseBlastSprite. Как и предыдущие спрайты взрывов и этот можно покрасить при помощи setColor(CollapseBlastColor.GREEN):
  • RED
  • BLUE
  • GREEN

Домашнее задание

Создать игру Арканоид, в которой будут минимум два (можно больше) разных видов блоков.

Каждый вид блока должен взрываться своим собственным взрывом.

Comments