Xatari

На Пикабу
169 рейтинг 3 подписчика 1 подписка 2 поста 1 в горячем
9

Пишем игру "Змейка"

Добрый день. Я тут в качестве хобби разрабатываю 2д движок для создания игр. Сегодня хочу с вами поделиться как на нем сделать классическую игру "змейка". Прошу внимательно прочитать, покритиковать, похвалить, посоветовать, и прочее.

О движке

Пишу я его на с++ с использованием графической библиотеке SDL, в качестве скриптового языка использую Питон.

Прошу прощения за скриншоты, но не понял как вставлять "правильный код", а вставлять цитатами было очень страшно и не красиво.

Для лиги лени сразу прикрепляю ссылку с готовым архивом:

Скачать архив

И демонстрация игры

Заранее спасибо. И так начнем.

Создаем пустой проект

Структура каталогов пустого проекта:

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Редактируем config.xml

config.xml - это файл который читается в движке первым.

имеет структуру xml

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Основная строка которая нас интересует

<AppMain value = "..\Assets\ScriptsP\AppMain.py" />

Application.Script.AppMain - это путь к скрипту с которого стартует приложение

Все конфиг нам больше не нужен.

Создаем Тайлы

В каталог /Assets/Tiles/ - добавляем следующие картинки (все имеют формат 120 на 120)

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост
  1. snakeApple.png - яблоко

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

2. snakeBody.png - часть тела змеи (кружочек зеленый)

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

3. snakeGrid.png - квадратик с полупрозрачными черными линиями(из него мы будем делать сетку)

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

4. snakeHeadDown.png - голова которая смотри вниз

5. snakeHeadLeft.png - голова которая смотри влево

6. snakeHeadRight.png - голова которая смотри вправо

7. snakeHeadUp.png - голова которая смотри вверх

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост
Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост
Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Создаем UI

Элементы ГУИ можно создавать как програмно так и задавать расположение в xml файлах.

Получается что то типа "Окна" - к которому прикреплены все элементы как дочерние.

создаем файл UISnake.xml

К основному объекту типа xdCanvas прикрепляем

Объект типа xdText с именем tFPS который будет счетчиком фпс

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Аналогично добавляем

Объект типа xdText с именем tObjects который будет счетчиком количества объектов на экране

Объект типа xdText с именем tScore который будет отображать текущий счет.

Ниже полный текст файла UISnake.xml

<?xml version="1.0"?>

<object type="xdCanvas">

<position x="0" y="0" />

<scale value="1" />

<order value="999998" />

<name value="UISnake" />

<relative value="XD_UI" />

<alignment value="XD_UI_ALI_NONE" />

<anchorVertical value="XD_UI_ANC_V_TOP" />

<anchorHorizontal value="XD_UI_ANC_H_LEFT" />

<childs>

<object type="xdText">

<position x="-100" y="-20" />

<text value="FPS:" />

<font name="..\Assets\Fonts\Comfortaa.ttf" size = "10" style = "1" colorR = "93" colorG = "86" colorB = "79" />

<name value="tFPS" />

<anchorVertical value="XD_UI_ANC_V_DOWN" />

<anchorHorizontal value="XD_UI_ANC_H_RIGHT" />

</object>

<object type="xdText">

<position x="-100" y="-10" />

<text value="Objects:" />

<font name="..\Assets\Fonts\Comfortaa.ttf" size = "10" style = "1" colorR = "93" colorG = "86" colorB = "79" />

<name value="tObjects" />

<anchorVertical value="XD_UI_ANC_V_DOWN" />

<anchorHorizontal value="XD_UI_ANC_H_RIGHT" />

</object>

<object type="xdText">

<position x="20" y="20" />

<text value="Счет:" />

<font name="..\Assets\Fonts\Comfortaa.ttf" size = "30" style = "1" colorR = "100" colorG = "50" colorB = "50" />

<name value="tScore" />

<anchorVertical value="XD_UI_ANC_V_TOP" />

<anchorHorizontal value="XD_UI_ANC_H_LEFT" />

</object>

</childs>

</object>

Создаем файл UISnakeMenu.xml

Который будет отвечать за меню начала игры и отображения результатов

Иерархия нашей меню будет следующая

  1. UISnakeMenu(xdCanvas) - основной канвас окна

    1. uiPanelCenterMenu(xdPanel) - панелька на которой все нарисуем

    2. tCaption(xdText) - Заголовок "Пиратская Змейка"

    3. tGameOver(xdText) - Надпись "Начните новую игру", или "Game over" (значение будем задавать скриптом)

    4. tScoreEnd(xdText) - Счет, если был проигрыш (значение будем задавать скриптом)

    5. btnNewGame(xdButton) - Кнопка новая игра (при нажатии которой игра начинается сначала)

    6. btnExit(xdButton) - Кнопка выход из игры

Из непонятного у нас только xdPanel и xdButton

это по сути те-же элементы UI, что и xdText - описанные выше, только с небольшими отличиями

xdPanel - элемент интерфейса отражает физическую панельку, на которой мы можем что то рисовать.

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

xdButton - это кнопка с текстом(есть разные варианты можно картинками задать статусы, но у нас кнопка простая по умолчанию)

Принципиально не отличается от текста вся логика будет задаваться на стороне скрипта.

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Ниже полный текст файла UISnakeMenu.xml

<?xml version="1.0"?>

<object type="xdCanvas">

<position x="0" y="0" />

<scale value="1" />

<order value="999998" />

<name value="UISnakeMenu" />

<relative value="XD_UI" />

<alignment value="XD_UI_ALI_NONE" />

<anchorVertical value="XD_UI_ANC_V_TOP" />

<anchorHorizontal value="XD_UI_ANC_H_LEFT" />

<childs>

<object type="xdPanel">

<position x="0" y="0" />

<sizePrecent x="20" y="50" />

<name value="uiPanelCenterMenu" />

<anchorVertical value="XD_UI_ANC_V_CENTER" />

<anchorHorizontal value="XD_UI_ANC_H_CENTER" />

<childs>

<object type="xdText">

<position x="0" y="+30" />

<text value="Пиратская Змейка" />

<font name="..\\Assets\\Fonts\\Comfortaa.ttf" size = "20" style = "1" colorR = "93" colorG = "86" colorB = "79" />

<name value="tCaption" />

<anchorVertical value="XD_UI_ANC_V_TOP" />

<anchorHorizontal value="XD_UI_ANC_H_CENTER" />

</object>

<object type="xdText">

<position x="0" y="80" />

<text value="Начните новую игру" />

<font name="..\\Assets\\Fonts\\Comfortaa.ttf" size = "18" style = "1" colorR = "190" colorG = "86" colorB = "79" />

<name value="tGameOver" />

<anchorVertical value="XD_UI_ANC_V_TOP" />

<anchorHorizontal value="XD_UI_ANC_H_CENTER" />

</object>

<object type="xdText">

<position x="0" y="100" />

<text value="Счет:" />

<font name="..\\Assets\\Fonts\\Comfortaa.ttf" size = "18" style = "1" colorR = "93" colorG = "86" colorB = "79" />

<name value="tScoreEnd" />

<anchorVertical value="XD_UI_ANC_V_TOP" />

<anchorHorizontal value="XD_UI_ANC_H_CENTER" />

</object>

<object type="xdButton">

<position x="0" y="0" />

<size x="130" y="50" />

<name value="btnNewGame" />

<text value="Новая Игра" />

<anchorVertical value="XD_UI_ANC_V_CENTER" />

<anchorHorizontal value="XD_UI_ANC_H_CENTER" />

</object>

<object type="xdButton">

<position x="0" y="70" />

<size x="130" y="50" />

<name value="btnExit" />

<text value="Выход" />

<anchorVertical value="XD_UI_ANC_V_CENTER" />

<anchorHorizontal value="XD_UI_ANC_H_CENTER" />

</object>

</childs>

</object>

</childs>

</object>

```

Скрипты

Теперь переходим к самому интересному к логике.

Файл globals.py - вспомогательный скрипт который в данной игре не имеет смысла большого, можно обойтись без него.

но по замыслу тут находятся какие-то глобальные константы и методы

например есть метод Debug который позволяет отлаживать скрипты в режиме реального времени в Visual Studio Code ооооочень удобно, но об этом в другой раз.

Создаем файл AppMain.py

Импортируем пространство имен xd

import xd # Импорт в питон методов движка. почти все находится в пространстве имен xd

добавляем самый первый метод OnStart

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

После чего делаем обертку в виде класса Application это не обязательно , но автору это кажется красивым

Application.OnStart - будет вызываться при старте сцены.

application - экземпляр класса приложение.

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

в глобальный метод **OnStart** добавляем вызов:

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Минимальный скрипт готов.

Далее создаем пустую сцену, а именно файл SceneGame.py

Сцена это объект порождённый от объекта xd.GameScene со следующими методами:

OnLoad - вызывается после загрузки сцены

OnStart - вызывается при старте сцены

OnFrame - вызывается каждый кадр.

Unload - метод где будем удалять все, что создали.

Текст файла SceneGame.py с минимальной сценой.

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Далее в файле AppMain.py добавляем следующие строки

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

где в

xd.GameScene.LoadScene("SceneGame.SceneGame", self.OnLoadScene)

Вызываем метод движка xd.GameScene.LoadScene для загрузки сцены.

1. "SceneGame.SceneGame" - строка с указанием класса сцены в питон скрипте. В формате [Имя файла скрипта].[Имя класса в файле]

2. self.OnLoadScene - обработчик вызываемый после загрузки сцены.

Реализация метода SceneGame.OnLoadScene

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

На данный момент полный текст файла AppMain.py:

```python

import xd # type: ignore

import globals

globals.Debug(False)

class Application:

""" Глобальный класс сцена"""

def OnStart(self):

xd.GameScene.LoadScene("SceneGame.SceneGame", self.OnLoadScene)

def OnLoadScene(self, scene):

self.scene = scene

xd.App.SetGame(scene)

pass

#Экземпляр класса сцены

application = Application()

def OnStart():

"""Обработчик при старте сцены (вызывается движком)"""

application.OnStart()

return 1

После запуска должно быть пустое окно с синеватым фоном. Если это так, от значит мы все делаем правильно.

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Файл AppMain.py - мы больше не меняем. Он принял конечный вид.

В методе SceneGame.OnStart добавляем следующий код

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

На любой сцене есть корневой объект с именем rootObject куда можно прикреплять объекты. Не прикрепленные объекты не отображаются на сцене (игнорируются циклом рендера)

Метод xd.BaseObject.FindByNameS это метод FindByNameS - ищет игровой объект на сцене с по имени. и возвращает ссылку на объект.

Метод xd.Panel.to - преобразовывает ссылку в Объект типа xdPanel есть аналогичные методы для любых предопределенных объектов xd.Text.to , xd.Button.to и др.

После запуска мы увидим Окно игровое с отображаемой меню.

Далее добавляем на сцену окно из файла UISnake.xml для отображения текущих игровых данных а запоминаем ссылки на элементы интерфейса см которыми после будем работать

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Первый обработчик событий. Начнем с простого, сделаем обработчик, который выходит из игры.

У нас есть кнопка для выходи из игры с именем btnExit

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Первая сцена и обработчик готовы

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

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Далее добавим в проект вспомогательный класс GameData

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

С высоты птичьего полета класс GameData выглядит так:

Пишем игру "Змейка" Gamedev, Движок, Разработка, Видео, RUTUBE, Короткие видео, Длиннопост

Методы:

  1. GameData.Unload - метод где описываются удаления элементов аля деструктор

  2. GameData.OnStart - обработчик который вызываем при старте приложения

  3. GameData.OnTick - обработчик таймера (обсудим позже)

  4. GameData.OnKeyPressed - обработчик нажатия клавиши

  5. GameData.GameOver - Метод проигрыша

  6. GameData.NewGame - метод новая игра

  7. GameData.IsPause - проверить на паузе ли игра

  8. GameData.NewApple - добавить новое яблоко на сцену

  9. GameData.DrawGrid - нарисовать сетку

Реализация этих методов будет позже и постепенно. Сейчас сосредоточимся на следующем.

....

Часть первая закончена (лимит картинок в посте закончился)

Спасибо, кто дочитал, и прокомментировал.

Показать полностью 24
67

Как я сделал Платформер Pixel Quest

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

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

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

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

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

Но, как говорится, сдаются только трусы! Мы учли ошибки, сделали выводы и принялись за новый проект. Так как наработки в части платформера уже были, выбрали стратегию “меньше кода, больше проработки” и начали удалять все сложное с точки зрения управления, например, лестницы и лазанье по цепям.

Если честно, я немного слукавил говоря, что принятие решения идет по принципу, что хочу то и делаю. Самое сложное в геймдеве – придумать контент и найти хорошего художника, который будет готов работать на голом энтузиазме и за доброе слово. Я встречал много таких людей, обычно они активно начинают работу и быстро пропадают, приходится искать другого, а он уже не может рисовать в том же стиле. Хорошо, что есть магазины, где люди продают свой нарисованный контент за деньги.

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

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

Подобрали замечательные сеты уровней и главного героя в стиле pixel art

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост
Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

Купили тайлы, нарисовали в редакторе Tiled первые версии уровней,

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

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

Когда появился прототип и главный герой, мы начали обсуждать разные варианты названий: Pixel Rogue, Pixel World, Pixel Man, Pixel Knight, Pixel Vixel, Pixel Adventure, Pixel Quest. Долгими дебатами выбрали “Pixel Quest” – это название хранит в себе какую-то загадочность и отражение в реальности вымышленного мира.

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

Подачу сюжета решили сделать в простом для понимания и реализации виде.

На уровне раскиданы три вида предметов:

1) Огонь – это обращение создателя к главному герою

2) Указатели – для знакомства игрока с миром, чтобы он не показался сухим и населенным роботами.

3) Свитки – это мысли самого персонажа

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

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

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

Любой уровень проходит в своем взрослении следующие жизненные этапы:

1. ЧВ (Черновой вариант) – это уровень нарисованный на листочке.

2. РЧВ (Реализованный черновой вариант) – это уровень, который можно "пробежать" в игре

3. ПВ 1 (Проверочный вариант 1) – это уровень, в котором есть примерные враги, монеты и сундуки

4. ПВ 2 (Проверочный вариант 1) – это уровень в котором уже меньше свободного и пустынного места, так сказать, ПВ 1 с устраненными замечаниями

5. ПВ 3 (Проверочный вариант 1) – это уже уровень, который на своем месте в порядке уровней. Имеет сложность адекватную своему местоположению. Ни один уровень не может стать ПВ 3, пока все уровни не прошли ПВ 2 проверку. Имеет чекпоинты

6. ПВ 4 (Проверочный вариант 1) – окончательный вариант уровня, у которого выровнен баланс, встроены диалоги. Устранены все замечания версии ПВ 3

Примерно по этой схеме мы старались провести каждый уровень, прогоняя его и тестируя много и много раз. Но самое интересное, что уровень на любой стадии может не быть включен в финальную версию игры. Для Pixel quest мы реализовали 25 уровней на разной стадии, а в релиз пошло только 18,самых отборных и лучших на наш взгляд.

Вот, например, один из последних уровней на разных стадиях:

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост
Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост
Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

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

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

и как в виде текстовых сообщений:

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

Как это выглядит на уровне:

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

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

Как я сделал Платформер Pixel Quest Gamedev, Game Art, Pixel Art, Видео, Длиннопост

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

1. Пройти все предыдущие уровни полностью и зафиксировать это;

2. Пройти текущий уровень, собрав все предметы;

3. Включить режим “имбы”;

4. Выпить зелье здоровья;

5. Надеть шкуру снежного человека;

6. Вернуться в шкуру главного героя;

7. Пройти уровень, собрав все пиксели “Силы”;

8. Пройти уровень, собрав все пиксели “Интеллекта”;

9. Пройти уровень, собрав все пиксели “Выносливости”;

10. Пройти игру с концовкой номер “1”;

11. Пройти игру с концовкой номер “2”;

12. Пройти игру с концовкой номер “3”.

А вот как мы старались сделать "красиво" на примере главного меню.

Музыкальное сопровождение оставили напоследок, когда вся игра уже была почти готова, потому что музыканту надо поиграть, погрузиться в процесс, а не абстрактно сочинять, что попало. Благодаря такому подходу у нас появились уникальные композиции, написанные для Pixel quest. На каждом уровне и для каждого босса – своя мелодия. Музыка занимает больше половины всего веса – 55 мегабайт из 80, но мы думаем, оно того стоит.



[b]Игра бесплатная[/b]. Скачайте, поиграйте, получите удовольствие. Буду очень благодарен за положительные отзывы и пятерки.


Вот ссылочка на видео:

https://www.youtube.com/watch?v=TDKoU7YZBTk


Вот ссылочка на приложение

https://play.google.com/store/apps/details?id=com.xatari.Pix...

Показать полностью 13 1
Отличная работа, все прочитано!