В данной статье я опишу один из способов организации игрового движка с использованием скриптов Lua. Я изменил свой подход к организации приложения перейдя от жестко связанных между собой классов к использованию интерфейсов, а также скриптов для создания и настройки всех компонентов игрового движка. Прошу не путать графический и игровой движки они отличаются тем что графический, это часть игрового отвечающая за отображение игровых объектов на экране она важна, но кроме нее потребуется еще очень много других систем и подсистем.Начну по порядку.
Центральным классом является класс Core, описывающий ядро системы и его состояния. Более подробнее я распишу, что такое состояние и как его использовать в другой статье т.к. не хочу сваливать все в одну кучу. Класс Core кроме состояний содержит переменную типа IEngine являющуюся интерфейсом, это сделано для того чтобы не было жесткой связи между ядром системы и графическим ядром(вы можете реализовать интерфейс используя любой графический движок, а не только JPCT например Java3D), думаю он будет переписан мною еще не раз в поисках оптимального подхода. Реализацией интерфейса IEngine является класс JPCTEngine в нем спрятана вся работа с графической частью он входит в пакет org.gram.engine.graph.jpctengine. В этом пакете также находится класс описывающий настройки графического движка. В данном пакете будут находиться все классы для работы с графическими объектами и эффектами. Класс LuaScript и работа с ним описаны в это статье. Приложение начинает свою работу с создания объекта типа Core и вызова функции start. Данная функция вызывает скрипт который соединяет в единое целое все компоненты и переходит в главный цикл. В скрипте передаваемом в функцию должна быть описана функция start с одним аргументом(таким образом я передаю созданный объект Core в скрипт, который он вызывает, для того чтобы не плодить static объекты) которая должна выполнить следующие действия: 1) загрузка строк или других данных необходимых для работы 2) создания состояния ядра и указание имени функции в скрипте описывающее что делает это состояние. 3) создание, инициализация и присоединение графического движка
После выполнения всех этих действий программа перейдет в игровой цикл и выполнит скрипт описывающий состояние ядра. В данном примере он пустой. Скрипт используемый в примере выглядит так: --входная функция function start(CoreClass) --объявление глобальной переменной Core Core = CoreClass initCore() createGraphicEngine(); end
--инициализация ядра и создание состояний ядра function initCore()
Core:loadLocale("data\\locale.xml","RU_ru") --создания состояния intromove local CoreStateClass = java.require("org.gram.engine.core.CoreState") local intromovecorestate = CoreStateClass:new() intromovecorestate:setRunScriptFunction("introMoveCoreStateScript") intromovecorestate:setName("intro") Core:addState(intromovecorestate) --это состояние активное Core:setActiveState("intro") end
--создание и инициализация графического движка function createGraphicEngine() local EngineClass = java.require("org.gram.engine.graph.jpctengine.JPCTEngine") local engine = EngineClass:new() Core:setGraphEngine(engine) engine:init() end
function introMoveCoreStateScript(CoreState)
end Вы должны понимать, что все загруженные скрипты находятся в одном контексте даже если вы загрузили их из нескольких файлов. А также то, что использование скриптов в таком виде не являются потоко-безопасными. Теперь немного о разном в рамках данной статьи. Для редактирования скриптов я использовал плагин luaSupport скачанный вот от сюда. Он позволяет редактировать скрипты прямо в NetBeans. Его недостаток заключается в отсутствии автозавершения кода так, что все пока приходится писать ручками. В данном виде в движке не хватает следующих компонентов: 1) Класса описывающего посредника для асинхронного связывания всех объектов игрового движка между собой(связи между элементами не должны быть жестко прописаны в коде, а должны грузится из вне) 2) Загрузки 3Д объектов, текстур, игровых данных, фабрики создающей объекты(используя загруженные данные) и их представление согласно паттерна MVC, что потребует наличие как минимум 2-х контроллеров один пользовательский второй AI а также класса посредника 3) GUI 4) Обработки ввода (потребует посредника) 5) Асинхронной очереди которой будет управлять посредник (в ней должны крутится скрипты, что потребует решить проблему потоко-безопасности с минимальной потерей быстродействия)
Все эти компоненты я буду последовательно дописывать и выкладывать сюда.
|