java實現(xiàn)飛機大戰(zhàn)案例詳解
前言
飛機大戰(zhàn)是一個非常經(jīng)典的案例,因為它包含了多種新手需要掌握的概念,是一個非常契合面向?qū)ο笏枷氲娜腴T練習案例
程序分析:
在此游戲中共有六個對象:
小敵機Airplane,大敵機BigAirplane,小蜜蜂Bee,天空Sky,英雄機Hero,子彈Bullet
其次我們還需要三個類:
超類Flyer,圖片類Images,測試類World
還需:
英雄機2張,小敵機,大敵機,小蜜蜂,子彈,天空各1張,爆炸圖4張,游戲開始,暫停,游戲結(jié)束各1張,共14張圖片放入與圖片類Images同包中

超類Flyer:
此類是用來封裝所有對象共有的行為及屬性的
不管是寫什么程序,都建議遵循兩點:數(shù)據(jù)私有化,行為公開化
import java.util.Random;
import java.awt.image.BufferedImage;
public abstract class Flyer {
//所有對象都有三種狀態(tài):活著的,死了的,及刪除的
//這里之所以選擇用常量表示狀態(tài)是因為首先狀態(tài)是一個不需要去修改的值
//其次狀態(tài)需要反復(fù)使用所以結(jié)合這兩個特點,我選擇了使用常量表示
//state是用來表示當前狀態(tài)的,每個對象都有一個實時的狀態(tài),此狀態(tài)是會改變的,且初始狀態(tài)都是活著的
public static final int LIVE = 0;//活著的
public static final int DEAD = 1;//死了的
public static final int REMOVE = 2;//刪除的
protected int state = LIVE;//當前狀態(tài)(默認狀態(tài)為活著的)
每個對象都是一張圖片,既然是圖片那么就一定有寬高,其次因為每個對象都是會隨時移動的 即為都有x,y坐標
protected int width;//寬
protected int height;//高
protected int x;//左右移動(x坐標)
protected int y;//上下移動(y坐標)
/**
* 飛行物移動(抽象)
* 每個飛行物都是會移動的,但是移動方式不同
* 所以這里就將共有的行為抽到了超類中
* 但是設(shè)置成了抽象方法,實現(xiàn)了多態(tài)的效果
*/
public abstract void step();
/**
* 獲取圖片(抽象)
* 所有對象都是圖片但圖片不相同所以抽象化了
*/
public abstract BufferedImage getImage();
/**
* 判斷對象是否是活著的
*/
public boolean isLive(){
return state == LIVE;
}
/**
* 判斷對象是否是死了的
*/
public boolean isDead(){
return state == DEAD;
}
/**
* 判斷對象是否刪除了
*/
public boolean isRemove(){
return state == REMOVE;
}
/**
* 判斷對象(大敵機,小敵機,小蜜蜂)是否越界
* 當敵人越界我們就需要刪除它否則程序越執(zhí)行越卡,會出現(xiàn)內(nèi)存泄露的問題,此方法就是為后續(xù)刪除越界對象做鋪墊的
* @return
*/
public boolean isOutOfBounds(){
return y >= World.HEIGHT;
}
/**
* 給小/大敵機,小蜜蜂提供的
* 因為三種飛行物的寬,高不同所以不能寫死。
* 若三種飛行物的寬,高相同,那么就可以將寬,高寫死
*/
public Flyer(int width,int height){
Random rand = new Random();
this.width = width;
this.height = height;
x = rand.nextInt(World.WIDTH-width);//x:0到負的width長度的之間的隨機數(shù)
y = -height;//y:負的height高度
}
/**
* 給天空,子彈,英雄機提供的
* 因為英雄機,子彈,天空的寬,高,x,y都是不同的,所以數(shù)據(jù)不能寫死,需要傳參
*/
public Flyer(int width,int height,int x,int y){
this.width = width;
this.height = height;
this.x = x;
this.y = y;
}
/**
*檢測碰撞
* this:敵人(小敵機/小蜜蜂/大敵機)
* other:子彈/英雄機
*@return
*/
public boolean isHit(Flyer other){
int x1 = this.x - other.width;//x1:敵人的x-英雄機/子彈的寬
int x2 = this.x + this.width;//x2:敵人的x加上敵人的寬
int y1 = this.y - other.height;//y1:敵人的y-英雄機/子彈的高
int y2 = this.y + this.height;//y2:敵人的y加上敵人的高
int x = other.x;//x:英雄機/子彈的x
int y = other.y;//y:英雄機/子彈的y
/*
x在x1與x2之間 并且 y在y1與y2之間,即為撞上了
*/
return x>x1 && x<=x2 && y>=y1 && y<=y2;
}
/**
* 飛行物死亡
*/
public void goDead(){
state = DEAD;//將當前狀態(tài)修改為死了的
}
}
圖片工具類Images:
此類用來獲取每個對象對應(yīng)的圖片
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
/**
* 圖片工具類
*/
public class Images {
// 公開的 靜態(tài)的 圖片數(shù)據(jù)類型 變量名
/**
* 對象圖片
*/
public static BufferedImage sky;//天空
public static BufferedImage bullet;//子彈
public static BufferedImage[] heros;//英雄機
public static BufferedImage[] airs;//小敵機
public static BufferedImage[] bairs;//大敵機
public static BufferedImage[] bees;//小蜜蜂
/**
* 狀態(tài)圖片
*/
public static BufferedImage start;//啟動狀態(tài)圖
public static BufferedImage pause;//暫停狀態(tài)圖
public static BufferedImage gameover;//游戲結(jié)束狀態(tài)圖
static {//初始化靜態(tài)圖片
sky = readImage("background01.png");//天空
bullet = readImage("bullet.png");//子彈
heros = new BufferedImage[2];//英雄機圖片數(shù)組
heros[0] = readImage("hero0.png");//英雄機圖片1
heros[1] = readImage("hero1.png");//英雄機圖片2
airs = new BufferedImage[5];//小敵機圖片數(shù)組
bairs = new BufferedImage[5];//大敵機圖片數(shù)組
bees = new BufferedImage[5];//小蜜蜂圖片數(shù)組
airs[0] = readImage("airplane.png");//小敵機圖片讀取
bairs[0] = readImage("bigairplane.png");//大敵機圖片讀取
bees[0] = readImage("bee01.png");//小蜜蜂圖片讀取
/**爆炸圖迭代讀取*/
for (int i=1;i<5;i++){//遍歷/迭代賦值
airs[i] = readImage("bom"+i+".png");//小敵機圖片數(shù)組其余元素賦值爆炸圖
bairs[i] = readImage("bom"+i+".png");//大敵機圖片數(shù)組其余元素賦值爆炸圖
bees[i] = readImage("bom"+i+".png");//小蜜蜂圖片數(shù)組其余元素賦值爆炸圖
}
start = readImage("start.png");//啟動狀態(tài)圖
pause = readImage("pause.png");//暫停狀態(tài)圖
gameover = readImage("gameover.png");//游戲結(jié)束狀態(tài)圖
}
/**
* 讀取圖片
* 此處的fileName:圖片文件名
*
* try.....catch:異常的一種處理方法
*/
public static BufferedImage readImage(String fileName){
try{
BufferedImage img = ImageIO.read(Flyer.class.getResource(fileName)); //讀取與Flyer在同一個包中的圖片
return img;
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException();
}
}
}
世界窗口類/測試類 World:
此類用來集合所有類進行排序及具體的操作,和程序的最終運行
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.nio.Buffer;
//定時器
import java.util.Timer;
//定時器任務(wù)
import java.util.TimerTask;
//打開隨機類
import java.util.Random;
//擴容類
import java.util.Arrays;
/**
* 世界測試類(整個游戲窗口)
*/
public class World extends JPanel{
public static final int WIDTH = 400;//窗口寬
public static final int HEIGHT = 700;//窗口高
public static final int START = 0;//啟動狀態(tài)
public static final int RUNNING = 1;//運行狀態(tài)
public static final int PAUSE = 2;//暫停狀態(tài)
public static final int GAME_OVER = 3;//游戲結(jié)束狀態(tài)
private int state = START;//當前狀態(tài)默認是啟動狀態(tài)
/**
* 聲明每個類具體的對象
* 如下為:窗口中所看到的對象
*/
private Sky s = new Sky();//天空對象
private Hero h = new Hero();//英雄機對象
private Flyer[] enemies ={};//敵人對象,分別是大敵機,小敵機,小蜜蜂所以寫成了數(shù)組
private Bullet[] bt ={};//子彈也是有很多的所以寫成了數(shù)組
/**
* 生成敵人對象(小敵機,大敵機,小蜜蜂)
*/
public Flyer nextOne(){
Random rand = new Random();
int type = rand.nextInt(20);//0-19之間的隨機數(shù)
if (type < 5){//當隨機數(shù)小于5
return new Bee();//返回小蜜蜂
}else if (type < 13){//當隨機數(shù)小于13
return new Airplane();//返回小敵機
}else{//大于十三則
return new BigAirplane();//返回大敵機
}
}
private int enterIndex = 0;
/**
* 敵人(大敵機,小敵機,小蜜蜂)入場
*/
public void enterAction() {//每10毫秒走一次
enterIndex++;
if (enterIndex%40 == 0 ){//四百毫秒走一次
Flyer fl = nextOne();//獲取敵人對象
enemies = Arrays.copyOf(enemies,enemies.length+1);//擴容(每產(chǎn)生一個敵人數(shù)組就擴容1)
enemies[enemies.length-1] = fl;//將生成的敵人fl放置enemies數(shù)組的末尾
}
}
int shootIndex = 0;
/**
* 子彈入場
*/
public void shootAction(){//10毫秒走一次
shootIndex++;
if (shootIndex%30 == 0){//每300毫秒走一次
Bullet[] bs = h.shoot();//獲取子彈數(shù)組對象
bt = Arrays.copyOf(bt,bt.length+bs.length);//擴容子彈數(shù)組(每入場一個子彈就加一個元素)
System.arraycopy(bs,0,bt,bt.length-bs.length,bs.length);//數(shù)組的追加
}
}
/**
* 讓除去英雄機外的所有對象(小敵機,大敵機,小蜜蜂,子彈,天空)移動
*/
public void setpAction() {//每10毫秒走一次
s.step();//天空移動
for (int i=0;i<enemies.length;i++) {//遍歷所有敵人
enemies[i].step();//敵人移動
}
for (int i=0;i<bt.length;i++){//遍歷所有子彈
bt[i].step();//子彈移動
}
}
/**
* 重寫outOfBoundsAction(方法)
*/
public void outOfBoundsAction() {//每10毫秒走一次
for (int i=0;i<enemies.length;i++){//遍歷所有敵人
if (enemies[i].isOutOfBounds() || enemies[i].isRemove()){
enemies[i] = enemies[enemies.length-1];//最后一個敵人和越界敵人替換
enemies = Arrays.copyOf(enemies,enemies.length-1);//縮容
}
}
for (int i=0;i<bt.length;i++){//迭代所有子彈
if (bt[i].isOutOfBounds() || bt[i].isRemove()){
bt[i] = bt[bt.length-1];//用最后一個子彈替換出界的子彈
bt = Arrays.copyOf(bt,bt.length-1);//縮容
}
}
}
private int score = 0;//玩家的得分
/**
* 子彈與敵人的碰撞
*/
public void bulletBangAction() {//每10毫秒走一次
for (int i=0;i<bt.length;i++){//遍歷所有子彈
Bullet b = bt[i];//獲取每一個子彈
for (int j=0;j<enemies.length;j++){//迭代每一個敵人
Flyer f = enemies[j];//獲取每一個敵人
if (b.isLive() && f.isLive() && f.isHit(b)){//若子彈活著的,敵人活著的,并且兩個對象相撞
b.goDead();//子彈當前狀態(tài)修改為死亡
f.goDead();//敵人當前狀態(tài)修改為死亡
if (f instanceof EnemyScore) {//判斷死亡的敵人類型能否強轉(zhuǎn)為得分接口類型
EnemyScore es = (EnemyScore) f;//將死亡敵人向下造型
score += es.getScore();//調(diào)用具體的敵人對象的得分接口的getScore()加分方法
}
if (f instanceof EnemyAward){//判斷死亡的敵人類型能否強轉(zhuǎn)為獎勵值接口類型
EnemyAward ea = (EnemyAward) f;//將死亡敵人強轉(zhuǎn)為獎勵值接口類型
int type = ea.getAwardType();//將具體的獎勵值賦值給type
switch (type){
case EnemyAward.FIRE://火力值
h.addFier();//返回增加火力值
break;
case EnemyAward.LIFE://生命值
h.addLife();//返回增加生命值
break;
}
}
}
}
}
}
/**
* 英雄機與敵人的碰撞
*/
private void heroBangAction() {//每10毫秒走一次
for (int i=0;i<enemies.length;i++){//迭代所有敵人
Flyer f = enemies[i];//獲取每個敵人
if (f.isLive() && h.isLive() && f.isHit(h)){//判斷碰撞
f.goDead();//敵人死亡
h.subtractLife();//英雄機減生命值
h.clearFier();//英雄機清空火力值
}
}
}
/**
* 檢測游戲結(jié)束
*/
private void checkGameOverAction() {//每10毫秒走一次
if (h.getLife() <= 0) {//若英雄機生命值為0或小于0
state = GAME_OVER;//將狀態(tài)修改為GAME_OVER游戲結(jié)束狀態(tài)
}
}
/**
* 啟動程序的執(zhí)行
*/
public void action() {//測試代碼
MouseAdapter m = new MouseAdapter() {
/**
* 重寫mouseMoved()鼠標移動事件
* @param e
*/
@Override
public void mouseMoved(MouseEvent e) {
if (state == RUNNING){//僅在運行狀態(tài)下執(zhí)行
int x = e.getX();//獲取鼠標的x坐標
int y = e.getY();//獲取鼠標的y坐標
h.moveTo(x,y);//接收鼠標具體坐標
}
}
/**
* 重寫mouseClicked() 鼠標點擊事件
* @param e
*/
public void mouseClicked(MouseEvent e){
switch (state){//根據(jù)當前狀態(tài)做不同的處理
case START://啟動狀態(tài)時
state = RUNNING;//鼠標點擊后改成運行狀態(tài)
break;
case GAME_OVER://游戲結(jié)束狀態(tài)時
/**
* 清理戰(zhàn)場(將所有數(shù)據(jù)初始化)
*/
score = 0;//總分歸零
s = new Sky();//天空初始化所有屬性
h = new Hero();//英雄機初始化所有屬性
enemies = new Flyer[0];//敵人初始化所有屬性
bt = new Bullet[0];//子彈初始化所有屬性
state = START;//鼠標點擊后修改為啟動狀態(tài)
break;
}
}
/**
* 鼠標移出窗口事件
* @param e
*/
public void mouseExited(MouseEvent e){
if (state == RUNNING){//若狀態(tài)為運行
state = PAUSE;//則將當前狀態(tài)修改為暫停
}
}
/**
* 鼠標的進入窗口事件
* @param e
*/
public void mouseEntered(MouseEvent e){
if (state == PAUSE){//若當前狀態(tài)為暫停
state = RUNNING;//則將當前狀態(tài)修改為運行
}
}
};
this.addMouseListener(m);
this.addMouseMotionListener(m);
Timer timer = new Timer();//定時器對象
int interval = 10;//定時的間隔(此間隔是以毫秒為單位)
timer.schedule(new TimerTask() {
@Override
public void run() {//定時干的事(每10毫秒自動執(zhí)行此方法當中的所有方法)
if (state == RUNNING){//只在運行狀態(tài)下執(zhí)行
enterAction();//敵人(大敵機,小敵機,小蜜蜂)入場
shootAction();//子彈入場
setpAction();//飛行物移動
outOfBoundsAction();//刪除越界的敵人
bulletBangAction();//子彈與敵人的碰撞
heroBangAction();//英雄機與敵人的碰撞
checkGameOverAction();//檢測游戲結(jié)束
}
repaint();//重新調(diào)用paint()方法(重畫)
}
}, interval, interval);//定時計劃表
}
/**
* 重寫paint方法,在窗口中畫圖片
* @param g:畫筆
*/
public void paint(Graphics g){//每10毫秒走一次
g.drawImage(s.getImage(), s.x, s.y, null);//畫天空
g.drawImage(s.getImage(), s.x, s.getY1(), null);//畫第二張?zhí)炜?
g.drawImage(h.getImage(),h.x,h.y,null);//畫英雄機
for (int i=0;i<enemies.length;i++){//遍歷所有敵人
Flyer f = enemies[i];//獲取每一個敵人
g.drawImage(f.getImage(),f.x,f.y,null);//畫敵人
}
for (int i = 0; i<bt.length; i++){//遍歷所有子彈
Bullet b = bt[i];//獲取所有子彈
g.drawImage(b.getImage(),b.x,b.y,null);//畫子彈
}
g.drawString("SCORE:"+score,10,25);//在窗口右上角畫分數(shù)
g.drawString("HP:"+h.getLife(),10,45);//在窗口右上角畫出英雄機的生命值
switch (state){//畫狀態(tài)圖
case START:
g.drawImage(Images.start,0,0,null);//啟動狀態(tài)圖
break;
case PAUSE:
g.drawImage(Images.pause,0,0,null);//暫停圖
break;
case GAME_OVER:
g.drawImage(Images.gameover,0,0,null);//游戲結(jié)束圖
break;
}
}
/**
* 主執(zhí)行方法
* @param args
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
World world = new World();
frame.add(world);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(WIDTH,HEIGHT);
frame.setLocationRelativeTo(null);
frame.setVisible(true);//1)設(shè)置窗口可見 2)盡快調(diào)用paint()方法
world.action();//啟動程序的執(zhí)行
}
}
/**
* 1.問:為什么要將引用設(shè)計再main方法的外面?
* 答:因為若將引用設(shè)計在main中,則引用只能在main中使用,其他方法都不能訪問,
* 為了能在其他方法中也能訪問這些引用,所以將引用設(shè)計在main外
*
* 2.問:為什么要單獨創(chuàng)建action方法來測試?
* 答:因為main方法時static的,在main方法中是無法訪問引用的,
* 所以需要單獨創(chuàng)建非static的方法來測試
*
* 3.問:為什么在main中要先創(chuàng)建world對象,然后再調(diào)用action()方法?
* 答:因為main方法是static的,再main中是無法調(diào)用action()方法的
* 所以要先創(chuàng)建world對象,然后再調(diào)用action()方法
*/
小敵機類Airplane:
此類存儲小敵機特有的屬性及行為:
移動速度,分值,及圖片的切換
繼承超類,且實現(xiàn)得分接口
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
/**
* 小敵機
*/
public class Airplane extends Flyer implements EnemyScore{
// 移動速度
private int speed;
public Airplane(){
super(66,89);
speed = 2;//小敵機的下落速度
}
/**重寫step方法(移動)*/
public void step(){
y += speed;//y+表示向下
}
int index = 1;
/**
* 重寫getImage()獲取對象圖片
* @return
*/
public BufferedImage getImage() {
if (isLive()){//若活著 則返回airs[0]圖片
return Images.airs[0];
}else if (isDead()){//若死了 則返回airs[1~4]圖片
BufferedImage img = Images.airs[index++];//獲取爆破圖
if (index == Images.airs.length){//若index到了5 則表示到了最后一張
state = REMOVE;//將當前狀態(tài)修改為REMOVE刪除的
}
return img;//返回爆炸圖
/*
index = 1
10M isLive返回true 則 return返回airs[0]圖片
20M isLive返回false 則 執(zhí)行isDead返回true img = airs[1] index = 2 返回airs[1]圖片
30M isLive返回false 則 執(zhí)行isDead返回true img = airs[2] index = 3 返回airs[2]圖片
40M isLive返回false 則 執(zhí)行isDead返回true img = airs[3] index = 4 返回airs[3]圖片
50M isLive返回false 則 執(zhí)行isDead返回true img = airs[4] index = 5 state修改為REMOVE 返回airs[4]圖片
60M isLive返回false 則 執(zhí)行isDead返回false return返回null空值(不返回圖片)
*/
}
return null;
}
/**
* 重寫getScore()方法
* @return:分值
*/
public int getScore(){
return 1;
}
}
大敵機類BigAirplane:
大敵機與小敵機幾乎無差別
同樣要繼承超類,且實現(xiàn)得分接口
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 大敵機
*/
public class BigAirplane extends Flyer implements EnemyScore{
// 移動速度
private int speed;
public BigAirplane(){//初始化默認屬性
super(203,211);//圖片寬,高
speed = 2;//移動速度
}
/**重寫step方法(移動)*/
public void step(){
y += speed;//y+表示直線向下移動
}
int index = 1;
@Override
public BufferedImage getImage() {
if (isLive()){//若活著 則返回airs[0]圖片
return Images.bairs[0];
}else if (isDead()){//若死了 則返回airs[1~4]圖片
BufferedImage img = Images.bairs[index++];//獲取爆破圖
if (index == Images.bairs.length){//若index到了5 則表示到了最后一張
state = REMOVE;//將當前狀態(tài)修改為REMOVE刪除的
}
return img;
}
return null;
}
/**
* 重寫getScore()方法
* @return:分值
*/
public int getScore(){
return 3;
}
}
小蜜蜂類Bee:
此類雖也可以算作敵人類,但是與小/大敵機有所不同,它是實現(xiàn)獎勵值接口
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 小蜜蜂
*/
public class Bee extends Flyer implements EnemyAward{
// x坐標移動速度,y坐標移動速度,
private int xSpeed;//x坐標移動速度
private int ySpeed;//y坐標移動速度
private int awardType;//獎勵類型
public Bee(){//初始化屬性
super(48,50);//圖片寬,高
Random rand = new Random();
awardType = rand.nextInt(2);//隨機獎勵值類型0~2之間(不包括2)0表示火力值,1表示生命值
xSpeed = 1;//平行移動
ySpeed = 2;//垂直移動
}
/**重寫step方法(移動)*/
public void step() {
y += ySpeed;//y+:向下移動
x += xSpeed;//x+:隨機向左或是向右移動
if (x <= 0 || x >= World.WIDTH - width) {
xSpeed *= -1;//到達邊界后反方向移動(正負為負,負負為正)
}
}
int index = 1;
public BufferedImage getImage() {
if (isLive()){//若活著 則返回airs[0]圖片
return Images.bees[0];//返回小蜜蜂圖
}else if (isDead()){//若死了 則返回airs[1~4]圖片
BufferedImage img = Images.bees[index++];//獲取爆破圖
if (index == Images.bees.length){//若index到了5 則表示到了最后一張
state = REMOVE;//將當前狀態(tài)修改為REMOVE刪除的
}
return img;//返回爆炸圖
}
return null;
}
/**
* 重寫getAwardType()方法
* @return
*/
public int getAwardType(){
return awardType;//返回獎勵類型
}
}
天空類Sky:
這里有一點需要強調(diào),就是為了實現(xiàn)天空圖片向下移動后會出現(xiàn)移動過的位置出現(xiàn)圖片丟失的情況,就使用了兩張圖上下拼接起來,當?shù)谀硰執(zhí)炜請D完全移出窗口的時候會讓它重新出現(xiàn)在窗口上方繼續(xù)向下移動
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
/**
* 天空
*/
public class Sky extends Flyer{
// 移動速度,y1
private int y1;//第二張圖片的y坐標
private int speed;//移動速度
public Sky(){//設(shè)置初始值(默認值)
//此處的寬高用常量是因為天空的寬高和窗口是一致的,x軸和y軸為若不為0就和窗口不匹配了
super(World.WIDTH,World.HEIGHT,0,0);//初始化圖片坐標及寬,高
speed = 1;//初始化移動速度
y1 = -World.HEIGHT;//第二張圖片設(shè)置在第一張圖片上方
}
/**重寫step方法(移動)*/
public void step(){
y += speed;//第一張圖向下移動
y1 += speed;//第二張圖向下移動
if (y >= World.HEIGHT){//若y>=窗口的高
y = -World.HEIGHT;//將移動出去的第一張?zhí)炜张驳酱翱谏戏?
}
if (y1 >= World.HEIGHT){//若第二張?zhí)炜张渤龃翱?
y1 = -World.HEIGHT;//將第二張?zhí)炜张驳酱翱谏戏?
}
}
/**重寫getImage()獲取對象圖片*/
@Override
public BufferedImage getImage() {//10毫秒走一次
return Images.sky;//返回天空圖片即可
}
/**
* 獲取y1坐標
*/
public int getY1(){
return y1;//返回y1
}
}
英雄機類Hero:
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
/**
* 英雄機
*/
public class Hero extends Flyer {
// 命數(shù),火力值
private int life;//命數(shù)
private int fire;//火力
/**
* 初始化英雄機坐標機具體數(shù)據(jù)
*/
public Hero() {
super(97,139,140,400);//寬,高,及初始坐標
fire = 0;//初始火力值 0:單倍火力
life = 3;//初始生命值
}
/**重寫step方法(移動)*/
public void step(){//每10毫秒走一次
//因為英雄機是跟隨鼠標移動的,而鼠標是在窗口上的所以這里就沒有寫具體的方法,而是在窗口類中去用鼠標的具體坐標計算出英雄機的移動位置
}
int index = 0;//下標
/**重寫getImage()獲取對象圖片*/
@Override
public BufferedImage getImage() {//每10毫秒走一次
return Images.heros[index++ % Images.heros.length];//heros[0]和heros[1]來回切換
/**
*過程
*index = 0
*10M 返回heros[0] index = 1
*20M 返回heros[1] index = 2
*30M 返回heros[0] index = 3
*40M 返回heros[1] index = 4
*50M 返回heros[0] index = 5
*60M 返回heros[1] index = 6
*...........
*/
}
/**
* 英雄機發(fā)射子彈(生成子彈對象)
*/
public Bullet[] shoot(){
int xStep = this.width/4;//子彈x坐標
int yStep = 5;//子彈y坐標
System.out.println(this.x+"\t"+this.y);
if (fire>0){//雙倍火力
Bullet[] bs = new Bullet[3];//2發(fā)子彈
bs[0] = new Bullet(this.x+1*xStep,this.y-yStep);//子彈坐標1
bs[1] = new Bullet(this.x+3*xStep,this.y-yStep);//子彈坐標2
bs[2] = new Bullet(this.x+2*xStep,this.y-yStep);
fire -= 2;//發(fā)射一次雙倍活力,則火力值-2
return bs;
} else {//單倍火力
Bullet[] bs = new Bullet[1];//1發(fā)子彈
bs[0] = new Bullet(this.x+2*xStep,this.y-yStep);//x:英雄機的x+2/4英雄機的寬,y:英雄機的y-
return bs;
}
}
/**
* 英雄機移動
*/
public void moveTo(int x,int y){//形參列表:鼠標的x坐標,y坐標
this.x = x - this.width/2;//英雄機的x = 鼠標的x減1/2英雄機的寬
this.y = y - this.height/2;//英雄機的y = 鼠標的y減1/2英雄機的高
}
/**
* 英雄機增生命值
*/
public void addLife(){
life++;//生命值+1
}
/**
* 獲取英雄機生命值
* @return
*/
public int getLife(){
return life;//返回生命值
}
/**
* 英雄機減少生命值
*/
public void subtractLife(){
life--;//生命值減1
}
/**
* 英雄機增火力值
*/
public void addFier(){
fire += 40;//火力值+40
}
/**
* 清空火力值
*/
public void clearFier(){
fire = 0;//火力值歸零
}
}
子彈類Bullet:
package cn.tedu.shoot;
import java.awt.image.BufferedImage;
/**
* 子彈
*/
public class Bullet extends Flyer {
// 移動速度
private int speed;
public Bullet(int x,int y) {//子彈有多個,每個子彈的初始坐標都不同,所以要寫活
super(8,20,x,y);
speed = 3;//初始移動速度
}
/**重寫step方法(移動)*/
public void step(){
y -= speed;//y-:表示直線向上移動
}
/**
* 重寫getImage()獲取對象圖片
* @return
*/
@Override
public BufferedImage getImage() {//10毫秒走一次
if (isLive()){//若活著則返回bullet圖片
return Images.bullet;
}else if (isDead()){//若死了則將state修改為REMOVE
state = REMOVE;
}
return null;//死了的和刪除的都返回null空值
/**
* 若活著 則返回bullet圖片
* 若死了 則修改REMOVE 再返回空值
* 若刪除 則返回空值
*/
}
/**
* 判斷子彈是否越界
* @return
*/
public boolean isOutOfBounds(){
return y <= -height;若子彈的y軸坐標小于自己的高則說明移動到了窗口外部
}
}
獎勵值接口 EnemyAward:
package cn.tedu.shoot;
/**
* 獎勵值接口
*/
public interface EnemyAward {
public int FIRE = 0;//火力
public int LIFE = 1;//生命值
/**
* 獲取獎勵值類型
* @return
*/
int getAwardType();
}
得分接口 EnemyScore:
package cn.tedu.shoot;
/*得分接口*/
public interface EnemyScore {
/*得分*/
public int getScore();
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
redis之基于SpringBoot實現(xiàn)Redis stream實時流事件處理方式
這篇文章主要介紹了redis之基于SpringBoot實現(xiàn)Redis stream實時流事件處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
Spring Boot插件spring tool suite安裝及使用詳解
這篇文章主要介紹了Spring Boot插件spring tool suite安裝及使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08
Java Set集合及其子類HashSet與LinkedHashSet詳解
這篇文章主要介紹了Java Set集合及其子類HashSet與LinkedHashSet詳解,文章通過Set集合存儲原理展開文章主題相關(guān)介紹,感興趣的小伙伴可以參考一下2022-06-06
創(chuàng)建Spring Boot項目的幾種方式總結(jié)(推薦)
這篇文章主要介紹了創(chuàng)建Spring Boot項目的幾種方式總結(jié)(推薦),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07
Quarkus中RESTEasy?Reactive集成合并master分支
這篇文章主要為大家介紹了Quarkus中RESTEasy?Reactive集成合并master分支的詳細作用分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-02-02
Java使用String類格式化當前日期實現(xiàn)代碼
這篇文章主要介紹了Java使用String類格式化當前日期實現(xiàn)代碼,需要的朋友可以參考下2014-02-02
SpringBoot通過ThreadLocal實現(xiàn)登錄攔截詳解流程
這篇文章主要介紹了SpringBoot(HandlerInterceptor)+ThreadLocal實現(xiàn)登錄攔截,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05

