仿雷電——飛機大戰類遊戲Ⅰ

簡介

我們仿照 QQ遊戲“”雷電這個風靡全球的遊戲,來把所有知識點串接起來了
多線程用來實現動畫效果、容器實現對於多發炮彈的存取和處理、常用類等等的應用。
但跟隨本文只能做出雷電的雛形,但你可以在這個基礎上改造出屬於你的“雷電”
這是最後效果圖:

第一階段:遊戲界面的繪畫及圖片加載

遊戲開發中,圖片加載是最常見的技術。我們在此處使用ImageIO類實現圖片加載,並且爲了代碼的複用,將圖片加載的方法封裝到GameUtil工具類中,便於我們以後直接調用。

​ 我們要先將項目用到的圖片拷貝到項目的src下面,我們可以建立新的文件夾images存放所有圖片

1.添加背景圖片

方法1:通過在JFrame中添加一個JPanel,背景圖片放在JPanel上來實現

方法2:我們用JLayeredPane,JLayeredPane 爲 JFC/Swing 容器添加了深度,允許組件在需要時互相重疊。Integer 對象指定容器中每個組件的深度,其中編號較高的組件位於其他組件之上。常用的幾個層如下圖:

之前我再添加背景圖片時一貫使用絕對路徑,每次添加修改極爲麻煩,本次我們學習如何使用相對路徑,首先通過GameUtil.class.getClaaaLoader().getResource來獲得資源的根目錄,從而獲取相對位置

paint會被自動被調用,g相當於一隻畫筆

代碼如下:
/**
 * 2019年9月21日
 */
package Thunder;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyListener;
import java.util.ArrayList;

import javax.swing.JFrame;

/**
 * 飛機大戰雛形:可以發炮彈,但是沒有解決連發炮彈的問題
 * 
 * 之後有兩個方向:畫面上有很多炮彈,控制飛機移動躲避炮彈
 * 或者經典的雷電遊戲,擊落敵機
 *
 * 2019年9月21日
 */
public class GameUI extends JFrame {
	
	
	// 將背景和飛機圖片定義爲成員變量
	Image background = GameUtil.getImage("images/back3.jpg");
	Image planeImg = GameUtil.getImage("images/plane1.png");
	Image shootImg = GameUtil.getImage("images/shoot1.png");
	
	public static int UIWidth = 1000;
	public static int UIHeigh = 1000;

	
	
	//ArrayList<Shell>  shellList = new ArrayList<Shell>();  
	Plane plane1 =  new Plane(planeImg,200,200,2,100,100);
	Shell shoot1 = new Shell(shootImg, 237,170,2,25,35);
	
	public void GFrame() {
		this.setTitle("雷電");
		this.setSize(UIWidth, UIHeigh);
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(3);
		this.addKeyListener(plane1);
		this.addKeyListener(shoot1);
		this.setVisible(true);
		//啓動線程
		PaintThread pt =new PaintThread();
		pt.start();
	}

	// paint方法作用是:畫出整個窗口及內部內容。被系統自動調用。
	 
	public void paint(Graphics g) {

		g.drawImage(background, 0, 0, 1000, 1000, null);
		plane1.drawMySelf(g);
		shoot1.drawMySelf(g);
			}

	// 定義內部類
	class PaintThread extends Thread {
		// 重寫
		public void run() {
			while (true) {
				repaint();// 重畫

				try {
					Thread.sleep(10);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	//雙緩衝解決閃爍
	private Image offScreenImage = null;
	 
	public void update(Graphics g) {
	    if(offScreenImage == null)
	        offScreenImage = this.createImage(500,500);//這是遊戲窗口的寬度和高度
	     
	    Graphics gOff = offScreenImage.getGraphics();
	    paint(gOff);
	    g.drawImage(offScreenImage, 0, 0, null);
	}  

	// 主方法
	public static void main(String[] args) {
		// 類裏面調用窗體
		GameUI gu = new GameUI();
		gu.GFrame();

	}

}

【要點】:

1.繼承Frame類,畫出窗口
2. 瞭解座標系,窗口座標以左上角爲(0,0)點
3. 物體就是矩形,物體的位置就是所在矩形左上角頂點的座標
4. 窗口關閉,居中等我們需要自己添加功能,如下

在JFrame中我們可以這樣寫:
drawframe.setDefaultCloseOperation(3);//關閉時程序結束
drawframe.setLocationRelativeTo(null);
但在Frame中,我們需要
/ 增加關閉窗口監聽,這樣用戶點擊右上角關閉圖標,可以關閉遊戲程�?
	this.addWindowListener(new WindowAdapter() {
		@Override
		public void windowClosing(WindowEvent e) {
			System.exit(0);
		}
	});

第二階段:使用多線程讓動畫動起來

第三階段:鍵盤操控飛機

第四階段:炮彈和飛機碰撞,爆炸

第五階段:顯示分數

項目結構如圖:
在這裏插入圖片描述
所有代碼:

/**
 * 2019年9月21日
 */
package Thunder;

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

import javax.swing.JFrame;

/**
 * 
 *
 * 2019年9月21日
 */
public class GameUI extends JFrame {
	// 將背景和飛機圖片定義爲成員變量
	Image background = GameUtil.getImage("images/back3.jpg");
	Image planeImg = GameUtil.getImage("images/plane1.png");
	
	public static int UIWidth = 1000;
	public static int UIHeigh = 1000;

	Plane plane1 =  new Plane(planeImg,200,200,2,100,100);
	
	public void GFrame() {
		this.setTitle("雷電");
		this.setSize(UIWidth, UIHeigh);
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(3);
		//添加監聽器
		//Listener li = new Listener();
		//this.addKeyListener(li);
		this.addKeyListener(plane1);
		this.setVisible(true);
		//啓動線程
		PaintThread pt =new PaintThread();
		pt.start();
	}

	// paint方法作用是:畫出整個窗口及內部內容。被系統自動調用。
	 
	public void paint(Graphics g) {

		g.drawImage(background, 0, 0, 1000, 1000, null);
		plane1.drawMySelf(g);
	}

	// 定義內部類
	class PaintThread extends Thread {
		// 重寫
		public void run() {
			while (true) {
				repaint();// 重畫

				try {
					Thread.sleep(10);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	//雙緩衝解決閃爍
	private Image offScreenImage = null;
	 
	public void update(Graphics g) {
	    if(offScreenImage == null)
	        offScreenImage = this.createImage(500,500);//這是遊戲窗口的寬度和高度
	     
	    Graphics gOff = offScreenImage.getGraphics();
	    paint(gOff);
	    g.drawImage(offScreenImage, 0, 0, null);
	}  

	// 主方法
	public static void main(String[] args) {
		// 類裏面調用窗體
		GameUI gu = new GameUI();
		gu.GFrame();

	}

}


package Thunder;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

/**
 * GameUtil類:加載圖片代碼
 *GameUtil獲得程序運行類加載器,加載資源的根目錄,
 * 2019年9月22日
 */
public class GameUtil {
	//工具類一般將構造器私有化
	public GameUtil() {
		
	}
	public static Image getImage(String path){
		BufferedImage bi = null;
		try {
			URL  u = GameUtil.class.getClassLoader().getResource(path);
			bi = ImageIO.read(u);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bi;
	}
	

}

/**
 * 2019年9月22日
 */
package Thunder;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;

/**
 * 遊戲中所有物體的父類
 *
 * 2019年9月22日
 */
public class GameObject {
	Image img; //該物體對應的圖片對象
    double x,y;    //該物體的座標
    int speed; //該物體的運行速度
    int width,height;  //該物體所在矩形區域的寬度和高度
    public void drawMySelf(Graphics  g){
        g.drawImage(img, (int)x, (int)y, (int)width, (int)height, null);
    }
     
    public GameObject(Image img, double x, double y) {
        this.img = img;
        this.x = x;
        this.y = y;
        if(img!=null){
            this.width = img.getWidth(null);
            this.height = img.getHeight(null);
        }
    }
    public GameObject(Image img, double x, double y, int width,
            int height) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
     
    public GameObject(Image img, double x, double y, int speed, int width,
            int height) {
        this.img = img;
        this.x = x;
        //這只是構造方法初始化化時的值,並不能作爲約束
        this.y = y;
        this.speed = speed;
        this.width = width;
        this.height = height;
    }
     
    public GameObject() {
    }
     
    /**
     * 返回物體對應矩形區域,便於後續在碰撞檢測中使用
     * @return
     */
    public Rectangle getRect(){
        return  new Rectangle((int)x,(int) y, width, height);
    }  

}


package Thunder;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

/**
 * 
 *
 * 2019年9月22日
 */
public class Plane extends GameObject implements KeyListener {

	boolean left, right, up, down,shoot;
	boolean live = true;
	

	public void drawMySelf(Graphics g) {
		super.drawMySelf(g);
		// 這裏可移動,但是下面不行,應該是判斷的問題
		 this.x+=2;
		 System.out.println("此時的座標"+x);
		 //System.out.println(left);
		if (left) {
			System.out.println("此時的座標"+x);
			x -= speed;
			if(x<=0){
	        	x=0;
	        }
		}
		if (right) {
			x += speed;
			if(x>=900){
	        	x=900;
	        }
			
		}
		if (up) {
			y -= speed;
			if(y<=10){
				y=10;
			}
			
		}
		if (down) {
			y += speed;
			if(y>=900){
				y=900;
			}
		}
	}
	public Plane(Image img, double x, double y, int speed, int width, int height) {

		super(img, x, y,width, height);
		//System.out.println("有被重畫");
		//this.speed = speed;
	}

	public void keyTyped(KeyEvent e) {
	}

	public void keyPressed(KeyEvent e) {
		System.out.println(e.getKeyCode());
		int key = e.getKeyCode();
		switch (key) {
		case 37:
			left = true;
			break;
		case 38:
			up = true;
			break;
		case 39:
			right = true;
			break;
		case 40:
			down = true;
			break;
		case 32:
			shoot = true;
			break;
		default:
			break;
		}
	}

	public void keyReleased(KeyEvent e) {
		//System.out.println(e.getKeyCode());
		int key = e.getKeyCode();
		switch (key) {
		case 37:
			left = false;
			break;
		case 38:
			up = false;
			break;
		case 39:
			right = false;
			break;
		case 40:
			down = false;
			break;
		case 32:
			shoot = true;
			break;
		default:
			break;
		}
	}
}

我原來打算共享飛機座標,這樣就可以將子彈和飛機關聯起來,但是這個語句導致 飛機完全不能動,因爲座標與圖片沒有關聯了,重繪只畫了一次
在這裏插入圖片描述
該怎麼把子彈放入數組列表中呢?
現在子彈是一個新的類,而且有構造器,得隨着飛機移動,但是
應該直接放入監聽就可以了,點一下,延遲幾秒,畫一個。

現在到這個方向有兩種結果可以走:
第一種:屏幕隨機生成炮彈,我們控制飛機去躲避,生存時間越長,得分越高
第二鍾:和遊戲雷電一樣,對面有敵機,我們在躲避敵機炮彈的同時擊落敵機,獲取分數。
在炮彈的任意角度飛行時,如果觸碰到邊界就反轉角度,模擬碰撞效果。
同時爲了效果美觀,我們需要在一些細節上注意:例如碰撞邊界時要減去球 的直徑,碰撞標題欄時需要減去標題欄的寬度。
但是一個炮彈遠遠不夠,我們希望增大一些挑戰難度,有很多炮彈,就可以用到數組了。
分爲三步:
1)定義數組
2)初始化五十個炮彈
3)畫出炮彈

當使用Frame時,屏幕閃爍如圖:

在這裏插入圖片描述

當使用JFrame解決屏幕閃爍問題時:
在這裏插入圖片描述
最後我們採用了frame+雙緩衝的技術來解決,解決效果如圖:
在這裏插入圖片描述

只需要把這段代碼放入界面的類中(任意位置即可)

//雙緩衝解決閃爍
	private Image offScreenImage = null;
	 
	public void update(Graphics g) {
	    if(offScreenImage == null)
	        offScreenImage = this.createImage(1000,1000);//這是遊戲窗口的寬度和高度
	     
	    Graphics gOff = offScreenImage.getGraphics();
	    paint(gOff);
	    g.drawImage(offScreenImage, 0, 0, null);
	}  

在Jfram和frame切換中可能的報錯:

當我們使用JFrame時可以調用這行語句關閉窗口
但是在Frame裏面沒有,所以我們需要添加監聽器
在這裏插入圖片描述

//this.setDefaultCloseOperation(3);
		//增加關閉窗口監聽,這樣用戶點擊右上角關閉圖標,可以關閉遊戲程序
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

遊戲中,多個元素是否碰到一起,實際上,通常是用“矩形檢測”原理實現的。 我們在前面提到,遊戲中所有的物體都可以抽象成“矩形”,我們只需判斷兩個矩形是否相交即可。對於一些複雜的多邊形、不規則物體,實際上是將他分解成多個矩形,繼續進行矩形檢測。

Java的API中,爲我們提供了Rectangle類來表示矩形相關信息,並且提供了intersects()方法,直接判斷矩形是否相交。
我們使用GameObject裏面的矩形檢測來判斷,飛機有,炮彈也有,這也是繼承的隱形好處.

爆炸圖片輪播:
圖片加載一次很耗費資源,所以我們將他設爲static,只初始化一次,之後直接用就可以,而不需要new了,
爆炸類如下

	package Thunder_two;

import java.awt.Graphics;
import java.awt.Image;
/**
 * 
 * 
 *
 */
public class Explode {
    double x,y;
    static Image[] imgs = new Image[16];
    static {
        for(int i=0;i<16;i++){
            imgs[i] = GameUtil.getImage("images/explode/e"+(i+1)+".gif");
            imgs[i].getWidth(null);
        }
    }
     
    int count;
     
    public void draw(Graphics g){
        if(count<=15){
            g.drawImage(imgs[count], (int)x, (int)y, null);
            count++;
        }
    }
     
    public Explode(double x,double y){
        this.x = x;
        this.y = y;
    }
}

到這一步,雷電遊戲的雛形大概就完成了,但是我們卻少了最重要的獎勵機制,玩家不知道自己的得分,自然也不會有興趣繼續挑戰了,所有我們加入時間類,在玩家死亡之後,在屏幕上顯示獲得的分數。
先定義兩個成員變量
Date startTime = new Date(); //遊戲起始時刻
Date endTime; //遊戲結束時刻
如果飛機死亡,調用顯示的方法

  if(!plane.live){
            if(endTime==null){
                endTime = new Date();
            }
            int period = (int)((endTime.getTime()-startTime.getTime())/1000);
            printInfo(g, "時間:"+period+"秒", 50, 120, 260, Color.white);
        }
//顯示的方法
public void printInfo(Graphics g,String str,int size,int x,int y,Color color){
        Color c = g.getColor();
        g.setColor(color);
        Font f = new Font("宋體",Font.BOLD,size);
        g.setFont(f);
        g.drawString(str,x,y);
        g.setColor(c);
    }  

至此,雷電小遊戲的第一個方向就完成了,但大家也許還有點意猶未盡呢吧!這和我們兒時玩的雷電差距太大了吧,下一篇文章中,我們就來開發自動發射+擊落敵機的部分,翹首以待吧。

以下是雷電Ⅰ的全部代碼
項目結構如圖:
在這裏插入圖片描述

package Thunder_one;

import java.awt.Graphics;
import java.awt.Image;
/**
 * 
 * 
 *
 */
public class Explode {
    double x,y;
    static Image[] imgs = new Image[16];
    static {
        for(int i=0;i<16;i++){
            imgs[i] = GameUtil.getImage("images/explode/e"+(i+1)+".gif");
            imgs[i].getWidth(null);
        }
    }
     
    int count;
     
    public void draw(Graphics g){
        if(count<=15){
            g.drawImage(imgs[count], (int)x, (int)y, null);
            count++;
        }
    }
     
    public Explode(double x,double y){
        this.x = x;
        this.y = y;
    }
}

/**
 * 2019年9月22日
 */
package Thunder_one;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;

/**
 * 遊戲中所有物體的父類
 *
 * 2019年9月22日
 */
public class GameObject {
	Image img; //該物體對應的圖片對象
    double x,y;    //該物體的座標
    int speed; //該物體的運行速度
    int width,height;  //該物體所在矩形區域的寬度和高度
    public void drawMySelf(Graphics  g){
        g.drawImage(img, (int)x, (int)y, (int)width, (int)height, null);
    }
     
    public GameObject(Image img, double x, double y) {
        this.img = img;
        this.x = x;
        this.y = y;
        if(img!=null){
            this.width = img.getWidth(null);
            this.height = img.getHeight(null);
        }
    }
    public GameObject(Image img, double x, double y, int width,
            int height) {
        this.img = img;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
     
    public GameObject(Image img, double x, double y, int speed, int width,
            int height) {
        this.img = img;
        this.x = x;
        //這只是構造方法初始化化時的值,並不能作爲約束
        this.y = y;
        this.speed = speed;
        this.width = width;
        this.height = height;
    }
     
    public GameObject() {
    }
     
    /**
     * 返回物體對應矩形區域,便於後續在碰撞檢測中使用
     * @return
     */
    public Rectangle getRect(){
        return  new Rectangle((int)x,(int) y, width, height);
    }  

}

package Thunder_one;

import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.Timer;
import javax.swing.JFrame;
import javax.swing.JLabel;

/**
 * :雷電第一個版本:
 * 屏幕有很多隨機生成的炮彈,我們需要控制飛機來躲避炮彈
 * 存活時間越長,得分越高
 *
 * 
 */
public class GameUI extends Frame {

	Date startTime = new Date(); // 遊戲起始時刻
	Date endTime; // 遊戲結束時刻
	private int score = 0;// �?獲分�?
	// 界面寬和�?
	public static int UIWidth = 1000;
	public static int UIHeigh = 1000;
	// 炮彈的數量
	int ShellNum = 20;
	// 飛機的速度
	int PlSpeed = 20;

	// 將背景和飛機圖片定義爲成員變量
	Image background = GameUtil.getImage("images/back3.jpg");
	Image planeImg = GameUtil.getImage("images/plane1.png");
	Image shootImg = GameUtil.getImage("images/shoot1.png");
	Plane plane1 = new Plane(planeImg, 500, 800, PlSpeed, 100, 100);

	// 炮彈的數�?
	Shell[] shellArr = new Shell[ShellNum];
	// 創建爆炸對象
	Explode bao;
	// 爆炸的輪播圖
	Image[] imgs = new Image[16];

	// 主界面
	public void GFrame() {
		this.setTitle("雷電");
		this.setSize(UIWidth, UIHeigh);
		this.setLocationRelativeTo(null);
		// 增加關閉窗口監聽,這樣用戶點擊右上角關閉圖標,可以關閉遊戲程�?
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		this.addKeyListener(plane1);
		// 初始化,生成炮彈
		for (int i = 0; i < ShellNum; i++) {
			shellArr[i] = new Shell();
		}
		this.setVisible(true);
		// 啓動線程
		PaintThread pt = new PaintThread();
		pt.start();
	}

	// paint方法作用是:畫出整個窗口及內部內容�被系統自動調用�
	public void paint(Graphics g) {
		g.drawImage(background, 0, 0, 1000, 1000, null);
		plane1.drawMySelf(g);
		// 畫出容器中所有的子彈
		for (int i = 0; i < shellArr.length; i++) {
			shellArr[i].draw(g);
			// 檢測碰撞
			boolean peng = shellArr[i].getRect().intersects(plane1.getRect());
			if (peng) {
				plane1.live = false;// 飛機死掉
				endTime = new Date();
				if (bao == null) {
					bao = new Explode(plane1.x, plane1.y);
				}
				bao.draw(g);
			}
		}
		if (!plane1.live) {
			if (endTime == null) {
				endTime = new Date();
			}
			int period = (int) ((endTime.getTime() - startTime.getTime()) / 1000);
			printInfo(g, "您的得分爲:" + period + "�?", 50, 120, 260, Color.white);
		}
	}

	// �?後計�?
	public void printInfo(Graphics g, String str, int size, int x, int y, Color color) {
		Color c = g.getColor();
		g.setColor(color);
		Font f = new Font("宋體", Font.BOLD, size);
		g.setFont(f);
		g.drawString(str, x, y);
		g.setColor(c);
	}

	// 定義內部�?
	class PaintThread extends Thread {
		// 重寫
		public void run() {
			while (true) {
				repaint();// 重畫
				try {
					Thread.sleep(10);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	// 雙緩衝解決閃�?
	private Image offScreenImage = null;

	public void update(Graphics g) {
		if (offScreenImage == null)
			offScreenImage = this.createImage(1000, 1000);
		// 這是遊戲窗口的寬度和高度
		Graphics gOff = offScreenImage.getGraphics();
		paint(gOff);
		g.drawImage(offScreenImage, 0, 0, null);
	}

	// 主方�?
	public static void main(String[] args) {
		// 類裏面調用窗�?
		GameUI gu = new GameUI();
		gu.GFrame();
	}
}

package Thunder_one;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

/**
 * GameUtil類:加載圖片代碼
 *GameUtil獲得程序運行類加載器,加載資源的根目錄,
 * 2019年9月22日
 */
public class GameUtil {
	
	//工具類一般將構造器私有化
	public GameUtil() {
		
	}
	public static Image getImage(String path){
		BufferedImage bi = null;
		try {
			URL  u = GameUtil.class.getClassLoader().getResource(path);
			bi = ImageIO.read(u);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bi;
	}
	

}

package Thunder_one;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

/**
 * 
 *
 * 2019年9月22日
 */
public class Plane extends GameObject implements KeyListener {

	boolean left, right, up, down, shoot;
	boolean live = true;

	public void drawMySelf(Graphics g) {
		if(live){

			super.drawMySelf(g);
			// 這裏可移動,但是下面不行,應該是判斷的問題
			// this.x+=2;

			// System.out.println(left);
			if (left) {

				x -= speed;
				if (x <= 0) {
					x = 0;
				}
			}
			if (right) {
				x += speed;
				if (x >= 900) {
					x = 900;
				}
			}
			if (up) {
				y -= speed;
				if (y <= 10) {
					y = 10;
				}
			}
			if (down) {
				y += speed;
				if (y >= 900) {
					y = 900;
				}
			}
		
		}
	}

	public Plane(Image img, double x, double y, int speed, int width, int height) {

		super(img, x, y, width, height);
		this.speed = speed;
	}

	public void keyTyped(KeyEvent e) {
	}

	public void keyPressed(KeyEvent e) {
		//System.out.println(e.getKeyCode());
		int key = e.getKeyCode();
		
		switch (key) {
		case 37:
			left = true;
			break;
		case 38:
			up = true;
			break;
		case 39:
			right = true;
			break;
		case 40:
			down = true;
			break;
		default:
			break;
		}
	}

	public void keyReleased(KeyEvent e) {
		// System.out.println(e.getKeyCode());
		int key = e.getKeyCode();
		switch (key) {
		case 37:
			left = false;
			break;
		case 38:
			up = false;
			break;
		case 39:
			right = false;
			break;
		case 40:
			down = false;
			break;

		default:
			break;
		}
	}
}
/**
 * 2019年9月26日
 */
package Thunder_one;

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

import Thunder.GameUtil;

/**
 * 
 *
 * 2019年9月26日
 */
public class Shell extends GameObject{
	double degree;
	
	Random ra = new Random();
    
    public Shell(){
        degree = Math.random()*Math.PI*2;
        x = ra.nextInt(700)+250;
        y = ra.nextInt(700)+150;
        width = ra.nextInt(15)+10;
        height = ra.nextInt(15)+10;
        speed = ra.nextInt(3)+2;
    }
     
    public void draw(Graphics g){
        //將外部傳入對象g的狀態保存好
        Color c = g.getColor();
        
        g.setColor(Color.yellow);
        
        Image shootImg = GameUtil.getImage("images/shoot1.png");
        g.drawImage(shootImg, (int)x, (int)y, width, height, null);
 
        //g.fillOval((int)x, (int)y, width, height);
         
        //炮彈沿着任意角度飛行
        x += speed*Math.cos(degree);
        y += speed*Math.sin(degree);
         
        //如下代碼,用來實現碰到邊界,炮彈反彈回來(原理和打檯球遊戲一樣)
        if(y>GameUI.UIHeigh-height||y<40){
            degree = -degree;
        }
        if(x<0||x>GameUI.UIWidth-width){
            degree = Math.PI-degree;
        }
        //返回給外部,變回以前的顏色
        //g.setColor(c);
    }

}


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