坦克游戏的学习及实现

《坦克游戏》相关分析说明及源码

程序目的:

掌握程序设计的基本算法和简单数据结构基础,能够综合运用基本控制语句、算法和数据结构,以及自顶向下、逐步求精的模块化设计方法和面向对象的设计方法,能够设计具有小规模的系统级Java语言程序,提高系统编程能力;

针对计算相关的复杂工程问题,能够使用恰当的算法和数据结构,完成计算、统计、排序、检索、匹配等相关的软件系统的构造、测试与实现;

能够基于面向对象的思想进行程序的设计与实现;

掌握常用的程序调试和测试方法。

程序内容:

设计一个Java坦克闯关游戏,并实现以下功能:

有一个初始游戏界面,为一个简约的panel;

游戏界面字体带有闪烁功能;

设置与缓冲阶段自动播放游戏音频,带有音效;

有一个菜单选项,包含进入或退出游戏选项(开始新游戏(N)、退出游戏(E)、存盘退出游戏(C)、    继续上局游戏(S));

创建游戏用户界面(包含我方与敌方坦克、炮弹、记录数据等元素);

坦克可以发射炮弹,并且可以实现连发(最多连发5发),并且可设置不同类型的坦克,它们攻击力、生命值、速度不同,级别越高的敌方坦克被消灭则玩家获得的分值越高;

敌方坦克之间不会相互攻击;

用户可以通过按键盘的W/S/A/D 4个键控制坦克向上下左右移动,按J键可以使坦克射击;

当游戏方生命值降为0时本局结束;

通用对3张GIF图片进行设置,使得当坦克被击毁时有爆炸的视觉效果;

游戏过程中有暂停选项;

每局游戏可以统计并记录玩家的成绩;

可用记录类对玩家姓名等信息进行记录,并统计各项数据,存盘退出时记录被保存。

 

实验环境:

操作系统:win10

集成开发环境:Eclipse

外部库:该坦克游戏为了优化用户体验设置有音效以及爆炸效果,借助文件流并引用3张图片来实现,所用音频及图片已一并打包放入素材文件夹中。

输入输出设计:

输入数据:

jmil =new JMenuItem("开始新游戏(N)");

jmi2 =new JMenuItem("退出游戏(E)");

jmi3 =new JMenuItem("存盘退出游戏(C)");

jmi4 =new JMenuItem("继续上局游戏(S)");

————进行菜单选项;

 

//画出我的坦克(到时再封装成一个函数)

//1.画出左边的矩形

g.fill3DRect(x, y, 5, 30,false);

//2.画出右边矩形

g.fill3DRect(x+15,y , 5, 30,false);

//3.画出中间矩形

g.fill3DRect(x+5,y+5 , 10, 20,false);

//4.画出圆形

g.fillOval(x+5, y+10, 10, 10);

//5.画出线

g.drawLine(x+10, y+15, x+10, y);

                                            ——————在graficse中输入数据绘制坦克

 

public void keyPressed(KeyEvent arg0) {

// TODO Auto-generated method stub

 

if(arg0.getKeyCode()==KeyEvent.VK_W)

{

//设置我的坦克的方向

this.hero.setDirect(0);

this.hero.moveUp();

 

}else if(arg0.getKeyCode()==KeyEvent.VK_D)

{

//向右

this.hero.setDirect(1);

this.hero.moveRight();

}else if(arg0.getKeyCode()==KeyEvent.VK_S)

{

//向下

this.hero.setDirect(2);

this.hero.moveDown();

}else if(arg0.getKeyCode()==KeyEvent.VK_A)

{

//向左

this.hero.setDirect(3);

this.hero.moveLeft();

}

 

if(arg0.getKeyCode()==KeyEvent.VK_J)

{

//判断玩家是否按下j

 

//开火

//System.out.println("this.hero.ss.size()="+this.hero.ss.size());

if(this.hero.ss.size()<=4)

{

this.hero.shotEnemy();

}

}                    ————玩家操控主函数体,通过A、D、W、S、J等按键进行移动以及攻击

 

输出数据:为int型数据

//画出提示信息坦克(该坦克不参与战斗)

this.drawTank(80,330, g, 0, 0);

g.setColor(Color.black);

g.drawString(Recorder.getEnNum()+"", 110, 350);

this.drawTank(130, 330, g, 0, 1);

g.setColor(Color.black);

g.drawString(Recorder.getMyLife()+"", 165, 350);

                         ——————显示敌方坦克状态

     //画出玩家的总成绩

g.setColor(Color.black);

Font f=new Font("宋体",Font.BOLD,20);

g.setFont(f);

g.drawString("您的总成绩", 420, 30);

 

this.drawTank(420, 60, g, 0, 0);

 

g.setColor(Color.black);

g.drawString(Recorder.getAllEnNum()+"", 460, 80);

 

                             ————————记录显示玩方成绩

该坦克游戏通过对用户输入的限制确保输入数据的合法性,通过public void actionPerformed(ActionEvent arg0)对用户不同的点击作出不同的处理,并且在class MyStartPanel extends JPanel implements Runnable中设置了提示信息,在public MyTankGame3()等函数中进行注册监听,此外,还对发射子弹进行监听,控制最大连续发射子弹数为5,在函数入口处检查了用户输入数据的有效性,函数封装恰当,保证了程序的健壮性;同时通过菜单选项等互动设置、加入音效、增加字体闪烁及坦克爆炸等视觉效果在一定程度上改善了用户体验。

 

系统设计与实现:

系统功能模块划分

对系统进行自顶向下的模块分解,画出系统各个功能模块之间的结构图如下:

坦克游戏的学习及实现

 

函数功能和外部接口设计

本系统总计设计了55个函数,每个函数的功能和接口设计如下表所示:

序号

函数名

函数功能

函数参数

函数返回值

1

main

程序的入口地址

String数组

2

MyTankGame3

启动mp线程、创建菜单及菜单选项、注册监听

3

actionPerformed

对用户不同的点击作出不同的处理并创建战场面板

ActionEvent arg0

4

paint

进行游戏面板提示信息的设置

Graphics g

 

5

run

缓冲与重画设置

6

MyPanel

创建并设置敌方坦克

String flag

7

showInfo

记录显示数据(敌方坦克状态、玩家成绩)等

Graphics g

8

paint

对玩家坦克进行创建设置

Graphics g

9

hitMe

对双方射出的子弹进行记录

10

hitEnemyTank

判断玩家进行的攻击是否有效并核算敌方数据,产生玩家记录

11

hitTank

专门判断子弹是否击中敌人坦克

 Shot s,Tank et

b2

12

drawTank

判断是什么类型的坦克并绘制

int x,int y,Graphics g,int direct,int type

13

keyPressed

对玩家坦克进行设置,使其能够控制移动、是否攻击

KeyEvent arg0

14

keyReleased

每隔100毫秒对坦克进行重绘

KeyEvent arg0

15

keyTyped

每隔100毫秒对坦克进行重绘并判断玩家是否被敌方击中

KeyEvent arg0

16

run

每隔100毫秒重绘面板以免游戏延迟,进行缓冲

17

AePlayWave

控制游戏音效

String wavfile

18

Node

进行二维绘图,帮助实现游戏界面

int x,int y,int direct

19

getNodesAndEnNums

进行读取

nodes

20

keepRecAndEnemyTank

实时根据游戏状态保存当前活的敌人坦克的坐标和方向

21

getRecoring

从文件中读取记录

22

keepRecording

把玩家击毁敌人坦克数量保存到文件中

23

getEnNum

记录剩余数值

enNum

24

getMyLife

记录玩家生命值

myLife

25

setEnNum

记录剩余数值

int enNum

26

setMyLife

计算玩家生命值

int myLife

27

reduceEnNum

记录减少的敌人数

28

addEnNumRec

记录消灭的敌人数

29

getAllEnNum

核算数值信息

allEnNum

30

setAllEnNum

核算数值信息

int allEnNum

31

getEts

读取信息

ets

32

setEts

核算数值信息

Vector<EnemyTank> ets1

33

Bomb

设置炸弹生命

Bomb(int x,int y)

34

lifeDown

控制生命值

35

Shot

记录位置

int x,int y,int direct

36

Tank

设置坦克速度

int x,int y

37

getX

记录坦克x方向速度

x

38

setX

设置坦克x方向速度

int x

39

getY

设置坦克y方向速度

y

40

setY

设置坦克y方向速度

int y

41

getDirect

设置坦克方向

direct

42

setDirect

设置坦克方向

int direct

43

getSpeed

记录坦克速度

speed

44

setSpeed

记录坦克速度

int speed

45

getColor

设置颜色

color

46

setColor

设置颜色

int color

47

EnemyTank

敌方添加子弹

int x,int y

48

setEts

得到MyPanel的敌人坦克向量

Vector<EnemyTank> vv

49

isTouchOtherEnemy

判断是否碰到了敌人的坦克

b/true

50

Hero

设置玩家坦克属性

int x,int y

51

shotEnemy

控制坦克开火攻击

52

moveUp

控制坦克向上移动

53

moveDown

控制坦克向下移动

54

moveLeft

控制坦克向左移动

55

moveRight

控制坦克向右移动

 

 

 

各个函数之间的调用关系如下所示:

坦克游戏的学习及实现

 

类设计

本系统总计设计了12个类,每个类的数据成员和成员函数设计如下所示。

(1)AePlayWave类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

filename

Object

引入文件流

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

run

每隔100毫秒重绘面板以免游戏延迟,进行缓冲

2

AePlayWave

控制游戏音效

String wavfile

 

(2) Node类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

x

int

游戏面板x方向的绘制

自然数

2

y

int

游戏面板y方向的绘制

自然数

3

direct

int

游戏面板方向的控制

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

Node

进行二维绘图,帮助实现游戏界面

int x,int y,int direct

 

(3)Recorder类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

enNum

int

记录每关有多少敌人

自然数

2

myLife

int

设置玩家可以用的人数

自然数

3

allEnNum

int

记录总共消灭的敌人数

自然数

4

nodes

Vector<Node>

从文件中恢复记录点

自然数

5

fw

FileWriter

设置文件流

自然数

6

bw

BufferedWriter

设置文件流

自然数

7

fr

FileReader

读取文件流信息

自然数

8

br

BufferedReader

设置文件流信息

自然数

9

ets

Object

设置敌机信息

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

getNodesAndEnNums

进行读取

nodes

2

keepRecAndEnemyTank

实时根据游戏状态保存当前活的敌人坦克的坐标和方向

3

getRecoring

从文件中读取记录

4

keepRecording

把玩家击毁敌人坦克数量保存到文件中

5

getEnNum

记录剩余数值

enNum

6

getMyLife

记录玩家生命值

myLife

7

setEnNum

记录剩余数值

int enNum

8

setMyLife

计算玩家生命值

int myLife

9

reduceEnNum

记录减少的敌人数

10

addEnNumRec

记录消灭的敌人数

11

getAllEnNum

核算数值信息

allEnNum

12

setAllEnNum

核算数值信息

int allEnNum

13

getEts

读取信息

ets

14

setEts

核算数值信息

Vector<EnemyTank> ets1

 

(4)Bomb类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

x

int

定义炸弹的x坐标

自然数

2

y

int

定义炸弹的y坐标

自然数

3

life

int

设置炸弹的生命

自然数

4

isLive

boolean

设置炸弹的生命

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

Bomb

设置炸弹生命

Bomb(int x,int y)

2

lifeDown

控制生命值

 

(5)Shot类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

x

int

定义子弹的x坐标

自然数

2

y

int

定义子弹的y坐标

自然数

3

direct

int

设置子弹的方向

自然数

4

isLive

boolean

设置子弹的生命

自然数

5

Speed

int

设置子弹的速度

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

run

每隔100毫秒重绘面板以免游戏延迟,进行缓冲

2

Shot

记录位置

int x,int y,int direct

 

(6)Tank类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

x

int

定义坦克的x坐标

自然数

2

y

int

定义坦克的y坐标

自然数

3

direct

int

设置坦克的方向

自然数

4

isLive

boolean

设置坦克的生命

自然数

5

Speed

int

设置坦克的速度

自然数

6

color

int

设置坦克的颜色

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

Tank

设置坦克速度

int x,int y

2

getX

记录坦克x方向速度

x

3

setX

设置坦克x方向速度

int x

4

getY

设置坦克y方向速度

y

5

setY

设置坦克y方向速度

int y

6

getDirect

设置坦克方向

direct

7

setDirect

设置坦克方向

int direct

8

getSpeed

记录坦克速度

speed

9

setSpeed

记录坦克速度

int speed

10

getColor

设置颜色

color

11

setColor

设置颜色

int color

 

(7)EnemyTank类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

times

int

设置敌人坦克的时间

自然数

2

ets

Vector<EnemyTank>

定义一个向量,可以访问到MyPanel上所有敌人的坦克

自然数

3

ss

Vector<Shot>

定义一个向量,可以存放敌人的子弹

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

EnemyTank

敌方添加子弹

int x,int y

2

setEts

得到MyPanel的敌人坦克向量

Vector<EnemyTank> vv

3

isTouchOtherEnemy

判断是否碰到了敌人的坦克

b/true

4

run

每隔100毫秒重绘面板以免游戏延迟,进行缓冲

 

(8)Hero类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

ss

Vector<Shot>

定义一个向量,可以存放玩方的子弹

自然数

2

s

Shot

记录玩方的子弹

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

Hero

设置玩家坦克属性

int x,int y

2

shotEnemy

控制坦克开火攻击

3

moveUp

控制坦克向上移动

4

moveDown

控制坦克向下移动

5

moveLeft

控制坦克向左移动

6

moveRight

控制坦克向右移动

 

(9)MyTankGame3类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

mp

object

设置游戏面板

自然数

2

msp

object

设置游戏面板

自然数

3

jmb

object

作出我需要的菜单

自然数

4

jm1

object

控制开始游戏

自然数

5

jmil

object

控制开始游戏

自然数

6

Jmi2

object

控制退出游戏

自然数

7

Jmi3

object

退出系统

自然数

8

Jmi4

object

存盘退出

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

main

程序的入口地址

String数组

2

MyTankGame3

启动mp线程、创建菜单及菜单选项、注册监听

3

actionPerformed

对用户不同的点击作出不同的处理并创建战场面板

ActionEvent arg0

 

(10)MyStartPanel类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

times

int

记录时间

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

paint

进行游戏面板提示信息的设置

Graphics g

 

2

run

缓冲与重画设置

 

(11)MyPanel类的数据成员和成员函数设计:

序号

数据成员

数据类型

意义说明

取值范围

1

hero

object

定义玩家坦克

自然数

2

ets

Vector

定义敌人的坦克组

自然数

3

nodes

Vector

定义敌人的坦克组

自然数

4

bombs

Vector

定义炸弹集合

自然数

5

enSize

int

定义炸弹集合

自然数

6

image1

object

定义三张照片组成炸弹

自然数

7

Image2

object

定义三张照片组成炸弹

自然数

8

Image3

object

定义三张照片组成炸弹

自然数

 

序号

成员函数

函数功能

函数参数

函数返回值

1

MyPanel

创建并设置敌方坦克

String flag

2

showInfo

记录显示数据(敌方坦克状态、玩家成绩)等

Graphics g

3

paint

对玩家坦克进行创建设置

Graphics g

4

hitMe

对双方射出的子弹进行记录

5

hitEnemyTank

判断玩家进行的攻击是否有效并核算敌方数据,产生玩家记录

6

hitTank

专门判断子弹是否击中敌人坦克

Shot s,Tank et

b2

7

drawTank

判断是什么类型的坦克并绘制

int x,int y,Graphics g,int direct,int type

8

keyPressed

对玩家坦克进行设置,使其能够控制移动、是否攻击

KeyEvent arg0

9

keyReleased

每隔100毫秒对坦克进行重绘

KeyEvent arg0

10

keyTyped

每隔100毫秒对坦克进行重绘并判断玩家是否被敌方击中

KeyEvent arg0

11

run

每隔100毫秒重绘面板以免游戏延迟,进行缓冲

 

(12)TestAudio类的数据成员和成员函数设计:

 

序号

成员函数

函数功能

函数参数

函数返回值

1

Main

创建一个AePlayWave 对象实例、启动该线程播放

String[] args

 

 

(3)类及类之间的关系如图所示:

坦克游戏的学习及实现

 

数据结构

本坦克游戏使用了如下数据结构:

1.基本类型数组;

2.结构体数组;

3.对象数组;

4.使用了Map类、Collections类中的多种容器类。

 

算法

本坦克游戏使用了如下算法:

使用了枚举、分类统计;

使用了排序与查找算法;

使用了文件操作,加入了对声音文件、文件流的操作,还有文件记录、存档、文件i/o等操作;

使用了递归算法;

使用了位集合;

使用了向量;

引入了事件监听机制、事件处理机制;

使用了Java绘图技术;

使用了界面编程;

10.实现了Java面向对象编程。

 

程序流程图

系统总体流程图如下:

 

坦克游戏的学习及实现

 

实现中遇到的问题及解决方法与思路:

 

问题1: 在设计游戏动态面板的时候无从下手。

原因:对Java绘图技术知之甚少。

解决方法:学习了Java绘图技术,学习如何绘制二维界面,成功建立好了坐标系,并以像素为单位,用component类、graphics提供绘图帮助。

 

问题2: 游戏窗口激活、关闭等总有问题。

原因:对Java的事件监听机制不了解。

解决方法:学习并应用了Java的事件监听机制、事件处理机制,分清了什么是事件源,什么是事件监听者,在事件源中需要注册事件监听类,明白了Mypanle的对象mypanle就是监听者,当他在其余操作上注册了监听,当其他操作被点击时,mypanle就会接收到信息,并在actionPerformed函数中处理,并可以借助多种事件类来处理。

 

问题3: 在引入游戏音频时总出错。

原因:对文件操作不熟悉。

解决方法:学习了文件操作,明白了借助文件流可以恰当加入音效。

 

问题4:刚开始编程时,对于需要使其具有多个功能的实现途径感到思路混乱。

原因:对于需要编写很长的代码有一定的畏惧心理

解决方法:理清楚各个功能之间的联系,列出一个需要实现的功能大纲,按次序将他们封装成函数,并放在恰当的容器类当中。这样思路清晰,结构也很严谨,增强了程序的健壮性和复用性,也很方便自己优化代码。

 

测试用例和系统测试结果:

测试用例1:

程序截图:

坦克游戏的学习及实现

 

测试方法以及目的:运行程序,检测是否正常

具体用例及内容:运行程序后初始状态面板中显示stage1,可继续进行后续操作。

 

 

测试用例2:

坦克游戏的学习及实现

测试方法以及目的:继续运行程序,检测是否正常

具体用例及内容:继续运行程序后点击panel中菜单选项,可正常选择“开始新游戏(N)、退出游戏(E)、存盘退出游戏(C)、继续上局游戏(S)”等操作。

 

测试用例3:

坦克游戏的学习及实现

测试方法以及目的:继续运行并试玩游戏,检测是否正常

具体用例及内容:继续运行程序,游戏可正常进行,坦克可以正常操控方向,进行攻击,分值记录等功能正确。

 

测试用例4:

坦克游戏的学习及实现

测试方法以及目的:试玩游戏,检测各功能是否正常

具体用例及内容:随意设置并试玩游戏,游戏可正常进行,分值核算、音效、画面等各内容正常。

 

程序的全部源代码:

所在文件:源码 > Class > src > com > test1 > Test.java

package com.test1;  

  

import java.io.*;  

  

import javax.sound.sampled.*;  

  

public class Test {  

  

    /** 

     * @param args 

     */  

    public static void main(String[] args) {  

        // TODO Auto-generated method stub  

        AePlayWave apw = new AePlayWave("./111.wav");  

        apw.start();  

    }  

  

}  

  

//播放声音的类  

class AePlayWave extends Thread {  

  

    private String filename;  

  

    public AePlayWave(String wavfile) {  

        filename = wavfile;  

  

    }  

  

    public void run() {  

  

        File soundFile = new File(filename);  

  

        AudioInputStream audioInputStream = null;  

        try {  

            audioInputStream = AudioSystem.getAudioInputStream(soundFile);  

        } catch (Exception e1) {  

            e1.printStackTrace();  

            return;  

        }  

  

        AudioFormat format = audioInputStream.getFormat();  

        SourceDataLine auline = null;  

        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);  

  

        try {  

            auline = (SourceDataLine) AudioSystem.getLine(info);  

            auline.open(format);  

        } catch (Exception e) {  

            e.printStackTrace();  

            return;  

        }  

  

        auline.start();  

        int nBytesRead = 0;  

        byte[] abData = new byte[512];  

  

        try {  

            while (nBytesRead != -1) {  

                nBytesRead = audioInputStream.read(abData, 0, abData.length);  

                if (nBytesRead >= 0)  

                    auline.write(abData, 0, nBytesRead);  

            }  

        } catch (IOException e) {  

            e.printStackTrace();  

            return;  

        } finally {  

            auline.drain();  

            auline.close();  

        }  

  

    }  

  

}  

 

 

 

所在文件:源码 > Class >  src > com > test1 > TestAudio.java

package com.test1;  

  

import java.io.*;  

import javax.sound.sampled.*;  

public class TestAudio {  

  

    /** 

     * @param args 

     */  

    public static void main(String[] args) {  

        // TODO Auto-generated method stub  

        //1.创建一个AePlayWave 对象实例  

        AePlayWave apw=new AePlayWave("d:\\111.wav");  

        //2.启动该线程播放  

        apw.start();  

    }  

  

}  

  

//播放声音的类  

/*class AePlayWave extends Thread { 

 

    private String filename; 

    public AePlayWave(String wavfile) { 

        filename = wavfile; 

 

    } 

 

    public void run() { 

 

        File soundFile = new File(filename); 

 

        AudioInputStream audioInputStream = null; 

        try { 

            audioInputStream = AudioSystem.getAudioInputStream(soundFile); 

        } catch (Exception e1) { 

            e1.printStackTrace(); 

            return; 

        } 

 

        AudioFormat format = audioInputStream.getFormat(); 

        SourceDataLine auline = null; 

        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 

 

        try { 

            auline = (SourceDataLine) AudioSystem.getLine(info); 

            auline.open(format); 

        } catch (Exception e) { 

            e.printStackTrace(); 

            return; 

        } 

 

        auline.start(); 

        int nBytesRead = 0; 

        //这是缓冲 

        byte[] abData = new byte[512]; 

 

        try { 

            while (nBytesRead != -1) { 

                nBytesRead = audioInputStream.read(abData, 0, abData.length); 

                if (nBytesRead >= 0) 

                    auline.write(abData, 0, nBytesRead); 

            } 

        } catch (IOException e) { 

            e.printStackTrace(); 

            return; 

        } finally { 

            auline.drain(); 

            auline.close(); 

        } 

 

    } 

 

     

}*/  

 

所在文件:源码 > Class > src > com > test2 > Members.java

package com.test3;  

  

import java.util.*;  

import java.io.*;  

  

import javax.sound.sampled.AudioFormat;  

import javax.sound.sampled.AudioInputStream;  

import javax.sound.sampled.AudioSystem;  

import javax.sound.sampled.DataLine;  

import javax.sound.sampled.SourceDataLine;  

  

//播放声音的类  

class AePlayWave extends Thread {  

  

    private String filename;  

    public AePlayWave(String wavfile) {  

        filename = wavfile;  

  

    }  

  

    public void run() {  

  

        File soundFile = new File(filename);  

  

        AudioInputStream audioInputStream = null;  

        try {  

            audioInputStream = AudioSystem.getAudioInputStream(soundFile);  

        } catch (Exception e1) {  

            e1.printStackTrace();  

            return;  

        }  

  

        AudioFormat format = audioInputStream.getFormat();  

        SourceDataLine auline = null;  

        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);  

  

        try {  

            auline = (SourceDataLine) AudioSystem.getLine(info);  

            auline.open(format);  

        } catch (Exception e) {  

            e.printStackTrace();  

            return;  

        }  

  

        auline.start();  

        int nBytesRead = 0;  

        //这是缓冲  

        byte[] abData = new byte[512];  

  

        try {  

            while (nBytesRead != -1) {  

                nBytesRead = audioInputStream.read(abData, 0, abData.length);  

                if (nBytesRead >= 0)  

                    auline.write(abData, 0, nBytesRead);  

            }  

        } catch (IOException e) {  

            e.printStackTrace();  

            return;  

        } finally {  

            auline.drain();  

            auline.close();  

        }  

  

    }  

  

      

}  

  

class Node{  

    int x;  

    int y;  

    int direct;  

    public Node(int x,int y,int direct)  

    {  

        this.x=x;  

        this.y=y;  

        this.direct=direct;  

    }  

}  

  

  

//记录类,同时也可以保存玩家的设置  

class Recorder  

{  

    //记录每关有多少敌人  

    private static int enNum=20;  

    //设置我有多少可以用的人  

    private static int myLife=3;  

    //记录总共消灭了多少敌人  

    private static int allEnNum=0;  

    //从文件中恢复记录点  

    static Vector<Node>  nodes=new Vector<Node>();  

      

    private static FileWriter fw=null;  

    private static BufferedWriter bw=null;  

    private static FileReader fr=null;  

    private static BufferedReader br=null;  

      

    private  Vector<EnemyTank> ets=new Vector<EnemyTank>();  

      

      

      

    //完成读取认为  

    public Vector<Node> getNodesAndEnNums()  

    {  

        try {  

            fr=new FileReader("d:\\myRecording.txt");  

            br=new BufferedReader(fr);  

            String n="";  

            //先读取第一行  

            n=br.readLine();  

            allEnNum=Integer.parseInt(n);  

            while((n=br.readLine())!=null)  

            {  

                String []xyz=n.split(" ");   

                  

                Node node=new Node(Integer.parseInt(xyz[0]),Integer.parseInt(xyz[1]),Integer.parseInt(xyz[2]));  

                nodes.add(node);  

            }  

              

          

        } catch (Exception e) {  

            e.printStackTrace();  

            // TODO: handle exception  

        }finally{  

              

            try {  

                //后打开则先关闭  

                br.close();  

                fr.close();  

            } catch (Exception e) {  

                e.printStackTrace();  

                // TODO: handle exception  

            }  

        }  

          

        return nodes;  

          

    }  

      

      

    //保存击毁敌人的数量和敌人坦克坐标,方向  

      

    public  void keepRecAndEnemyTank()  

    {  

        try {  

              

            //创建  

            fw=new FileWriter("d:\\myRecording.txt");  

            bw=new BufferedWriter(fw);  

              

            bw.write(allEnNum+"\r\n");  

              

            System.out.println("size="+ets.size());  

            //保存当前活的敌人坦克的坐标和方向  

            for(int i=0;i<ets.size();i++)  

            {  

                //取出第一个坦克  

                EnemyTank et=ets.get(i);  

                  

                if(et.isLive)  

                {  

                    //活的就保存  

                    String recode=et.x+" "+et.y+" "+et.direct;  

                      

                    //写入  

                    bw.write(recode+"\r\n");  

                      

                }  

            }  

              

        } catch (Exception e) {  

            e.printStackTrace();  

            // TODO: handle exception  

        }finally{  

          

            //关闭流  

            try {  

                //后开先关闭  

                bw.close();  

                fw.close();  

            } catch (Exception e) {  

                e.printStackTrace();  

                // TODO: handle exception  

            }  

        }  

    }  

      

      

    //从文件中读取,记录  

    public static void getRecoring()  

    {  

        try {  

            fr=new FileReader("d:\\myRecording.txt");  

            br=new BufferedReader(fr);  

            String n=br.readLine();  

            allEnNum=Integer.parseInt(n);  

        } catch (Exception e) {  

            e.printStackTrace();  

            // TODO: handle exception  

        }finally{  

              

            try {  

                //后打开则先关闭  

                br.close();  

                fr.close();  

            } catch (Exception e) {  

                e.printStackTrace();  

                // TODO: handle exception  

            }  

        }  

    }  

      

    //把玩家击毁敌人坦克数量保存到文件中  

    public static void keepRecording()  

    {  

        try {  

              

            //创建  

            fw=new FileWriter("d:\\myRecording.txt");  

            bw=new BufferedWriter(fw);  

              

            bw.write(allEnNum+"\r\n");  

              

        } catch (Exception e) {  

            e.printStackTrace();  

            // TODO: handle exception  

        }finally{  

          

            //关闭流  

            try {  

                //后开先关闭  

                bw.close();  

                fw.close();  

            } catch (Exception e) {  

                e.printStackTrace();  

                // TODO: handle exception  

            }  

        }  

    }  

      

    public static int getEnNum() {  

        return enNum;  

    }  

    public static void setEnNum(int enNum) {  

        Recorder.enNum = enNum;  

    }  

    public static int getMyLife() {  

        return myLife;  

    }  

    public static void setMyLife(int myLife) {  

        Recorder.myLife = myLife;  

    }  

      

    //减少敌人数  

    public static void reduceEnNum()  

    {  

        enNum--;  

    }  

    //消灭敌人  

    public static void addEnNumRec()  

    {  

        allEnNum++;  

    }  

    public static int getAllEnNum() {  

        return allEnNum;  

    }  

    public static void setAllEnNum(int allEnNum) {  

        Recorder.allEnNum = allEnNum;  

    }  

  

  

    public  Vector<EnemyTank> getEts() {  

        return ets;  

    }  

  

  

    public  void setEts(Vector<EnemyTank> ets1) {  

          

        this.ets = ets1;  

        System.out.println("ok");  

    }  

}  

  

//炸弹类  

class Bomb   

{  

    //定义炸弹的坐标  

    int x,y;  

    //炸弹的生命  

    int life=9;  

    boolean isLive=true;  

    public Bomb(int x,int y)  

    {  

        this.x=x;  

        this.y=y;  

    }  

      

    //减少生命值  

    public void lifeDown()  

    {  

        if(life>0)  

        {  

            life--;  

        }else{  

            this.isLive=false;  

        }  

          

    }  

      

      

      

}  

  

//子弹类  

class Shot implements Runnable  {  

    int x;  

    int y;  

    int direct;  

    int speed=1;  

    //是否还活着  

    boolean isLive=true;  

    public Shot(int x,int y,int direct)  

    {  

        this.x=x;  

        this.y=y;  

        this.direct=direct;  

    }  

    public void run() {  

          

        while(true)  

        {  

              

            try {  

                Thread.sleep(50);  

            } catch (Exception e) {  

                // TODO: handle exception  

            }  

              

            switch(direct)  

            {  

            case 0:  

                //上  

                y-=speed;  

                break;  

            case 1:  

                x+=speed;  

                break;  

            case 2:  

                y+=speed;  

                break;  

            case 3:  

                x-=speed;  

                break;  

            }  

              

        //  System.out.println("子弹坐标x="+x+" y="+y);  

            //子弹何时死亡???  

              

            //判断该子弹是否碰到边缘.  

            if(x<0||x>400||y<0||y>300)  

            {  

                this.isLive=false;  

                break;  

            }  

        }  

    }  

}  

  

  

//坦克类  

class Tank  

{  

    //表示坦克的横坐标  

    int x=0;  

    //坦克纵坐标  

    int y=0;  

      

    //坦克方向  

    //0表示上 1表示 右 2表示下  3表示左  

    int direct=0;  

    int color;  

      

    boolean isLive=true;  

      

    //坦克的速度  

    int speed=1;  

    public Tank(int x,int y)  

    {  

        this.x=x;  

        this.y=y;  

    }  

  

    public int getX() {  

        return x;  

    }  

  

    public void setX(int x) {  

        this.x = x;  

    }  

  

    public int getY() {  

        return y;  

    }  

  

    public void setY(int y) {  

        this.y = y;  

    }  

  

    public int getDirect() {  

        return direct;  

    }  

  

    public void setDirect(int direct) {  

        this.direct = direct;  

    }  

  

    public int getSpeed() {  

        return speed;  

    }  

  

    public void setSpeed(int speed) {  

        this.speed = speed;  

    }  

  

    public int getColor() {  

        return color;  

    }  

  

    public void setColor(int color) {  

        this.color = color;  

    }  

      

}  

  

//敌人的坦克,把敌人做成线程类  

class EnemyTank extends Tank implements Runnable  

{  

      

    int times=0;  

      

    //定义一个向量,可以访问到MyPanel上所有敌人的坦克  

    Vector<EnemyTank> ets=new Vector<EnemyTank>();  

      

    //定义一个向量,可以存放敌人的子弹  

    Vector<Shot> ss=new Vector<Shot>();  

    //敌人添加子弹,应当在刚刚创建坦克和敌人的坦克子弹死亡后  

    public EnemyTank(int x,int y)  

    {  

        super(x,y);   

    }  

      

    //得到MyPanel的敌人坦克向量  

    public void setEts(Vector<EnemyTank> vv)  

    {  

        this.ets=vv;  

    }  

  

    //判断是否碰到了别的敌人坦克  

    public boolean isTouchOtherEnemy()  

    {  

        boolean b=false;  

          

          

        switch(this.direct)  

        {  

        case 0:  

            //我的坦克向上  

            //取出所有的敌人坦克  

            for(int i=0;i<ets.size();i++)  

            {  

                //取出第一个坦克  

                EnemyTank et=ets.get(i);  

                //如果不是自己  

                if(et!=this)  

                {  

                    //如果敌人的方向是向下或者向上  

                    if(et.direct==0||et.direct==2)  

                    {  

                        //左点  

                        if(this.x>=et.x&&this.x<=et.x+20&&this.y>=et.y&&this.y<=et.y+30)  

                        {  

                            return true;  

                        }  

                        if(this.x+20>=et.x&&this.x+20<=et.x+20&&this.y>=et.y&&this.y<=et.y+30)  

                        {  

                            return true;  

                        }  

                    }  

                    if(et.direct==3||et.direct==1)  

                    {  

                        if(this.x>=et.x&&this.x<=et.x+30&&this.y>=et.y&&this.y<=et.y+20)  

                        {  

                            return true;  

                        }  

                        if(this.x+20>=et.x&&this.x+20<=et.x+30&&this.y>=et.y&&this.y<=et.y+20)  

                        {  

                            return true;  

                        }  

                    }  

                }  

            }  

            break;  

        case 1:  

            //坦克向右  

            //取出所有的敌人坦克  

            for(int i=0;i<ets.size();i++)  

            {  

                //取出第一个坦克  

                EnemyTank et=ets.get(i);  

                //如果不是自己  

                if(et!=this)  

                {  

                    //如果敌人的方向是向下或者向上  

                    if(et.direct==0||et.direct==2)  

                    {  

                        //上点  

                        if(this.x+30>=et.x&&this.x+30<=et.x+20&&this.y>=et.y&&this.y<=et.y+30)  

                        {  

                            return true;  

                        }  

                        //下点   

                        if(this.x+30>=et.x&&this.x+30<=et.x+20&&this.y+20>=et.y&&this.y+20<=et.y+30)  

                        {  

                            return true;  

                        }  

                    }  

                    if(et.direct==3||et.direct==1)  

                    {  

                        if(this.x+30>=et.x&&this.x+30<=et.x+30&&this.y>=et.y&&this.y<=et.y+20)  

                        {  

                            return true;  

                        }  

                        if(this.x+30>=et.x&&this.x+30<=et.x+30&&this.y+20>=et.y&&this.y+20<=et.y+20)  

                        {  

                            return true;  

                        }  

                    }  

                }  

            }  

            break;  

        case 2:  

            //坦克向下  

            //取出所有的敌人坦克  

            for(int i=0;i<ets.size();i++)  

            {  

                //取出第一个坦克  

                EnemyTank et=ets.get(i);  

                //如果不是自己  

                if(et!=this)  

                {  

                    //如果敌人的方向是向下或者向上  

                    if(et.direct==0||et.direct==2)  

                    {  

                        //我的左点  

                        if(this.x>=et.x&&this.x<=et.x+20&&this.y+30>=et.y&&this.y+30<=et.y+30)  

                        {  

                            return true;  

                        }  

                        //我的右点  

                        if(this.x+20>=et.x&&this.x+20<=et.x+20&&this.y+30>=et.y&&this.y+30<=et.y+30)  

                        {  

                            return true;  

                        }  

                    }  

                    if(et.direct==3||et.direct==1)  

                    {  

                        if(this.x>=et.x&&this.x<=et.x+30&&this.y+30>=et.y&&this.y+30<=et.y+20)  

                        {  

                            return true;  

                        }  

                          

                        if(this.x+20>=et.x&&this.x+20<=et.x+30&&this.y+30>=et.y&&this.y+30<=et.y+20)  

                        {  

                            return true;  

                        }  

                    }  

                }  

            }  

            break;  

        case 3:  

            //向左  

            //取出所有的敌人坦克  

            for(int i=0;i<ets.size();i++)  

            {  

                //取出第一个坦克  

                EnemyTank et=ets.get(i);  

                //如果不是自己  

                if(et!=this)  

                {  

                    //如果敌人的方向是向下或者向上  

                    if(et.direct==0||et.direct==2)  

                    {  

                        //我的上一点  

                        if(this.x>=et.x&&this.x<=et.x+20&&this.y>=et.y&&this.y<=et.y+30)  

                        {  

                            return true;  

                        }  

                        //下一点  

                        if(this.x>=et.x&&this.x<=et.x+20&&this.y+20>=et.y&&this.y+20<=et.y+30)  

                        {  

                            return true;  

                        }  

                    }  

                    if(et.direct==3||et.direct==1)  

                    {  

                        //上一点  

                        if(this.x>=et.x&&this.x<=et.x+30&&this.y>=et.y&&this.y<=et.y+20)  

                        {  

                            return true;  

                        }  

                        if(this.x>=et.x&&this.x<=et.x+30&&this.y+20>=et.y&&this.y+20<=et.y+20)  

                        {  

                            return true;  

                        }  

                    }  

                }  

            }  

            break;  

        }  

          

          

        return b;  

    }  

      

      

      

    public void run() {  

        // TODO Auto-generated method stub  

          

        while(true)  

        {  

              

          

            switch(this.direct)  

            {  

            case 0:  

                //说明坦克正在向上  

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

                {  

                    if(y>0&&!this.isTouchOtherEnemy())  

                    {  

                        y-=speed;  

                    }  

                    try {  

                        Thread.sleep(50);  

                    } catch (Exception e) {  

                        e.printStackTrace();  

                        // TODO: handle exception  

                    }  

                }  

                break;  

            case 1:  

                //向右  

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

                {  

                    //保证坦克不出边界  

                    if(x<400&&!this.isTouchOtherEnemy())  

                    {  

                        x+=speed;  

                    }  

                    try {  

                        Thread.sleep(50);  

                    } catch (Exception e) {  

                        e.printStackTrace();  

                        // TODO: handle exception  

                    }  

                }  

                break;  

            case 2:  

                //向下  

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

                {  

                    if(y<300&&!this.isTouchOtherEnemy())  

                    {  

                        y+=speed;  

                    }  

                    try {  

                        Thread.sleep(50);  

                    } catch (Exception e) {  

                        e.printStackTrace();  

                        // TODO: handle exception  

                    }  

                }  

                break;  

            case 3:  

                //向左  

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

                {  

                    if(x>0&&!this.isTouchOtherEnemy())  

                    {  

                        x-=speed;  

                    }  

                    try {  

                        Thread.sleep(50);  

                    } catch (Exception e) {  

                        e.printStackTrace();  

                        // TODO: handle exception  

                    }  

                }  

                break;  

              

            }  

              

            this.times++;  

              

            if(times%2==0)  

            {  

                if(isLive)  

                {  

                    if(ss.size()<5)  

                    {  

                        //System.out.println("et.ss.size()<5="+et.ss.size());  

                        Shot s=null;  

                        //没有子弹  

                        //添加  

                        switch(direct)  

                        {  

                        case 0:  

                            //创建一颗子弹  

                             s=new Shot(x+10,y,0);  

                            //把子弹加入向量  

                            ss.add(s);  

                            break;  

                        case 1:  

                            s=new Shot(x+30,y+10,1);  

                            ss.add(s);  

                            break;  

                        case 2:  

                             s=new Shot(x+10,y+30,2);  

                            ss.add(s);  

                            break;  

                        case 3:  

                            s=new Shot(x,y+10,3);  

                            ss.add(s);  

                            break;  

                        }  

                          

                        //启动子弹  

                        Thread t=new Thread(s);  

                        t.start();  

                    }  

                }  

            }  

              

              

            //让坦克随机产生一个新的方向  

            this.direct=(int)(Math.random()*4);  

              

            //判断敌人坦克是否死亡  

            if(this.isLive==false)  

            {  

                //让坦克死亡后,退出线程.  

                break;  

            }  

              

              

              

              

              

        }  

          

    }  

}  

  

//我的坦克  

class Hero extends Tank  

{  

      

    //子弹  

      

    //Shot s=null;  

    Vector<Shot> ss=new Vector<Shot>();  

    Shot s=null;  

    public Hero(int x,int y)  

    {  

        super(x,y);  

          

          

    }  

      

    //开火  

    public void shotEnemy()  

    {  

          

          

        switch(this.direct)  

        {  

        case 0:  

            //创建一颗子弹  

             s=new Shot(x+10,y,0);  

            //把子弹加入向量  

            ss.add(s);  

            break;  

        case 1:  

            s=new Shot(x+30,y+10,1);  

            ss.add(s);  

            break;  

        case 2:  

             s=new Shot(x+10,y+30,2);  

            ss.add(s);  

            break;  

        case 3:  

            s=new Shot(x,y+10,3);  

            ss.add(s);  

            break;  

              

        }  

        //启动子弹线程  

        Thread t=new Thread(s);  

        t.start();  

          

    }  

      

      

    //坦克向上移动  

    public void moveUp()  

    {  

        y-=speed;  

    }  

    //坦克向右移动  

    public void moveRight()  

    {  

        x+=speed;  

    }  

      

    //坦克向下移动  

    public void moveDown()  

    {  

        y+=speed;  

    }  

      

    //向左  

    public void moveLeft()  

    {  

        x-=speed;  

    }  

}  

 

 

所在文件:源码 > Class >  src > com > test1 > MyTankGame3.java

package com.test3;  

  

import javax.imageio.ImageIO;  

import javax.swing.*;  

  

import java.awt.*;  

import java.awt.event.*;  

import java.util.*;  

import java.io.*;  

public class MyTankGame3 extends JFrame implements ActionListener {  

  

    MyPanel mp=null;  

      

    //定义一个开始面板  

    MyStartPanel msp=null;  

      

    //作出我需要的菜单  

    JMenuBar jmb=null;  

    //开始游戏  

    JMenu jm1=null;  

    JMenuItem jmil=null;  

    //退出系统  

    JMenuItem jmi2=null;  

    //存盘退出  

    JMenuItem jmi3=null;  

    JMenuItem jmi4=null;  

    public static void main(String[] args) {  

        // TODO Auto-generated method stub  

        MyTankGame3 mtg=new MyTankGame3();  

    }  

      

    //构造函数  

    public MyTankGame3()  

    {  

        //mp=new MyPanel();  

          

        //启动mp线程  

        //Thread t=new Thread(mp);  

        //t.start();  

        //this.add(mp);  

        //注册监听  

        //this.addKeyListener(mp);  

          

        //创建菜单及菜单选项  

        jmb=new JMenuBar();  

        jm1 =new JMenu("游戏(G)");  

        //设置快捷方式  

        jm1.setMnemonic('G');  

        jmil =new JMenuItem("开始新游戏(N)");  

        jmi2 =new JMenuItem("退出游戏(E)");  

        jmi3 =new JMenuItem("存盘退出游戏(C)");  

        jmi4 =new JMenuItem("继续上局游戏(S)");  

          

        //注册监听  

        jmi4.addActionListener(this);  

        jmi4.setActionCommand("conGame");  

          

        //注册监听  

        jmi3.addActionListener(this);  

        jmi3.setActionCommand("saveExit");  

          

        jmi2.addActionListener(this);  

        jmi2.setActionCommand("exit");  

        jmi2.setMnemonic('E');  

        //对jmil相应  

        jmil.addActionListener(this);  

        jmil.setActionCommand("newgame");  

        jm1.add(jmil);  

        jm1.add(jmi2);  

        jm1.add(jmi3);  

        jm1.add(jmi4);  

        jmb.add(jm1);  

          

        msp=new MyStartPanel();  

        Thread t=new Thread(msp);  

        t.start();  

          

        this.setJMenuBar(jmb);  

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  

        this.add(msp);  

        this.setSize(600, 500);  

        this.setVisible(true);  

    }  

  

    public void actionPerformed(ActionEvent arg0) {  

        // TODO Auto-generated method stub  

        //对用户不同的点击作出不同的处理  

        if(arg0.getActionCommand().equals("newgame"))  

        {  

            //创建战场面板  

            mp=new MyPanel("newGame");  

              

            //启动mp线程  

            Thread t=new Thread(mp);  

            t.start();  

            //先删除旧的开始面板  

            this.remove(msp);  

            this.add(mp);  

            //注册监听  

            this.addKeyListener(mp);  

            //显示,刷新JFrame  

            this.setVisible(true);  

              

              

        }else if(arg0.getActionCommand().equals("exit"))  

        {  

            //用户点击了退出系统的菜单  

            //保存击毁敌人数量.  

            Recorder.keepRecording();  

              

            System.exit(0);  

        }//对存盘退出左处理  

        else if(arg0.getActionCommand().equals("saveExit"))  

        {  

            System.out.println("111");  

            System.out.println("mp.ets.size="+mp.ets.size());  

            //工作  

            Recorder rd=new Recorder();  

            rd.setEts(mp.ets);  

            //保存击毁敌人的数量和敌人的坐标  

            rd.keepRecAndEnemyTank();  

              

            //退出  

            System.exit(0);  

        }else if(arg0.getActionCommand().equals("conGame"))  

        {  

            //创建战场面板  

            mp=new MyPanel("con");  

          

              

            //启动mp线程  

            Thread t=new Thread(mp);  

            t.start();  

            //先删除旧的开始面板  

            this.remove(msp);  

            this.add(mp);  

            //注册监听  

            this.addKeyListener(mp);  

            //显示,刷新JFrame  

            this.setVisible(true);  

        }  

    }  

  

}  

//就是一个提示作用  

class MyStartPanel extends JPanel implements Runnable  

{  

    int times=0;  

      

    public void paint(Graphics g)  

    {  

        super.paint(g);  

        g.fillRect(0, 0, 400, 300);  

        //提示信息  

          

        if(times%2==0)  

        {  

            g.setColor(Color.yellow);  

            //开关信息的字体  

            Font myFont=new Font("华文新魏",Font.BOLD,30);  

            g.setFont(myFont);  

            g.drawString("stage: 1", 150, 150);  

        }  

          

    }  

  

    public void run() {  

        // TODO Auto-generated method stub  

        while(true)  

        {  

            //休眠  

            try {  

                  

                Thread.sleep(100);  

            } catch (Exception e) {  

                e.printStackTrace();  

                // TODO: handle exception  

            }  

              

            times++;  

              

            //重画  

            this.repaint();  

        }  

          

    }  

      

}  

  

//我的面板  

class MyPanel extends JPanel implements KeyListener,Runnable  

{  

  

    //定义一个我的坦克  

    Hero hero=null;  

      

      

      

      

    //定义敌人的坦克组  

    Vector<EnemyTank> ets=new Vector<EnemyTank>();  

    Vector<Node> nodes=new Vector<Node>();  

      

    //定义炸弹集合  

    Vector<Bomb> bombs=new Vector<Bomb>();  

      

    int enSize=3;  

      

    //定义三张图片,三张图片才能组成一颗炸弹  

    Image image1=null;  

    Image image2=null;  

    Image image3=null;  

      

    //构造函数  

    public MyPanel(String flag)  

    {  

          

        //恢复记录   

        Recorder.getRecoring();  

          

        hero=new Hero(100,100);  

          

          

          

          

        if(flag.equals("newGame"))  

        {  

            //初始化敌人的坦克  

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

            {  

                //创建一辆敌人的坦克对象  

                EnemyTank et=new EnemyTank((i+1)*50,0);  

                et.setColor(0);  

                et.setDirect(2);  

                //将MyPanel的敌人坦克向量交给该敌人坦克  

                et.setEts(ets);  

                  

                //启动敌人的坦克  

                Thread t=new Thread(et);  

                t.start();  

                //给敌人坦克添加一颗子弹  

                Shot s=new Shot(et.x+10,et.y+30,2);  

                //加入给敌人坦克  

                et.ss.add(s);  

                Thread t2=new Thread(s);  

                t2.start();  

                //加入  

                ets.add(et);  

            }  

        }else{  

              

            System.out.println("接着玩");  

            nodes=new Recorder().getNodesAndEnNums();  

            //初始化敌人的坦克  

            for(int i=0;i<nodes.size();i++)  

            {  

                Node node=nodes.get(i);  

                //创建一辆敌人的坦克对象  

                EnemyTank et=new EnemyTank(node.x,node.y);  

                et.setColor(0);  

                et.setDirect(node.direct);  

                //将MyPanel的敌人坦克向量交给该敌人坦克  

                et.setEts(ets);  

                  

                //启动敌人的坦克  

                Thread t=new Thread(et);  

                t.start();  

                //给敌人坦克添加一颗子弹  

                Shot s=new Shot(et.x+10,et.y+30,2);  

                //加入给敌人坦克  

                et.ss.add(s);  

                Thread t2=new Thread(s);  

                t2.start();  

                //加入  

                ets.add(et);  

            }  

        }  

          

          

        try {  

            image1=ImageIO.read(new File("bomb_1.gif"));  

            image2=ImageIO.read(new File("bomb_2.gif"));  

            image3=ImageIO.read(new File("bomb_3.gif"));  

        } catch (Exception e) {  

            e.printStackTrace();  

            // TODO: handle exception  

        }  

          

        //播放开战声音  

        AePlayWave apw=new AePlayWave("./111.wav");  

        apw.start();  

          

        //初始化图片d  

//      image1=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));  

//      image2=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));  

//      image3=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));  

    }  

      

      

    //画出提示信息  

    public void showInfo(Graphics g)  

    {  

        //画出提示信息坦克(该坦克不参与战斗)  

        this.drawTank(80,330, g, 0, 0);  

        g.setColor(Color.black);  

        g.drawString(Recorder.getEnNum()+"", 110, 350);  

        this.drawTank(130, 330, g, 0, 1);  

        g.setColor(Color.black);  

        g.drawString(Recorder.getMyLife()+"", 165, 350);  

          

        //画出玩家的总成绩  

        g.setColor(Color.black);  

        Font f=new Font("宋体",Font.BOLD,20);  

        g.setFont(f);  

        g.drawString("您的总成绩", 420, 30);  

          

        this.drawTank(420, 60, g, 0, 0);  

          

        g.setColor(Color.black);  

        g.drawString(Recorder.getAllEnNum()+"", 460, 80);  

    }  

      

    //重新paint  

    public void paint(Graphics g)  

    {  

        super.paint(g);  

        g.fillRect(0, 0, 400, 300);  

          

        //画出提示信息  

        this.showInfo(g);  

          

        //画出自己的坦克  

        if(hero.isLive)  

        {  

            this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);  

        }  

        //从ss,中取出每颗子弹,并画出  

        for(int i=0;i<hero.ss.size();i++)  

        {  

            Shot myShot=hero.ss.get(i);  

              

            //画出子弹,画出一颗子弹  

            if(myShot!=null&&myShot.isLive==true)  

            {  

                g.draw3DRect(myShot.x, myShot.y, 1, 1,false);  

            }  

            if(myShot.isLive==false)  

            {  

                //从ss中删除掉该子弹  

                hero.ss.remove(myShot);  

            }  

              

        }  

          

          

          

        //画出炸弹  

        for(int i=0;i<bombs.size();i++)  

        {  

            System.out.println("bombs.size()="+bombs.size());  

              

            //取出炸弹  

            Bomb b=bombs.get(i);  

              

            if(b.life>6)  

            {  

                g.drawImage(image1, b.x, b.y, 30, 30, this);  

            }else if(b.life>3)  

            {  

                g.drawImage(image2, b.x, b.y, 30, 30, this);  

            }else{  

                g.drawImage(image3, b.x, b.y, 30, 30, this);  

            }  

              

            //让b的生命值减小  

            b.lifeDown();  

            //如果炸弹生命值为0,就把该炸弹重bombs向量去掉  

            if(b.life==0)  

            {  

                bombs.remove(b);  

            }  

              

              

        }  

          

        //画出敌人的坦克  

        for(int i=0;i<ets.size();i++)  

        {  

            EnemyTank et=ets.get(i);  

              

            if(et.isLive)  

            {  

              

                this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 0);  

                //再画出敌人的子弹  

                //System.out.println("坦克子弹有:"+et.ss.size());  

                for(int j=0;j<et.ss.size();j++)  

                {  

                    //取出子弹  

                    Shot enemyShot=et.ss.get(j);  

                    if(enemyShot.isLive)  

                    {  

                        //System.out.println("第 "+i+"坦克的 "+j+"颗子弹x="+enemyShot.x);  

                        g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1,false);  

                    }else{  

                        //如果敌人的坦克死亡就从Vector去掉  

                        et.ss.remove(enemyShot);  

                    }  

                }  

            }  

        }  

          

          

    }  

      

    //敌人的坦克是否击中我  

    public void hitMe()  

    {  

        //取出每一个敌人的坦克  

        for(int i=0;i<this.ets.size();i++)  

        {  

            //取出坦克  

            EnemyTank et=ets.get(i);  

              

            //取出每一颗子弹  

            for(int j=0;j<et.ss.size();j++)  

            {  

                //取出子弹  

                Shot enemyShot=et.ss.get(j);  

                if(hero.isLive)  

                {  

                    if(this.hitTank(enemyShot, hero))  

                    {  

                          

                    }  

                }  

            }  

        }  

    }  

      

      

    //判断我的子弹是否击中敌人的坦克  

    public void hitEnemyTank()  

    {  

        //判断是否击中敌人的坦克  

        for(int i=0;i<hero.ss.size();i++)  

        {  

            //取出子弹   

            Shot myShot=hero.ss.get(i);  

            //判断子弹是否有效  

            if(myShot.isLive)  

            {  

                //取出每个坦克,与它判断  

                for(int j=0;j<ets.size();j++)  

                {  

                    //取出坦克  

                    EnemyTank et=ets.get(j);  

                      

                    if(et.isLive)  

                    {  

                        if(this.hitTank(myShot, et))  

                        {  

                            //减少敌人数量  

                            Recorder.reduceEnNum();  

                            //增加我的记录  

                            Recorder.addEnNumRec();  

                        }  

                    }  

                      

                }  

            }  

        }  

    }  

      

    //写一个函数专门判断子弹是否击中敌人坦克  

    public boolean hitTank(Shot s,Tank et)  

    {  

        boolean b2=false;  

          

        //判断该坦克的方向  

        switch(et.direct)  

        {  

        //如果敌人坦克的方向是上或者是下  

        case 0:  

        case 2:  

            if(s.x>et.x&&s.x<et.x+20&&s.y>et.y&&s.y<et.y+30)  

            {  

                //击中  

                //子弹死亡  

                s.isLive=false;  

                //敌人坦克死亡  

                et.isLive=false;  

                b2=true;  

                //创建一颗炸弹,放入Vector  

                Bomb b=new Bomb(et.x,et.y);  

                //放入Vector  

                bombs.add(b);  

                  

            }  

              

            break;  

        case 1:  

        case 3:  

            if(s.x>et.x&&s.x<et.x+30&&s.y>et.y&&s.y<et.y+20)  

            {  

                //击中  

                //子弹死亡  

                s.isLive=false;  

                //敌人坦克死亡  

                et.isLive=false;  

                b2=true;  

                //创建一颗炸弹,放入Vector  

                Bomb b=new Bomb(et.x,et.y);  

                //放入Vector  

                bombs.add(b);  

                  

            }  

        }  

          

        return b2;  

          

    }  

      

    //画出坦克的函数(扩展)  

    public void drawTank(int x,int y,Graphics g,int direct,int type)  

    {  

        //判断是什么类型的坦克  

        switch(type)  

        {  

        case 0:  

            g.setColor(Color.cyan);  

            break;  

        case 1:  

            g.setColor(Color.yellow);  

            break;  

        }  

          

        //判断方向  

        switch(direct)  

        {  

        //向上  

        case 0:  

            //画出我的坦克(到时再封装成一个函数)  

            //1.画出左边的矩形  

            g.fill3DRect(x, y, 5, 30,false);  

            //2.画出右边矩形  

            g.fill3DRect(x+15,y , 5, 30,false);  

            //3.画出中间矩形  

            g.fill3DRect(x+5,y+5 , 10, 20,false);  

            //4.画出圆形  

            g.fillOval(x+5, y+10, 10, 10);  

            //5.画出线  

            g.drawLine(x+10, y+15, x+10, y);  

            break;  

        case 1:  

            //炮筒向右  

            //画出上面矩形  

            g.fill3DRect(x, y, 30, 5,false);  

            //画出下面的矩形  

            g.fill3DRect(x, y+15, 30, 5, false);  

            //画出中间的矩形  

            g.fill3DRect(x+5, y+5, 20, 10, false);  

            //画出圆形  

            g.fillOval(x+10, y+5, 10, 10);  

            //画出线  

            g.drawLine(x+15, y+10, x+30, y+10);  

            break;  

        case 2:  

            //向下  

            //画出我的坦克(到时再封装成一个函数)  

            //1.画出左边的矩形  

            g.fill3DRect(x, y, 5, 30,false);  

            //2.画出右边矩形  

            g.fill3DRect(x+15,y , 5, 30,false);  

            //3.画出中间矩形  

            g.fill3DRect(x+5,y+5 , 10, 20,false);  

            //4.画出圆形  

            g.fillOval(x+5, y+10, 10, 10);  

            //5.画出线  

            g.drawLine(x+10, y+15, x+10, y+30);  

            break;  

        case 3:  

            //向左  

              

            //画出上面矩形  

            g.fill3DRect(x, y, 30, 5,false);  

            //画出下面的矩形  

            g.fill3DRect(x, y+15, 30, 5, false);  

            //画出中间的矩形  

            g.fill3DRect(x+5, y+5, 20, 10, false);  

            //画出圆形  

            g.fillOval(x+10, y+5, 10, 10);  

            //画出线  

            g.drawLine(x+15, y+10, x, y+10);  

            break;  

              

        }  

          

          

    }  

  

    //键按下处理 a 表示向左 s 表示 下 w 表示向上  d表示右  

      

    public void keyPressed(KeyEvent arg0) {  

        // TODO Auto-generated method stub  

          

        if(arg0.getKeyCode()==KeyEvent.VK_W)  

        {  

            //设置我的坦克的方向  

            this.hero.setDirect(0);  

            this.hero.moveUp();  

              

        }else if(arg0.getKeyCode()==KeyEvent.VK_D)  

        {  

            //向右  

            this.hero.setDirect(1);  

            this.hero.moveRight();  

        }else if(arg0.getKeyCode()==KeyEvent.VK_S)  

        {  

            //向下  

            this.hero.setDirect(2);  

            this.hero.moveDown();  

        }else if(arg0.getKeyCode()==KeyEvent.VK_A)  

        {  

            //向左  

            this.hero.setDirect(3);  

            this.hero.moveLeft();  

        }  

          

        if(arg0.getKeyCode()==KeyEvent.VK_J)  

        {  

            //判断玩家是否按下j  

              

            //开火  

            //System.out.println("this.hero.ss.size()="+this.hero.ss.size());  

            if(this.hero.ss.size()<=4)  

            {  

                this.hero.shotEnemy();  

            }  

              

        }  

          

          

          

          

        //必须重新绘制Panel  

        this.repaint();  

    }  

  

    public void keyReleased(KeyEvent arg0) {  

        // TODO Auto-generated method stub  

          

    }  

  

    public void keyTyped(KeyEvent arg0) {  

        // TODO Auto-generated method stub  

          

    }  

  

    public void run() {  

        // TODO Auto-generated method stub  

        //每隔100毫秒去重绘  

        while(true)  

        {  

            try {  

                Thread.sleep(100);  

            } catch (Exception e) {  

                e.printStackTrace();  

                // TODO: handle exception  

            }  

              

              

            this.hitEnemyTank();  

            //函数,判断敌人的子弹是否击中我  

            this.hitMe();  

  

              

            //重绘  

            this.repaint();  

        }  

    }  

}  

 

分析总结、收获和体会:

优点:将各个功能模块化,合理封装函数,设置各种类,彼此之间联系紧密,使用率高,使用方便快捷,代码简洁,可读性强,程序健壮性、复用性强。也对程序显示界面做了一定的改观。

 

创新之处:通过文件操作加入了音效,还借助三张图片使坦克被摧毁时拥有爆炸效果,在一定   程度上优化了游戏体验。还引用事件监听机制让游戏更稳定,增强了程序的健壮性。还运用了向量、Java绘图技术、界面编程等多项知识

 

不足之处:游戏功能不够全面,游戏界面不够美观

 

需要改进的地方:1.增强自信心,不畏惧大型程序的编写;

2.还需要学习怎样实现多人游戏模式、如何实现远程联机需要、如何加入更多的元素来美化游戏界面以改善用户体验。让游戏更加成熟。

 

收获与体会:通过实现该坦克游戏,通过解决自己在编程过程中遇到的一个个实际问题,我深刻理解了许多以前一知半解的知识点。也学会了许多其他的知识。比如说我们原先不会解决图像绘制、加入音效、使用文件流、正确设置事件监听机制等操作,后来经过学习终于能够解决程序中的这些问题。也丰富了自己的知识体系,学会了许多原先未曾接触过的知识。

     其次,通过这次编程,动手能力得到了很大的锻炼与提高,能够很好地注意细节问题,比如说不会忘记在正确的位置加分号这类最基础细节的问题。编程速度也大大提高。

     自信心与耐心也在这个过程中得到了提升,明白了不用惧怕编程过程,理清思路,注意细节,即便是很长的程序也能够被编写完成。也学会了在问题出现时静下心寻找方法,耐心解决,比如原先对于需要实现多个功能感到思路混乱,其实只需将各个功能区块化,合理的运用函数调用、用各种类去实现即可。

 

 

                                                           1190201411蒋婷婷

上一篇:bash 跟着敲 基础部分(适合初学者学习和非初学者参考)


下一篇:Nike Mercurial GS 360 fodboldsko udsætter alle sko