Java飛機大戰【4】遊戲的主要類

這是飛機大戰遊戲的基礎工具類代碼及解釋,其他的也在博客中

遊戲中上層的主要類,統一放在包com.airbattle.game下

遊戲的主要邏輯在這個包裏實現

類名 用途
Drawer 畫圖,用畫筆Graphics,在畫板上指定位置處畫出img圖像,這是靜態方法
Property 關於遊戲配置的所有常量,包括:設置背景、各個角色的圖片,飛機移動速度、飛機開火速度、飛機最大生命值、遊戲幀率、遊戲的其他配置信息。這裏還有變量frame,用於記錄遊戲幀數
Heroplane 英雄機,即遊戲主角
BulletArray 子彈陣列類,遊戲產生的所有子彈,放在這個類中。類中是一個類似堆的數據結構,有兩個堆,一個存儲英雄機的子彈對象,一個存儲敵機的子彈對象,還有兩個指針,表示每個堆中有多少個子彈對象,指向堆頂
HostileArray. 敵機陣列類,所有的敵機對象存儲在這個類中
PlaneController 按鍵事件處理器,繼承了Java類庫的KeyAdapter類,用於處理鍵盤事件
Game 主程序及畫圖類的繼承與實現

下面是源代碼,命名很清晰,有註釋

Drawer類

package com.airbattle.game;

import java.awt.Graphics;

import com.airbattle.gameproperty.Image;
import com.airbattle.gameproperty.Position;

public class Drawer {
	//用畫筆Graphics,在畫板上位置pos處畫出img圖像
	static public void draw(Graphics g, Image img, Position pos) {
		g.drawImage(img.img, pos.y, pos.x, null);
	}
}

Property類

package com.airbattle.game;

public class Property {
	public static final int FRAME_RATE = 100;	//幀率,FPS
	public static final int SPACE = (int)(1000.0 / FRAME_RATE);	//每幀之間的延遲時間,ms
	
	public static final int HERO_FIRE_TIMESPACE = 400;	//英雄開火間隔,ms
	public static final int HERO_FIRE_FRAME = //英雄機開火間隔的幀數
			(int)((double)HERO_FIRE_TIMESPACE / SPACE);
	
	public static final int HERO_MOVE_SPEED = 5;	//英雄移動速度
	
	
	public static final int ENEMY_FIRE_TIMESPACE = 300;	//敵軍開火間隔,ms
	public static final int ENEMY_FIRE_FRAME = 	//敵軍開火間隔的幀數
			(int)((double)ENEMY_FIRE_TIMESPACE / SPACE);
	
	public static final int ENEMY_MOVE_SPEED = 1;	//敵軍移動速度
	public static final int ENEMY_MOVE_SPACE = 20;	//敵人移動的時間間隔
	public static final int ENEMY_MOVE_FRAME =	//敵人移動的幀數間隔
			(int)((double)ENEMY_MOVE_SPACE / SPACE);
	
	public static final int BULLET_MOVE_SPEED = 2;	//子彈移動速度
	public static final int BULLET_MOVE_SPACE = 10;//子彈移動的時間間隔
	public static final int BULLET_MOVE_FRAME =	//敵人移動的幀數間隔
			(int)((double)BULLET_MOVE_SPACE / SPACE);
	
	
	
	public static final int ENEMY_ARRAY_COL = 20;	//敵軍陣列的列數
	public static final int ENEMY_ARRAY_ROW = 6;	//敵軍陣列的行數
	
	public static final String HERO_IMAGE_FILEPATH = 
			"D:\\workspace\\AirBattle\\src\\plane.jpg";	//英雄機圖片文件
	public static final int HERO_IMAGE_WIDTH = 40;
	public static final int HERO_IMAGE_HEIGHT = 40;
	
	public static final String ENEMY_IMAGE_FILEPATH = 
			"D:\\workspace\\AirBattle\\src\\hostile.jpg";	//敵機圖片文件
	public static final int ENEMY_IMAGE_WIDTH = 15;
	public static final int ENEMY_IMAGE_HEIGHT = 15;
	
	public static final String BACKGROUND_IMAGE_FILEPATH = 
			"D:\\workspace\\AirBattle\\src\\stars.jpg";	//背景圖片文件
	public static final int BACKGROUND_IMAGE_WIDTH = 480;
	public static final int BACKGROUND_IMAGE_HEIGHT = 640;
	
	public static final String HEROBULLET_IMAGE_FILEPATH = 
			"D:\\workspace\\AirBattle\\src\\herobullet2.jpg";	//英雄機子彈圖片文件
	public static final int HEROBULLET_IMAGE_WIDTH = 10;
	public static final int HEROBULLET_IMAGE_HEIGHT = 20;
	
	public static final String ENEMYBULLET_IMAGE_FILEPATH = 
			"D:\\workspace\\AirBattle\\src\\enemybullet.jpg";	//敵軍子彈圖片文件
	public static final int ENEMYBULLET_IMAGE_WIDTH = 5;
	public static final int ENEMYBULLET_IMAGE_HEIGHT = 10;
	
	public static final int ENEMYARRAY_SPACE_X = 30;	//敵軍陣列的x,y間距
	public static final int ENEMYARRAY_SPACE_Y = 5;
	
	public static final int BULLET_BUFFER_SIZE = 10000;	//子彈緩衝區大小,太小會發生溢出
	
	public static final int MAX_HERO_HEALTH = 10;	//英雄機的最大生命值
	
	public static int frame = 0;	//總幀數
	
	
	public Property() {
		
	}
	
}

Heroplane類

package com.airbattle.game;

import com.airbattle.gameinterface.HeroplaneInterface;
import com.airbattle.gameobject.Aircraft;
import com.airbattle.gameobject.Bullet;
import com.airbattle.gameproperty.Image;
import com.airbattle.gameproperty.Position;
import com.airbattle.gameproperty.Rect;

public class Heroplane extends Aircraft implements HeroplaneInterface{
	//英雄機形態,沒有實現相關功能
	int form;
	//有僚機時的圖像,沒有實現相關功能
	Image wingmanImg;
	//是否無敵,沒有實現相關功能
	boolean matchless;
	//攻擊力,沒有實現相關功能
	int damage;
	//生命值
	int health;
	//得分
	int score;
	//飛機的寬和高
	public static final int width = Property.HERO_IMAGE_WIDTH;
	public static final int height = Property.HERO_IMAGE_HEIGHT;
	public Heroplane() {
		
		this.form = 0;
		this.matchless = false;
		this.damage = 1;
		this.health = Property.MAX_HERO_HEALTH;
		this.score = 0;
		//System.out.println("英雄機初始化完成,圖像已加載到內存");
	}
	//設置飛機位置,因爲鍵盤事件處理程序在圖像類中,所以需要從圖像類中更新飛機的位置信息
	public void setPos(Position pos) {
		this.pos = pos;
	}
	//開火,從英雄機當前位置生成一顆飛向敵機陣列的子彈
	public Bullet fire() {
		return new Bullet(1, new Position(this.pos.x, this.pos.y + Property.HERO_IMAGE_WIDTH/2));
		
	};
	
	//獲取飛機的外接矩形框,用於判斷飛機是否和敵人子彈的矩形框接觸
	public Rect getRect() {
		return new Rect(this.pos.x, this.pos.y, 
				height, width);
	}
	
	//被子彈打中,減生命值
	public void onHit(int numHit) {
		this.health -= numHit;
		//System.out.println("英雄生命值已扣除");
	};
	//變形,未實現
	public void transform() {
		
	};
	public int getHealth() {
		return this.health;
	};
	public int getScore() {
		return this.score;
	};
	public void moveStep() {
		
	}
	
}

BulletArray類

package com.airbattle.game;

import com.airbattle.gameinterface.GameObjectInterface;
import com.airbattle.gameobject.Bullet;
import com.airbattle.gameproperty.Rect;
/**
 * 
 * @author William
 *子彈陣列類,遊戲產生的所有子彈,放在這個類中。
 *類中是一個類似堆的數據結構,有兩個堆,
 *一個存儲英雄機的子彈對象,一個存儲敵機的子彈對象,
 *還有兩個指針,表示每個堆中有多少個子彈對象,指向堆頂
 */
public class BulletArray  implements GameObjectInterface{
	Bullet[] enemyBullet = new Bullet[Property.BULLET_BUFFER_SIZE];
	Bullet[] heroBullet = new Bullet[Property.BULLET_BUFFER_SIZE];
	public int pointerEnemy = 0;
	public int pointerHero = 0;
	//構造器,剛開始沒有子彈,指針全都指向null
	public BulletArray() {
		for (int i = 0; i < enemyBullet.length; i++) {
			enemyBullet[i] = null;
		}
		for (int i = 0; i < heroBullet.length; i++) {
			heroBullet[i] = null;
		}
		//System.out.println("子彈圖像已加載到內存");
		//System.out.println("子彈初始化完畢");
	}
	
	
	//敵軍開火時,添加敵軍子彈
	public void addEnemyBullet(Bullet bullet) {
		
		enemyBullet[pointerEnemy++] = bullet;
		//System.out.println("新增的子彈已經加入敵人子彈陣列 ");
	}
	//英雄機開火時,添加敵軍子彈
	public void addHeroBullet(Bullet bullet) {
		heroBullet[pointerHero++] = bullet;
		//System.out.println("新增的子彈已經加入英雄子彈陣列");
	}
	
	//子彈移動
	public void bulletMove() {
		//System.out.println("英雄子彈移動...");
		for (int i = 0; i < pointerHero; i++) {
			heroBullet[i].moveStep(-Property.BULLET_MOVE_SPEED);
		}
		
		//System.out.println("敵人子彈移動...");
		for (int i = 0; i < pointerEnemy; i++) {
			enemyBullet[i].moveStep(Property.BULLET_MOVE_SPEED);
		}
		
	}
	
	//刪除已經出界的子彈,清理內存空間
	public void deleteInvalidBullet() {
		for (int i = 0; i < pointerHero; i++) {
			if (heroBullet[i].pos.x < 0 || heroBullet[i].pos.x > 640) {
				deleteHeroBullet(i);
			}
		}
		for (int i = 0; i < pointerEnemy; i++) {
			
			if (enemyBullet[i].pos.x < 0 || enemyBullet[i].pos.x > 640) {
				deleteEnemyBullet(i);
				//System.out.println("Actually deleted!");
			}
		}
		//System.out.println("無效子彈已刪除");
	}
	
	//刪除堆中特定的子彈
	public void deleteHeroBullet(int i) {
		heroBullet[i] = null;
		for (int j = i; j < pointerHero-1; j++) {
			heroBullet[j] = heroBullet[j+1];
			heroBullet[j+1] = null;
		}
		pointerHero--;
	}
	public void deleteEnemyBullet(int i) {
		enemyBullet[i] = null;
		for (int j = i; j < pointerEnemy-1; j++) {
			enemyBullet[j] = enemyBullet[j+1];
			enemyBullet[j+1] = null;
		}
		pointerEnemy--;
	}
	
	public void moveStep() {
		
		
	}

	//根據給定的英雄機的外界矩形,判斷有幾個敵軍子彈打到了英雄機
	//打到之後進行計數,然後將敵軍子彈刪除
	public int heroInRange(Rect rect) {
		int hitCnt = 0;
		for (int i = 0; i < pointerEnemy; i++) {
			Rect bulletRect = new Rect(enemyBullet[i].pos.x,
					enemyBullet[i].pos.y,
					Property.ENEMYBULLET_IMAGE_HEIGHT,
					Property.ENEMYBULLET_IMAGE_WIDTH);
			
			if (rect.hit(bulletRect) == true) {
				hitCnt++;
				deleteEnemyBullet(i);
			}
		}
		return hitCnt;	
	}
	
	//根據給定的敵機的外界矩形,判斷有幾個英雄機子彈打到了英雄機
	//打到之後返回非0值,並將英雄機子彈刪除
	public int enemyInRange(Rect rect) {
		int hitCnt = 0;
		for (int i = 0; i < pointerHero; i++) {
			Rect bulletRect = new Rect(heroBullet[i].pos.x,
					heroBullet[i].pos.y,
					Property.HEROBULLET_IMAGE_HEIGHT,
					Property.HEROBULLET_IMAGE_WIDTH);
			
			if (rect.hit(bulletRect) == true) {
				hitCnt++;
				deleteHeroBullet(i);
			}
		}
		return hitCnt;	
	}	
	
}

HostileArray類

package com.airbattle.game;

import java.util.Random;

import com.airbattle.gameinterface.GameObjectInterface;
import com.airbattle.gameobject.Bullet;
import com.airbattle.gameobject.HostilePlane;
import com.airbattle.gameproperty.Image;
import com.airbattle.gameproperty.Position;

/**
 * 
 * @author William
 * 敵軍陣列類
 * 陣列大小在配置文件中指定
 * 陣列的樣式在主函數中傳入一個和陣列相同形狀的矩陣
 * 非0值代表該位置有敵機,0代表沒有敵機
 */
public class HostileArray implements GameObjectInterface{
	//敵機陣列數組
	HostilePlane[][] planes = new HostilePlane[Property.ENEMY_ARRAY_ROW][Property.ENEMY_ARRAY_COL];
	
	//陣列的位置(左上角座標)
	Position pos = new Position(0, 0);
	
	//移動速度(負代表向左,正代表向右)
	public int moveDir = Property.ENEMY_MOVE_SPEED;

	
	public HostileArray(short[][] array) {
		int cnt = 0;
		for (int i = 0; i < planes.length; i++)
			for (int j = 0; j < planes[i].length; j++) {
				if (array[i][j] != 0) {
					planes[i][j] = new HostilePlane(
							new Position(i*Property.ENEMYARRAY_SPACE_X, 20)
							);
					cnt++;
				}
				else
					planes[i][j] = null;
			}
		//System.out.println("敵機圖像已加載到內存");
		//System.out.println("敵機陣列初始化完畢,共初始化 " + cnt +" 臺敵機");
		
	}
	//實例化敵軍陣列對象,
	//按照arrayDefine數組提供的規則初始化敵軍陣列
	public Bullet randomFire() {
		Random rand = new Random();
		int firingMark = -1;
		int col = -1, row = -1;
		while (firingMark == -1) {
			int random_fire = rand.nextInt(Property.ENEMY_ARRAY_ROW * Property.ENEMY_ARRAY_COL);
			row = random_fire/Property.ENEMY_ARRAY_COL;
			col = random_fire%Property.ENEMY_ARRAY_COL;
			if (planes[row][col] != null)
				firingMark = random_fire;
		}
		
		return new Bullet(1, new Position(row, planes[row][col].pos.y));
	}
	
	//判斷陣列是否碰到了窗體邊界,如果碰到了返回true
	private boolean isCollide() {
		if (this.pos.y + this.moveDir <= 0 ||
				this.pos.y + this.moveDir +
				Property.ENEMY_ARRAY_COL*Property.ENEMY_IMAGE_WIDTH
				+ Property.ENEMYARRAY_SPACE_Y * (Property.ENEMY_ARRAY_COL + 1)
				>= Property.BACKGROUND_IMAGE_WIDTH
				) 
			return true;
		return false;
	}
	
	//移動到下一個位置
	//先判斷敵軍陣列下次移動會不會移出窗體,如果能,向相反方向運動
	public void nextPos() {
		if (this.isCollide()) 
			moveDir *= -1;
		this.pos.y += moveDir;
		//System.out.println("敵軍陣列移動完成,當前位置:"+ pos.x + ", " + pos.y + ")");
	}
	
	public void moveStep() {
		
	}
	
	//因爲更新敵軍位置時都是更新陣列左上角的座標
	//想要獲取每個敵機的具體位置時,需要進行計算
	public void refreshPos() {
		for (int i=0; i<Property.ENEMY_ARRAY_ROW; i++)
			for (int j=0; j<Property.ENEMY_ARRAY_COL; j++)
				if (planes[i][j] != null) {
					Position pos = planes[i][j].pos;
					pos.y = this.pos.y + j*(Property.ENEMY_IMAGE_WIDTH + Property.ENEMYARRAY_SPACE_Y);
					
				}
		
	}
}

PlaneController類

package com.airbattle.game;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class PlaneController extends KeyAdapter{
	
	public MyJPanel jpanel;
	public PlaneController(MyJPanel jpanel) {
		this.jpanel = jpanel;
	}
	//重寫這個函數,定義按下左鍵、右鍵時英雄機移動
	public void keyPressed(KeyEvent e) {
		
		int code = e.getKeyCode();
		//System.out.println("按鍵按下,鍵值:" + code);
		switch(code) {
		case 37:
			if (jpanel.heroPos.y > 0)
				jpanel.heroPos.y-=Property.HERO_MOVE_SPEED;
			break;
		case 39:
			if (jpanel.heroPos.y + Property.HERO_MOVE_SPEED + Property.HERO_IMAGE_WIDTH
					< Property.BACKGROUND_IMAGE_WIDTH)
				jpanel.heroPos.y+=5;
			else jpanel.heroPos.y = Property.BACKGROUND_IMAGE_WIDTH - Property.HERO_IMAGE_WIDTH;
			break;
		}
	}
	
	
	
}

Game類

package com.airbattle.game;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Scanner;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import com.airbattle.gameobject.Bullet;
import com.airbattle.gameproperty.Image;
import com.airbattle.gameproperty.Position;
import com.airbattle.gameproperty.Rect;

import com.airbattle.game.Property;

public class Game {
	static public void main(String[] argv) throws InterruptedException {
		//System.out.println("遊戲開始——————————————");
		
		//實例化英雄機對象
		Heroplane hero = new Heroplane();
		
		//定義一個數組,用於確定敵軍陣列的陣型
		//數組中數字不爲0,代表該點有敵軍,在構造函數中將新建一個敵軍對象放在該位置
		//如果是0,則該位置沒有敵軍,初始化爲null
		short[][] arrayDefine = new short[Property.ENEMY_ARRAY_ROW][Property.ENEMY_ARRAY_COL];
		
		//將數組全部設置爲1,如果需要設置敵軍陣型,只需要修改這個數組
		for (int i=0; i<Property.ENEMY_ARRAY_ROW; i++)
			for (int j=0; j<Property.ENEMY_ARRAY_COL; j++) {
				arrayDefine[i][j] = 1;
			}
		
		//實例化敵軍陣列對象,其中包含一個敵機數組,按照arrayDefine數組提供的規則初始化敵軍陣列
		HostileArray hostile = new HostileArray(
				arrayDefine);
		
		//System.out.println("-------------- 敵機陣列初始化 --------------");
		
		//實例化子彈陣列對象,其中是一個類似堆的數據結構
		//有兩個堆,一個存儲英雄機的子彈對象,一個存儲敵機的子彈對象
		//還有兩個指針,表示每個堆中有多少個子彈對象
		BulletArray bullet = new BulletArray();
		//System.out.println("-------------- 子彈陣列初始化 --------------");
		
		//定義窗口對象
		JFrame jFrame = new JFrame();
        //定義畫板對象,在該對象的paint函數中實現繪圖
		MyJPanel jpanel = new MyJPanel(hostile, bullet);
        
		//設置窗口標題
		jFrame.setTitle("飛機大戰-WilliamCode");
		//將畫板對象加入窗體中
		jFrame.add(jpanel);
		// 設置畫框大小(寬度,高度),默認都爲0
		//這裏設置爲背景圖片的寬和高
		jFrame.setSize(Property.BACKGROUND_IMAGE_WIDTH, Property.BACKGROUND_IMAGE_HEIGHT);
        // 將畫框展示出來。true設置可見
		jFrame.setVisible(true);
		//向窗體加入按鍵事件監聽器
		//PlaneController是一個監聽器,繼承了java類庫中的KeyAdapter
		//需要重寫其中的KeyPressed方法,在其中定義按鍵按下時的操作
		jFrame.addKeyListener(new PlaneController(jpanel));
		
		//主循環開始
		while(true) {
			//遊戲幀數計數器,提供遊戲從開始運行一共渲染了多少幀
			Property.frame ++;
			//System.out.println("\n\n-------------- 遊戲幀開始 --------------");
			
			//System.out.println("正在檢測敵軍是否被英雄子彈擊中,擊中減生命值,到0則銷燬對象");
			
			//刷新敵機陣列的位置信息
			hostile.refreshPos();
			
			//遍歷敵軍陣列,判斷敵軍是否被子彈打中
			//如果打中,將該敵機銷燬
			for (int i=0; i<Property.ENEMY_ARRAY_ROW; i++) 
				for (int j=0; j<Property.ENEMY_ARRAY_COL; j++){
					if (hostile.planes[i][j] != null) {
						Rect r = hostile.planes[i][j].getRect();
						//System.out.println(r.x1 + " " + r.x2 + " " + r.y1 + " " + r.y2);
						int numHit = bullet.enemyInRange(hostile.planes[i][j].getRect());
						if (numHit != 0) {
							hostile.planes[i][j] = null;
							jpanel.score++;
						}
					}
			}
			
			//判斷敵軍子彈是否機中英雄機,返回擊中的子彈數目
			int numHit = bullet.heroInRange(hero.getRect());
			//System.out.println("正在檢測英雄機是否被敵軍子彈擊中,擊中減生命值,到0則遊戲結束");
			
			//英雄機被擊中,扣除生命值,並更新到窗體中
			//System.out.println("擊中英雄機的子彈數量:" + numHit);
			hero.onHit(numHit);
			jpanel.health = hero.health;
			
			//System.out.println("正在佈置敵軍開火");
			
			//判斷是否到達幀數,到達一定幀數時,敵機開火
			if (Property.frame % Property.ENEMY_FIRE_FRAME == 0) {
					//任選一個敵機開火,返回子彈文件
					Bullet newBullet = hostile.randomFire();
					//將子彈加入子彈陣列中
					bullet.addEnemyBullet(newBullet);
			}	
			
			//判斷是否到達幀數,到達一定幀數時,敵軍移動
			if (Property.frame % Property.ENEMY_MOVE_FRAME == 0) {
				//System.out.println("正在更新敵軍移動");
				//這裏只需要更改敵軍的左上角的x,y座標,敵機陣列作爲一個整體移動
				//因爲每個敵機的具體座標在使用前,都會使用refreshPos函數進行計算
				hostile.nextPos();
			}
			
			
			//System.out.println("正在佈置友軍開火");
			//判斷是否到達幀數,到達一定幀數時,友軍開火
			if (Property.frame % Property.HERO_FIRE_FRAME == 0) {
				//友軍開火,返回一個子彈對象,該子彈從英雄機所在位置發出,垂直打向敵機陣列
				Bullet newBullet = hero.fire();
				//將子彈加入子彈陣列
				bullet.addHeroBullet(newBullet);
			}
			//System.out.println("正在更新友軍移動");
			
			//按鍵監聽器存儲在JPanel對象中,所以英雄機的位置信息暫存在JPanel中
			//使用前需要把位置信息更新到英雄機對象
			hero.setPos(jpanel.heroPos);
			
			//System.out.println("正在佈置背景移動");
			//System.out.println("背景暫時不用移動");

			//判斷是否到達幀數,到達一定幀數時,進行子彈的移動和刪除
			if (Property.frame % Property.BULLET_MOVE_FRAME == 0) {
				//System.out.println("正在更新子彈移動");
				//子彈的移動,敵軍子彈向英雄機移動,英雄機子彈向敵軍移動
				bullet.bulletMove();
				//System.out.println("出界子彈處理");
				//處理出界的子彈,直接從子彈的堆中刪除,防止內存溢出和泄露
				bullet.deleteInvalidBullet();
			}
				
			
			//System.out.println("遊戲幀結束,準備渲染下一幀(按Enter繼續)");
			//System.out.println("+++++++++++");
			//System.out.println("英雄機血量" + hero.health);
			//System.out.println("敵機子彈數量" + bullet.pointerEnemy);
			//System.out.println("英雄機子彈數量" + bullet.pointerHero);
			
			//等待一定時間	
			Thread.sleep(Property.SPACE);
		}
		
		
	}

}
//繼承的JPanel對象
//在創建對象時,自動調用一次paint方法
//我們在paint方法結束時,新啓動了一個進程
//在改進程中重新啓動了畫圖,即調用了repaint方法
//repaint方法會調用一系列方法,確保畫圖時不會發生窗口閃爍等問題
//最後,repaint方法會自動調用paint方法,重新畫圖
//我們只需要修改paint方法中畫圖時用到的對象即可,畫圖會自己進行
class MyJPanel extends JPanel{
    
	//需要顯示的英雄機生命值、得分
	public int health = 0;
	public int score = 0;
	
	//因爲鍵盤事件監聽器放在對象中,所以這裏存放了英雄機的位置信息
    Position heroPos = new Position((int)((Property.BACKGROUND_IMAGE_HEIGHT+0.1)*0.8), Property.BACKGROUND_IMAGE_WIDTH/2-Property.HERO_IMAGE_WIDTH/2);
   
    //各種遊戲元素的圖片文件
    static Image heroImage = new Image(Property.HERO_IMAGE_FILEPATH, Property.HERO_IMAGE_WIDTH, Property.HERO_IMAGE_HEIGHT);
    static Image hostileImage = new Image(Property.ENEMY_IMAGE_FILEPATH, Property.ENEMY_IMAGE_WIDTH, Property.ENEMY_IMAGE_HEIGHT);
    static Image backgroundImage = new Image(Property.BACKGROUND_IMAGE_FILEPATH, Property.BACKGROUND_IMAGE_WIDTH, Property.BACKGROUND_IMAGE_HEIGHT);
    static Image enemyBulletImage = new Image(Property.ENEMYBULLET_IMAGE_FILEPATH, Property.ENEMYBULLET_IMAGE_WIDTH, Property.ENEMYBULLET_IMAGE_HEIGHT);
    static Image heroBulletImage = new Image(Property.HEROBULLET_IMAGE_FILEPATH, Property.HEROBULLET_IMAGE_WIDTH, Property.HEROBULLET_IMAGE_HEIGHT);
    
    //定義敵軍陣列、子彈陣列的引用,和主函數中引用同一對象
    HostileArray hostile;
    BulletArray bullet;
    
    //構造函數,將上述兩個引用在構造對象時賦值
    public MyJPanel(HostileArray hostile, BulletArray bullet) {
    	super();
    	this.hostile = hostile;
    	this.bullet = bullet;
    }
    
    //畫圖函數,這是JPanel對象規定的方法,每次在畫圖時,這個函數將會被調用
    public void paint(Graphics graphics) {
        // 必須先調用父類的paint方法
        super.paint(graphics);
        
        //畫背景圖片
        //Drawer是自己實現的一個類
        //使用畫筆graphics在畫板上畫圖,draw是靜態方法
        Drawer.draw(graphics, backgroundImage, new Position(0,0));
        
        //畫英雄機
        Drawer.draw(graphics, heroImage, heroPos);
        
        //遍歷敵軍子彈陣列,畫子彈
        for (int i=0; i<bullet.pointerEnemy; i++) {
        	Drawer.draw(graphics, enemyBulletImage, bullet.enemyBullet[i].pos);
        }
        
        //遍歷友軍子彈陣列,畫子彈
        for (int i=0; i<bullet.pointerHero; i++) {
        	Drawer.draw(graphics, heroBulletImage, bullet.heroBullet[i].pos);
        }
        //更新敵軍陣列的所有敵機的位置信息
        hostile.refreshPos();
        //遍歷敵軍陣列,畫敵軍
        for (int i=0; i<Property.ENEMY_ARRAY_ROW; i++)
        	for (int j=0; j<Property.ENEMY_ARRAY_COL; j++) {
        		if(hostile.planes[i][j] != null) {
        			Drawer.draw(graphics, hostileImage, hostile.planes[i][j].pos);  
        		}
        	}
    
        //java.awt.Image image = new ImageIcon(file).getImage();
        // 用畫筆Graphics,在畫板JPanel上畫一個小人
        //graphics.drawImage(heroImage.img,x++,y++,this);// 頭部(畫圓形)
        
        //顯示生命值和得分
        graphics.setFont(new Font("微軟雅黑", Font.BOLD, 20));
        graphics.setColor(Color.white);
        graphics.drawString("HP:" + health, 10, Property.BACKGROUND_IMAGE_HEIGHT-50);
        graphics.drawString("Score:" + score, 10, Property.BACKGROUND_IMAGE_HEIGHT-70);
        
        new updateClass().start();
    }
    
    //這個進程用於重畫圖像
    //這個內部類在paint方法調用完成時進行了run方法的調用
    class updateClass extends Thread{
    	public void run() {
    		repaint();
    	}
    	
    }
    
}



 

 

發佈了86 篇原創文章 · 獲贊 59 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章