微信打飞机--Java版

世风日下啊,大家现在动不动就打飞机。。。

上个周末实在是无聊,就写了个Java版的微信打飞机游戏。。拿上来和大家交流交流,不喜勿喷(网络上这个资源已经很多了很多了)


目前实现的功能:

1、敌方有两类飞机:小飞机和大BOSS飞机(小飞机1滴血;BOSS有10滴血,我方我只设置一滴血,可以修改blood参数)

2、药丸:有蓝色药丸和红色药丸 

3:蓝色药丸能双发子弹 (有时间限制)

4:红色药丸全屏爆炸  屏幕下方显示已有的红色药丸数目

5:按键说明:游戏暂停p  游戏继续s   游戏重开始 r  方向键控制上下左右  红色药丸使用空格

 

先上几副图看看吧(那个。。。飞机爆炸有点土。。。用一陀屎黄色的东西代替哈。。)

    微信打飞机--Java版     微信打飞机--Java版   微信打飞机--Java版   微信打飞机--Java版

(注意)游戏制作中细节的地方:

(1)图一中左下角的显示

(2)双发子弹的设计,如果有一发击中敌机,另一发也应该继续往前走


那个图形美化实在是不善长,就借用微信上的飞机截图做素材哈,,,版权归原作者所有。


------------------------------------------------------------------------

1 简单入门

其实做这个游戏主要你规划好有什么角色,每帧他们都在做什么就好了,然后用什么数据结构去表示(应该说压根就不设计什么算法,数据结构的东西)

在进行冗长的说明之前,我先举个例子,比如如何实现一个物体在界面中随着时间移动(暂时不考虑边界问题)

实现:
1:实时绘制背景 为黑色
2:一红色小球从界面顶部下落
3:随着时间增长,速度增快
4:为了不出先卡吨,实现双缓冲机制


首先,我们需要一个JFrame窗口,这个继承就好,然后实现paint()方法,来实现我们的绘制,制作背景简单,可是为什么要实时更新呢?

因为这里我们所看见的动画就是每帧图像快速拼接起来的,而每幅图像都需要我们重新绘制,否则都是在原有图像上再次绘制,所以,如果每次都不刷新界面,那么会有上一次的滞留图像。

paint方法如下:


@Override
	public void paint(Graphics g) {
		//super.paint(arg0);
		//before draw, move first
		time++;
		y += velocity + time;
		//draw
		Color c = g.getColor();
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, 480, 800);
		g.setColor(Color.RED);
		g.fillOval(x, y, 10, 10);
		g.setColor(c);
	}

可是,如果绘制物体过多,我们会发现,存在卡顿现象,这也是所有显示都会遇到的问题,一般采用双缓冲方式解决,我们这里不是什么大型游戏,就简单用下面方法实现双缓冲机制,即我们先绘制好下一帧图像,再显示,而不是边显示边绘制。

我们在先申明一个公共变量Image buffer;专门存储下一帧图像,并且在update()函数里实现绘制

@Override
	public void update(Graphics g) {
		//super.update(g);
		if(buffer == null)
			buffer = this.createImage(480, 800);
		Graphics gBuffer = buffer.getGraphics();
		paint(gBuffer);//先绘制在缓冲中
		g.drawImage(buffer, 0, 0, null);
	}

当然,这里update()传入的g参数就是我们这个窗口的画笔。

随着时间增加,速度增快,这个在paint()函数里已经简单实现了。。

然后就是怎么实现实时绘制,当然是需要开一个定时器啦。。那就开一个线程专门负责更新图像不久好了?

这里关键的更新就是利用mf.update(mf.getGraphics());然后就调用我们刚才实现的update(),然后里面再调用paint()

class MainThread implements Runnable{
		MainFrame mf = null;
		public MainThread(MainFrame mf) {
			this.mf = mf;
		}
		@Override
		public void run() {
			while(true){
				try{
					Thread.sleep(50);
					mf.update(mf.getGraphics());
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}
	}

上面这个流程很清晰了,就是让线程负责时间刷新,然后通知窗口,要更新啦!!窗口对象调用更新函数,更新函数通知逻辑绘制函数paint(),要更新啥,你说了算。。。所以把这个程序分为两部分:

UI更新:逻辑更新(目前都是在paint()里面具体实现的)

所以这个程序一封装,以后我们要先游戏,不久只需要在paint()函数里做手脚不就行了么?


下面给出这个小demo的代码

package ylf.graphics;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.JFrame;
/**
 * @author ylf
 */
public class MainFrame extends JFrame{
	int time ;
	int velocity ;
	int x ;
	int y;
	Image buffer = null;
	
	public MainFrame() {
		init();
		
		this.setSize(480, 800);
		this.setVisible(true);
		
		new Thread(new MainThread(this)).start();
	}
	
	public void init(){
		time = 0;
		velocity = 0;
		x = 240;
		y = 0;
	}
	
	@Override
	public void paint(Graphics g) {
		//super.paint(arg0);
		//before draw, move first
		time++;
		y += velocity + time;
		//draw
		Color c = g.getColor();
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, 480, 800);
		g.setColor(Color.RED);
		g.fillOval(x, y, 10, 10);
		g.setColor(c);
	}
	
	@Override
	public void update(Graphics g) {
		//super.update(g);
		if(buffer == null)
			buffer = this.createImage(480, 800);
		Graphics gBuffer = buffer.getGraphics();
		paint(gBuffer);//先绘制在缓冲中
		g.drawImage(buffer, 0, 0, null);
	}
	
	class MainThread implements Runnable{
		MainFrame mf = null;
		public MainThread(MainFrame mf) {
			this.mf = mf;
		}
		@Override
		public void run() {
			while(true){
				try{
					Thread.sleep(50);
					mf.update(mf.getGraphics());
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String[] args) {
		MainFrame m = new MainFrame();
	}
}


2 打飞机逻辑

好了,能自己实现上面这段就说明:你已经会打飞机啦!微信打飞机--Java版

下面教你怎么打更comfortable

继续刚才的,既然我们可以把飞机的逻辑业务都抽取出来,那么这个Frame类我们就不去打扰了,我们独立出一个Controller的类,该类负责游戏业务控制,比如我方飞机的对象持有,敌方一群飞机对象持有(用什么数据结构?当然就用链表呗。。)该逻辑也就是控制分数,还有游戏开始,暂停以及重新开始一些外围以及游戏运行的整体逻辑。

我把Controller的onDraw()函数贴出来,大家就清楚这个游戏逻辑

定期安排敌人飞机出现

定期安排药丸出现

刷新我们飞机位置 状态

刷新敌人飞机位置 状态

刷新爆炸动画

刷新药丸个数显示

刷新分数

public void onDraw(Graphics g) {
		///////游戏逻辑/////////////
		//schedular produce plane-other
		//定期安排出飞机,出飞机的类型有飞机工厂来生成
		if((++readyOther)%10==0){
			readyOther = 0;
			Random rand = new Random();
			OtherPlaneFactory.getPlanes(rand.nextInt(2), others, this);
		}
		//schedular produce equipment
		//定期安排药丸出现  其实这里也可以弄一个药丸工厂
		if((++readyPowerful)%600==0){
			Random rand = new Random();
			if(rand.nextBoolean())
				equipments.add(new PowerEquipment(rand.nextInt(MainFrame.FRAME_WIDIH), 0, this));
			else
				equipments.add(new BombEquipment(rand.nextInt(MainFrame.FRAME_WIDIH), 0, this));
		}
		
		/////下面就是把逻辑分配给这些游戏角色了
		Color oldColor = g.getColor();
		
		myPlane.onDraw(g);  //我方飞机逻辑控制
		for(int i=0;i<others.size();i++)
			others.get(i).onDraw(g);   //敌方飞机逻辑控制
		for(int i=0;i<explosions.size();i++)
			explosions.get(i).onDraw(g);   //爆炸的绘制
		
		// 下面这段是为了实现界面左下角的药丸个数提醒的绘制,实现方法有很多,我这里粗略实现了
		int bombNum = 0;
		for(int i=0;i<equipments.size();i++){
			Equipment e = equipments.get(i); 
			e.onDraw(g);
			if(e.getType() == Equipment.TYPE_BOMB){
				if(!((BombEquipment)e).isLive()){
					bombNum++;
				}
			}
		}
		if(bombNum != 0){
			g.drawImage(bombNumImg, 10, MainFrame.FRAME_HEIGHT-50, null);
			g.drawString(""+bombNum, 85, MainFrame.FRAME_HEIGHT-22);
		}
			
		//绘制分数
		g.setColor(Color.BLACK);
		g.drawImage(pauseFace, 10, 30, null);
		g.drawString(""+score, 60, 50);
		g.setColor(oldColor);
	}


3 打飞机的角色

主要的还是角色的设置才是学习java的途径

如何把java的一些设计原则使用的好就在这里。

接口的封装和字符类的继承,我觉得最好能用接口就使用接口,还有功能不能定的太死,最好能用插拔接口的形式。

例如某个物体是需要能运动的。我们不需要对所有角色都继承一个有onMove()的父类,而是可以用实现了Moveable这个接口。这种灵活性比使用类好的多。当然我实现上也有许多缺陷,仅供参考:下载地址

http://download.csdn.net/detail/ylf13/6870955

还在弄git。。不太会用,传上去后再给出地址下载哈



微信打飞机--Java版

上一篇:微信二维码扫描无法下载APK文件的解决办法


下一篇:微信开发--入门(二)