DelphiX 游戏教程
当我开始编程的时候为的就是开发游戏。但一段时间以后我放弃了,因为用DELPHI做开发实在不到合适的游戏API来支持。我曾考虑改用C/C++,因为它们有那么多的API支持,例如DirectX和OpenGL。但是对我来说使用那么多API来开发C/C++程序实在我人恐惧。
后来我碰巧遇见DelphiX。它把API封装的简单易用,相当迅速、强大。我非常喜欢它并使用至今,现在我愿意和大家一起分享。
这里并不介绍如何安装DelphiX ,也不会介绍DirectX,因为这会占用太多的文章篇幅。感兴趣想了解这方面知识的人,我推荐你们看看Dominique Louis的文章以及其它Borland 开发社区的文章(1, 2, 3)。
这篇系列教程的基本目标是创建一个基本的游戏引擎。将包括这些主题:建立一个等尺寸的贴图引擎;活动单元和贴图;路径寻、基本的游戏AI、碰撞检测。
这一章将创建一个基本的等角投影贴图引擎,用来从磁盘读取地图。与此相关的编辑器可以从这里下载downloaded here。
开始
首先预览一下下面文章中会遇到的特殊词汇。
TILE:一个具有规则形状的小图片。一个tile不能表现什么,但是大量的tile可以组成某些东西。一般用来生成游戏中的地形。Tile可以有不同的形状。最常用的有菱形、方形和六边性,由于这是一个等投影tile引擎,所以我们使用菱形tile。
TILING ENGINE. 将tile绘制到各自位置的有序代码(一般是过程或者部分过程)。它也要决定拿一个渲染帧被显示。
TILING:设置所有tile到正确位置的过程。也就是tiling 引擎要做的事。
制作一个等投影的地形
这个技巧制作一个等投影的环境,将所有的tile的边相连。此例使用菱形的tile。如果我们简单的将它们一行一行的边边相连放置在一起效果如下所示:
正如你所见,我们创建的只能叫西洋跳棋。图片的透明部分形成巨大的漏洞。边缘没有很好的相连,为什么?这就是我些这篇文章要解决的。
通常的方法是将第一行画好,下一行的起始不是在32象素(tile的高度)而是16象素。也要向左侧偏移32个象素开始。然后每个新行都向上移动16个象素并左移(右移)32个象素。
但这不是全部,你玩Age of empires或AoE2 时一定注意到地图的边缘不是锯齿型,这个地图的形状是菱形。解决的方法是第一行只画一个tile,然后画2个、3个等等, 到某一个点为止。然后开始逐行减少直到为零。这时候你不需要左右来回切换偏移方向,只要在增加的时候向左偏移,减少的时候向右偏移即可。如果做一个3x3 的tile地图看上去如下:
你想为地图增加草和水吗?如果你想知道答案就看这里。如果在地图中增加变化(策略游戏) ,我们就不得不从某些地方将地图加载进来。一个2维的整型数组可以解决这个问题。. 在数组中检测当前的tile是否绘制。可以使用多张地图,在运行期不要重定义。我们将它们存储为文件。在代码中你会看到这是一件简单的事。这篇文章有一个地图编辑器,这是一个非常简单的地图编辑期,用来保持地形数组。你必须下载它并自行编译才能使用。
理论听烦了,下面看看实践吧!
建立一个TILING 引擎
首先,建立一个文件夹用来存放所有的图片和地图文件,以防丢失。
第二步下载图片here。如果你选择使用自己的图片,记住图片一定要是64 pixels宽32 pixels高。
然后下载编辑器,确定安装了DelphiX 后编译编辑器。喝点东西,张舒适的沙发,我们开始吧。
建立一个新的Delphi应用程序。把它保持到图片的目录中。命名为uGame.pas 和Game.dpr。
代码编辑器怎么下载首先建立一个窗体,将窗体申明的类从TForm 改为TDXForm。在对象查看器中设置如下属性。
现在需要一个绘画用的surface。选择TDXDraw 组件,将它拖放在窗口上并设置如下:
下面拖放一个TDXImageList组件用来放置图片,并设置如下:
增加图片的Items属性,(You will figure out how, it's self-explanatory.) ,添加有4个图片,编号0-3。
然后我们需要一个Timer告诉计算机如何绘图。不要使用Delphi自带的Timer,对于游戏来说,它太慢了。DXTimer很快,一次我用两个时钟定时,一个每秒走了19次,一个每秒1200次。拖放一个DXTimer 并设置属性:
下一步我们增加滚屏功能,这一次使用DXInput 组件,属性设置如下:
现在放置一个panel到form上。清除它的caption 字"Panel.",设置Align属性为"alBottom." ,在上面防止一个button。我们将用它来关闭应用程序。
现在拷贝粘贴程序吧!
现在转到代码窗口并加入如下申明到private 段:
procedure DrawTiles(StartX, StartY : Integer);
这个过程用来绘制tiles,是tiling engine。你可以看到,它需要两个值确定从什么地方开始绘制tiles。建立两个如下的类型申明:
Type TTile = Record
TileImage : Integer;
end;
Type TTileMap = Record
Map : array[1..50,1..50] of TTile;
end;
全局变量:
Map : TTileMap;
StartX, StartY : Integer;
这里创建了地图信息,尺寸是50x50 tiles的。我听见你问为什么不建立一个整型数组来代替它?可以,我把它定义成记录,这样以后可以扩展它而不需要改变很多代码。这样增加了系统的灵活性。
在button的onClick 事件写:
Close;
用来退出应用程序。在全屏模式时,我们将不能看到系统菜单和系统按钮。
现在实现我们前面申明的DrawTiles 过程:
procedure TMainForm.DrawTiles(StartX, StartY : Integer);
var PosX, PosY, LoopX, LoopY, XTile, YTile, NumOfTilesY,
TileImage : Integer;
begin
PosY := 0;
PosX := 1;
NumOfTilesY := 1;
for LoopY := 1 to 50 do
begin
XTile := 1;
YTile := LoopY;
for LoopX := 1 to NumOfTilesY do
begin
TileImage := Map.Map[XTile, YTile].TileImage;
TileMaps.Items[TileImage].Draw(DXDraw. Surface,
StartX + PosX + LoopX * 64, StartY + LoopY * 16, 0);
XTile := XTile + 1;
YTile := YTile - 1;
NumOfTilesY := NumOfTilesY + 1;
PosX := PosX - 32;
PosY := PosY + 16;
end;
NumOfTilesY := NumOfTilesY - 2;
PosX := PosX + 64;
for LoopY := 1 to 49 do
begin
XTile := LoopY;
YTile := 3;
for LoopX := 1 to NumOfTilesY do
begin
TileImage := Map.Map[XTile, YTile].TileImage;
TileMaps.Items[TileImage].Draw(DXDraw. Surface, StartX +
PosX + LoopX * 64, StartY + PosY + LoopY * 16, 0);
XTile := XTile + 1;
YTile := YTile - 1;
end;
NumOfTilesY := NumOfTilesY - 1;
PosX := PosX + 32;
end;
end;
这个过程从StartX, StartY坐标开始绘制tiles。TileImage控制当前的tile 进行绘制。它重新计算每一个tile,可以看到,访问这个过程我们需要在DXTimer的: onTimer事件中实现:
if not DXDraw.CanDraw then Exit;
DXDraw.Surface.Fill(0);
Panel.Caption := 'FPS:' + InttoStr(DXTimer.FrameRate);
DrawTiles(StartX, StartY);
DXDraw.Flip;
DXInput.Update;
If isLeft in DXInput.States then StartX := StartX + 16;
If isRight in DXInput.States then StartX := StartX - 16;
If isUp in DXInput.States then StartY := StartY + 8;
If isDown in DXInput.States then StartY := StartY - 8;
第一个过程检测是否能够绘制。然后全黑,清除当前的帧。帧率通过Caption of the panel显示。然后调用DrawTiles 过程,以StartX 和StartY为起始位置进行绘制。然后flips到屏幕。之后更新输入状态,测试按钮状态,调整地图的移动。确保在onCreate 事件for the form中增加如下代码:
StartX := 1;
StartY := 1;
DXTimer.Enabled := True;
支持自定义地图
这就是全部的地图显示。如果要显示自定义地图怎么办?请增加如下的申明:
MapFile : file of TTileMap;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论