[ AmberSkyNet VR ]Трёхмерные предметы у нас вертятся и летают, и это, конечно, хорошо.. Но например, если мы захотим написать изометрическую игру, или даже совсем двумерную, то не обязательно в ней использовать трёхмерные модельки.. Можно вполне обойтись плоскими картинками, т.е. спрайтами. Реализацией класса, который бы отрисовывал на сцене спрайты мы сейчас и займёмся. Возможно, для двумерной или изометрической игры понадобится специализированный класс мира (интерфейс IWorld), но им мы займёмся несколько позже, если надо будет... CNodeSpriteСделаем класс узла сцены, который бы отрисовывал нам спрайт. Наследовать его, конечно, будем от базового класса CNode, который реализует основные функции, общие для всех узлов сцены... Сразу предусмотрим возможность анимации, чтобы не писать отдельный класс NodeSpriteAnimate,
т.к. в общем-то отрисовка анимации делается простым смещением текстурных координат. class CNodeSprite: public CNode { public: CNodeSprite(IEngine* engine); ~CNodeSprite(); virtual bool LoadResource(); // загружаем ресурсы virtual bool Draw(); // рисуем virtual char Update(float tms);// изменяем состояние спрайта на время tms // "перехватываем" установку параметров, характерных только для спрайта virtual void SetParam(const char* param_name,const char* param_value); protected: UINT current_frame; //текущий анимационный кадр UINT Repeat; // число повторений анимации, 0 - бесконечно UINT Anim_Count_X; // количество кадров, умещающихся в текстуре по X UINT Anim_Count_Y; // количество кадров, умещающихся в текстуре по Y UINT Start_Anim; // номер кадра, с которого начинается анимация UINT Count; // число кадров в анимации bool Billbord; // если true - всегда повёрнут к камере float lifeTime; // "время жизни" (используется для анимации) float *dataBuffer; // буфер точек и текстурных координат IDrawObject *DrawSprite; // объект для отрисовки спрайта граф.менеджером IMaterial *DrawMaterial; // "материал" спрайта }; Функция LoadResource предназначена для загрузки ресурсов, которые использует класс спрайта
для отрисовки. Первым делом проверяется значение параметра "Texture" (которое устанавливается
извне через функцию INode->SetParam() ). Если параметр не установлен - функция возвращает true,
т.к. попытка загрузки ресурсов закончилась ошибкой. Функция Draw устанавливает матрицу вида и отрисовывает спрайт. Если установлен признак Billbord, то координаты точек в буфере dataBuffer пересчитываются чтобы они были перпендикулярны вектору камеры. Функция Update увеличивает LifeTime на величину tms и если она
больше параметра "Speed", то уменьшает величиную LifeTime на Speed
и производит пересчёт текстурных координат с учётом заданных параметров
анимации и номера текущего кадра. Базовые объектыВ предыдущем шаге мы научили класс мира загружать и сохранять элементы сцены в
виде XML-файлов. Доработаем его немного - введём возможность описания базовых объектов.
bool SetBaseObject(const char *ObjName, const char *InitString); Функция SetBaseObject задаёт классу World имя базового объекта и его характеристики. Пока в качестве характеристики я использовал строку инициализации, но никто не мешает подвесить XML-парсер и туда.. Это позволит нам создавать группу базовых объектов вызовом одной функци createNode. Но это возможно в будущем, если возникнет такая потребность. Пока же - строка инициализации, которая выглядит так: Параметр=Значение;Параметр=Значение;...Параметр=Значение; Функцию LoadWorld доработаем так, чтобы она различала секции описания базовых объектов и описания самого мира. В XML-файле может быть такое содержимое: <?xml version="1.0" ?> <file Name="FileName" /> ... <BaseObject > <BaseName Type="BaseType" ParamName="ParamValue" ... > ... </BaseObject > <World> <NodeType ParamName="ParamValue" ... > ... </World> Мы можем написать в отдельном XML-файле список базовых объектов одного нашего мира
и использовать их в разных сценах. Не обязательно подключать этот список "вручную",
можно прописать в XML-файле описания сцены строчку <file Name="FileName" />,
где FileName - имя файла, в котором описаны наши базовые объекты. При разборе XML-файла
нашей карты парсер обнаружит эту строчку и подгрузит в мир данные из файла с именем FileName.
А некоторые базовые объекты будут общими для всех наших миров (например - логотипы SDL, OpenGL
и AmberSkyNetVR :). BaseName - имя базового объекта, при помощи которого на него будут ссылаться в файле сцены Type - название класса базового объекта. Экземпляр класса с таким именем попытается создать наш менеджер плагинов. Остальные параметры различны для разных классов... Например вот так выглядит описание логотипа AmberSkyNet в базовой секции: <LogoAmberSkyNet Type="NodeSprite" Texture="AmberSkyNet.png" Size="5 5 5" Billbord="1" Repeat="0" /> NodeType - либо название базового объекта, либо название экземпляра базового класса, который будет создан менеджером плагинов. Если в списке базовых объектов такого не будет найдено - мендеджер плагинов попытается создать такой класс... Например, если мы захотим в сцене увидеть логотип AmberSkyNet в точке 100,100,100 мы можем написать в секции описания мира строчку: <LogoAmberSkyNet Pos="10 10 10" />Остальные параметры различны для разных классов.. Менеджер звуков ISound и реализация CSoundSDL_mixerАнимационные взрывы нам надо озвучивать, а наш движок пока молчит.. Пора делать менеджер звука. Повременим пока с трёхмерным звуком, пусть у нас менеджер делает 2 вещи - играет постоянно фоновую музыку и однократно играет эффект. Интерфейс будет простой: class ISound { public: virtual ~ISound(){} virtual bool PlayFX(const char *FxName)=0; virtual bool PlayMusic(const char *FxName)=0; virtual bool StopMusic()=0; }; Функция StopMisuc останавливает проигрыш музыки. Класс CSoundSDL_mixer, как ясно из его названия, реализует функции этого интерфейса при помощи библиотеки SDL_mixer. Но ничего не мешает написать свой менеджер звука, использующий совсем другую звуковую библиотеку. Изменения в исходникахinclude/: Убран интерфейс менеджера плагинов, который теперь скрыт в недрах IEngine.
Создание объектов теперь производится через вызов IEngine->CreateObject. src/asnCSoundSDL_mixer/: Новый плагин - менеджер звука. src/asnDeviceGl/: В плагин добавлена поддержка текстурных шрифтов,
а так же отслеживание событий выхода/входа курсора мышки в пределы окна, сворачивание окна, итп...
А еще функция MakeScreenshot заработала - теперь можно делать скриншоты
формата bmp. src/asnWorld/: Доработаны процедуры загрузки/сохранения сцены с учётом базовых объектов. src/asnMain/: Небольшая аркадная демка с падающими предметами,
на которые надо быстренько кликнуть мышкой пока они не упали.
Модели по-прежнему позаимствованными из
проекта S.C.O.U.R.G.E. Исходники этого шага выложены в SVN. Скачать их можно набрав команду: svn co https://svn.sourceforge.net/svnroot/ambernet/tags/AmberSkyNet-0.10 ambernet_0.10 |