`
费文—jmiss
  • 浏览: 34890 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

坦克大战游戏技术点总结(基于多线程)

 
阅读更多

一.游戏编写的背景

为加深对多线程的理解与运用,熟悉多线程的机制,编写了坦克大战这一个小游戏。其中实现了多个线程的控制及线程的监听功能。通过着以游戏的开发,确实加深了我对多线程的理解,也加深了对键盘监听机制、界面的熟悉,还有是双缓冲的学习与使用。


二.游戏截图




 

 

 

三.技术点

①.多线程:敌方坦克由五个线程控制,还有一个监听线程,还有一个控制屏幕刷新的线程,还有若干控制子弹的线程。有两个方法判断子弹是否与击中坦克,一个是用一个监听线程,在监听线程里得到装载有子弹属性的队列,装载坦克属性的队列,通过判断坦克种类是否与子弹种类一致(即自己一方的坦克发出标记为己方类型的子弹,敌方的坦克发出的子弹标记为敌方类型的子弹),在判断子弹与坦克是否有交集,就可以知道子弹是否击中坦克了。

有一个坦克的父类,父类中油坦克的属性,坦克开火、移动的方法,自己的坦克与敌方的坦克分别继承父类坦克,己方坦克用主线程,敌方坦克新建一个线程,子弹通过坦克的方法发射,所以子弹线程中要得到坦克发射的坐标,子弹线程中还需要判断子弹是否与地图上的元素相撞(坦克也如此)。地图通过一个二维数组保存,不同元素标记为不同的数值,通过数值的不同,就可以判断子弹,坦克是否可以前行了。

所以,总结一点就是,框架很重要,线程的控制是重点,框架要实现各个线程对各种因素的控制。




②.重绘与双缓冲技术

坦克大战还有重要的一个,就是实现界面上各个因素的重绘。随意每个因素都必须要写一个draw()的方法,再在panit()中调用。不过随着图片的增多,界面会出现闪烁的线程,要解决这种现象,就要用到双缓冲技术,即重写update()方法,在update()方法中创建一个图片对象,相当于以后重绘的各种图片都绘在这张图片上一样。

 

 

// 声明缓冲图像
		Image offScreenImage = null;

		// 双缓冲机制的具体实现
		// 重写update方法,先将窗体上的图形画在图片对象上,再一次性显示
		public void update(Graphics g) {
			if (offScreenImage == null) {
				// 截取窗体所在位置的图片
				offScreenImage = this.createImage(GameWidth, GameHeight);
			}
			// 获得截取图片的画布
			Graphics gImage = offScreenImage.getGraphics();
			// 获取画布的底色并且使用这种颜色填充画布(默认的颜色为黑色)
			Color c = Color.BLACK;
			gImage.setColor(c);
			gImage.fillRect(0, 0, GameWidth, GameHeight); // 有清除上一步图像的功能,相当于gImage.clearRect(0,
			// 0, WIDTH, HEIGHT)
			// 将截下的图片上的画布传给重绘函数,重绘函数只需要在截图的画布上绘制即可,不必在从底层绘制
			paint(gImage);
			// 将接下来的图片加载到窗体画布上去,才能考到每次画的效果
			g.drawImage(offScreenImage, 0, 0, null);
		}

		// 重绘坦克、子弹、地图
		public void paint(Graphics g) {

			 // 在重绘函数中实现双缓冲机制  
        		offScreenImage = this.createImage(WIDTH, HEIGHT);  
        		// 获得截取图片的画布  
        		gImage = offScreenImage.getGraphics();  
        		// 获取画布的底色并且使用这种颜色填充画布,如果没有填充效果的画,则会出现拖动的效果  
       			 gImage.setColor(gImage.getColor());  
        		 gImage.fillRect(0, 0, WIDTH, HEIGHT); // 有清楚上一步图像的功能,相当于gImage.clearRect(0, 0, WIDTH, HEIGHT)  
			// 调用父类的重绘方法,传入的是截取图片上的画布,防止再从最底层来重绘
			super.paint(gImage);
			gImage.setColor(Color.RED);
			gImage.drawString("敌方坦克数量:" + ThreadListener.count2, 10, 20);
			gImage.drawString("我方坦克数量:" + ThreadListener.count1, 10, 40);
			if (!Cannonball.isStop) {
				paintBallCollide(gImage);
				paintMap(g, Map.Map1Copy);

				paintTank(gImage);
			}
			if (Cannonball.isStop) { // 如果停止,再将Map1赋给Map1
				for (int i = 0; i < Map.Map1.length; i++) {
					for (int j = 0; j < Map.Map1[i].length; j++) {

						Map.Map1Copy[i][j] = Map.Map1[i][j];
					}
				}
				paintMap(gImage, Map.Map1Copy);
			}

			// System.out.println("<__>" + tankarray.size());
		}
 

 

还有一种解决办法就是用一个线程,不断地刷新界面,消除闪烁。

// 利用一线程实现画面不停的刷新
	class PaintThread implements Runnable {
		public void run() {
			while (true) {
				repaint();
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
 

 

 

  • 大小: 38.7 KB
  • 大小: 51 KB
  • 大小: 50.3 KB
  • 大小: 41.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics