Создание игры с режимом разделения экрана

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

В данном уроке вы научитесь:

1. Создавать игры с разделением экрана.
2. Создавать индикатор жизни в виде полосы.
3. Хитро применять возможности инструмента Canvas.
4. Пользоваться слоями
...и многому другому, в зависимости от вашего уровня подготовки.


P.S. Урок рассчитан на людей, которые как минимум знают основы конструкта и не будут спрашивать: "А как создать спрайт?", "Как поменять цвет фона?" или "Где находится объект MouseAndKeyboard?".


Итак, приступим...

Создавать будем некое подобие TDS для двух игроков (с разделенным экраном) с режимом Deathmatch.

Как всегда, сначала необходимо создать новый проект и сохранить его. Теперь начнем создавать все объекты, которые пригодятся вам в ходе урока.

Вам понадобятся:

1. Объект MouseAndKeyboard, чтобы управлять игроками.

2. Два спрайта (Sprite) игроков — каждый может нарисовать их по своему, я сделал все как можно проще player1.png и player2.png.

3. Объект TiledBackground для создания пола в игре (проявите фантазию и нарисуйте пол, как вам хочется).

4. Два спрайта (Sprite) пуль — я нарисовал в фотошопе одну пулю и сделал два одинаковых спрайта bullet.png.

5. Один спрайт (Sprite) блока — этот спрайт будет выполнять роль стен, ограничивающих уровень, да и просто создающих препятствия. У меня получилась такая стена
block.png.

6. Два объекта Canvas — они будут выполнять роль камер, чтобы у нас была возможность создать два экрана в одном (далее будет рассказано, как именно).

7. Один спрайт (Sprite) табло — поверх этого спрайта мы будем выводить информацию об очках игроков. Вот пример такого табло tab.png.

8. Два объекта Text — с их помощью мы будем выводить на экран информацию об очках игроков.

9. Один спрайт (Sprite) в виде бара, но с прозрачной серединой healthLine 1.png
и два объекта TiledBackground в виде линии, которая бы подходила под предыдущий спрайт healthLine 2.png.

— эти объекты мы используем для создания индикаторов жизней игроков.

Теперь, когда все объекты на месте, пора объяснить, каким образом будет достигаться эффект разделения экрана.

Скорее всего, для слежения за объектом вы привыкли ставить в его свойствах галочку Center View On Me или пользоваться плагином AdvancedCamera. В любом из этих случаев, камера действительно двигалась за объектом. В нашем же примере камера всегда будет на одном и том же месте, а следить за игровым миром мы будем при помощи двух объектов Canvas, которые вы создали.

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

Давайте настроим размеры экрана и размеры игрового мира, чтобы мне было удобнее объяснять дальше.

Пусть размер зоны будет 2800х2600 (настраивается в свойствах Layout):

а размер экрана 800х600 (настраивается в свойствах Layout):

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

1. Зона камеры — в этой зоне будут изначально располагаться оба наших объекта Canvas, а так же все графическое оформление экрана, выводящее данные об игре (HUD). Эта зона должна иметь размер окна(в нашем случае 800х600).

2. Запретная зона — это очень важная зона, которая исключает баги вроде двойного наложения изображения. Зона должна выдаваться за зону камеры по X - 1/4 от X размера зоны камеры(то есть 800/4 = 200) и по Y - 1/2 от Y размера зоны камеры(то есть 600/2 = 300) почему именно так — я объясню позже, сейчас все равно не поверите 😀

3. Зона игры — в этой зоне и будут происходить все игровые действия и события. В ней будут находится блоки, игроки, пули и т.д. Размер зоны, как видно из рисунка, это то пространство, которое останется. В нашем случае это — 1800х1700.

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

Ну вот и подошли вплотную к самому главному — алгоритм разделенных экранов (или алгоритм отрисовки).

Construct выполняет все действия по очереди, в той последовательности, которую вы сами задаете в Event Sheet Editor, этим прекрасным свойством мы и воспользуемся. Алгоритм распишу по шагам.

1 шаг — расстановка объектов. Наши "канвасы" стоят в зоне камеры (см. предыдущий рисунок), а игроки, стены и все остальное (если вы еще что-то сделаете) стоит в зоне игры.
2 шаг — Каждый из объектов "канвас" перемещается в положение игрока, за которым следит.
3 шаг — Каждый из объектов "канвас" отрисовывает на себя все объекты, которые в ходят в зону его действия, т.е. отрисовывает игрока и все прилежащие объекты.
4 шаг — Каждый из объектов "канвас" возвращается на свое место в зоне камеры с отрисованной частью игрового мира.

Чтобы лучше понять посмотрите небольшую схему:

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

Начнем с создания слоев:

Перейдите во вкладку Layers (справа внизу) и в этой вкладке создайте 3 слоя.
1. Самый нижний слой будем использовать для размещения всех игровых объектов которые буду находиться в зоне игры(игроки, пол, блоки, пули).

2. Средний слой будем использовать для размещения объектов Canvas.

3. Самый верхний слой будем использовать для размещения всех элементов HUD (текст, бары, линии жизни).
Разместите все объекты, как указано выше и пойдем дальше.

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

Также там же должны располагаться оба объекта канвас.

Разберемся с каждым из игровых объектов в отдельности:

1. Игроки — это два объекта Sprite ,как уже и говорилось. Каждому из этих объектов необходимо: применить 8Direction Behavior, чтобы можно было управлять, а также создать числовую переменную live со значением = 100 (эта переменная будет отвечать за количество жизней игрока). Расположите игроков, где вам угодно в зоне игры. И не забудьте настроить image point на то место, откуда будет вылетать пуля.

2. Пули — это два объекта Sprite (один для первого игрока, другой для второго) с настроенным поведением Bullet Behavior (настройте по вкусу) и включенным атрибутом Destroy on startup (чтобы при включении их сразу не было в игре). Разместите их где угодно, это не важно.

3. Камеры — это два объекта Canvas с размерами 400x600 и размещенные рядом, чтобы как бы разделять экран на две области. Никаких настроек не требует, только соблюдайте размеры и разместите в зоне камеры.

4. Блок — квадратный объект Sprite с рисунком стены. В настройках включите атрибут Solid, чтобы игроки не проходили сквозь стены.

5. Табло — объект Sprite с нарисованным табло. Никаких настроек.

6. Текст — два объекта Text с подходящими шрифтами, для отображения игрового счета.

7. Покрытие полосы жизни — объект Sprite с рисунком (см. рис healthLine 1.png). Никаких настроек.

8. Полоса жизни — два объекта TiledBackground с рисунком полосы. Никаких настроек. Расположите под покрытием.

Так же необходимо создать две глобальные переменные p1score и p2score, которые будут хранить информацию о игровом счете.

Когда все готово и настроено, перейдем непосредственно к "программированию".
Перейдите в окно Event Sheet Editor и создайте событие:

EVENT:

Always

(всегда) — в этом событии мы поместим действия, которые будут происходить постоянно, и первые такие действия будут относиться к нашим камерам (объектам canvas). Вспомните алгоритм, который был описан выше, будем действовать согласно ему.

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

EVENT:

-> Canvas: Set position to Player1.X, Player1.Y

Этим действием мы помещаем центр объекта Canvas точно в положение игрока 1.
Далее необходимо отрисовать все объекты по очереди, начиная с самых нижних. Для отрисовки служит действие Paste to Canvas. Создавайте это действие для всех объектов, задействованных в игре начиная с самых нижних и заканчивая самыми верхними (в нашем случае, начиная с пола и заканчивая игроками) :

EVENT:

-> Canvas: Paste floorbackground into canvas
-> Canvas: Paste block into canvas
-> Canvas: Paste bullet1 into canvas
-> Canvas: Paste bullet2 into canvas
-> Canvas: Paste Player1 into canvas
-> Canvas: Paste Player2 into canvas

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

EVENT:

-> Canvas: Set position to 200, 300

Вам необходимо самостоятельно создать точно такие же действия для второго объекта Canvas, только в конце поместить его в положение не (200, 300), а (600,300), чтобы он стоял рядом и не перекрывал первый объект канвас.

Если вы все сделали правильно, то при запуске игры вы уже сможете увидеть игроков и все их окружение.

Дело осталось за малым — настроить управление игрокам, заставить работать HUD для отображения очков и жизней и создать возможность стрельбы и учета очков.
Начнем с настройки управления.
Выделите второго игрока, зайдите в настройки 8Direction Behavior и в строке Control поставьте Player2 :


Далее перейдите в Layout Properties >>> Properties >>> Controls >>>Add/Edit и настройте все как на следующем рисунке:

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

- стрельба -

EVENT:

+ System: Every 100 milliseconds //каждые 100 миллисекунд
+ MouseKeyboard: Key Space is down //при зажатой клавише space
-> Player1: Spawn object bullet1 on layer 1 (image point 1) //игрок 1 выстреливает пулю 1 из точки 1

- застревание пуль в стенах -

EVENT:

+ bullet1: On collision between bullet1 and block //если пуля прикасается к стене
-> bullet1: Destroy //пуля уничтожается.

- попадание пули в игрока -

EVENT:

+ bullet2: On collision between bullet2 and Player1 //при попадании пули игрока 2 в игрока 1
-> Player1: Subtract Random(15)+Random(global('P2Score')) from 'live' //отнять от жизни игрока 1 случайное количество пунктов с учетом счета игрока 2.
-> bullet2: Destroy //уничтожить пулю.

- смерть игрока -

EVENT:

+ Player1: Value 'live' Less or equal 0 //если количество жизней у игрока 1 меньше или равно нулю(0)
-> Player1: Set position to 1104, 848 //перенести игрока на стартовую позицию
-> Player1: Set 'live' to 100 //вновь восстановить все жизни
-> System: Add 1 to global variable 'P2Score' //добавить игроку 2 одно(1) очко.

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

Начнем с реализации простейшего, а именно отображения счета для первого игрока, для второго сделайте самостоятельно:

EVENT:

+ System: Always (every tick) //всегда
-> score1: Set text to "Player 1 Score: "&ZeroPad(global('P1Score'), 7) //в строке очков игрока 1 показывать следующий текст: Player 1 Score + значение переменной p1score.

Как вы видите здесь используется функция ZeroPad, которую вы можете и не использовать. Данная функция выводит числовое значение не в обычном виде: (135) а в виде числового табло с нулями: (000135)
Если вы решите не использовать данную функцию, ваш код будет выглядеть следующим образом:

EVENT:

+ System: Always (every tick)
-> score1: Set text to "Player 1 Score: "&global('P1Score')

Теперь займемся полоской жизни. Там также все просто. Узнайте длину полоски, в нашем случае это 250 пикселей, и поделите на количество жизней (250/100 = 2.5) — это и будет одно деление нашей полосы. Теперь осталось только составить следующие действия:

EVENT:

+ System: Always (every tick) //всегда
-> lifeline1: Set width to Player1.Value('live')*2.5 //длинна полосы равна количеству жизней игрока 1 умножить на 2.5

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

Ну вот и все, ваша простенькая игра готова. Вы можете самостоятельно усовершенствовать игру, но это уже ваше дело, а моя миссия на сегодня выполнена! Удачи!

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

Вопросы по уроку можно задать в этой теме.



Автор статьи: GeorgeThreeD

Опубликовано: 1 августа, 2010

Категория: Другие уроки

Комментарии:

  1. danil111:

    а как сделать чтобы когда идеш за пределы уровня камера следила за игроком? *HELP*

  2. GeorgeThreeD:

    А зачем ходить за пределы уровня? 😀 На то он и уровень, чтобы не ходить за него)

  3. DARD4:

    Спасибо за статью, давно хотел создать игру на двоих =)