转载请标明是引用于 http://blog.csdn.net/chenyujing1234
例子代码:
玩家操作一辆坦克,必须消灭所有电脑控制的10辆敌军坦克。本游戏的背景墙砖为金属,不可以被击毁。在游戏中,玩家通过键盘的方向键控制己方坦克的行进方向,并可以按空格键发射子弹,当对方坦克被中,产生爆炸图案和音效。如果玩家的坦克被销毁或敌方坦克全部被击毁,游戏便告终止。游戏运行界面如图11-1所示。
程序设计的思路
A、
游戏画面看成10*10的方格,窗体中Map[10, 10]保存游戏砖块位置的地图,其中0代表空地,1代表墙砖。TMap[10, 10]保存坦克位置和砖位置的地图,其中0代表空地,1代表墙砖;2到5为敌方坦克,6为己方坦克。游戏面板重画时,TMap保存的信息传入,便于判断子弹是否击中坦克和墙砖。
B、
游戏画面的刷新采用2个定时器控件timer1和timer2。timer1控件定时控制敌方坦克的移动并刷新游戏面板,timer2控件定时产生新的敌方坦克直到达到敌方坦克最大量。
1.
坦克类
Tank
设计
——
重点讲解
A、
坦克类Tank:游戏中,主要角色是坦克,设计的坦克类Tank需要实现坦克发射子弹,显示坦克图案,坦克爆炸,改变方向,产生子弹,控制子弹的移动功能。
定义以下描述坦克特征的字段。
private int width; //坦克的宽度
private int height; //坦克的高度
private int top; //坦克位置的纵坐标
private int left; //坦克位置的横坐标
private int type; //坦克的类型(2---5敌方,6己方)
private int direct; //0--上,1--下,2--左,3--右
public ArrayList bList=new ArrayList();//子弹序列
B、
每辆坦克发射的子弹序列采用
ArrayList
列表数组
bList
,可以动态的增删。
坦克类Tank构造函数
坦克类Tank构造函数,随机产生坦克的方向代号以及坐标,类型代号由参数传入。
public Tank(int tank_type)//构造函数
{
Random r = new Random();
this.direct = r.Next(0, 4);//产生0—3的数
this.width = 32;
this.height = 32;
this.left = r.Next(0, 10);//产生0—9的数
this.top = r.Next(0, 10);//产生0—9的数
this.type = tank_type;
}
设计访问坦克的5个私有字段的相应属性
设计访问坦克的宽度,高度,位置坐标,类型,方向5个私有字段的相应属性。用private会使得它们不能被类外访问,于是就设计了有可供外部访问相应属性,以使得那些不能和外界接触的变量有被访问渠道。
public int Top//Top
属性
{
get
{
return top;
}
set
{
if (top >= 0 && top <= 9)
{
top = value;
}
}
}
public int Left//Left属性
public int Type//坦克的类型属性
public int Direct//Direct属性(坦克方向)
改变坦克移动方向
当坦克遇到障碍物时,需要改变方向。newDirect()方法根据随机产生新的坦克移动方向。
public void newDirect()
{
Random r = new Random();
int new_Direct=r.Next(0, 4);//产生0—3的数
while(this.direct == new_Direct)
new_Direct = r.Next(0, 4);//产生0—3的数
this.direct = new_Direct;
}
//0--
上
,1--
下
,2--
左
,3--
右
绘制坦克在游戏面板中
public void Draw(Graphics g,int type)//根据坦克类型选择不同图片
{
Image
tankImage
= Image.FromFile("BMP/ETANK1.BMP");
if (type == 2) tankImage = Image.FromFile("BMP/ETANK2.BMP");
if (type == 3) tankImage = Image.FromFile("BMP/ETANK3.BMP");
if (type == 4) tankImage = Image.FromFile("BMP/ETANK4.BMP");
if (type == 5) tankImage = Image.FromFile("BMP/ETANK1.BMP");
if (type == 6) tankImage = Image.FromFile("BMP/MYTANK.BMP");
//得到绘制这个坦克图形的在游戏面板中的矩形区域
Rectangle destRect = new Rectangle(this.left * width, this.top * height, width,height);
Rectangle srcRect = new Rectangle(direct * width, 0, width, height);
g.
DrawImage
(
tankImage
, destRect,srcRect,GraphicsUnit.Pixel );
}
Explore(Graphics g)在屏幕上画出坦克爆炸动画
坦克被击中,Explore(Graphics g)在屏幕上画出坦克爆炸动画。
public void Explore(Graphics g)//坦克爆炸动画
{
//得到绘制这个坦克图形的在游戏面板中的矩形区域
Rectangle destRect = new Rectangle(this.left * width, this.top * height, width, height);
Rectangle srcRect = new Rectangle(0, 0, width, height);
Image tankImage = Image.FromFile("BMP/explode1.bmp");
g.DrawImage(tankImage, destRect, srcRect, GraphicsUnit.Pixel);
tankImage = Image.FromFile("BMP/explode2.bmp");
g.DrawImage(tankImage, destRect, srcRect, GraphicsUnit.Pixel);
PlaySound.Play("Sound/Explode.wav");
}
发射子弹
敌我不同坦克,发射不同样式的子弹,发射的子弹加入每辆坦克的子弹序列bList中,如果己方发射子弹并产生发射子弹声音效果。Fire方法实现此功能。
public void fire()
{
bullet b = new bullet(this.type);//根据坦克产生不同子弹
b.Direct = this.Direct;//坦克的朝向
b.Top = this.Top;
b.Left = this.Left;
bList.Add(b);
if(this.type==6) PlaySound.Play("Sound/Shoot.wav");//己方发射声音效果
}
移动子弹
public void MoveBullet(ref int [,]Map)
{
for (int i = bList.Count-1; i>=0; i--)//遍历子弹序列
{
bullet t = ((bullet)bList[i]);
t.move();//移动子弹
if (t.Left < 0 || t.Left > 9 || t.Top < 0 ||t.Top > 9)
//超出边界
{
bList.RemoveAt(i);continue;//删除此颗子弹
}
if (Map[t.Left, t.Top] != 0)//已遇到物体
{
bList.RemoveAt(i); //删除此颗子弹
if (t.hitE(Map[t.Left, t.Top]))//击中对方坦克
Map[t.Left, t.Top] = -1;//此处坦克被打中
continue;
}
}
}
画子弹DrawBullet( )方法
public void MoveBullet(ref int [,]Map)
{
for (int i = bList.Count-1; i>=0; i--)//遍历子弹序列
{
bullet t = ((bullet)bList[i]);
t.move();//移动子弹
if (t.Left < 0 || t.Left > 9 || t.Top < 0 ||t.Top > 9)
//超出边界
{
bList.RemoveAt(i);continue;//删除此颗子弹
}
if (Map[t.Left, t.Top] != 0)//已遇到物体
{
bList.RemoveAt(i); //删除此颗子弹
if (t.hitE(Map[t.Left, t.Top]))//击中对方坦克
Map[t.Left, t.Top] = -1;//此处坦克被打中
continue;
}
}
}
画子弹DrawBullet( )方法
DrawBullet方法中遍历子弹序列,并调用子弹的Draw方法将子弹显示在屏幕上。
public void DrawBullet(Graphics g, int[,] Map)//画子弹
{
MoveBullet(ref Map);
foreach (bullet t in bList)//遍历子弹序列
t.Draw(g);
}
2.子弹(bullet)类设计
子弹类比较简单,主要完成子弹的移动和在屏幕上的显示。子弹类型type有两种:敌方子弹和己方子弹,从而使用bool类型。
己方子弹值为
true
,
敌方子弹值为
false
。
定义以下描述子弹特征的字段。
private int top; //
子弹坐标(
Top,Left)
private int left;
private int direct;//
子弹行进方向
private int width = 32;
private int height = 32;
private bool type; //
己方子弹
true,
敌方子弹
false
public bullet(int type) // 子弹类构造函数
{
if (type == 6)//己方
this.type =
true;
else
this.type =
false;
}
子弹的显示
n子弹类的Draw方法根据传入的游戏面板图形对象g,在游戏面板根据子弹坐标显示子弹图案。
public void Draw(Graphics g)
{
Image bulletImage;
if (type == true)//己方
bulletImage = Image.FromFile("BMP/missile1.bmp");
else
bulletImage = Image.FromFile("BMP/missile2.bmp");
//得到绘制这个子弹图形的在游戏面板中的矩形区域
Rectangle destRect = new Rectangle(left * width, top * height, width, height);
Rectangle srcRect = new Rectangle(0, 0, width, height);
g.DrawImage(bulletImage, destRect, srcRect, GraphicsUnit.Pixel);
}
子弹移动
n
判断子弹行进方向Direct,修改坐标值。子弹行进方向是坦克在发射子弹时设置的,和坦克的行进方向一致。坦克的方向上下左右分别用数字0,1,2,3表示,子弹的方向同样表示。例如Direct属性值为0,表示向上行进,所以Top值减1。
public void move()
{
switch (Direct)
{
case 0: //向上
Top--; break;
case 1:
Top++; break;
case 2:
Left--; break;
case 3:
Left++; break;
}
}
判断是否击中对方坦克
public bool hitE(int tanktype)//是否击中对方坦克
{
if (type == false)//
敌方子弹
if (tanktype >= 2 && tanktype <= 5)//
敌方
坦克
//坦克的类型(2---5敌方,6己方)
return false;
else
return true;
if (type == true)//
己方子弹
if (tanktype == 6)//坦克的类型(2---5敌方,6己方)
return false;
else
return true;
return false;
}
4.游戏窗体类设计
下面讲解游戏窗体代码
窗体Load的事件
窗体Load的事件中随机产生背景墙砖图案,保存Map[10, 10]中。同时将己方坦克定位到(4,9)坐标处,行进方向初始化为向上。
private void Form1_Load(object sender, System.EventArgs e)
{
pictureBox1.Width = 10 * width;
pictureBox1.Height = 10 * width;
path = Application.StartupPath;
Random r = new Random();
for(int x=0;x<10;x+=2)
for (int y = 0; y < 10; y+=2)
{
//产生0,1数其中0代表空地,1代表墙砖
Map[x, y] = r.Next(0, 2);
}
Map[4, 9] = 0;
MyTank.Top = 9;
MyTank.Left = 4 ;
MyTank.Direct = 0;
lblX.Text = "X坐标:" + MyTank.Left+" Y坐标:" + MyTank.Top;
}
画游戏墙砖
private void DragWall(Graphics g)//画游戏地图墙砖
{
Image WallImage = Image.FromFile("BMP/TQ.BMP");
for(int x=0;x<10;x++)
for (int y = 0; y < 10; y++)
{
if (Map[x, y] == 1)
{
//得到绘制这个墙砖块的在游戏面板中的矩形区域
Rectangle Rect = new Rectangle(x * width, y * width, width, width);
g.DrawImage(WallImage, Rect);
}
}
}
定时产生新敌方坦克
private void timer2_Tick(object sender, EventArgs e)//定时产生新敌方坦克
{
if (eCount < eMaxCount)//eMaxCount敌方坦克最大量
{
//敌方坦克类型为3,改变此数可以产生不同图案的地方坦克
eTank = new Tank(3);
eTanks.Add(eTank);// eTanks[eCount] = eTank;
eCount++;
}
else
timer2.Enabled = false;//不再产生新的敌方坦克
}
timer1
控件定时控制敌方坦克的移动
timer1控件定时控制敌方坦克的移动并刷新游戏面板。
private void timer1_Tick(object sender, EventArgs e)
{
foreach (Tank t in eTanks)
{
switch (t.Direct)//0--上,1--下,2--左,3--右
{
case 0: //向上……
case 1: //向下 ……
case 2: //向左 …..
case 3:
//
向右
if (t.Left == 9 || Map[t.Left+1, t.Top ] == 1
|| Meet_Tank(t.Left+1, t.Top))//遇到墙砖或坦克
t.newDirect();//坦克转向
else
t.Left++;
break;
}
Random r = new Random();
int fire_bool = r.Next(0, 8);//产生0—7的数
if (fire_bool == t.Direct) t.fire();
}
pictureBox1.Invalidate();//重画游戏面板区域
}
游戏面板
pictureBox1
的
Paint
事件
n游戏面板pictureBox1的Paint事件最复杂。
nPaint事件中完成以下任务:
1.完成修改TMap[10, 10] ,保存墙砖位置
2.完成重画墙砖,
3.画敌方坦克及子弹,
4.画己方坦克和己方子弹。
5.最后根据Tmap数组中某处的值是否为-1,处理坦克爆破。
6.当玩家自己的坦克被击中,timer1控件定时器无效,游戏结束。
7.调用CheckWin()检查是否敌方所有坦克被击毁,如果是则玩家胜利,游戏结束。