Elite Games - Свобода среди звезд!

Уроки для программистов - Основа движка

Глава 3. Основа движка

Для начала разберемся со структурой движка.

Должны быть такие объекты:

— Геометрия (собственно, модели).
— Источники света.
— Спрайты.
— Системы частиц.
— Камеры.

Внимание! Данная структура не претендует на суперсовременную, она рассчитана на простые игры.

Но как это хранить в сцене?

Нужен массив объектов.. Но создавать отдельно массив геометрии, отдельно источников света и т.д. не очень удобно. Поэтому мы сделаем по-другому.

Для начала нужно создать базовый класс с общими свойствами для всех объектов. Общих свойств не слишком много. Это:

— Имя. Уникальный идентификатор (Например, «камера_1» или «станция_5»)
— Трансформация (матрица/кватернионы, короче что пожелаете)

Еще есть общие процедуры такие как:

— Render (рисование)
— Update (обновление, например, при движении корабля)
— Загрузка из файла
— Сохранение в файл
— Копирование информации из другого объекта в этот.

Код:

type
JLSceneObj=class
IdName:string;
Trans:PJLTransformation;

constructor Create; virtual;

procedure Render; virtual; abstract;
procedure Update; virtual; abstract;
procedure LoadFromFile(var f:file); virtual; abstract;
procedure SaveToFile(var f:file); virtual; abstract;

procedure Assign(a:JLSceneObj); virtual;
end;

Теперь тип трансформации. Я использую матрицы, но мне легко будет переделать все на кватернионы, например.

Код:

type
JLTransformation=class
rotMat:TDotMatrix3x3;
pos:TDotVector3;
constructor Create;

procedure LoadTransform;
procedure DoTransform;
end;
PJLTransformation=^JLTransformation;


constructor JLTransformation.Create;
begin
rotMat:=DOT_IDENTITY3;
pos:=DOT_ORIGIN3;
end;



OpenGL лучше давать матрицу не в представлении 4х4, а 1х16.
Для этого объявим новый тип

type
TDotMatrix16=array [0..15] of single;



procedure JLTransformation.LoadTransform;
var MatGL:TDotMatrix16;
begin
MatGL:=jlMatToMat16(rotMat);
jlSetPosMat(pos,MatGL);

glLoadMatrixf(@MatGL);
end;

Вот код jlSetPosMat (из математической библиотеки):


procedure jlSetPosMat(Pos:TDotVector3; var Mat:TDotMatrix16); overload;
begin
mat[12]:=pos.x;
mat[13]:=pos.y;
mat[14]:=pos.z;
end;


procedure JLTransformation.DoTransform;
var MatGL:TDotMatrix16;
begin
MatGL:=jlMatToMat16(rotMat);
jlSetPosMat(pos,MatGL);

glMultMatrixf(@MatGL);
end;


Функция jlMatToMat16 просто переводит матрицу 3х3 в матрицу 16. Вот её
Код:

function jlMatToMat16(const m:TDotMatrix3x3):TDotMatrix16;
begin
result[0] :=m[0,0];
result[1] :=m[0,1];
result[2] :=m[0,2];
result[3] :=0;

result[4] :=m[1,0];
result[5] :=m[1,1];
result[6] :=m[1,2];
result[7] :=0;

result[8] :=m[2,0];
result[9] :=m[2,1];
result[10]:=m[2,2];
result[11]:=0;

result[12]:=0;
result[13]:=0;
result[14]:=0;
result[15]:=1;
end;


Все просто. Теперь, как же хранить это все в Сцене? Ну для начала опишем какой-нибудь класс-потомок. Особо выбирать не пришлось. Все же лучше посмотреть на геометрию, чем на источник света, который ничего не освещает за отсутствием геометрии. Итак, что нужно для геометрии?
Как я уже писал, она описывается Вершинами, Нормалями и Текстурными Координатами (на самом деле там может быть несколько текстурных координат, цвет и еще много всего, но это уже дополнительно, то что я назвал – основа, хотя в формате 3ds нет нормалей, за что я его и не люблю).

Заведем класс JLGeometry описывающий геометрию в сцене.

Здесь возникает сложность. Хранить информацию о вершинах напрямую в классе JLGeometry – это неправильно. Например, у нас есть 2 одинаковых корабля. Информацию о вершинах придется дублировать, а если кораблей 20? Или 100? Проблема решается, если создать класс-хранитель именно этой информации.

Называться он будет Mesh.

JLMesh=class
IdName:string;

Vertex:JLGeomData3;
Normal:JLGeomData3;
TexCoord:JLGeomData2;
Indx:array of cardinal;

Count:integer;


constructor Create;
destructor Destroy; override;

procedure LoadFromFile(var f:file);
procedure SaveToFile(var f:file);

procedure Assign(geo:PJLMesh);
end;

Описывать каждую процедуру не и имеет особого смысла, т.к. они довольно просты. Здесь нет работы с OpenGL.

У класса JLGeometry должны быть ссылки на материал и mesh.

JLGeometry=class(JLSceneObj)
MeshId,MatID:string;
и т.д.


Так как же хранить JLGeometry в сцене?

Нужно создать JLObjArray — класс-хранитель объектов типа JLSceneObj и его наследников.

Самое интересное, что объявив тип JLSceneObj вы можете превратить его в любой класс-наследник. Например:
Var a: JLSceneObj;

A:=JLGeometry.Create;
или
A:=JLSprite.Create;
и т.д.

Вот, попробуйте написать класс JLObjArray сами, потом посмотрим у кого лучше вышло.

Возможности у этого класса должны быть следующие:

— Добавить объект (а: JLSceneObj)
— Взять последний из списка:JLSceneObj;
— Найти по имени(nam:String):integer; вернуть номер
— Найти по имени(nam:String):JLSceneObj; вернуть сам объект
— Очистить список.
— function IsChanged:boolean; — вот такая функция, говорящая изменился ли список со времен предыдущего вызова ЭТОЙ функции. (по желанию)

Пока удаление из списка, загрузка из файла тоже по желанию.

Учтите, в массиве не должно быть двух объектов с одинаковыми именами.
Так же могут быть проблемы с разным написанием имени. ‘Camera1’ и ‘camera1’-не одно и то же!


Этот класс добавляется в Сцену. Теперь чтоб нарисовать, например, прямоугольник требуется сделать следующее.

Meshes: хранитель mesh;
Objects: хранитель JLObjArray;


procedure TDelphi3DForm.CreateScene;
var Geome:JLGeometry; убираем
begin
Geome:=JLGeometry.Create;
Scene.Objects.AddObj(Geome);
Geome.Free; // все, удалили
end;

а вместо
Geome.Render;
пишем
Scene.Render;

Материалов пока нет, а вот с mesh`ами нужно поработать – сделать класс-хранитель объектов mesh. Этот класс будет похож на хранитель JLObjArray. Попробуйте реализовать сами.
Jurec
К началу раздела | Наверх страницы Сообщить об ошибке
Уроки для программистов - Основа движка
Все документы раздела: Для тех, кто хочет писать игры | Движок на OpenGL | Создание игр в Game Maker | Bump mapping | Использование Direct Input | XNA framework |


Дизайн Elite Games V5 beta.18
EGM Elite Games Manager v5.17 02.05.2010