Пишем Space Invaders при помощи Corona. Заключение

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

Если вы пропустили какую-либо из предыдущих статей, настоятельно рекомендуем вам прочитать их. Прилагаем полный список уроков в текущем цикле:

  1. Настройка проекта.
  2. Реализация геймплея. Часть 1.
  3. Реализация геймплея. Часть 2.
  4. Заключение.

Стрельба врагов

Мы будем ограничивать стрельбу захватчиков при помощи таймера. Добавьте следующий код в gamelevel.lua:

В этой функции мы проверяем количество врагов, которые способны стрелять. Если их нет (а следовательно, врагов нет в принципе) — уровень считается пройденным. Иначе захватчики будут стрелять.

Для реализации стрельбы мы генерируем случайное число в интервале от 0 до #invadersWhoCanFire — количества всех захватчиков, которые способны стрелять. Это число будет индексом того захватчика, который сделает выстрел.

Далее создаем пулю с изображением, присваиваем ей название и вставляем на сцену. Лететь пуля будет при помощи линейного ускорения, которое мы задаем физическому телу пули. И не забываем вставить новую пулю в таблицу invaderBullets.

А чтобы этот метод работал с некоторой задержкой (для чего мы используем таймер, как говорилось выше), добавим следующий код в метод scene:show:

Как следует из вышеприведенного кода, метод fireInvaderBullet вызывается каждые 1500 миллисекунд. Обратите внимание на последний параметр метода performWithDelay — здесь используется -1, что означает, что таймер будет повторяться бесконечно.

Не забываем про принцип «сколько раз new, столько раз delete» и удаляем созданный таймер в методе scene:hide:

Удаление выстрелов

Так же, как и в случае с пулями игрока, выстрелы захватчиков тоже будут лететь до бесконечности вниз. Чтобы исправить это, вставьте следующий код в gamelevel.lua:

Более подробно говорить об этом методе не будем, поскольку он в полностью идентичен проверке выстрелов игрока на выход за границы экрана.

Получение урона

Шаг 1: Обнаружение столкновений

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

Так же, как и в прошлый раз, мы не знаем, что будет храниться в event.object1 и event.object2, а потому рассматриваем обе ситуации. Когда пуля все-таки попала в игрока, мы удаляем ее из таблицы invaderBullets, очищаем ее с экрана, присваиваем ее переменной nil и, если игрок не является непобедимым, то уничтожаем его.

Шаг 2: Уничтожение игрока

Когда мы уничтожаем корабль игрока, мы делаем его на некоторое время неуязвимым. Это делается для того, чтобы игрок смог сосредоточиться на происходящем на экране.

Если переменная numberOfLives равна 0, то мы знаем, что игра закончена. В этом случае мы переходим к сцене start, где начинаем новую игру.

Шаг 3: Генерация нового игрока

Функция spawnNewPlayer возрождает игрока, причем заставляет корабль моргать (исчезать/появляться) в течение нескольких секунд. Это позволяет игроку понять, что он стал неуязвимым.

Здесь мы используем локальную функцию fadePlayer, которая использует библиотеку Transition для того, чтобы менять прозрачность корабля игрока. Мы отслеживаем, сколько раз корабль стал полностью прозрачным (т. е. исчез), и, если numberOfTimesToFadePlayer раз, то с этих пор игрок уже перестает быть неуязвимым. Для неоднократного вызова локальной функции fadePlayer используется таймер.

Запустите игру и проверьте правильность работы написанных нами функций. После того, как захватчик попал в ваш корабль, последний должен заморгать. Если попадание было зафиксировано 3 раза, то вы переместитесь на сцену start.

Чтобы тестирование прошло быстрее, закомментируйте функцию, отвечающую за движение врагов:

Завершение уровня

Если вы убили всех своих врагов, то вызывается функция levelComplete, которой пока еще не существует. Давайте напишем ее:

Здесь мы увеличиваем значение переменной gameData.invaderNum на единицу. Если полученное значение меньше либо равно gameData.maxLevels, то мы переходим к сцене gameover. В противном случае игрок завершил все уровни. Тогда мы присваиваем переменной gameData.invaderNum единицу и возвращаем игрока на сцену start, где он может начать игру заново.

Запустите игру и протестируйте вышеперечисленное. Так же, как и в прошлый раз, можете закомментировать перемещение врагов. Более того, можно закомментировать функцию killPlayer в методе onCollision.

Конец игры

Добавьте следующий фрагмент кода в gameover.lua:

Приведенный код очень прост, а потому комментировать его не станем.

Столкновение с захватчиком

Мы почти закончили всю игру, но забыли про одну обработку столкновений. Это столкновение между игроком и захватчиком. Добавьте следующий код в метод onCollision:

Как обычно, мы должны проверить обе ситуации. При столкновении корабля игрока с захватчиком мы сразу обнуляем количество оставшихся жизней и уничтожаем игрока. Далее можно переходить на сцену start.

Больше возможностей

На этом наша разработка подходит к концу. Но мы предлагаем вам расширить возможности игрока. Например, выводить на экран информацию об оставшихся жизнях.

В исходных файлах есть изображение НЛО. Вы можете сделать так, чтобы оно случайным образом появлялось в игре. При попадании в него игрок получал бы дополнительную жизнь.

Вывод

Если вы следовали всем инструкциям из этой серии, то у вас имеется полностью готовая игра, похожая на оригинальную Space Invaders.

Перевод статьи «Create a Space Invaders Game in Corona: Finishing Gameplay»