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 篇原创文章 · 获赞 56 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/WilliamCode/article/details/103788276
今日推荐