一、引言
Delphi以其高效、易使用和强大的数据库功能成为众多程序员首选的一种面向对象的程序开发工具。一说到游戏开发,很多人马上会想到VC,Java等,对Delphi能否开发游戏持否定态度,VC和Java在游戏的开发上有着传统的优势,但是不是Delphi就不能开发游戏呢?答案是否定的,像《传奇》、《浩远游戏》、《千年》还有很多流行的小游戏都是用Delphi开发出来的。Asphyre游戏引擎是一款开源的游戏引擎,其作者是乌克兰人,世界上有很多专业网站讨论它的使用方法和提供更新,国内最著名的有火人论坛(http://bbs.huosoft.com)等提供其开发的基础知识和例程,可以说 Asphyre是Delphi开发2D游戏的首选引擎。
现在就用Delphi7.0+Asphyre3.1引擎开发一款简单的空战小游戏,游戏截图如图1。
图1 空战小游戏截图
二、开发步骤
第一步:设计游戏剧情,根据需求准备素材。
这款小游戏属于空战类游戏,简单地说就是一架喷射尾焰的战舰在天上飞,发出子弹打爆不断出现的样式不同的敌舰,为增加真实感,会有战舰在地面上的投影和云雾出现;按CTRL键战舰发射子弹,按ALT+CTRL键改变窗口大小,按ESC键结束游戏。
在Asphyre3.1中,游戏中用到的战舰、云雾等图片和声音字体都是存放在*.asdb的资源文件里,首先要用图形处理软件将所需图片处理好,然后用AsphyreManager这个资源包管理工具(可以在火人论坛下载)将图片等导入到*.asdb文件中,该工具如图2。
图2 AsphyreManager游戏资源工具
在图2浏览窗口中由四张飞机图片组成的序列就是本游戏中战舰的模型,大家可以发现每张战舰的姿势不同,就是靠循环播放姿势不同的战舰图片来产生战舰的动态效果。该管理工具的具体用法大家可以到火人论坛查询。
第二步:在Delphi7中安装Asphyre3.1控件组。
首先到活人论坛下载Asphyre3.10增强版压缩包,解压后,用Delphi7.0打开Source目录下的AsphyrePackage.dpk包文件,在弹出的对话框里点击“install”完成安装。安装完,在控件栏上就会出现Asphyre3.1控件组,如图3所示。
图3 Asphyre控件组
控件组里包括了2D和3D游戏开发所需的声音、显示、操纵等所有控件,这里重点介绍将要用到的几个控件:
TAsphyreDevices负责管理DX引擎设备;TAsphyreCanvas负责屏幕画图; TAsphyreDb负责管理游戏中需要用到的图片、声音、字体等资源文件;TAsphyreFonts负责在屏幕上显示字体;TAsphyreImages负责在屏幕上显示图片;TAsphyreTime负责控制屏幕的刷新;TAsphyreKeyboard:负责捕捉键盘的事件。
第三步:新建一个工程,将第一步介绍的七种控件拖放到窗口中,开始编写代码。利用Asphyre3.1游戏引擎编写游戏代码由精灵的类定义、精灵变化特性的定义、精灵的初始化、游戏功能的渲染实现四个部分组成。
1.精灵的定义
精灵是游戏的核心,精灵的定义关系到游戏开发的成功与否。Asphyre3.1精灵引擎中有TanimatedSprite、TjumperSprite、TparticleSprite、TplayerSprite等几类精灵,像经典游戏《超级玛丽》中那个蹦蹦跳跳可爱的小玛丽就可以用TjumperSprite来实现。从游戏截图中可以发现,在这款空战小游戏中需要定义的精灵有战舰、战舰的尾焰、战舰的投影、敌舰、敌舰的投影、飘动的云朵、射击的子弹、爆炸的焰火等,这些精灵的父类都是TanimatedSprite类,但是为适应游戏剧情的需要,精灵在定义中存在属性、方法等的重载和覆盖,变量、函数、过程的定义等。例如游戏的中心角色战舰类的定义如下:
TCustomShip = class(TAnimatedSprite) //定义战舰的通用类
private
FMoveSpeed: Single; //定义速度控制变量
public
procedure SetAnim(DoMirror: Boolean; APlayMode: TAnimPlayMode); //定义战舰动作设置方法
procedure Move(const MoveCount: Single); override; //重载Move方法
property MoveSpeed: Single read FMoveSpeed write FMoveSpeed; //MoveSpeed属性的值从FMoveSpeed读写
end;
TShip = class(TCustomShip) //从战舰的通用类定义战舰类
private
FShadow: TCustomShip; //定义投影
FTail: TTail; //定义战舰的尾焰
public
constructor Create(const AParent: TSpriteEngine); override; //重构Create方法
property Shadow: TCustomShip read FShadow write FShadow;
property Tail: TTail read FTail write FTail;
end;
TTail = class(TAnimatedSprite) //定义战舰尾焰类
private
FMoveSpeed: Single; //尾焰速度控制变量
public
procedure Move(const MoveCount: Single); override; //重载Move方法
property MoveSpeed: Single read FMoveSpeed write FMoveSpeed;
end;
战舰由战舰本身、战舰投影、战舰尾焰三部分构成,其中战舰本身和战舰投影有很多共同特性,所以他们都派生自TCustomShip。在战舰飞行时,战舰尾焰必须出现在战舰尾部正确的位置,所以战舰尾焰定义了一个速度控制变量来保持和战舰速度同步。
2. 精灵变化特性的定义
精灵变化特性是指在游戏者的交互下,精灵将产生怎样的变化。比如精灵的运动方向与轨迹、碰撞检测与效果等。精灵变化特性的定义关系到能否吸引玩家,激起玩家的参与欲望,所以在游戏设计开发中,一定要动脑筋考虑精灵的变化特性定义。比如在这款空战小游戏中,战舰运动的速度总是大于战舰投影,这样就可以很好的体现出战舰飞行的空间感。这款游戏需要定义变化特性的精灵主要战舰、战舰的尾焰、战舰的投影、敌舰、敌舰的投影、飘动的云朵、射击的子弹、爆炸的焰火等。例如战舰的变化特性定义如下:
首先定义组成战舰的图片序列变化方式,即战舰在做不同运动姿态时图片序列的播放方向、起始帧、播放速度、播放模式等。其中DoMirror控制是否将动画序列中的单帧图片进行水平翻转,APlayMode控制正向或反向播放图片序列。
procedure TCustomShip.SetAnim(DoMirror: Boolean; APlayMode: TAnimPlayMode);
begin
MirrorX := DoMirror; //在x方向翻转战舰
AnimStart := 0; //从序列的第0帧开始播放
AnimPlayMode := APlayMode;
AnimCount := 4; //播放4侦图片
AnimSpeed := 0.15;//播放速度
DoAnimate := True;
end;
其次定义在玩家的交互下,战舰的变化特性。即战舰根据用户交互动作的不同,产生不同的运动效果,在本款游戏中,主要是利用方向键控制战舰的运动,实现的核心代码如下:
procedure TCustomShip.Move(const MoveCount: Single); //战舰通用类的移动控制
begin
inherited;
if MainForm.Keyboard.Key[205] then //如果按下的是键盘上的右方向键
begin
X := X + FMoveSpeed; //战舰向右移动
if X > 560 then X:=560; //移动到右边界处停止向右运动
if Trunc(AnimPos) = 0 then //从图片序列的第0帧开始
SetAnim(False, pmForward); //不翻转、正向播放动画序列
end;
if MainForm.Keyboard.KeyReleased[205] then //如果释放右方向键
SetAnim(False, pmBackward); //翻转、反向播放动画序列
if MainForm.Keyboard.Key[203] then //如果按下的是键盘上的左方向键
begin
X := X - FMoveSpeed;
if X < -50 then X:=-50;
if Trunc(AnimPos) = 0 then
SetAnim(True, pmForward);
end;
if MainForm.Keyboard.KeyReleased[203] then //如果释放左方向键
SetAnim(True, pmBackward);
if MainForm.Keyboard.Key[200] then //如果按下的是键盘上的上方向键
begin
Y := Y - FMoveSpeed; //战舰向上运动
if Y < -40 then Y := -40;
end;
if MainForm.Keyboard.Key[208] then //如果按下的是键盘上的下方向键
begin
Y := Y + FMoveSpeed; //战舰向下运动
if Y > 380 then Y := 380;
end;
end;
当用户按下右方向键时,通过调整图片序列的播放,机身向右倾斜,释放右方向键后,机身又会有一个向左倾斜的调整姿势,运动姿态非常逼真。
3.精灵的初始化
精灵的初始化是指创建精灵并设置精灵参数。包括设定精灵实例化后在屏幕上的初始坐标、显示效果等,例如游戏开始后,战舰本身及其投影是静止悬浮在屏幕的下部,尾焰不断喷射效果的初始化如下:
constructor TShip.Create(const AParent: TSpriteEngine); //重构Create方法
begin
inherited;
X := 300; //战舰出现的横坐标
Y := 300; //战舰出现的纵坐标
ScaleX := 0.5; //战舰图片序列在x方向上以原图片的0.5倍的大小出现
ScaleY := 0.5;
MoveSpeed := 2;
ImageName := 'ship4'; //图片序列名称
Animlooped:=False; //不循环播放图片序列
Shadow := TCustomShip.Create(MainForm.ShipEngine); //在显示战舰的同时显示战舰的投影
Shadow.X := 300; //战舰投影出现的横坐标
Shadow.Y := 250;
Shadow.ScaleX := 0.4;//战舰投影在x方向上以原图片的0.4倍出现,比战舰略小增强立体感
Shadow.ScaleY := 0.4;
Shadow.MoveSpeed := 1.2; //战舰投影速度低于战舰速度以体现战舰的加速度效果
Shadow.Red := 0; //战舰投影图片是由战舰图片的RGB变为000后改变透明度实现
Shadow.Green := 0;
Shadow.Blue := 0;
Shadow.Alpha := 80;
Shadow.ImageName := 'ship4';
Tail := TTail.Create(MainForm.ShipEngine); //在显示战舰的同时显示战舰的尾焰
……………
…………..
end;
4. 游戏功能的渲染实现
前期准备工作完成后,就进入到怎么把以上的定义在计算机屏幕上按照预定的设计正常显示的环节。Asphyre3.1引擎的工作思路非常清晰:首先FormCreate初始化游戏窗体,然后DeviceInitialize初始化游戏引擎设备,接着开始在时间控件TimerTimer事件的控制下循环调用DeviceRender和TimerProcess,程序员的主要工作就是在DeviceRender过程中写画图代码,在TimerProcess过程中写逻辑代码:
procedure TMainForm.FormCreate(Sender: TObject);
begin
if (not Device.Initialize()) then //在主窗体创建时初始化DX引擎设备
begin
MessageDlg('Unable to initialize device!', mtError, [mbOk], 0);
Close();
Exit;
end;
Randomize;
Screen.Cursor := crNone; //在屏幕上不显示鼠标指针
ShipEngine := TSpriteEngine.Create; //产生动画精灵引擎
ShipEngine.Canvas := MyCanvas; //为动画精灵指定画布
ShipEngine.Image := Images; //为动画精灵引擎制定图片资源
Ship := TShip.Create(ShipEngine);
Ship.Z := -5; // Z轴坐标,主要控制对象在Z轴上的层次关系
BackX := -100;
end;
procedure TMainForm.DeviceInitialize(Sender: TObject; var Success: Boolean);
//初始化DX引擎设备
begin
Success := Images.LoadFromASDb(ASDb); //从定义好asdb文件导入图片资源
if (Success) then //如果图片导入成功,则从该asdb文件导入字体资源
Success := Fonts.LoadFromASDb(ASDb);
Timer.Enabled := Success; //所有导入工作结束后,启动控制时钟
end;
procedure TMainForm.TimerTimer(Sender: TObject);
begin
Device.Render(0, True); //渲染
Timer.Process; //按固定频率调用TimerProcess过程
Device.Flip(); //将显存的的内容,也就是程序画好的图像翻转到屏幕上
end;
procedure TMainForm.DeviceRender(Sender: TObject); //渲染
begin
Keyboard.Update; //检测键盘按键事件
MyCanvas.DrawPortion(Images.Image['jungle'], 0, BackX, 0, 0, Y1, 800, 1024 + Y2, clWhite4, fxNone); //将背景图像的一部分画到屏幕上
Y1 := Y1 - 1;
Y2 := Y2 + 1;
CreateEnemy; //在屏幕上产生敌舰
CreateCloud; //在屏幕上产生云
ShipEngine.Move(1); //检测精灵的移动
ShipEngine.Dead; //检测在循环中被标注的需要释放的精灵,在这里正式被释放
ShipEngine.Draw; //渲染精灵
ShipEngine.Collision; //检测碰撞
if MainForm.Keyboard.Key[205] then //通过方向键控制背景的移动
BackX := BackX - 0.25;
if MainForm.Keyboard.Key[203] then
BackX := BackX + 0.25;
Fonts[0].TextOut('Press " Ctrl " to shoot', 280, 450, $FF00FF00);
//在屏幕的(280,450)处以$FF00FF00色显示提示字体
end;
procedure TMainForm.TimerProcess(Sender: TObject);
var
i: Integer;
Bullet: TBullet;
begin
if MainForm.Keyboard.Key[29] then //按CTRL键发射子弹
begin
for i := 0 to 1 do
begin
Bullet := TBullet.Create(ShipEngine);
Bullet.DoCollision := True;
Bullet.CollideMethod := cmRadius;
Bullet.CollideRadius := 5;
Bullet.MoveSpeed := 7;
Bullet.DoCenter := False;
Bullet.X := ship.X + 43;
if i = 1 then Bullet.X := Ship.X + 58; //左右开火
Bullet.Y := ship.Y + 10;
Bullet.ImageName := 'Bulletr'; //子弹的图片序列
Bullet.DrawFx := fxAdd;
Bullet.ScaleX := 0.1;
Bullet.ScaleY := 0.15;
Bullet.MirrorY := True;
end;
end;
end;
最后完成游戏窗体关闭时释放设备、内存的操作。
procedure TMainForm.FormDestroy(Sender: TObject);
begin
Device.Finalize(); //在主窗体关闭时释放设备
end;
三、结语
以上就是利用Delphi7+Asphyre3.1开发空战小游戏的流程,整个程序在Delphi7+Asphyre3.1环境下调试通过。这款空战小游戏的开发涉及了游戏开发的基本环节,是Delphi游戏编程初学者比较理想的学习代码。在这个游戏的基础上加上声音、网络控制等就可以实现简单的网络游戏对战。 Asphyre游戏引擎现在已经更新到版本4,注入了更多新的游戏设计思想,相信将会有越来越多的人参与到Asphyre的研究和开发中来。
|