Java坦克大战游戏设计

更新时间:2024-01-28 07:18:02 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

Java大作业报告(截止5月20日)

北方民族大学 大作业报告

(游戏程序设计)

系(部、中心) 计算机科学与工程学院 姓 名 王鑫 学 号 20122201

专 业 软件工程 班 级 2012级 软件三 班 课程名称 Java语言程序设计

作业题目名称 《 简易版坦克大战游戏程序设计》 起止时间 2014年4月21日——2014年5 月21日 成 绩

指导教师签名 贾艳波 、林淑飞

Java大作业报告(截止5月20日)

简易版坦克大战游戏程序设计

一、游戏的基本规则

坦克种类分为敌方坦克和我方坦克,敌方有n辆蓝色坦克(n值可以自己设定),我方有一辆红色坦克,我方坦克发射子弹,击中敌人坦克后,敌方坦克消失,并产生爆炸效果,同理,敌方坦克击中我之后,我方坦克消失并爆炸。游戏结束。

二、主要实现思想和算法

gui图形界面显示:界面的显示是通过TankGame类(继承了JFrame)和MyPanel(继承了JPanel)类实现。其中,MyPanel重写了paint方法,利用画笔Graphics绘制活动区域、坦克和子弹。

画坦克的思想:选择一个参考点,如右图,首先参照参考点,画出 左边的矩形,然后参照参考点分别画出中间的正方形, 圆形,直线和右边的矩形。这些形状组合起来就形成了 参考点 一辆坦克。然后将画坦克的步骤封装成一个方法。 我的坦克发射子弹的思想:首先创建一个Shot类,他拥有坐标(根据坦克的坐标换算得到)、方向、速度和是否存活的属性,因为,子弹的坐标要不断的改变,所以将它做成一个线程。然后,在我的坦克里面定义了一个vactor(因为他是线程安全的)类集框架存放我的坦克的子弹。然后在pannel的paint方法中绘制。让MyPanel实现KeyListener接口,将TankGame注册让MyPanel监听,这样的话我按下j键,就在vactor里面添加一个子弹,然后让Shot实现Runnable接口,然后重写run方法,在run方法中通过改变子弹的坐标实现子弹的运动。 我的坦克移动的思想:让MyPanel实现KeyListener接口,将TankGame注册让MyPanel监听,这样我按下相应的键,就相应的改变坦克的坐标,利用repaint重新绘制坦克。

敌人坦克移动的思想:将敌人的坦克做成一个线程,然后在run方法中改变坦克坐标,重绘坦克。里随机数生成不同的方向,从而让敌人的坦克自主选择方向移动。

实现动态画面的思想:将MyPanel做成一个线程,然后将repaint函数方将run函数中,这样repaint函数就会被不断的调用,从而不断地刷新画面,达到动态效果。 判断子弹是否击中坦克的算法:获得子弹的坐标和坦克的坐标,如果子弹坐标进入坦克坐标范围,就判为击中。

让已经死亡的坦克和子弹消失的方法:被击中的坦克的isLive和子弹isLive的设置为false,这样,在绘制的时候会首先判断要绘制对象的isLive的值,如果为true才绘制,这样死亡的坦克和子弹就消失了。

让敌人坦克和子弹自动移动的思想:将敌人坦克和子弹做成一个线程,然后分别在各自的run函数中添加一个修改坐标的程序段。然后在MyPanel中启动对应的线程。坐标不断的自动修改,另一方面,paint函数不断的重新绘制,从而让坦克和子弹自动的移动了起来。 让坦克和子弹在规定的区域内移动的方法:通过比较坦克坐标和区域坐标范围,如果坦克坐标达到区域坐标范围边界,就不让坦克的坐标继续修改,从而将坦克控制在规定的范围。通过比较子弹坐标和区域坐标范围,如果子弹坐标超出区域坐标范围,就将子弹的isLive置为false,这样在paint函数中就不再绘制这个子弹了,从而超出区域的子弹就消失了。

显示爆炸效果的方法:首先我准备了一张爆炸的图片,然后创建一个爆炸的类Bomb,它拥

Java大作业报告(截止5月20日)

坐标属性,和生命值属性。还有减少生命的方法,当子弹击中坦克后,就坦克的坐标传递给Bomb,当做Bomb的坐标,然后开始绘制炸弹,同时让炸弹的生命不断减小,paint函数根据炸弹不同的生命值绘制不同大小的爆炸效果,不同的爆炸效果组合起来就形成了一个完整的爆炸。

三、游戏软件系统的设计

Java大作业报告(截止5月20日)

四、程序关键类的实现

Tank类,拥有坐标X,Y和方向,速度属性,以及对应的set和get方法。还有判断坦克是否死亡的isLive属性。

Hero类,继承了Tank类,有子弹属性,有shotEnemy方法,和上下左右移动的方法

Shot类,实现了线程接口,run方法里面放置了修改子弹坐标和判断子弹是否处境的算法。有坐标、速度、方向、和是否活着的属性。

Java大作业报告(截止5月20日)

炸弹类,有坐标、生命值和是否存活的属性。有生命减少的方法。

EenmyTank类,继承了Tank类,实现了线程接口,在run方法中添加了修改坦克坐标的程序段,从而让坦克自动移动。

MyPanel类,是本游戏最主要的类,他继承了JPanel实现了keylistener和runnable接口,他的paint函数绘制了游戏中的坦克和子弹以及活动范围。keyPressed函数监听键盘输入,run函数里面放了repaint和比较是否击中坦克的代码。

TankGame类,是本游戏的入口,其构造方法包含将面板添加到JFrame,设置窗口大小、可见性和默认的关闭方式。

Java大作业报告(截止5月20日)

五、游戏软件的主要界面截图

六、程序代码:

import javax.swing.*;

public class TankGame extends JFrame { //面板

MyPanel mp = null;

public static void main(String[] args) { //创建窗口

TankGame tankegame = new TankGame(); }

//构造函数

Java大作业报告(截止5月20日)

public TankGame(){ //创建面板对象 mp = new MyPanel(); //将面板添加到JFrame this.add(mp);

this.addKeyListener(mp);

//启动面板线程,让其paint方法不断调用,从而不断刷新,达到动态效果

Thread t = new Thread(mp); t.start(); //设置窗口大小

this.setSize(400,300); //设置小图标

this.setIconImage(new

ImageIcon(\).getImage());

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.setVisible(true); } }

Java大作业报告(截止5月20日)

********************************************** public class Tank { //坦克的很坐标 int x; //坦克的纵坐标 int y; //坦克的方向

//0表示上,1右,2下,3表示左 int direct=0; //坦克的速度 int speed=4; //坦克的外观 int color=0; //坦克是否死亡

boolean isLive =true;

public int getColor() { return color; }

public void setColor(int color) { this.color = color;

Java大作业报告(截止5月20日)

} public int getSpeed() { return speed; } public void setSpeed(int speed) { this.speed = speed; } public int getDirect() { return direct; } public void setDirect(int direct) { this.direct = direct; }

public Tank(int x,int y){ this.x = x; this.y = y; }

Java大作业报告(截止5月20日)

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; } }

*********************************************** import java.util.Vector;

public class Hero extends Tank{ //放置子弹的类集框架

Vector ss= new Vector(); //子弹

Java大作业报告(截止5月20日)

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);

Java大作业报告(截止5月20日)

ss.add(s); break; }

//启动子弹线程

Thread t = new Thread(s); t.start(); }

//坦克向上移动

public void moveUp(){ y-=speed; }

//坦克向右移动

public void moveRiget(){ x+=speed; }

//坦克向下移动

public void moveDown(){ y+=speed; }

//坦克向左移动

public void moveLeft(){ x-=speed;

Java大作业报告(截止5月20日)

} }

*******************************************************************************

import java.awt.*;

import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Vector;

import javax.swing.*;

public class MyPanel extends JPanel implements KeyListener,Runnable{ //定义一个我的坦克 Hero hero = null;

//定义敌人的坦克组,用Vector,因为他是线程安全的 Vector ets = new Vector(); //敌人坦克的初始量 int enSize = 2; //定义炸弹集合

Vector bombs = new Vector(); //定义爆炸图片 Image image1 = null;

Java大作业报告(截止5月20日)

Image image2 = null; Image image3 = null; //定义背景图片

Image imagebg = null; //MyPanel构造函数 public MyPanel(){ //初始化我的坦克

hero = new Hero(200,200); //初始化敌人的坦克

for(int i = 0;i

EnemyTank et = new EnemyTank((i+1)*50,0); //设置颜色 et.setColor(1); //设置方向 et.setDirect(2); //启动敌人坦克

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);

Java大作业报告(截止5月20日)

t2.start(); //加入类集框架 ets.add(et); }

//初始化爆炸图片 image1 =

Toolkit.getDefaultToolkit().getImage(Panel.class.getResource(\)); image2 =

Toolkit.getDefaultToolkit().getImage(Panel.class.getResource(\)); image3 =

Toolkit.getDefaultToolkit().getImage(Panel.class.getResource(\)); //初始化背景图片 imagebg

=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource(\)); }

//重写paint(必须的步骤) public void paint(Graphics g){

Java大作业报告(截止5月20日)

super.paint(g); //画一个活动区域

g.drawImage(imagebg, 0, 0, 400, 300,this); if(hero.isLive == true){ //画我的坦克

this.drawTank(hero.getX(), hero.getY(), g, this.hero.getDirect(), this.hero.getColor()); }

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

for(int i = 0 ; i < this.hero.ss.size() ; i++){ Shot myShot = this.hero.ss.get(i); //画一颗子弹,要先判断是否为空,因为坦克刚创建的时候,没有按J的时候,子弹是空的,这个时候不能画,要不然会异常

if(myShot!=null&&myShot.isLive == true){ g.draw3DRect(myShot.x, myShot.y, 1, 1, false); }

//判断子弹是否死亡,如果死亡,就从Vocetor中移除

Java大作业报告(截止5月20日)

if(myShot.isLive == false){ hero.ss.remove(myShot); } }

//画出敌人的坦克

for(int i = 0 ;i

this.drawTank(et.getX(), et.getY(), g, et.getDirect(), et.getColor()); //画出敌人的子弹

for(int j = 0 ; j

Shot enemyShot = et.ss.get(j); //开始画

if(enemyShot.isLive){ g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1, false); }else{

//如果子弹死亡,就把子弹移除 et.ss.remove(enemyShot);

Java大作业报告(截止5月20日)

} } } }

//画出炸弹

for(int i = 0 ; i < bombs.size(); i++){ //取出炸弹

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, 15, 15,this);

}else{

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

Java大作业报告(截止5月20日)

}

//减小炸弹的生命值 b.lifeDown();

//如果炸弹死亡,就移除数组 if(b.life == 0){ bombs.remove(b); } } }

//判断敌人是否击中我 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); this.hitTank(enemyShot, hero); }

Java大作业报告(截止5月20日)

} }

//判断我的子弹是否击中敌人的坦克 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

EnemyTank et = ets.get(j);

if(et.isLive){

this.hitTank(myShot, et); } } } } }

Java大作业报告(截止5月20日)

//判断子弹是否碰撞到坦克的函数

public void hitTank(Shot s , Tank et){ //判断敌军坦克的方向 switch(et.direct){ //向上或者向下的情况下 case 0: case 2:

if(s.x>et.x&&s.xet.y&&s.y

//击中 //子弹死亡

s.isLive = false; //坦克死亡

et.isLive = false; //创建一个炸弹,放入Vector Bomb b = new Bomb(et.x,et.y); bombs.add(b); }

//向左或者向右的情况下 case 1:

Java大作业报告(截止5月20日)

case 3:

if(s.x>et.x&&s.xet.y&&s.y

//击中 //子弹死亡

s.isLive = false; //坦克死亡

et.isLive = false; //创建一个炸弹,放入Vector Bomb b = new Bomb(et.x,et.y); bombs.add(b); } } }

//画坦克的函数。四个参数分别为:起始画的坐标,方向,类型

public void drawTank(int x,int y,Graphics g,int direct,int type){ //判断坦克的类型 switch(type){ case 0:

Java大作业报告(截止5月20日)

g.setColor(Color.RED);//我的坦克 break; case 1:

g.setColor(Color.blue);//敌军坦克 break; }

switch(direct){ case 0://炮筒向上 //画坦克

//第一步 画左边的那条履带

g.fill3DRect(x, y, 5, 30,false);//四个参数分别表示起始点和大小

//第二步 画出右边的那条履带

g.fill3DRect(x+15, y, 5, 30,false); //第三部 画出中间的驾驶舱

g.fill3DRect(x+5, y+5, 10, 20,false); //第四部 画出中间的炮塔

g.fillOval(x+5, y+9, 10, 10); //第五步 画出炮筒

g.drawLine(x+10, y+15, x+10, y);//四个参数分别表示起始点和终止点 break;

Java大作业报告(截止5月20日)

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+9, y+5, 10, 10); //第五步 画出炮筒

g.drawLine(x+15, y+10, x+30, y+10);//四个参数分别表示起始点和终止点 break;

case 2://炮筒向下

//第一步 画左边的那条履带

g.fill3DRect(x, y, 5, 30,false);//四个参数分别表示起始点和大小

//第二步 画出右边的那条履带

g.fill3DRect(x+15, y, 5, 30,false); //第三部 画出中间的驾驶舱

Java大作业报告(截止5月20日)

g.fill3DRect(x+5, y+5, 10, 20,false); //第四部 画出中间的炮塔

g.fillOval(x+5, y+9, 10, 10); //第五步 画出炮筒

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+9, y+5, 10, 10); //第五步 画出炮筒

g.drawLine(x+15, y+10, x, y+10);//四个参数分别表示起始点和终止点 } }

Java大作业报告(截止5月20日)

@Override

public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub }

//本游戏用到这个方法,就来处理这个方法,其他的先不管

//键按下

//W表示向上,A表示向左,S表示向下,D表示向右 public void keyPressed(KeyEvent e) { if(e.getKeyCode()==KeyEvent.VK_W){ //设置我的坦克的方向 this.hero.setDirect(0); if(this.hero.y>0){ this.hero.moveUp(); }

}else if(e.getKeyCode()==KeyEvent.VK_D){ //向右

this.hero.setDirect(1); if(this.hero.x<370){

Java大作业报告(截止5月20日)

this.hero.moveRiget(); }

}else if(e.getKeyCode()==KeyEvent.VK_S){ //向下

this.hero.setDirect(2); if(this.hero.y<270){ this.hero.moveDown(); }

}else if(e.getKeyCode()==KeyEvent.VK_A){ //向左

this.hero.setDirect(3); if(this.hero.x>0){ this.hero.moveLeft(); } }

//判断是否玩家按下j开火

if(e.getKeyCode()==KeyEvent.VK_J){ //开火

//if语句控制屏幕上同时最多只有多少颗子弹

Java大作业报告(截止5月20日)

if(this.hero.ss.size()<5){ this.hero.shotEnemy(); } }

this.repaint(); }

@Override

public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub }

@Override

public void run() {

// TODO Auto-generated method stub while(true){ try {

Thread.sleep(100); } catch (Exception e) { // TODO: handle exception

Java大作业报告(截止5月20日)

}

//调用判断我的子弹是否击中敌人的函数 this.hitEnemyTank();

//调用判断敌人子弹是否击中我的函数 this.hitMe(); //判断是否要加子弹

for(int i = 0 ;i

if(et.ss.size()<1){ Shot s =null; switch(et.direct){ case 0:

s = new Shot(et.x+10, et.y,0); et.ss.add(s); break; case 1:

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

et.ss.add(s); break; case 2:

Java大作业报告(截止5月20日)

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

et.ss.add(s); break; case 3:

s = new Shot(et.x, et.y+10,3); et.ss.add(s); break; }

//启动子弹线程

Thread t = new Thread(s); t.start(); } } } //重绘

this.repaint(); } } }

**********************************************

Java大作业报告(截止5月20日)

import java.util.Random; import java.util.Vector;

public class EnemyTank extends Tank implements Runnable{

//定义一个类集框架,存放敌人的子弹 Vector ss = new Vector();

public EnemyTank(int x, int y) { super(x, y); }

@Override

public void run() {

// TODO Auto-generated method stub while(true){ try {

Thread.sleep(50); } catch (Exception e) { // TODO: handle exception }

Java大作业报告(截止5月20日)

switch (this.direct){ case 0:

for(int i = 0 ;i <30;i++){ if(y>0) y= y-speed; try {

Thread.sleep(50); } catch (Exception e) { // TODO: handle exception } } break; case 1:

for(int i = 0 ;i <30;i++){ if(x<370) x= x+speed; try {

Thread.sleep(50); } catch (Exception e) { // TODO: handle exception

Java大作业报告(截止5月20日)

} } break; case 2:

for(int i = 0 ;i <30;i++){ if(y<270) y= y+speed; try {

Thread.sleep(50); } catch (Exception e) { // TODO: handle exception } } break; case 3:

for(int i = 0 ;i <30;i++){ if(x>0) x= x-speed; try {

Thread.sleep(50); } catch (Exception e) { // TODO: handle exception

Java大作业报告(截止5月20日)

} } break; }

//随机产生方向

Random random = new Random(); this.direct = random.nextInt(4); //判断是否死亡

if(this.isLive == false){ break; } } } }

********************************************** public class Shot implements Runnable{ //子弹坐标 int x; int y; //子弹发射方向

Java大作业报告(截止5月20日)

int direct; //子弹的速度 int speed = 6; //子弹是否生存

boolean isLive = true;

public Shot(int x,int y,int direct){ this.x=x; this.y=y;

this.direct = direct; }

@Override

public void run() {

// TODO Auto-generated method stub while(true){

//线程休眠50毫秒,每隔50毫秒子弹坐标修改一次 try {

Thread.sleep(50); } catch (Exception e) { // TODO: handle exception }

switch(direct){ case 0 ://向上飞

Java大作业报告(截止5月20日)

y=y-speed; break; case 1 ://向右飞 x = x+speed; break;

case 2 :///向下飞 y = y+speed; break; case 3 ://向左飞 x = x - speed; break; }

//子弹是否处境

if(x<0||x>400||y<0||y>300){ this.isLive = false; break; } } } }

***********************************************

Java大作业报告(截止5月20日)

public 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; } } }

本文来源:https://www.bwwdw.com/article/7zlw.html

Top