Программирование - это просто
Advertisement
Главная arrow Уроки Delphi arrow Пишем компьютерную игру на Delphi arrow Создаем библиотеку для написания игр (TObject, игра, действия, action, игровая сущность).
30.11.2021 г.
Главное меню
Главная
Интернет магазин
Программные продукты
Биржевые роботы
Искусственный интеллект
Математика и информатика
1С:Предприятие
Уроки C#
Уроки Delphi
Уроки программирования
Web-программирование
Дизайн и графика
Компьютер для блондинок
Исходники
Статьи
Платный раздел
Рассказы про компьютеры
Хитрости и секреты
Системный подход
Размышления
Наука для чайников
Друзья сайта
Excel-это не сложно
Все о финансах
.
Создаем библиотеку для написания игр (TObject, игра, действия, action, игровая сущность). Печать E-mail
Автор megabax   
25.10.2009 г.
New Page 2

Создаем библиотеку для написания игр (TObject, игра, действия, action, игровая сущность).

На прошлом уроке я сообщил о том, что начал писать библиотеку для создания игр. Сегодня расскажу об этом более подробнее. И так, писать библиотеку я начал с того, что объявил базовый класс:

TEasyGameBaseClass=class(TObject)
end;

От этого класса я объявил остальные классы, большинство из которых пока сделал шаблонами. В частности, так был объявлен класс сущности:

TEasyGameNoun=class(TEasyGameBaseClass)
public
       procedure MakeQuantumOfTime; virtual; abstract;
end;

Спрашивается, для чего я объявил базовый класс игрового объекта? Сперва я сделал это "на всякий случай", но уже в версии 1.1 (забегаю вперед), я добавил в этот класс методы Serialize и Unserialize, общие для всех классов игровой библиотеки.

Теперь объясняю, для чего нужен класс сущности. Сущность - это такой игровой объект, который может обрабатывать квант времени. В частности, это сама платформа игры (во время обработки она вызывает обработчик кванта времени у всех входящих в нее объектов), а так же сами игровые объекты. Сущности могут быть объектными и не объектными. Платформа игры - это не объектная сущность, а юнит (бегающий по экрану человечек) - объектная сущностью.

Для описания объектных сущностей я создал отельный класс TEasyGameObject:

TEasyGameObject=class(TEasyGameNoun)
protected
       FOwner:TEasyGameContainer;
public
       procedure Action(ADestansion:TEasyGameObject; AAction:TEasyGameAction); virtual; abstract;
end;
 

В отличии от не объектных сущностей, объектная сущность может совершить действие по отношению к другой объектной сущности. Для этого в классе TEasyGameObject предусмотрен метод Action. Заметьте, в параметрах этого метода передается объект класса TEasyGameAction - действие. Самое действие сущностью не является (квант времени ему раздавать не нужно), поэтому этот класс объявлен от базового класса (пока только шаблон):

TEasyGameAction=class(TEasyGameBaseClass)
end;

Некоторые сущности (например, игровая платформа или карта) могут включать объектные сущности. Для этой цели я объявил класс TEasyGameContainer:

TEasyGameContainer=class(TEasyGameNoun)
protected
     FObjects:TList;
public
    procedure AddGameObject(AGameObject:TEasyGameObject);
    procedure MakeQuantumOfTime; override;
end;

Игровая платформа более сложный класс, вот как я объявил его в версии 1.0:

TEasyGamePlatform=class(TEasyGameContainer)
protected
     FDateTime:TDateTime;
     FTimeSpeed:integer; //коэффициент замедления (ускорения времени)
     FSizeOfQuantumOfTime:integer; // размер кванта времени
     procedure SetTimeSpeed(ATimeSpeed:integer);
     procedure SetSizeOfQuantumOfTime(ASizeOfQuantumOfTime:integer);
public
    property DateTime:TDateTime read FDateTime;
    property TimeSpeed:integer read FTimeSpeed write SetTimeSpeed;
    property SizeOfQuantumOfTime:integer read FSizeOfQuantumOfTime write SetSizeOfQuantumOfTime;
    constructor Create(ADateTime:TDateTime);
    destructor Destroy;
    procedure MakeQuantumOfTime; override;
end;
 

Класс TEasyGameContainer так же является родителем для класса карты TEasyGameMap. Естественно, если есть карта, то должны быть и объекты, имеющие на этой карте координаты. Поэтому я разделил объекты сущности еще на два подкласса: объектная сущность не привязанная к карте и привязанная к карте TEasyGameLocationObject:

TEasyGameLocationObject=class(TEasyGameObject)
protected
    FX,FY:integer;
    procedure SetX(AX:integer); virtual; abstract;
    procedure SetY(AY:integer); virtual; abstract;
public
    property X:integer read FX write SetX;
    property Y:integer read FY write SetX;
end;

Почему я к координатам привязал объект, а не расположил его в матрице координат? Предположим, что карта имеет размер 1000 на 1000. Значит, в матрице будет миллион элементов. Представляете, сколько памяти займет такая карта?  В оперативке ее будет хранить очень неудобно, а если подругжать с диска - то будут сильные тормоза. И при том, большинство локаций этой карты будет просто не заполнено.

Какие могут быть объектные сущности, не привязанные к координатам? Например те, что моделируют явления природы. Они могут происходить одновременно в нескольких локациях. Или, например, моделирование освещение карты солнцем - карата освещается сразу вся. Само сонце в данном случае будет не привязанная к координатам объектная сущность.

Ну, и что бы закончить урок, приведу пример реализации некоторых методов, но уже из версии 1.1

TEasyGameBaseClass=class(TPersistent)
protected
    FVersion:integer;
    function GetVersion:integer;
public
    procedure Serialize(AStream:TStream); virtual;
    procedure Unserialize(AStream:TStream); virtual;
end;
procedure TEasyGameBaseClass.Serialize(AStream:TStream);
var sign:string; version:integer;
begin
   Sign:=ClassName;
   version:=GetVersion;
   SerializeString(sign, AStream);
   AStream.Write(version,sizeof(version));
end;

procedure TEasyGameBaseClass.Unserialize(AStream:TStream);
var sign,s:string; l:integer;
begin
    sign:=UnserializeString(AStream);
    if sign<>ClassName then Raise Exception.Create('TEasyGameBaseClass.Unserialize: Неправильный формат файла (потока)');
    AStream.Read(FVersion,sizeof(FVersion));
end;

И немного комментариев. Во первых, теперь базовый класс объявлен не от TObject  а от TPersistent. Это связано с тем, что групповом чтении объектов из потока необходимо знать, какой это класс, что бы создать его. А класс для этого нужно зарегистрировать командой RegisterClass, но она может регистрировать только потомки TPersistent. Теперь о работе методов сериализации. Сперва мы пишем в поток имя класса. Для этого используем специальную процедуру SerializeString, которая входит в данную библиотеку. Для чего это см. здесь.

Затем пишем в поток номер версии. Читаем в обратном порядке. Если у нас в потоке не те данные - вызываем исключение:

if sign<>ClassName then Raise Exception.Create('TEasyGameBaseClass.Unserialize: Неправильный формат файла (потока)');

Для чего пишем номер версии? Что бы потом можно было запрограммировать корректное чтение объектов,  созданных в ранних версиях программы.

Если у нас объект содержит какие либо специальные поля, их тоже следует сериализовать, например, так:

procedure TEasyGameLocationObject.Serialize(AStream:TStream);
begin
    inherited Serialize(AStream);
    AStream.Write(FX, sizeof(FX));
    AStream.Write(FY, sizeof(FY));
end;

На этом урок закончен, до новых встреч.

 

Последнее обновление ( 06.11.2011 г. )
 
« След.   Пред. »
 
© 2021 Программирование - это просто
Joomla! - свободное программное обеспечение, распространяемое по лицензии GNU/GPL.
Русская локализация © 2005-2008 Joom.Ru - Русский Дом Joomla!
Design by Mamboteam.com | Powered by Mambobanner.de
Я принимаю Яндекс.Деньги