01. Пишем движок. Defo Engine - начало
Автор: crionuke
Итак приступим.
Сначало я упамяну , что писать я буду на Delphi 2006 (Borland Developer Studio), по идеи движок должен компилироваться и на более ранних версиях (Delphi 7), но честно скажу я не проверял.
Про организацию файлов вы посмотрите в исходниках, которые приложены к статье, лучше я расскожу про стиль написания кода, про имена и т.п.
• Я не использую в своих идентификаторах знак подчеркивания
• Все имена фалов начинаются с большой буквы D (DHeader.pas, Dfactory.pas)
• Каждое новое слово в идентификаторе начинается с заглвной буквы (myCounter)
• Имена классов начинаются с большой буква C (CFactory, CResManager)
• Имена интерфейсов с заглавной буквы I (IFactory, IResManager, и т.д.)
• Имена экземпляров классов с маленькой буква o (oFactory, oResManager, и т.д.)
В свое время я перепробывал многие способы организации кода движка (написал аж 9-10 версий), исходники (набор классов), DLL-ки, как COM – технология, так и просто пытался писать процедурно ориентированный движок, скажу лишь, что дальше реализации загрузки текстур не продвинулся. Мое мнение, что при написании движка на Delphi (не компонентного) лучше всего помимо использования ООП (без сомнения), весь код движка запихивать в DLL-ку, причем доступ к объекта получать с помощью интерфейсов, аля COM-технология.
Для тех, кто не знает, что такое интерфейсы и как их использовать лучше всего будет перд прочтением статьи ознакомится с этим понятием.
Для того чтобы создать экземпляр класса описанного в dll-ки, будем использовать специальный метод экспортированный из dll-файла, который будет возвращать интерфес на объект. А именно: function DefoCreate:IEngine; Его описание находится в конце заголовочного фалйа DHeader.pas.
Вот как им пользоваться:
... var Engine:IEngine; Begin Engine:=DefoCreate; ... End;
Все теперь в переменной Engine хранится интерфейс, который моно использовать для доступа к экземпляру главного класса движка. Как известно необходимо освобождать занятые ресурсы, т.е. удалять объекты... для этого во всех классах будем реализовывать метод: procedure Free; которая будет уничтожать объект, т.е. этот метод необходимо будет описывать в каждом интерфейсе.
Как известно, объект, на который создан интерфейс существует, только когда этот интерфейс используется в программе использующей dll, этот механизм реализуется спомощью подсчета ссылок (детали я опущу), так вот из-за этого механизма, возможны некоторые ошибки и проблемы при использовании движка, связаные с обнулением счетчика ссылок и соответственно удалением объектов, которые еще нужны (до конца, причины обнуления до сих пор мне не понятны). Что бы избежать этих ошибок мы не будем использовать подсчет, для этого в файле DClassEx.pas, описан класс, который переопределяет методы подсчета ссылок своими, не выполняющие этой операции. Именно от этого класса и должны будут наследоваться все классы в движке.
Класс каждой подсистемы реализованн в отдельном юните, там же находится и экзепляр этого класса, это демонстрируется в следующем коде:
... Type CWindow = class(CClassEx, IWindow) ... End; Var oWindow:IWindow;
Объекты классов всех подсистем создаются во время создания движка, т.е во время вызова DefoCreate, который вызывает конструктор у главного объекта движка :
oEngine:=CEngine.Create;
Самым главным классом движка является CEngine, через него можно получить интерфейсы на подсиситемы движка, с помощью соответствующих методов:
... function Window:IWindow; function Render:IRender; ...
Мой движок будет хранить все свои настройки в специальном классе – CStates, в нем будут методы: SetState(), GetState, SetDefault(), соответственно для установки, получения значения какого-нибудь стейта и установки всех стейтов по-умолчанию.
Так же надо добавить, что все обращения к OpenGl будут скрыты абстракцией, а именно классом CRender, ниже него опуститься будет нельзя, позже я расскожу про организацию рендера и сцены (которая и является самым высоким уровнем рендера).
Ну пока все. Код я пытался вмеру комментировать, чтобы было понятно что и за чем. Но если все же возникнут вопросы, то всегда с радостью отвечу на форуме, или по e-mail’у, ну или когда будет время по ICQ.
22 мая 2008 (Обновление: 23 мая 2008)