Главная » Статьи » Программирование » Delphi, Pascal, ObjectPascal » Создание базового движка для игры. Часть 1. Графика и клавиатура
|
Создание базового движка для игры. Часть 1. Графика и клавиатура
[ Поделиться ]
[ Спасибо! ]
|
давайте начнем.
Создайте новый проект. Сразу назовите форму fMain. На форму киньте таймер и назовите его StepEvent интервал задайте одному (Interval: 1). Теперь создайте новый модуль (File / New / Unit)
в Uses пропишите следующее (вписывайте после ключевого слова interface):
uses
Graphics, ExtCtrls, Windows, Classes, JPEG;
Эти модули нам нужны для рисовании графики. Теперь создадим базовые классы:
TCoordinates = record
X: Integer;
Y: Integer;
end;
TDevice = class
public
Width: Integer;
Height: Integer;
Windowed: Boolean;
procedure Update;
constructor Create;
end;
TSprite = class
public
Position: TCoordinates;
Tag: Integer;
Name: String;
Image: TImage;
constructor Create;
end;
TCamera = class
public
Position: TCoordinates;
Clamp: TCoordinates;
CameraObject: TSprite;
Width: Integer;
Height: Integer;
procedure Update;
constructor Create;
end;
TScene = class
public
SpritesCount: Integer;
Sprites: array[0..999] of TSprite;
Camera: TCamera;
function AddSprite: TSprite;
procedure LoadFromFile(const FileName: String);
constructor Create;
end;
TViewer = class(TImage)
public
Device: TDevice;
Scene: TScene;
BackBuffer: TImage;
procedure Update;
constructor Create(AOwner: TComponent);
end;
Здесь TCoordinates это координаты объекта, камеры и т.д... TDevice - это у нас экран он нам нужен для того что бы мы могли сделать игру не в оконном режиме. TSprite - собственно сам спрайт. TCamera - камера, она нам понадобится, если мы хотим делать "скролл" тоесть комнату любых размеров. TScene - сама сцена, в которой находится массив спрайтов и камера. TViewer - место на котором мы будем рисовать. Теперь давайте опишем процедуры и функции, которые мы создали. После ключевого слова implementation впишите следующее:
//*TDevice*//
procedure TDevice.Update;
var
DeviceMode: TDevMode;
begin
if Windowed then
begin
ChangeDisplaySettings(TDevMode(nil^), CDS_FULLSCREEN);
end else
begin
with DeviceMode do
begin
dmSize := SizeOf(DeviceMode);
dmPelsWidth:= Width;
dmPelsHeight:= Height;
dmBitsPerPel:= 32;
dmFields:= DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL;
end;
ChangeDisplaySettings(DeviceMode, CDS_FULLSCREEN);
end;
end;
constructor TDevice.Create;
begin
inherited Create;
Width:= 800;
Height:= 600;
Windowed:= true;
end;
//*TSprite*//
constructor TSprite.Create;
begin
inherited Create;
Image:= TImage.Create(nil);
Image.Visible:= false;
Image.AutoSize:= true;
end;
//*TCamera*//
procedure TCamera.Update;
begin
if CameraObject <> nil then
begin
if CameraObject.Position.X > Position.X + Clamp.X div 2 then
Position.X:= CameraObject.Position.X - Clamp.X div 2;
if CameraObject.Position.X < Position.X - Clamp.X div 2 then
Position.X:= CameraObject.Position.X + Clamp.X div 2;
if CameraObject.Position.Y > Position.Y + Clamp.Y div 2 then
Position.Y:= CameraObject.Position.Y - Clamp.Y div 2;
if CameraObject.Position.Y < Position.Y - Clamp.Y div 2 then
Position.Y:= CameraObject.Position.Y + Clamp.Y div 2;
end;
end;
constructor TCamera.Create;
begin
inherited Create;
Clamp.X:= 320;
Clamp.Y:= 0;
end;
//*TScene*//
function TScene.AddSprite: TSprite;
begin
Sprites[SpritesCount]:= TSprite.Create;
Result:= Sprites[SpritesCount];
SpritesCount:= SpritesCount + 1;
end;
procedure TScene.LoadFromFile(const FileName: String);
begin
end;
constructor TScene.Create;
begin
inherited Create;
SpritesCount:= 0;
end;
//*TViewer*//
procedure TViewer.Update;
Var
i: Integer;
begin
BackBuffer.Canvas.CopyRect(Rect(0,0,Width,Height),Canvas,Rect(0,0,Width,Height));
BackBuffer.Canvas.Brush.Color:= $000000;
BackBuffer.Canvas.FillRect(Rect(0,0,Width,Height));
for i:= 0 to Scene.SpritesCount - 1 do
BackBuffer.Canvas.Draw((Scene.Sprites[i].Position.X - (Scene.Sprites[i].Image.Width div 2)) -
(Scene.Camera.Position.X - (Scene.Camera.Width div 2)),
(Scene.Sprites[i].Position.Y - (Scene.Sprites[i].Image.Height div 2)) -
(Scene.Camera.Position.Y - (Scene.Camera.Height div 2)),
Scene.Sprites[i].Image.Picture.Graphic);
Canvas.CopyRect(Rect(0,0,Width,Height),BackBuffer.Canvas,Rect(0,0,Width,Height));
end;
constructor TViewer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
BackBuffer:= TImage.Create(nil);
BackBuffer.Parent:= Parent;
BackBuffer.Visible:= false;
end;
сохраните модуль под именем uGraphics. Далее в главном модуле в uses допишите модуль uGraphics. Теперь вернемся на форму. В обработчике событий формы OnCreate пропишиете следующее:
GameDevice:= TDevice.Create;
GameCamera:= TCamera.Create;
GameScene:= TScene.Create;
GameViewer:= TViewer.Create(nil);
with GameViewer do
begin
Parent:= fMain;
Device:= GameDevice;
Scene:= GameScene;
Scene.Camera:= GameCamera;
Width:= fMain.ClientWidth;
Height:= fMain.ClientHeight;
BackBuffer.Width:= Width;
BackBuffer.Height:= Height;
GameCamera.Width:= Width;
GameCamera.Height:= Height;
end;
так же не забудьте объявить глобальные переменные:
GameDevice: TDevice;
GameCamera: TCamera;
GameScene: TScene;
GameViewer: TViewer;
теперь в обработчике событий таймера впишите следующее:
GameViewer.Update;
GameCamera.Update;
Если вы все сделали правильно то при запуске экран заполнится черным цветом. Теперь давайте добавим спрайт в нашу сцену, в обработчике событий OnCreate допишите следующее:
with GameScene.AddSprite do
begin
Image.Picture.LoadFromFile('Data\Images\1.bmp');
Image.Transparent:= true;
end;
Запустите приложение, у вас должно получиться вроде этого:
Поэкспериментируйте немного с параметрами, например с параметром Position если ввести в обработчик событий в таймере строчку:
GameScene.Sprites[0].Position.X:= GameScene.Sprites[0].Position.X + 4;
то наш спрайт полетит вправо =)
Теперь давайте разберемся с клавиатурой... создайте новый модуль и переименуйте его в uSystem. Я приведу полный код модуля:
unit uSystem;
interface
uses
Windows;
function OnKey(key: Char): Boolean; overload;
function OnKey(key: Word): Boolean; overload;
implementation
//*Keyboard*//
function OnKey(key: Char): Boolean;
var
vk : Integer;
begin
vk:= VkKeyScan(key) and $FF;
if vk <> $FF then
Result:= (GetAsyncKeyState(vk) < 0)
else Result:= False;
end;
function OnKey(key: Word): Boolean;
begin
Result:= (GetAsyncKeyState(key) < 0);
end;
end.
Как обычно добавьте модель uSystem в uses главного модуля. Теперь в обработчике события таймера введите следующее:
if OnKey(VK_LEFT) then GameScene.Sprites[0].Position.X:= GameScene.Sprites[0].Position.X - 4;
if OnKey(VK_RIGHT) then GameScene.Sprites[0].Position.X:= GameScene.Sprites[0].Position.X + 4;
if OnKey(VK_UP) then GameScene.Sprites[0].Position.Y:= GameScene.Sprites[0].Position.Y - 4;
if OnKey(VK_DOWN) then GameScene.Sprites[0].Position.Y:= GameScene.Sprites[0].Position.Y + 4;
теперь мы можем управлять нашим объектом нажимая стрелочки =). Ах да, совсем забыл про камеру. В обработчике события OnCreate главной формы введите следующее:
with GameScene.AddSprite do
begin
Image.Picture.LoadFromFile('Data\Images\1.bmp');
Image.Transparent:= true;
Position.X:= 250;
end;
GameScene.Camera.CameraObject:= GameScene.Sprites[0];
Второй объект нам нужен для того что бы заметить изменения. Теперь если походить по комнате, можно увидет как камера передвигается вместе с нами =) Ну на сегодня все =) В следующем уроке мы научимся сталкиваться с объектами, воспроизводить анимацию и музыку =) а щас приведу полный код того что у меня получилось из этого:
uMain (Главный модуль)
unit uMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, uGraphics, uSystem;
type
TfMain = class(TForm)
StepEvent: TTimer;
procedure FormCreate(Sender: TObject);
procedure StepEventTimer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
fMain: TfMain;
GameDevice: TDevice;
GameCamera: TCamera;
GameScene: TScene;
GameViewer: TViewer;
implementation
{$R *.dfm}
procedure TfMain.FormCreate(Sender: TObject);
begin
GameDevice:= TDevice.Create;
GameCamera:= TCamera.Create;
GameScene:= TScene.Create;
GameViewer:= TViewer.Create(nil);
with GameViewer do
begin
Parent:= fMain;
Device:= GameDevice;
Scene:= GameScene;
Scene.Camera:= GameCamera;
Width:= fMain.ClientWidth;
Height:= fMain.ClientHeight;
BackBuffer.Width:= Width;
BackBuffer.Height:= Height;
GameCamera.Width:= Width;
GameCamera.Height:= Height;
end;
with GameScene.AddSprite do
begin
Image.Picture.LoadFromFile('Data\Images\1.bmp');
Image.Transparent:= true;
end;
with GameScene.AddSprite do
begin
Image.Picture.LoadFromFile('Data\Images\1.bmp');
Image.Transparent:= true;
Position.X:= 250;
end;
GameScene.Camera.CameraObject:= GameScene.Sprites[0];
end;
procedure TfMain.StepEventTimer(Sender: TObject);
begin
GameViewer.Update;
GameCamera.Update;
if OnKey(VK_LEFT) then GameScene.Sprites[0].Position.X:= GameScene.Sprites[0].Position.X - 4;
if OnKey(VK_RIGHT) then GameScene.Sprites[0].Position.X:= GameScene.Sprites[0].Position.X + 4;
if OnKey(VK_UP) then GameScene.Sprites[0].Position.Y:= GameScene.Sprites[0].Position.Y - 4;
if OnKey(VK_DOWN) then GameScene.Sprites[0].Position.Y:= GameScene.Sprites[0].Position.Y + 4;
end;
end.
uGraphics:
unit uGraphics;
interface
uses
Graphics, ExtCtrls, Windows, Classes, JPEG;
type
TCoordinates = record
X: Integer;
Y: Integer;
end;
TDevice = class
public
Width: Integer;
Height: Integer;
Windowed: Boolean;
procedure Update;
constructor Create;
end;
TSprite = class
public
Position: TCoordinates;
Tag: Integer;
Name: String;
Image: TImage;
constructor Create;
end;
TCamera = class
public
Position: TCoordinates;
Clamp: TCoordinates;
CameraObject: TSprite;
Width: Integer;
Height: Integer;
procedure Update;
constructor Create;
end;
TScene = class
public
SpritesCount: Integer;
Sprites: array[0..999] of TSprite;
Camera: TCamera;
function AddSprite: TSprite;
procedure LoadFromFile(const FileName: String);
constructor Create;
end;
TViewer = class(TImage)
public
Device: TDevice;
Scene: TScene;
BackBuffer: TImage;
procedure Update;
constructor Create(AOwner: TComponent);
end;
implementation
//*TDevice*//
procedure TDevice.Update;
var
DeviceMode: TDevMode;
begin
if Windowed then
begin
ChangeDisplaySettings(TDevMode(nil^), CDS_FULLSCREEN);
end else
begin
with DeviceMode do
begin
dmSize := SizeOf(DeviceMode);
dmPelsWidth:= Width;
dmPelsHeight:= Height;
dmBitsPerPel:= 32;
dmFields:= DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL;
end;
ChangeDisplaySettings(DeviceMode, CDS_FULLSCREEN);
end;
end;
constructor TDevice.Create;
begin
inherited Create;
Width:= 800;
Height:= 600;
Windowed:= true;
end;
//*TSprite*//
constructor TSprite.Create;
begin
inherited Create;
Image:= TImage.Create(nil);
Image.Visible:= false;
Image.AutoSize:= true;
end;
//*TCamera*//
procedure TCamera.Update;
begin
if CameraObject <> nil then
begin
if CameraObject.Position.X > Position.X + Clamp.X div 2 then
Position.X:= CameraObject.Position.X - Clamp.X div 2;
if CameraObject.Position.X < Position.X - Clamp.X div 2 then
Position.X:= CameraObject.Position.X + Clamp.X div 2;
if CameraObject.Position.Y > Position.Y + Clamp.Y div 2 then
Position.Y:= CameraObject.Position.Y - Clamp.Y div 2;
if CameraObject.Position.Y < Position.Y - Clamp.Y div 2 then
Position.Y:= CameraObject.Position.Y + Clamp.Y div 2;
end;
end;
constructor TCamera.Create;
begin
inherited Create;
Clamp.X:= 320;
Clamp.Y:= 0;
end;
//*TScene*//
function TScene.AddSprite: TSprite;
begin
Sprites[SpritesCount]:= TSprite.Create;
Result:= Sprites[SpritesCount];
SpritesCount:= SpritesCount + 1;
end;
procedure TScene.LoadFromFile(const FileName: String);
begin
end;
constructor TScene.Create;
begin
inherited Create;
SpritesCount:= 0;
end;
//*TViewer*//
procedure TViewer.Update;
Var
i: Integer;
begin
BackBuffer.Canvas.CopyRect(Rect(0,0,Width,Height),Canvas,Rect(0,0,Width,Height));
BackBuffer.Canvas.Brush.Color:= $000000;
BackBuffer.Canvas.FillRect(Rect(0,0,Width,Height));
for i:= 0 to Scene.SpritesCount - 1 do
BackBuffer.Canvas.Draw((Scene.Sprites[i].Position.X - (Scene.Sprites[i].Image.Width div 2)) -
(Scene.Camera.Position.X - (Scene.Camera.Width div 2)),
(Scene.Sprites[i].Position.Y - (Scene.Sprites[i].Image.Height div 2)) -
(Scene.Camera.Position.Y - (Scene.Camera.Height div 2)),
Scene.Sprites[i].Image.Picture.Graphic);
Canvas.CopyRect(Rect(0,0,Width,Height),BackBuffer.Canvas,Rect(0,0,Width,Height));
end;
constructor TViewer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
BackBuffer:= TImage.Create(nil);
BackBuffer.Parent:= Parent;
BackBuffer.Visible:= false;
end;
end.
uSystem:
unit uSystem;
interface
uses
Windows;
function OnKey(key: Char): Boolean; overload;
function OnKey(key: Word): Boolean; overload;
implementation
//*Keyboard*//
function OnKey(key: Char): Boolean;
var
vk : Integer;
begin
vk:= VkKeyScan(key) and $FF;
if vk <> $FF then
Result:= (GetAsyncKeyState(vk) < 0)
else Result:= False;
end;
function OnKey(key: Word): Boolean;
begin
Result:= (GetAsyncKeyState(key) < 0);
end;
end.
P.S.: Удачи в игростроении
Авторские права принадлежат Каыблину Андрею (Xakep) (с) 2008 год
Категория: Delphi, Pascal, ObjectPascal |
Просмотров: 5837 |
Добавил: ДядяВолк (11.08.2010)
| Рейтинг: 0.0/0
Теги: Источник: http://quadrathell.cn.ua/ | Автор: Михаил Христосенко | |
HTML ссылка на материал: BB ссылка на материал: |
Всего комментариев: 0 | |