admin 管理员组

文章数量: 1086019


2024年4月27日发(作者:selectedindex怎么设置)

坦克项目总结

一、需求分析:

要实现一个坦克大战游戏。游戏中包括我方坦克、对方坦克、障碍物(可摧

毁的墙、不可摧毁的墙、草地、水面)、我方的基地。双方坦克都不能穿越

除草地以外的障碍物;游戏的玩家通过键盘控制我方坦克的前进、后退、向

左、向右移动;对方坦克可以在窗体内自主移动,撞墙或边界后自动改变方

向;我方坦克与对方坦克都可以发射子弹,双方坦克被敌对方的子弹打中都

会有火花产生,被子弹打中后我方坦克生命值减1并且回到初始位置,对方

坦克被移除;双方子弹打到墙上都有火花产生,打中后子弹被移除,可摧毁

的墙被子弹打中后也会被移除;双方子弹移出窗体后被移除;当我方坦克生

命值减为0或我方基地被摧毁,玩家输,游戏结束;当对方坦克全部被子弹

打中,玩家赢,游戏结束。

二、游戏的设计图

游戏中的类及类的关系

三、游戏效果图 :

游戏主体图

游戏结束提示1 游戏结束提示2

游戏结束提示3

四、游戏设计中的问题:

1、我方坦克的绘制及移动问题

问题描述:

创建我方坦克,使其在主窗口中显示出来;按下不同的

键,画出不同方向的我方坦克,然后我方坦克向不同方

向移动。

解决方法:

我方坦克的属性继承于坦克,所以我们现在父类Tanke中

完成坦克的属性(高度,宽度,速度和位置);

在My Tanke类中添加一个构造函数,在构造函数中添加

我方坦克的位置;

public MyTanke()

{

_Location = new Point(300, 600);

}

在主程序中添加一个paint的刷新窗体的事件,在paint方

法中绘制我方坦克;

void GameManager_Paint(object sender, PaintEventArgs e)

{

_(cs);

}

在Tank抽象类中,定义Direction,然后在我方坦克的属性

中定义坦克的四个方位,当我们按下不同的键时,改变我

方坦克的方向;

在MyTanke的Draw方法中,根据传过来的方向,画出不

同方向的我方坦克;

同样,在MyTanke的Draw方法中,根据传过来的方向,

解决我方坦克的移动问题。

2、敌方坦克的绘制、自动移动及自动转向问题

问题描述:

创建对方坦克,使对方坦克自行移动,并能够自

行随机转换方向

解决方法:

在主线程中创建一个线程来创建对方坦克,X坐标取0—

950之间的随机数,Y坐标取0—60之间的随机数,然后

创建一个泛型集合,把创建的坦克加入其中;

在主程序的Draw方法中,绘制对方坦克,用for循环;

for (int i = 0; i < _; i++)

{

_ListOtherTanke[i].Draw(cs);

}

我们所创建的对方坦克只有一类,因为有不同方向需插入

不同图片,只需在对方坦克的Draw方法中,根据

Direction的不同Draw出不同图片;

创建一个线程来让对方坦克在移动过程中可以随机转换

方向;

Random random = new Random();

int tankeNum = (1, 5);

OtherTanke otherTanke = null;

int _direction = (1, 5);

对方坦克Move的方向各不相同,所以需要在它们各自的

Move方法中进行相应的设置;

在主线程中添加一个MoveTanke的线程。

void MoveOtherTanke()

{

while (1 == 1)

{

OtherTanke otherTanke = null;

for (int i = 0; i < _; i++)

{

otherTanke = _ListOtherTanke[i];

if (otherTanke != null)

{

();

}

}

(50);

h();

}

}

3、基地、障碍物的绘制问题

问题描述:

创建我方基地,并在窗体中绘制出来,根据基地位置,在

其周围绘制保护基地的障碍物(RuinedWall),设计不同障

碍物在窗体中的位置并绘制出来。

解决方法:

在Base类中定义基地的属性,并添加一个构造函数,在构

造函数中添加我方基地的位置;

public Base()

{

_width = 30;

_height = 30;

_Location = new Point(450, 620);

}

在主程序的Paint事件中绘制我方基地;

在父类Wall中定义障碍物的属性,在构造函数中定义障碍

物的长和宽,在Draw方法中绘制障碍物;

在Bankground类中定义障碍物的泛型集合,并在

Bankground的带参构造函数中,用多个for循环创建障碍

物,然后将其加入泛型集合中。

4、我方子弹的创建及移动问题

问题描述:

创建我方子弹,在按下F键的时候,根据我方坦克方向

的不同,我方坦克向不同方向发射子弹,子弹被发射后

能够自行移动。

解决方法:

在Bullet抽象类中创建子弹的属性(宽度,高度,位置,

速度,方向)及方法(绘制、移动);

在子弹的默认构造函数中定义它的宽度和高度;

public Bullet()

{

_height = 9;

_width = 9;

_speed = 15;

}

在带参(位置)的构造函数中定义它的位置,在绘制方

法中把子弹绘制出来;

在Move方法中(因为移动方法继承于抽象类所以void

前面需要加上override)定义在不同的方向上的不同的

x,y坐标变化。用一个switch语句;

public override void Move()

{

switch (_direction)

{

case 1:

_location.Y = _location.Y - _speed;

break;

case 2:

_location.Y = _location.Y + _speed;

break;

case 3:

_location.X = _location.X - _speed;

break;

case 4:

_location.X = _location.X + _speed;

break;

default:

break;

}

我方子弹由我方坦克发射,在我方坦克的Fire方法中定

义我方子弹的位置,并且返回值为子弹:public override

Bullet Fire().定义两个变量来表示子弹位置的x和y坐标,

用一个switch循环,当坦克位于不同的方向时,子弹总

是从中间的位置处出来;

public override Bullet Fire()

{

int x = 0;

int y = 0;

Bullet myBullet = null;

switch (_Direction)

{

case 1:

x = _Location.X + _width / 2;

y = _Location.Y;

break;

case 2:

x = _Location.X + _width / 2;

y = _Location.Y + _height ;

break;

case 3:

x = _Location.X - 10;

y = _Location.Y + _height / 2;

break;

case 4:

x = _Location.X + _width;

y = _Location.Y + _height / 2;

break;

default:

break;

}

Point myBulletLocation = new Point(x, y);

myBullet = new MyBullet(myBulletLocation, _Direction);

return myBullet;

}

在主程序中定义一个my bullet的泛型集合,在key down事件

中,添加一个当我们按下F键时,我方子弹发射;

if (e == Keys.F)

{

if (e == Keys.F)

{

MyBullet myBullet = new MyBullet();

myBullet = (MyBullet)_();

_(myBullet);

}

h();

}

添加一个Move Bullet 的线程,在线程中定义个死循环来不

停的使子弹移动;

void MoveBullet()

{

while (1 == 1)

{

Bullet bullet = null;

for (int i = 0; i < _; i++)

{

bullet = _listMyBullet[i];

if (bullet != null)

{

();

}

}

(100);

}

}

在主程序的Paint事件中绘制我方子弹;用for循环;

for (int i = 0; i < _; i++)

{

_listMyBullet[i].Draw(cs);

}

5、对方子弹的创建及移动问题

问题描述:

创建对方子弹,根据我方坦克方向的不同,对方坦克自动

向不同方向发射子弹, 子弹被发射后能够自行移动。

解决方法:

在Other Tank中,定义默认构造函数和带参(位置和方向)

构造函数,在Move方法一样根据方向的不同来设定子弹不

同的x,y坐标变换;

在Other Tank中的Fire方法中,创建对方子弹的位置;

public override Bullet Fire()

{

int x = 0;

int y = 0;

Bullet OtherBullet = null;

x = _Location.X + _width / 2;

y = _Location.Y + _height / 2;

Point OtherBulletLocation = new Point(x, y);

OtherBullet = new OtherBullet(OtherBulletLocation, _Direction);

return OtherBullet;

}

在主程序中创建一个创建子弹的线程,在这个线程中写创

建子弹的代码;

void CreateBullet()

{

while (1 == 1)

{

OtherBullet bullet = null;

for (int i = 0; i < _; i++)

{

bullet = (OtherBullet)_ListOtherTanke[i].Fire();

= ng();

_(bullet);

}

h();

(2000);

}

}

添加一个Move OtherBullet 的线程,在线程中定义个死循

环来不停的使子弹移动;

在主程序的Paint事件中绘制对方子弹;

6、撞击事件问题

问题描述:

我方坦克撞墙,我方坦克不能再移动,需改变方向才能够

再移动;对方坦克撞墙,自动改变方向;我方子弹打中对

方坦克,我方子弹及对方坦克被移除,有火花产生;对方

子弹打中我方坦克,对方子弹被移除,我方坦克生命值减

一,回到初始位置,有火花产生;双方子弹打中RuinedWall,

子弹及RuinedWall被移除,有火花产生;双方子弹打中

NotRuinedWall或Water,子弹被移除,有火花产生;

解决方法:

1)我方坦克与墙的撞击:当我方坦克与墙相撞时,我方坦

克停止移动,只有改变它的方向,它才会继续移动;

A)在坦克的抽象类中,定义一个方法:

public Rectangle GetRect()

{

return new Rectangle(_Location, new Size(_width, _height));

}

B)在我方坦克的Move方法中,由于Direction的不同,它

们所对应的Location也不同,当Direction向上时(即

Direction==1时):

Rectangle selfrec = GetRect();

if (_Direction == 1)

{

_Location.Y -= _speed;

for (int i = 0; i < nagerObj._; i++)

{

Rectangle ruinedwallrec = nagerObj._inedwall[i].GetRect();

if (ectsWith(ruinedwallrec))

{

_Location.Y = _Location.Y + _speed+10;

}

}

}

我方坦克撞NotRuinedWall及Water时方法类似;

Direction不同时,我方坦克的撞墙事件方法类似;

2)其他的碰撞事件与以上的碰撞事件都类似,只是具体细节略

有不同;

3)需要注意的是:对方子弹打到我方坦克时,我方坦克会在起

始位置重新绘制,我们需要在我方坦克的属性中添加一个生

命值,并对生命值赋予初值,当我方坦克被击中时,生命值

减1,当我方基地被击中时,生命值也会减1,当我方生命值

被减到0时,再次被击中就会导致游戏的结束;

void OtherBulletHitMyTanke(OtherBullet otherBullet)

{

_--;

if (_ == 0)

{

("Game Over,你输喽~ !");

rentProcess().Kill();

}

}

4)当我方坦克把对方的坦克全部消灭掉时,我们就赢得了这个

游戏;

if (_ == 0)

{

("哇塞!你赢喽!");

rentProcess().Kill();

}

五、 用到的知识点

委托:

在实现敌方子弹打中东西和我方子弹打中东西的处理中都用到了

委托,都在主窗体中分别定义相应的方法来等待被调用。

委托实质上是一个类,委托的实例化就是一个包装好的方法。

事件:

游戏中使用了KeyDown事件和Paint事件

void GameManager_KeyDown(object sender, KeyEventArgs e)

void GameManager_Paint(object sender, PaintEventArgs e)

事件是当有动作发生或状态改变时,类发出的信息或通知;

产生事件的类(发出通知的类)叫事件源sender,接受事件的类

叫做事件接收者receiver;

线程:

在敌方坦克的创建和移动、子弹的创建和移动、敌方坦克方向的

改变、窗体的刷新分别有一个线程来实现;

线程的创建:

Thread RefreshThread = new Thread(new ThreadStart(RefreshFrmMain));

();

线程的开启:

();

线程所要实现的方法:

RefreshFrmMain(){}

泛型集合:

我方子弹、地方子弹、敌方坦克、障碍物都分别装在不同的集合

中以方便调用;

泛型集合时创建一个集合,这个集合只能存储所规定的类型的数

据,在取值时不需要进行强制类型转换;

private List _listMyBullet = new List();


本文标签: 坦克 子弹 对方 移动 创建