Введение
В этом уроке мы рассмотрим процесс создания нового игрового типа (Game Type). Урок будет состоять из двух частей:
Добавления типа в список игровых типов, чтобы он был доступен в редакторе карт,
Создания игрового окна.
Для этого урока мы создадим простой игровой тип и сделаем для него класс игрового окна с интерфейсом пользователя.
Добавление типа в список
Чтобы наш игровой тип появился в списке игровых типов карты, необходимо отредактировать файл GameMap.cs проекта GameEntities.
Список игровых типов находится в перечислении GameTypes.
public enum GameTypes { None, Action, RTS, TPSArcade, TurretDemo, JigsawPuzzleGame, //Put here your game type. NewGameType }
Добавляем новый тип после комментария "Put here your game type."
После чего компилируем проект и запускаем редактор карт. Новый игровой тип появится в списке.
Создание игрового окна
Создание простого игрового окна
Начнем создание игрового окна с пустого класса. Все классы игровых окон в NeoAxis Engine унаследованы от базового класса GameWindow.
Откроем проект Game и добавим к нему новый файл NewGameTypeWindow.cs. Скопируем туда следующий код:
using System; using System.Collections.Generic; using System.Text; using Engine; using Engine.UISystem; using Engine.MathEx; using Engine.EntitySystem; using Engine.MapSystem; namespace Game { class NewGameTypeWindow : GameWindow { } }
Чтобы закончить наш простейший класс игрового окна, в него необходимо добавить реализацию абстрактного метода OnGetCameraTransform. Этот метод сообщает движку о положении камеры. Мы будем передавать данные о положении камеры, которая сохранилась в карте после редактора карт.
protected override void OnGetCameraTransform(out Vec3 position, out Vec3 forward, out Vec3 up, ref Degree cameraFov) { //Позиция камеры position = Map.Instance.EditorCameraPosition; //Направление взгляда камеры forward = Map.Instance.EditorCameraDirection.GetVector(); //Угол обзора камеры cameraFov = Map.Instance.Fov; //Вертикальное направление up = Vec3.ZAxis; }
На этом простейший класс готов. Теперь нам нужно дать движку возможность использовать наш класс игрового окна.
Все в том же проекте Game откроем файл GameEngineApp.cs. В нем найдем метод CreateGameWindowByGameType. Как видим, в нем создаются игровые окна для стандартных игровых типов NeoAxis Engine.
GameWindow CreateGameWindowByGameType( GameMap.GameTypes gameType ) { switch( gameType ) { case GameMap.GameTypes.Action: case GameMap.GameTypes.TPSArcade: return new ActionGameWindow(); case GameMap.GameTypes.RTS: return new RTSGameWindow(); case GameMap.GameTypes.TurretDemo: return new TurretDemoGameWindow(); case GameMap.GameTypes.JigsawPuzzleGame: return new JigsawPuzzleGameWindow(); //Here it is necessary to add a your specific game mode. case GameMap.GameTypes.NewGameType: return new NewGameTypeWindow(); } return null; }
Добавляем обработку нашего игрового типа после комментария "Here it is necessary to add a your specific game mode.".
Скомпилируем наш проект.
Приступим к тестированию нашего игрового типа. Для демонстрации нам понадобится карта. В качестве примера можно взять WindowAppExample.map. Выставим в ее настройках параметр GameType (свиток GameMap в настройках карты) в значение NewGameType.
После этого запустим карту в режиме симуляции.
Как вы можете видеть, созданный нами класс действительно получился пустым (нет интерфейса и нет никакой интерактивности). В следующем разделе мы добавим в него немного интерактивности.
Расширение класса игрового окна
Начнем с того, что воспользуемся некоторой информацией о нашей карте - WindowAppExample.map. На этой карте расположено несколько камер, почему бы нам не понаблюдать за игровым миром через одну из них?
Перепишем метод OnGetCameraTransform. Мы обратимся к камере через ее имя, получив тем самым доступ к информации о ее трансформации. Также, на случай, если игровой тип будет использоваться на другой карте, где нет камеры с таким именем, мы оставим прежний способ получения данных о трансформации - из сохраненного в карте положении карты редактора.
protected override void OnGetCameraTransform(out Vec3 position, out Vec3 forward, out Vec3 up, ref Degree cameraFov) { //Получаем доступ к камере MapCamera mapCamera = Entities.Instance.GetByName("MapCamera_0") as MapCamera; //Если камера найдена if (mapCamera != null) { position = mapCamera.Position; forward = mapCamera.Rotation * new Vec3(1, 0, 0); cameraFov = mapCamera.Fov; } //Иначе получаем трансформацию камеры редактора else { position = Map.Instance.EditorCameraPosition; forward = Map.Instance.EditorCameraDirection.GetVector(); cameraFov = Map.Instance.Fov; } //Вертикальное направление up = Vec3.ZAxis; }
Теперь перейдем к интерактивности. Добавим к нашем игровому типу меню, состоящее из одной кнопки: Create Box. Пусть по ее нажатию на карту падает ящик.
Итак, для начала нам понадобится пользовательский интерфейс (GUI). Для простоты он состоит из единственной кнопки Create Box.
Перед нами встают две задачи:
Прикрепить к игровому окну пользовательский интерфейс,
Написать метод, который бы добавлял на карту ящик при нажатии на кнопку.
Сначала определим переменную, осуществляющую доступ к пользовательскому интерфейсу. После этого добавим реализацию метода OnAttach. Он вызывается при создании игрового окна. В нем мы создадим пользовательский интерфейс (загрузим из файла) и добавим его к окну. Кроме того, мы назначим кнопке CreateBox реакцию на нажатие. Вот так будет выглядеть код:
//Переменная для доступа к пользовательскому интерфейсу игрового окна Control hudControl; protected override void OnAttach() { //Вызов родительского метода base.OnAttach(); //Загрузка пользовательского интерфейса hudControl = ControlDeclarationManager.Instance.CreateControl("Gui\\NewGameTypeHUD.gui"); //Добавление GUI к окну Controls.Add(hudControl); //Добавляем реакцию на нажатие кнопки ((Button)hudControl.Controls["CreateBox"]).Click += CreateBoxButton_Click; }
Для завершения нашего игрового класса недостает функции добавления ящика на карту. Вот код этой функции:
void CreateBoxButton_Click( Button sender ) { //Если имеется доступ к карте if (Map.Instance != null) { //Создаем новый игровой объект - ящик MapObject box = (MapObject)Entities.Instance.Create("Box", Map.Instance); //Задаем позицию ящика box.Position = new Vec3(1.6f, 18.0f, 10.0f); //Завершаем инициализацию ящика box.PostCreate(); } }
На этом класс игрового окна закончен, осталось только скомпилировать наш проект.
Для того, чтобы увидеть игровой тип в действии запустим карту WindowAppExample.map в режиме симуляции (параметр GameType у карты должен быть выставлен в значение NewGameType).
Чтобы протестировать пользовательский интерфейс нашего игрового типа, нажмем на кнопку Create Box, после чего на карту должен упасть ящик.
Заключение
В этом уроке мы научились добавлять в движок новые игровые типы, создавать классы игровых окон. Для того, чтобы лучше разобраться в работе игровых окон, вы можете ознакомиться с уже имеющимися классами, которые находятся в проекте Game:
ActionGameWindow - Игровое окно для реализации игры или других проектов, где нужно управлять персонажем от первого лица или третьего лица.
TurretDemoGameWindow - Пример надстройки над ActionGameWindow, для реализации карты TurretDemo.
RTSGameWindow - Пример реализации стратегии в реальном времени. Смотрите карту RTSDemo для примера.
JigsawPuzzleGameWindow - Пример реализации настольной игры собирания пазла. Поддержка сети для нескольних игроков.