Java Android. Урок 12 (“Делаем игру”)

После того, как мы закончили делать достаточно простую игру “Быки и коровы”, научились базовым методам программирования под Андроид, можно приступить к работе над более сложными вещами. Будем делать 2D игру “леталка-стрелялка”. Такие игры ещё иногда называют плоскими, т.к. движение персонажей происходит только вверх-вниз и вправо-влево. Однако уже здесь потребуются знания несколько большие, чем просто программирование. Возможно, когда вы учились в школе, то спрашивали себя,- Зачем мне эта математика, зачем мне эта физика?- Вот как раз для программирования это всё и нужно, если вы кончено собираетесь делать игры и программы хоть как-то отдалённо моделирующих окружающий нас мир. Как я обычно говорю, программирование это всего лишь инструмент, вроде молотка, чтобы не заколачивать гвозди руками. Но чтобы сколачивать дом, вам нужно всё рассчитать, прежде чем брать в руки молоток и обладать какими-то базовыми знаниями в области строительства. В играх чуть более сложных, чем та, которую мы делали, это тоже становится неизбежно необходимостью. Но огорчаться по этому вопросу не нужно, всё что потребуется из этих наук, я буду это использовать, и тут вам останется либо проверять меня и вступать в полемику, либо поверить наслово. Сразу скажу – идея игры, которую мы будем делать, я позаимствовал с другой, прочно уже забытой игры, но это не меняет нашей задачи. Выглядеть она будет как-то так:

Видео самого экшена:

После её написания, полагаю, вы сможете уже делать любую другую игру. Делать мы её будем совместно, а так же вы сможете:

  • Создать для неё какой-нибудь объект
  • Дать исходник его мне
  • Я опубликую игру с ним на своём аккаунте https://apps.rustore.ru/developer/ZFQbCo1eEp3jOqp5fKusWsz0L%2B8vFUgs, а в самом приложении будет информация о вас, как о разработчике со ссылкой на ваш сайт и/или email.

Итак, приступим, что тут у нас есть; а есть следующее:

  • Игровое поле, которое чуть меньше экрана по высоте, и на несколько экранов в право и влево.
  • Есть масштабный экран сверху.
  • Есть один пользовательский объект, которым он может управлять и перемещать его в пределах экрана.
  • Само рабочее поле тоже подвижное, но только влево и вправо.
  • Объекты могут стрелять – пользовательский объект лазером, игровые юниты – каждое своим вооружением.
  • Игровые юниты могут быть различной конфигурации.
  • Элементы управления вынесены на рабочий экран.
  • В игровом поле есть рельеф местности.
  • Есть юниты испытывающие гравитацию.
  • Все юниты имеют “физику”, т.е. двигаются с ускорением и торможением.
  • Игра должна иметь звуковые эффекты.
  • Игра должна иметь динамические сцены, присущие играм такого типа.

Все это мы будем реализовывать не при помощи каких-то движков, типа Unity, а непосредственно сами. Как понимаете, тут в 10 уроков мы никак не уложимся.

Имя проекта Salvador, что переводится как “Спасающий” (с испанского). Почему так – просто имя проекта должно быть латиницей, а английский язык как-то слегка приелся)). В игре будут юниты, которых нужно будет спасать)).

Для формирования рабочей области экрана, нам придется отказаться от стандартных элементов. По этому метод создания MainActivity будет начинаться так:

Всё что этот код делает, так это скрывает такие системные элементы на экране, как часы, уровень мобильной связи, верхний бар Активити и т.п. В результате нам нужно получить идеально черный экран, полностью и целиком. Но вопросы должно вызывать следующее – я закомментировал setContentView(), который вызывается с параметром xml окна, а вместо этого создаю экземпляр какого-то класса GameEngine и передаю его в качестве параметра для своего setContentView(). Из этого действа можно заключить, что мой GameEngine – это какой-то класс, который способен принять в качестве параметра метод setContentView(), и который и будет рисовать наш экран, а вот стандартный нам не нужен. Как теперь понятно, что и сам activity_main.xml (который среда разработки создала автоматически) нам теперь тоже не нужен:

Теперь создадим этот самый класс GameEngine (ПКМ по названию пакета):

Вот так:

В результате среда разработки создаст нам этот класс:

Однако, такой класс метод setContentView() в качестве параметра не примет, т.к. параметром его должно быть что-то, что наследуется от класса View – помните в прошлом курсе мы делали activity_main.xml и корневым элементом был ConstraintLayout (наследный от View). Наш класс мы тоже должны наследовать от него, по этому сделаем так:

Тут как только мы попытались добавить это наследование, Андроид Студио стала ругаться, что мол если ты наследуешь, то обязательно реализуй конструктор того, от чего наследуешь, т.е. от суперкласса View.. Все они нам сейчас не нужны, нам нужен только первый и то, немного доработанный, выберем его и окейнем:

Получается теперь так:

Однако, если вы парой минут назад заметили, я вызывал конструктор GameEngine с двумя параметрами, вторым из которых был параметры экрана (в модуле MainActivity). Доработаем с учетом этого:

Этот параметр нужен нам будет чтобы иметь представление какого размера экран устройства, на котором запускает игру пользователь. Он как раз в себе эту информацию и хранит. Заметьте, я не трогаю суперкласс, его формат вызова строго определен во View.

Пока писал эту статью заметил, что одна версия Андроид некорректно отрабатывает один метод, по этому переделайте его на вот так:

Однако давайте теперь запустим наше приложение и посмотрим что будет на экране, а должно быть вот так:

Кстати, повернуть экран можно вот этими кнопками:

Поскольку мы наследовали наш класс GameEngine от класс View, то как следствие можем пользоваться и его методами, т.е. использовать наследование класса в полной мере, а именно – не просто будем вызывать метод родительского класса, а вообще перепишем его на свой собственный. Нужно нам это потому, что класс View в своём составе имеет метод onDraw(). Этот метод делает ни что иное, как отображает элементы этого класса View на экране – непосредственно их рисует при помощи графических методов. Происходит это тогда, когда View получает запрос на то, что теперь вдруг данные на экране стали недостоверными. Причин может быть много, например одна из них это то, что мы только что открыли приложение. Откуда там достоверным данным, их нет, мы же только что его открыли. Также, если ввиду функционала, на экране происходят какие-то изменения, например, как в прошлом уроке мы таймер на экран выводили и меняли раз в секунду его значение на экране. Когда мы записывали новое значение в TextView автоматически его в родительском классе (в том же самом View) вызывался метод недостоверности сведений и опять-таки запускался следом метод onDraw() для новой отрисовки элемента. Давайте сделаем наконец-таки и мы этот метод и отрисуем чёрный квадрат Малевича экран. Добавим в наш класс GameEngine этот метод и ещё одну переменную класса:

Ну вообще круть! Так что собственно происходит, давайте подытожим:

  • Создаётся наше Активити
  • При создании создаётся экземпляр нашего класса GameEngine, который наследуется от базового класса View
  • Этот экземпляр передаётся методу отрисовки Активити, а поскольку он наследованный от View, то вызывается сразу следом метод недостоверности содержимого (метод invalidate() ).
  • Этот метод invalidate() выполняет ряд функционала, частным случаем которого является вызов метода onDraw() класса View, но этот метод теперь в нашем классе GameEngine, по этому вызов происходит не родительского метода, а нашего. А в нашем методе уже есть код установить цвет отрисовки на чёрный (параметр Color.BLACK) и вывести его на канву canvas (полотно рисования, экранное полотно, холст) методом drawPaint().

Теперь добавим ещё ряд методов и посмотрим как рисовать на экране что-то вразумительное:

Тут видно для чего нам нужно было знать параметры экрана (чтобы знать где находится правый край) и посмотрели как нарисовать простой тонкий прямоугольник размером в ширину экрана и по высоте 10 пикселей (по координатам Y от 100 до 110). Заметьте, рисование происходит в два этапа – сначала устанавливаем стиль того как и каким цветом будем рисовать, а потом – что будем рисовать (геометрию фигуры).

Задание по уроку:

1. Самостоятельно разберитесь какие методы рисуют линию, точку, круг

2. Нарисуйте согласно плану нашей разработки эту верхнюю часть масштабного представления (саму красную рамку и белый позиционер текущего экрана).

3. Попробуйте нарисовать посередине экрана, как в нашем проекте, космический корабль игрока:

Если всё получилось как нужно – молодцы! Если нет, давайте разберёмся что не так.

Урок 11 Урок 13

El Vinto, 2023 (Copyright)

Добавить комментарий