`
Coco_young
  • 浏览: 126509 次
  • 性别: Icon_minigender_1
  • 来自: 湖南长沙
社区版块
存档分类
最新评论

我的多线程小游戏——坦克大战

阅读更多

经过一段时间的小奋斗,终于做出了一个还能玩的多线程小游戏啦!

 

1:游戏介绍:
游戏一共3关,每关的不同点是敌方坦克的强度不同,玩家坦克用键盘操控(按键说明已写在附件中),每隔一段时间还会出现道具,其余游戏说明也已经写在附件中。

(开始界面)


(游戏运行界面)
 

2:主要技术要点和学到的经验

    (1):技术要点:

           技术要点主要有两个:一是多线程的应用,二就是双缓冲技术。关于线程的使用,在这里,我并没有去考虑机器的承受能力(做的比较猥琐),每个坦克一个线程,每个子弹一个线程,每次出现的爆炸效果也是一个线程,同时还有一个局面的监控线程(主要是负责判断游戏是否结束,是否进入下一关,和道具出现),线程之间的关系是:坦克线程(坦克线程在运行过程中判断是否捡到道具,是否可移动)在运行过程中调用开火方法启动一个子弹线程,子弹线程在运行过程中判断是否应该爆炸(是否打中了东西),如果爆炸的话,这启动爆炸效果线程,同时结束自己的生命。下面是关键代码:

// 坦克的run()
	public void run() {
		while (true) {
			setBody();// 设置坦克属性值
			if (getProperty() == 0) {
				if (level < 2) {
					level++;
				}// 最高只能生到2级
				setBody();
				count = 0;
				TankClient.properties.remove(0);
			} else if (getProperty() == 1) {// 减少玩家剩余生命次数
				TankClient.lifeTime--;
				TankClient.lab.setText("剩余生命次数:" + TankClient.lifeTime);
				TankClient.properties.remove(0);
			} else if (getProperty() == 2) {// 炸掉玩家一架坦克
				if (TankClient.Client.size() > 0) {
					Bang bang = new Bang(TankClient.Client.get(0).getX(),
							TankClient.Client.get(0).getY());
					TankClient.Visual.add(bang);
					bang.start();
					TankClient.Client.remove(0);
					TankClient.properties.remove(0);
				}
			}
			if (TankClient.tanks.size() == 0) {
				break;
			}
			TankMove();
			count++;
			if (count == SHOOT) {
//每循环一次,计数变量加一,当等于开火次数时,开火。
				Fire();
				count = 0;
			}
			if (Ruined) {
				break;
			}
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

 

      

// 子弹的run
	public void run() {
		while (true) {
			if (indoor()) {
				if (TankClient.bullets.size() == 0) {
					break;
				}
				Fly();
				if (shoot_bride()) {//如果击中砖头
					Bang bang = new Bang(this.getX(), this.getY());//启动爆炸效果线程
					TankClient.Visual.add(bang);
					bang.start();
					TankClient.bullets.remove(this);
					break;
				}
				if (shoot_fe()) {//如果击中铁
					Bang bang = new Bang(this.getX(), this.getY());//启动爆炸效果线程
					TankClient.Visual.add(bang);
					bang.start();
					TankClient.bullets.remove(this);
					break;
				}
				if (Succeed()) {// 如果击中目标
					Bang bang = new Bang(this.getX(), this.getY());//启动爆炸效果线程
					TankClient.Visual.add(bang);
					bang.start();
					TankClient.bullets.remove(this);
					// 如果到达死亡水平
					if (TankClient.Client.get(0).getLevel() == -1) {
						TankClient.Client.remove(0);
					}
					break;
				}
			} else {
				Bang bang = new Bang(this.getX(), this.getY());//启动爆炸效果线程
				TankClient.Visual.add(bang);
				bang.start();
				TankClient.bullets.remove(this);
				break;
			}
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

 
 

 

//爆炸效果run(setNum是控制绘制第几张爆炸效果图片,以形成动态的效果)
	public void run(){
		int i = 0;
		setNum(i++);
		try {
			Thread.sleep(TankClient.FRANK-30);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		setNum(i++);
		try {
			Thread.sleep(TankClient.FRANK-30);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		setNum(i++);
		try {
			Thread.sleep(TankClient.FRANK-30);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		setNum(i++);
		try {
			Thread.sleep(TankClient.FRANK-30);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		setNum(i++);
		try {
			Thread.sleep(TankClient.FRANK-30);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		setNum(i++);
		try {
			Thread.sleep(TankClient.FRANK-30);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		TankClient.Visual.remove(this);
	}
}

 

   这个是主监控线程的代码:

 

package TankWarv10;

import java.util.Random;

/**
 * 监控线程:监控局面是否结束
 * 
 * @author dell
 * 
 */
public class Monitor extends Thread {

	private int Count = 0;// 计数器,每数100次出现一个道具
	private Random ran = new Random();// 随机算子,产生随机道具

	public void run() {
		while (true) {
			Count++;

			if (Count == 100) {// 每数100次出现一个道具
				int x, y;// 随机坐标
				x = ran.nextInt(430) + 50;
				y = ran.nextInt(430) + 50;
				property tmp = new property(x,y);
				int kind = ran.nextInt(3);
				tmp.setKind(kind);// 设置道具种类
				tmp.start();// 启动道具线程
				TankClient.properties.add(tmp);
				Count = 0;
			}
			// 如果我方坦克被摧毁,则游戏结束,清空所有局面
			if (TankClient.Client.size() == 0) {
				if (TankClient.lifeTime <= 0) {
					TankClient.bullets.clear();
					TankClient.pb.clear();
					TankClient.tanks.clear();
					TankClient.Visual.clear();
					TankClient.stop = true;
					break;
				} else {
					// 加入我的坦克
					TankClient.Client.add(new PlayerTank(250, 480));
					TankClient.Client.get(0).start();
					TankClient.lifeTime--;
					TankClient.lab.setText("剩余生命次数:" + TankClient.lifeTime);
				}
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// 如果敌方坦克被摧毁完毕,则游戏结束,清空所有局面
			switch (TankClient.mission) {
			case 1://如果是第一关
				if (TankClient.tanks.size() == 0) {
					TankClient.bullets.clear();
					TankClient.pb.clear();
					TankClient.Visual.clear();
					TankClient.clear();
					TankClient.mission++;
					TankClient.mis.setText("当前关卡:"+TankClient.mission);
					TankClient.initBackground();
				}break;
			case 2://如果是第二关
				if (TankClient.Sec_tanks.size() == 0) {
					TankClient.bullets.clear();
					TankClient.pb.clear();
					TankClient.Visual.clear();
					TankClient.clear();
					TankClient.mission++;
					TankClient.mis.setText("当前关卡:"+TankClient.mission);
					TankClient.initBackground();
				}break;
			case 3://如果是第三关
				if (TankClient.Tri_tanks.size() == 0) {
					TankClient.bullets.clear();
					TankClient.pb.clear();
					TankClient.Visual.clear();
					TankClient.clear();
					TankClient.Client.clear();
					TankClient.properties.clear();
					TankClient.stop = true;
				}break;
			}

				
		}
	}
}

 

 关于双缓冲技术的使用:双缓冲技术我理解也不能算十分深刻,在参见人家的代码以后,还算是能够做到吧。

 我自己的理解:双缓冲主要就是去重写update方法,在更新窗体时把下一个要显示的图片整体的画到窗体上去。

 下面是引用stchou博客中对闪屏的解释,和对双缓冲的解释:

paint闪烁的原因:

每一个paint的过后,程序会自行的调用repaint的方法,但是repaint方法中的绘制有的分配一个与原来窗口一样的的内存空间,但里面是没有存储东西的,所以一次次的paint,repaint的交替就会产生闪烁

 

解决方法:双缓冲技术的工作原理:先在内存中分配一个和窗口一样大的空间(在内存中的空间我门是看不到的),然后利用getGraphics()方法去获得该空间并将它全部一次性的显示到屏幕上.这样显示出来就非常的流畅了.避免了闪烁效果.

双缓冲的原理:
 1.建立一个Image对象DbBuffer,通过DbBuffer=createrImage(int width,int height)来在内存中开辟一个长为width 宽为heithr空间.次空间的大小可以和你动画窗口的大小保持一致,也可以利用getwidth()和getheight()来获得动画窗口的大小.
 2.建立一个Graphics 对象GraImage通过GraImage=DbBuffer.getGraphics();去把要绘制的对象并存放到分配好的内存空间中.
 3.利用paint(GraImage);将其全部绘制带内存之中,最后调用我门的paint(Graphics g)方法中的g.drawImage(DbBuffer,0,0,null)将DbBuffer全部一次性的绘制到我门的动画窗口,然后把我门内存中分配的空间窗口关闭调用dispose()方法.

下面是关键代码:

 

// 重写paint()
	public void paint(Graphics g) {
		super.paint(g);

		if (start) {
			// 我方tank
			if (Client.size() != 0) {
				Client.get(0).drawTank(g);
			}
			// 敌方坦克
			for (int i = 0; i < tanks.size(); i++) {
				tanks.get(i).drawTank(g);
			}
			for (int i = 0; i < Sec_tanks.size(); i++) {
				Sec_tanks.get(i).drawTank(g);
			}
			for (int i = 0; i < Tri_tanks.size(); i++) {
				Tri_tanks.get(i).drawTank(g);
			}

			// 画河流
			for (int i = 0; i < rivers.size(); i++) {
				rivers.get(i).drawBride(g);
			}
			// 敌方子弹
			for (int i = 0; i < bullets.size(); i++) {
				bullets.get(i).drawBullet(g);
			}
			// 我方子弹
			for (int i = 0; i < pb.size(); i++) {
				pb.get(i).drawBullet(g);
			}

			// 命中效果
			for (int i = 0; i < Visual.size(); i++) {
				Visual.get(i).drawBang(g);
			}
			// 画草
			for (int i = 0; i < Grass.size(); i++) {
				Grass.get(i).drawGrass(g);
			}
			// 画铁
			for (int i = 0; i < Fes.size(); i++) {
				Fes.get(i).drawFe(g);
			}
			// 画砖头
			for (int i = 0; i < brides.size(); i++) {
				brides.get(i).drawBride(g);
			}
			// 遍历道具队列
			for (int i = 0; i < properties.size(); i++) {
				properties.get(i).drawProperty(g);
			}
			if (stop) {
				new GameConsole().drawImage(g);// 画出游戏结束图片
			}
		} else {
			new GameConsole().drawStart(g);// 画出游戏开始图片
		}
	}

	// 重写update() 实现双缓冲
	public void update(Graphics g) {
		// super.update(g);
		if (buf_image == null) {
			buf_image = this.createImage(WINDOW_WHITH, WINDOW_HEIGHT);
		}
		Graphics gImage = buf_image.getGraphics();
		Color c = gImage.getColor();
		gImage.setColor(Color.BLACK);
		gImage.fillRect(0, 0, WINDOW_WHITH, WINDOW_HEIGHT);
		gImage.setColor(c);
		paint(gImage);
		g.drawImage(buf_image, 0, 0, null);
	}

	// 重绘线程
	class PaintThread extends Thread {
		private int Count = 0;// 计数变量(有时候会出现爆炸效果不消失现象,在此暂时解决);

		public void run() {
			while (true) {
				if (stop) {
					repaint();
					break;
				}
				Count++;
				if (Count == 50) {
					Visual.clear();
					Count = 0;
				}
				repaint();
				try {
					Thread.sleep(FRANK);
				} catch (InterruptedException e) {

					e.printStackTrace();
				}
			}
		}
	}

 

 经过这次坦克大战游戏的编写我所获得的经验:
 (1):每个软件的编写都是徐徐渐进的,先实现简单的功能,在逐步逐步加入新的功能,最后达到质变的阶段.

  附上几张小图:(版本的进程和最初版本的效果)

 


(2):做软件的过程中难免会碰到瓶颈,这时候要主动查询资料,和请教别人。
(3):做软件并不是随随便便,三下五除二就搞定的,它需要我们长时间的琢磨,无论是我们的UI还是AI,打造一个精美的软件是很有挑战性的。


最后,在附件中附上我的这个小游戏和源代码(在jar包中解压即可)。 感谢大家~~~~

  • 大小: 20.7 KB
  • 大小: 15.5 KB
  • 大小: 5.2 KB
  • 大小: 4.1 KB
7
5
分享到:
评论
2 楼 igdnss 2012-05-09  
static List<Home> symbol=new ArrayList<Home>();//司令部

//加入司令部

Home home = new Home(250,465);
  symbol.add(home);



//画司令部
   symbol.get(0).drawHome(g);
//击中司令部让司令部消失

private boolean shoot_home()
{  
          int symbol_x = TankClient.symbol.get(0).getX();
          int symbol_y = TankClient.symbol.get(0).getY();

          if(x>symbol_x&&x<symbol_x+75&&y>symbol_y&&y<symbol_y+50)
          {
           TankClient.symbol.remove(0);
           return true;
          }
          

return false;

}

我是学着你写的,自己会的不多,希望谅解。不知道为什么,总出现越界问题,却找不出错误来,谢谢你的帮助。链表里面只有一个司令部。用下标从0开始应该没有什么问题啊
1 楼 yinger_fei 2011-11-04  
赞一个!!

相关推荐

    坦克大战——C++游戏代码

    功能方面,游戏参考于80年代任天堂红白机(FC/FamilyComputer)上的游戏坦克大战(Battle City),包括地图,游戏模式等等(当时的游戏直接烧在电路板上)。所以游戏平衡方面已经有了很好的参考,无需再花大量时间测试平衡...

    坦克大战小游戏

    《坦克大战小游戏——Java编程实践解析》 在IT领域,编程语言的学习往往伴随着各种各样的实战项目,以加深对语言特性和编程思维的理解。今天我们要探讨的是一款经典的“坦克大战”小游戏,它采用Java语言进行开发,...

    java编的小游戏-坦克大战

    《Java编程实现的小游戏——坦克大战》 在IT领域,编程语言的应用无处不在,而Java作为其中的一员,因其跨平台、面向对象的特性,深受开发者喜爱。本篇将详细介绍一款利用Java语言编写的经典小游戏——坦克大战。这...

    java自制小游戏坦克大战

    本项目是一个基于Java编程语言的小型游戏——坦克大战,非常适合初学者进行实践和学习。通过参与这个项目,你可以深入理解Java编程的基础知识,并逐步提升编程技能。以下是对该项目涉及的主要Java知识点的详细解析:...

    使用java开发的一款小游戏,坦克大战,新手第一次写,请多多关照

    在本项目中,我们讨论的是一个使用Java编程语言开发的小游戏——坦克大战。作为一个新手的初次尝试,这个项目展示了开发者对Java基础知识的理解以及将其应用于实际游戏开发的能力。下面我们将深入探讨涉及的Java知识...

    java小游戏坦克大战代码

    本篇文章将深入探讨一款基于Java编写的经典小游戏——坦克大战。这款坦克大战代码提供了三个不同版本,适配Eclipse环境,方便开发者直接运行和学习。 坦克大战是一款历史悠久的游戏,其基本玩法是控制己方坦克,...

    Java实现坦克大战

    在本文中,我们将深入探讨如何使用Java编程语言来实现一款经典的小游戏——坦克大战。Java是一种广泛应用于桌面应用、移动应用、服务器端开发以及游戏开发的面向对象的编程语言。其丰富的类库和强大的性能使得它成为...

    基于C#的坦克大战小游戏

    在这个项目中,开发者利用C#的强大功能,构建了一个经典的游戏——坦克大战。 在C#中开发游戏,通常会用到.NET Framework或.NET Core作为运行环境,以及Visual Studio作为集成开发环境(IDE)。这个坦克大战游戏...

    使用Swing开发的java版坦克大战小游戏.zip

    在这个项目中,开发者利用Swing库构建了一个经典的游戏——坦克大战。这个项目不仅展示了Swing的应用,还体现了Java在游戏开发中的潜力。 首先,让我们深入了解一下Swing。Swing是Java Foundation Classes (JFC)的...

    WIN32API 坦克大战

    本文将通过一个经典的游戏——“坦克大战”,来深入探讨如何利用WIN32 API进行程序开发,不涉及MFC(Microsoft Foundation Classes)库。 首先,我们来看什么是WIN32 API。WIN32 API 是一组由微软提供的函数库,...

    坦克大战游戏

    《坦克大战游戏开发详解——基于WPF的入门教程》 在计算机编程的世界里,游戏开发一直是最吸引人的领域之一,而“坦克大战”作为一款经典的街机游戏,更是深受玩家们的喜爱。本文将深入探讨如何使用WPF(Windows ...

    基于Swing实现的FC经典游戏-坦克大战.zip

    在本项目中,开发者使用Java Swing库来复刻了经典的FC游戏——坦克大战。Swing是Java的一个图形用户界面(GUI)工具包,它允许程序员创建丰富的桌面应用程序。以下是关于Swing和坦克大战游戏实现的一些关键知识点: ...

    Java桌面_坦克大战小游戏.zip

    总的来说,"Java桌面_坦克大战小游戏.zip"是一个集Java编程、游戏设计、多线程应用、资源管理等多个知识点于一体的实战项目。通过学习和分析,开发者不仅能深化对Java的理解,还能提升解决问题的能力,为未来的项目...

    这是一个使用Java实现的坦克大战小游戏.zip

    在这个名为“Java实现的坦克大战小游戏”的项目中,开发者使用了Java编程语言来创建一个经典的游戏——坦克大战。Java是一种广泛使用的面向对象的编程语言,以其跨平台的特性而闻名,这使得这个游戏可以在多种操作...

    这是韩顺平零基础学Java课程中的坦克大战的小游戏.zip

    其次,它是一个实际的项目——坦克大战游戏,这意味着它将涉及到游戏开发的基础知识,包括游戏逻辑、碰撞检测、用户交互等方面。最后,由于是学习项目,它应该是可运行的,方便学习者通过实践来理解Java编程。 ...

    VB经典项目坦克大战源码

    本篇文章将深入探讨一个基于VB .NET实现的经典项目——坦克大战的源码,旨在帮助初学者理解游戏开发的基本原理和VB .NET的运用。 坦克大战是一款历史悠久的双人合作或对战游戏,源自任天堂的FC(Family Computer)...

    VB课程设计--- 坦克大战

    ### VB课程设计——坦克大战知识点总结 #### 一、系统概述 本项目旨在利用VB.NET环境重现经典游戏“坦克大战”。此游戏对于90后来说是童年记忆的一部分,因此选择将其作为课程设计的主题,不仅能够唤起怀旧情感,还...

    坦克大战java代码

    接着,深入到游戏的核心——坦克的移动与射击。在Java中,这通常涉及到类的设计与对象的创建。坦克类(Tank Class)会包含属性(如位置、速度、生命值)和方法(如移动、开火)。这里,初学者将学习到如何使用面向...

    坦克大战Java版,一共约1000行代码

    这个项目是一个基于Java编程语言实现的经典游戏——坦克大战。坦克大战是一款历史悠久的双人合作或对战游戏,玩家控制坦克在复杂的地形中与敌方坦克作战,保护基地不被击中。通过Java来重制这个游戏,我们可以深入...

    android 坦克大战

    本文将深入探讨一个专为初学者设计的Android项目——“坦克大战”。这款小游戏虽然功能相对简单,但它提供了理解Android游戏开发的基础框架,是学习Android编程的良好起点。 首先,我们要明白Android游戏开发的基础...

Global site tag (gtag.js) - Google Analytics