程序下载
介绍:
这是一个我提供的紧凑的框架。
我喜欢那种传统的泡泡龙之类的游戏。简单,而且好玩。许多不同的版本是可以在许多平台上运行的,但是我看到的唯一一个掌上电脑的版本不是开源的。所以我自己建立了一个基于.net框架的紧凑结构游戏。我从四月开始该项目,当我看到有一个该方面的讨论,到了四月低,还没有完成。只有功能,没有图象,只有随机的游戏等级。好在,其他人做了改进,所以我有时间推进该项目。不管怎样,许多事可以进一步改进:
更好的图象(还不完善,泡泡看上去还不太好看,)
一些声音
积分系统
游戏等级控制
更多的级别(事例等级是由notepad建立。这很容易等级编辑器已经完成!)
添加特别的泡泡(爆炸,多种颜色,或其它)
也许用GAPI来增进动画速度(很少有这种机会)
一个出色的网络多用户版本(也许是v2.0或v3.0)
更糟的是我现在还没有一个掌上电脑,在项目初期从老板那借了一个,就是为了看看动画的速度是否合适,然后我只是用模拟器,所以我希望在一个真的掌上电脑环境下是否运行良好,在游戏菜单上,可以找到一个'Constant frame rate'进入按钮,如果游戏速度很慢可以调整。
游戏规则:
主导思想是基于泡泡龙游戏:游戏的主要意图是清除所有的泡泡。你有一个时间限制来发射泡泡。泡泡会粘住第一个遇到的泡泡。如果相邻的泡泡的颜色相同并超过3个,就炸掉,所有粘在其上的泡泡也会凋落。泡泡的层级会每8秒增加一层。当底层接触到发射器后游戏就结束。
使用代码:
这里有一些类,实现游戏的所有部分:
BubbleGame :是游戏的主类,包含所有高等级的特征和游戏逻辑(其中许多使用‘GO‘方法)
Bubble :该类在游戏界面上显示泡泡,包含一些相关信息如泡泡的类型(颜色),在游戏面板上的位置,泡泡在屏幕上的矩形区域。
BubbleImages :该类中你可以找到一些静态方法和字段,是类似泡泡图片的缓冲。
LauncherImages :就象BubbleImages类,该类用来显示图片。
BubbleSprite :实现移动泡泡(玩家泡泡,和用来下落和爆炸的泡泡),该类跟踪每个泡泡的方向和路径,使在屏幕上的位置和在游戏面板上的位置一致。
MovingSprites :该类处理所有泡泡在移动时的爆炸和下落。
GameBoard :该类提供游戏面板。拥有调用层级方法,检测玩家泡泡的碰撞事件,检测相邻泡泡和下落泡泡,检测层级是否接触底线。有个'CreateBoardBitmap '方法用来建立游戏面板的位图(完整的背景,墙体,拼图,和锁定的泡泡)。该位图在缓存并在整个游戏过程中使用(通过BubbleGame类)作为背景,我们只需要在不同角度和距离上绘制泡泡图片。
AngleHelper :该类用来计算玩家泡泡的角度和距离。
GraphicsHelper :该类包含静态成员,由不同的GDI方法使用(其中一些用于测试目的)。
GXInput :该类来自一个MSDN的游戏项目,该类注册所有的掌上电脑的硬件信息,这是很重要的。这样当你按了一个按钮后,在游戏窗口的将运行一个相应程序。
感兴趣的几个方面:
首要问题是,控制按钮比相关的窗口事件更精确。
好在,在'coredll.dll'中有个函数解决类似问题:
[DllImport("coredll.dll")]
public static extern int GetAsyncKeyState(int vkey);
We can use this function in the main game loop (the 'Go' method of the 'BubbleGame' class):
if ((GetAsyncKeyState((int)System.Windows.Forms.Keys.Left) & 0x8000) !=0)
angle+=2; //x--;
if ((GetAsyncKeyState((int)System.Windows.Forms.Keys.Right) & 0x8000) !=0)
angle-=2; //x++;
该技术在项目的开始使用到,当时,我读了一些关于游戏开发方面不错的文章在MSDN上,是在掌上电脑上用.net做开发,作者讲了另一种观点:截取硬件点击,这些按键作为热键:直接运行或激活一个软件。在不断的使用中是很有效的,但在游戏中却另人苦恼,因为在游戏中我们用这些按键做一些特殊的功能。可是我们有不能没有DllImport和P/Invoke。这样便引用了GXInput:这里给出MSDN上这篇文章的网址(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/html/WrapGAPI3.asp),注册硬件按键,并在程序中使用!事实上GXInput除了注册按键还做了其它事情,但自从我把它添加到项目里以来还没用到其它功能。
另外,我必须围绕一个奇怪的问题工作:在游戏的主框架里,我想要有一个菜单在左上角显示按钮。框架自身定义了填充整个屏幕(MinimizeBox=false, MaximizeBox= false, WindowState= Maximized)。。没有菜单,框架象希望的那样被显示出来,但是,我一添加菜单,窗口就不再是全屏模式了(标题,和开始菜单出现,设置了控制框也不行)为了解决该问题,我添加了一个按钮在框架左下角,当我点击该按钮会显示菜单。
层级设计:
层级设计是保存在一个文本文件中(我建立了一个'codeproject.lvl'文件,并设置了10个层级),你可以建立你自己的层级,通过编辑该文件,我建立一个新的(必须用.LVL 做扩展名),然后拷贝到游戏目录里,然后你可以在菜单里选择它。
[Level]
06,06,08,08,02,02,03,03
06,06,08,08,02,02,03,00
02,02,03,03,06,06,08,08
02,03,03,06,06,08,08,00
每个层级设计用'[Level]'开始,然后,有一系列的数字指定泡泡的颜色。
00 = no bubble
01 = Black
02 = Blue
03 = Green
04 = Magenta
05 = Orange
06 = Red
07 = White
08 = Yellow
每行可以安排8个泡泡,可以安排10行。以后的版本会有一个层级编辑器。
这是怎样做到的?
GameBoard类包含泡泡的数组:
private Bubble[][] gameBoard = new Bubble[GRID_X_SIZE][];
Each Bubble has a kind (a color) and a position on grid, those bubbles are created in the LoadLevel method of the GameBoard class.
int[,] BubbleData= this.GetLevelData(LevelFile,LevelNum);
for (int x=0;x<GRID_X_SIZE;x++)
for (int y=0;y<GRID_Y_SIZE;y++)
{
if (x!=GRID_X_SIZE-1 || y%2==0)
{
if (BubbleData[x,y]!=0)
this.gameBoard[x][y] = new Bubble(x,y,(BubbleKind)BubbleData[x,y]);
}
}
每当泡泡建立时,构造器指明它的位置,种类。从在网格的位置,可以计算它在屏幕的位置(在屏幕上一个矩形包含一个泡泡)。Bubble类的UpdateBubbleRectangle方法更新矩形所需的信息:
public void UpdateBubbleRectangle()
{ this.bubbleRectangle = new Rectangle(
(int)((this.gridX*this.bubbleBitmap.Width)+
GameBoard.X_POS_OFFSET +((this.bubbleBitmap.Width/2)
* (this.gridY%2))),
(int)(this.gridY*(this.bubbleBitmap.Height*GameBoard.ROW_DIST)
+GameBoard.Y_POS_OFFSET),
this.bubbleBitmap.Width, this.bubbleBitmap.Height); }
泡泡在屏幕上的位置保存在一个矩形里:
X位置是被泡泡的GridPosition的X乘上泡泡的宽度得到的,增加GameBoard的X偏移(在游戏面板上),最后增加泡泡的半个宽度仅当这个泡泡在奇数列上。Y位置是用泡泡的GridPosition的Y值乘上泡泡的高度再乘上一个常量(bubbleBitmap.Height*GameBoard.ROW_DIST),所以每列'超出'一点,最后增加GameBoard的Y偏移(偏移会在每次层级下落时改变--这将一次改动8个泡泡的偏移)。
矩形的宽度和高度是泡泡位图的高度和宽度。
当调用了一个层级编辑文件后,GameBoard类的CreateBoardBitmap()被调用并返回一个位图对象。作为游戏的背景,用一个简单的背景图片加上当前的泡泡图片。整个背景将被刷新当玩家的泡泡碰上游戏中的泡泡时,这时可能有的泡泡会爆炸或下落。
public Bitmap CreateBoardBitmap()
...
for (int x=0;x<GRID_X_SIZE;x++)
for (int y=0;y<GRID_Y_SIZE;y++)
{
oneBubble= this.gameBoard[x][y];
if (oneBubble!=null)
{
oneBubble.UpdateBubbleRectangle();
// update the bubble rectangle in case of board shift down
gameBoardGraphics.DrawImage(oneBubble.BubbleBitmap,
oneBubble.BubbleRectangle,0,0,
oneBubble.BubbleBitmap.Width, oneBubble.BubbleBitmap.Height ,
GraphicsUnit.Pixel,
BubbleImages.GetTranspImageAttr());
}
}
...
return gameBoardBitmap
在这个‘完整背景’上发射器和玩家的动画被显示出来(就象下落和销毁的泡泡)。BubbleSprite类负责处理玩家的泡泡动画。该类有一个BubbleRectangle属性返回泡泡的矩形区域。(就象Bubble类一样,该属性被用来在屏幕上显示动画)。它同时有一个PositionOnGrid属性,返回动画的一个点信息。(相对于Bubble类的UpdateBubbleRectangle方法,这主要用来做碰撞检测)。
这种检测在每次玩家的泡泡移动时发生,但是是在两种状态下完成:
第一,我们需要知道是否有一个或几个泡泡在玩家的泡泡周围。通过当前泡泡的相邻信息来完成检测。这就是PositionOnGrid方法的作用,同时GameBoard类的一个GetNeighbors方法,返回一个相邻泡泡信息的数组列表。
第二,在玩家泡泡周围至少有一个泡泡,我们需要更精确的碰撞检测在玩家泡泡和相邻泡泡之间。这是GameBoard类的CheckSpriteCollision方法实现的。
以下测试是用来计算玩家和相邻泡泡之间的距离:
dist = (Sprite.BubbleRectangle.X-OneBubble.BubbleRectangle.X)
*(Sprite.BubbleRectangle.X-OneBubble.BubbleRectangle.X)+
(Sprite.BubbleRectangle.Y-OneBubble.BubbleRectangle.Y)*
(Sprite.BubbleRectangle.Y-OneBubble.BubbleRectangle.Y);
如果距离是小于一个指定的值,玩家泡泡必须被添加到游戏面板上。
添加完以后,需要检测该泡泡是否被至少两个泡泡连接,如果是这样,这些泡泡必须销毁。用GameBoard类的GetSameKindNeighbors方法来实现。通过调用每个泡泡的GetNeighbors方法。一旦所有相同种类的相邻的泡泡在玩家周围被检测到,就从游戏面板上移除然后添加到MovingSprites。该方法用来跟踪下落或爆炸的泡泡,并用动画显示。
如果有一些泡泡被销毁,我们需要检测是否他们从游戏面板上的泡泡上消失。游戏中其他保留的泡泡是用从每列开始的泡泡的GetNeighbors递归调用实现的,所以我们确认这些泡泡应该保留在游戏面板上。GameBoard类的GetFallingBubbles()方法的一种检测方式。其余的泡泡将被清除掉,然后添加到MovingSprites,用来做下落的动画效果显示。
除了这些,没什么特别的了:双缓冲用来消除抖动(有许多文章介绍这种技术,所以我也拿来使用),用GDI来绘出图片和动画。
结束语:
我希望有更多的时间来完成该游戏,再增加一些更好的特性,想网络功能,或特殊的泡泡等。我不知道什么时候v2.0会更新,如果有的话。我是用模拟器开发的,因为我没有掌上电脑,希望参加这个讨论能获得好成绩(可能会有其它更好的作品)。如果在掌上电脑上测试该游戏的玩家请提出意见,这样我可以继续调整代码,多谢!