微信打飛機--Java版

世風日下啊,大家現在動不動就打飛機。。。

上個週末實在是無聊,就寫了個Java版的微信打飛機遊戲。。拿上來和大家交流交流,不喜勿噴(網絡上這個資源已經很多了很多了)


目前實現的功能:

1、敵方有兩類飛機:小飛機和大BOSS飛機(小飛機1滴血;BOSS有10滴血,我方我只設置一滴血,可以修改blood參數)

2、藥丸:有藍色藥丸和紅色藥丸 

3:藍色藥丸能雙發子彈 (有時間限制)

4:紅色藥丸全屏爆炸  屏幕下方顯示已有的紅色藥丸數目

5:按鍵說明:遊戲暫停p  遊戲繼續s   遊戲重開始 r  方向鍵控制上下左右  紅色藥丸使用空格

 下載地址

先上幾副圖看看吧(那個。。。飛機爆炸有點土。。。用一陀屎黃色的東西代替哈。。)

            

(注意)遊戲製作中細節的地方:

(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 打飛機邏輯

好了,能自己實現上面這段就說明:你已經會打飛機啦!大笑

下面教你怎麼打更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。。不太會用,傳上去後再給出地址下載哈



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章