Блог » 2012»марта»5 » Пишу свой игровой движок - 1 (первая часть)
Пишу свой игровой движок - 1 (первая часть)
17:28
Продолжаю. Сегодня нужно создать окно и инициализировать рендер.
Вчера я определил, какие у движка должны быть библиотеки. Но то была больше теория. Сегодня я создал проект и применил теорию на практике. Вот что у меня получилось:
Вот так вот я организовал структуру своего движка. Давайте я рассмотрю подробней. Начну с папок. Всего создано шесть папок. Первая - _Doc, будет содержать ссылки на используемую документацию по движку (история, лист задач и т.д.). Фишка: обратили внимание на подчеркивание? Так вот, это сделано специально чтобы папка была в самом вверху и не смешивалась с папками движка (папки сортируются по имени). Application - это уровень приложения. Как вы видите в ней всего один проект с тем же именем. Данный проект - это динамическая библиотека (подробнее о видах библиотек можете прочитать http://ru.wikipedia.org/wiki/Библиотека_(программирование)). Пользователь в идеале должен будет работать только с этой библиотекой. Папка Core - это основа из схемы. Она содержит 4 проекта. Каждый проект - это статическая библиотека. Папка Engine - это ядро из схемы. Все проекты из папки, также являются статическими библиотеками. Папка Framework пуста, потому что пока нет смысла в ней что-то делать. И папка Test будет хранить приложения для тестирования частей движка.
То есть в итоге у нас одна динамическая библиотека, одинадцать статических которые будут линковаться к динамической. И проект.
Я не стану пояснять как я создал такой проект, так как это долго. Да и не расчитанно на новичков.
На этом подготовка завершена. Продолжим.
Любое приложение должно с чего-то начинаться. Это называется точкой старта (или входа) приложения. Обычно это или main() или WinMain(), а также все их производные... Но в движке нет точки старта, потому что движок не запускается сам по себе. Точку старта задает пользователь при создании приложения. Но я начну именно с нее проектировать и писать код. Наша точка старта будет в приложении test.
Пользователь должен при старте, создать наследника от класса Application, полиморфировать нужные методы, инициализировать наследник, запустить его на выполнение и затем очистить ресурсы. То есть получается так:
Поясню. Start - это условный момент запуска приложения. End - это условный момент завершения приложения. WinMain и MyApplication - это уровень приложения. Данные сущности пишутся пользователем. iApplication - это интерфейс из библиотеки Application. Как вы видите, я выделил их цветом согласно схемы из предыдущей статьи. Я так буду поступать и дальше чтобы вам было легче ориентироваться.
Начнем писать код. Для начала создадим класс приложения. Находим Application и пишем: Application.h
Code
#pragma once
#include "export.h"
class ENGINE_DLL Application { public: Application(); virtual ~Application();
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow) { MyApp app;
app.Run();
return 0; }
Собственно вы уже можете собрать (но не забудьте прилинковать Application). Но запускать не советую - уйдет в бесконечность:) Мы ведь еще условий выхода не написали.
Так, теперь двигаемся дальше. Вспомним для чего нам был нужен Application - для обертывания остальных сущностей. Среди которых главной была Engine. Значит теперь ее нужно создать. Далее, по текущей задаче мы должны создать окно и инициализировать рендер. Значит в модуле рендера появляются два класса - Window и Render. Но так как мы решили что сущность рендера абстрактна, то тогда нужен еще один класс RenderDX11 и WindowWin32, которые будут выполнять реализацию использования в рендере DirectX 11 в окне операционной системы Windows.
Схема усложняется:). Начнем выполнение с конца. Находим библиотеку рендера и пишем код: Window.h
Code
#pragma once
#include <string>
class Window { public: Window(); virtual ~Window();
/// Создать окно virtual bool createWindow(const std::wstring &caption, unsigned int width, unsigned int height)=0;
/// Закрыть окно. virtual void closeWindow()=0;
/** Показать/Скрыть окно. @param value определяет, показывать ли окно (при true) или не показывать. */ virtual void showWindow(bool value)=0;
/// Изменить заголовок окна. virtual void setWindowCaption(const std::wstring& _caption)=0;
protected: std::wstring _caption; ///< заголовок окна unsigned int _width; ///< ширина клиентской части окна unsigned int _height; ///< высота клиентской части окна };
Теперь нам нужен класс Render. Но тут я хочу сказать вот что - наш рендер должен быть единственным. Реализуем мы это через паттерн синглтон (погуглите, кому интересны подробности, прям по запросу "паттерн синглтон"). Так что сначала надо написать сам паттерн. Переходим к библиотеке Common. и пишем: macros.h
Code
#pragma once
#include <cassert>
#define Assert(a, b) assert(a && b)
Singleton.h
Code
#pragma once
#include "macros.h"
/** Singleton pattern implemented using templates. @remarks Using singleton is useful for objects such as engine or managers which should have no more than a single instance in the whole application. @remarks If you want to make object of some class singleton you have to derive this class from Singleton class. @remarks If something goes wrong during singleton object creation, deletion or on attempt to access it, assertion arises. By "something going wrong" I also mean attempts to create more than single object of class marked singleton. */ template <typename T> class Singleton { public: /** Creates singleton of type T. */ Singleton() { Assert(!s_pSingleton, "Singleton class already instantiated.");
virtual ~Singleton() { Assert(s_pSingleton, "Singleton class not instantiated."); s_pSingleton=0; }
/** Returns reference to a singleton. */ static T& getSingleton() { Assert(s_pSingleton, "Singleton class not instantiated."); return(*s_pSingleton); }
/** Returns pointer to a singleton. */ static T* getSingletonPtr() { return s_pSingleton; }
/// A static pointer to an object of T type. /// This is the core member of the singleton. /// As it is declared as static no more than /// one object of this type can exist at the time. static T* s_pSingleton; };
Паттерн не мой, поэтому сохранен язык оригинала :-D
Вообщем, я к сожалением на сегодня на этом завершаю:-( Хотел бы написать дальше, но 12 часов - пора спать. Ждите до завтра, будет продолжение. Мы наконец-то создадим окно и инициализируем движок.
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:
Игровые объявления и предложения:
Если вас заинтересовал материал «Пишу свой игровой движок - 1 (первая часть)», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела.
Предлагаются такие схожие материалы:
Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.
Будет редактор, но много-много позже. Сейчас движок главней.. А может и не так поздно. В общем посмотрю когда начну вторую статью про работу с 3D моделями
Так. Отпишись в теме http://gcup.ru/forum/3-21180-1 Если найдется пять человек которым это надо, я осуществлю рендер на dx 9 (по качеству оно будет одинаково, но это будет эмуляция фич dx 11)
Либо да, вместо dx 11 инициализировать dx 10... И вообще-то данный код, по идее так и должен был сделать (там есть обход всех поддерживаемых версий от 11 до 9)
Эх материала много, а я мало понял... Я в смысле о коде, еще читать и читать кучу книг, но хоть кое-где я принцип понял, а по визуальным подсказкам более менее лучше понятно. Но я думаю из этого можно было бы даже книгу составлять. "Пишем свой, игровой движок" или более пафосно и гордо "Технология создания игрового движка".
И кому интересно, мой план: - завтра появится завершающая статья. В ней мы создадим окно, инициализируем DX11 (поэтому если у вас до сих пор нет DirectX SDK - поспешите скачать самый новый (или не совсем новый)B) ), также мы начнем реализацию модуля ввода Затем будет очень сложная статья, по завершению которой мы сможем выводить модели созданные в сторонних программах (3ds max, maya, blender). То есть никаких треугольников, квадратов и шариков - только реальные задачи, только реальный опыт:D. Сразу оговорюсь - статья будет сложной, будут затронуты очень сложные темы (уменьшение количества DIP к примеру, текстурирование, материалы). Возможно статья будет разбита на части. Но из-за сложности самой статьи и малом количестве времени которое я могу этому уделять - статья будет не скоро. Сожалею - но там слишком много материала.