1. 程式人生 > >Java小專案——飛機大戰(一、實現執行緒繪製背景和我方飛機,鍵盤控制飛機運動)

Java小專案——飛機大戰(一、實現執行緒繪製背景和我方飛機,鍵盤控制飛機運動)

1 總體需求分析

1.1 類

1、主類

2、我方飛機類

3、執行緒類

2.2 效果圖

2 實現

2.1 飛機類 MyPlane

飛機類包括以下引數:

位置x、y

速度vx、vy

圖片圖示myicom:設定為飛機的圖片

 

飛機類包括以下方法:

有參構造方法:初始化x、y,保證第一次繪製飛機能夠有座標

public MyPlane(int x, int y) {
    this.x = x;
    this.y = y;
}

繪製飛機方法:用引數畫筆g來繪製飛機,再更新vx和vy,

public void drawPlane(Graphics g) {
    g.drawImage(myicon.getImage(), x, y, null);
    x += vx;
    y += vy;
}

程式碼:

package com.java8.planewarsV1;

import javax.swing.*;
import java.awt.*;

public class MyPlane {
    private int x, y;
    private int vx, vy;

    private ImageIcon myicon = new ImageIcon(this.getClass().getResource("PaperPlane.png"));

    /**
     * 我方飛機的建構函式
     * @param x:繪製座標x
     * @param y:繪製座標y
     */
    public MyPlane(int x, int y) {
        this.x = x;
        this.y = y;
    }

    /**
     * 繪製飛機物件的函式,每次呼叫,則繪製一次飛機
     * @param g:畫筆
     */
    public void drawPlane(Graphics g) {
        g.drawImage(myicon.getImage(), x, y, null);
        x += vx;
        y += vy;
    }

    /**
     * setVx
     * setVy
     * 用於在按鍵後,設定其每次移動的大小,並在釋放的時候清0
     * @param vx
     */
    public void setVx(int vx) {
        this.vx = vx;
    }

    public void setVy(int vy) {
        this.vy = vy;
    }
}

 

2.2 主介面類 GameUI

介面類和監聽器類:兩個寫在一個類中,方便引數的傳入和傳出

介面類:主要實現一個面板JFrame jf,jf上新增鍵盤監聽器,jf上獲取畫筆g

監聽器類:KeyListener。按space空格開始遊戲,按上下左右控制飛機運動。

 

GameUI類的引數為:

private JFrame jf;
private Graphics g;
private MyPlane myPlane;
private MyThread myThread;
private ImageIcon bgicon = new ImageIcon(this.getClass().getResource("bg.jpeg"));

private int speed = 5;

空格 VK_SPACE:

1.建立飛機物件,初始化飛機的x和y;2.若執行緒為null,則建立myThread執行緒,傳入mayplane飛機、g畫筆、jf物件; 3.使用Thread()方法,執行myThread執行緒,開始不斷繪製飛機類

// 按下空格,開啟執行緒
// 執行緒每隔0.02s就繪製背景圖、飛機
if(myThread == null){
    //1.建立飛機物件
    myPlane = new MyPlane((jf.getWidth() - 150) / 2,
            jf.getHeight() - 150);
    //2.建立myThread執行緒
    myThread = new MyThread(myPlane,g,jf);
    //3.使用Thread()方法,執行myThread執行緒
    new Thread(myThread).start();
}

左右上下 KeyEvent.VK_LEFT:

設定飛機類的x/y速度為+speed或者-speed

case KeyEvent.VK_LEFT:
    myPlane.setVx(-speed);
    break;

程式碼:

package com.java8.planewarsV1;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class GameUI implements KeyListener {

    private JFrame jf;
    private Graphics g;
    private MyPlane myPlane;
    private MyThread myThread;
    private ImageIcon bgicon = new ImageIcon(this.getClass().getResource("bg.jpeg"));

    private int speed = 5;


    public static void main(String arg[]) {
        GameUI gameUI = new GameUI();
        gameUI.showUI();
    }


    private void showUI() {
        jf = new JFrame();
        jf.setTitle("飛機大戰1.0");
        jf.setSize(800, 800);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(3);

        jf.setVisible(true);

        g = jf.getGraphics();
        g.drawImage(bgicon.getImage(),0,0,null);
        
        jf.addKeyListener(this);

    }


    public void keyTyped(KeyEvent e) {

    }

    /***
     * 按下對應按鈕,獲取按鈕的值e.getKeyCode(),進行不同操作
     * 空格:開始遊戲;上下左右:對應移動
     * @param e
     */
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        switch (key) {
            case KeyEvent.VK_LEFT:
                myPlane.setVx(-speed);
                break;
            case KeyEvent.VK_RIGHT:
                myPlane.setVx(speed);
                break;
            case KeyEvent.VK_UP:
                myPlane.setVy(-speed);
                break;
            case KeyEvent.VK_DOWN:
                myPlane.setVy(speed);
                break;
            case KeyEvent.VK_SPACE:
                // 按下空格,開啟執行緒
                // 執行緒每隔0.02s就繪製背景圖、飛機
                if(myThread == null){
                    //1.建立飛機物件
                    myPlane = new MyPlane((jf.getWidth() - 150) / 2,
                            jf.getHeight() - 150);
                    //2.建立myThread執行緒
                    myThread = new MyThread(myPlane,g,jf);
                    //3.使用Thread()方法,執行myThread執行緒
                    new Thread(myThread).start();
                }
                break;
        }
    }


    /**
     * 清空上一次操作的speed
     * @param e
     */
    public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();
        switch (key) {
            case KeyEvent.VK_LEFT:
                myPlane.setVx(0);
                break;
            case KeyEvent.VK_RIGHT:
                myPlane.setVx(0);
                break;
            case KeyEvent.VK_UP:
                myPlane.setVy(0);
                break;
            case KeyEvent.VK_DOWN:
                myPlane.setVy(0);
                break;
        }
    }
}

2.3 MyThread

重寫執行緒run():

執行緒暫停0.02s繪製一次;在bufferedImage內繪製背景+繪製飛機(bg);將bufferedImage繪製到jf上(g)

 

繪製飛機執行緒建構函式:

需要傳入飛機、畫筆g、面板jf

/**
 * 繪製飛機執行緒建構函式
 */
public MyThread(MyPlane myPlane, Graphics g,JFrame jf){
    this.myPlane = myPlane;
    this.g = g;
    this.jf = jf;
}

 

快取技術bufferedImage:

使用bufferedImage的畫筆bg,來繪製背景、繪製飛機。解決了畫面交替繪製閃爍問題。

/**
 * 使用快取技術bufferedImage,解決畫面交替繪製閃爍問題
 * 1 首先將所有物體繪製於bufferedImage內
 * 2 再將bufferedImage繪製於JFrame內
 */
//1.建立bufferedImage物件:大小為jf大小,型別為RGB
BufferedImage bufferedImage = new BufferedImage(jf.getWidth(),jf.getHeight(),BufferedImage.TYPE_INT_BGR);
//2.獲取bufferedImage物件的畫筆:bg
Graphics bg = bufferedImage.createGraphics();
//3.繪製背景和飛機,於bufferedImage物件上
bg.drawImage(bgicon.getImage(),0,0,null);
myPlane.drawPlane(bg);
//4.繪製bufferedImage,到JFrame上
g.drawImage(bufferedImage,0,0,null);

程式碼:

package com.java8.planewarsV1;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public class MyThread implements Runnable{

    private MyPlane myPlane;
    private Graphics g;
    private JFrame jf;
    private ImageIcon bgicon = new ImageIcon(this.getClass().getResource("bg.jpeg"));

    /**
     * 繪製飛機執行緒建構函式
     */
    public MyThread(MyPlane myPlane, Graphics g,JFrame jf){
        this.myPlane = myPlane;
        this.g = g;
        this.jf = jf;
    }

    /**
     * 不使用執行緒,每次繪製之間間隔過長;
     * 使用執行緒,加速繪製飛機移動軌跡。
     */
    public void run() {

        while(true) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            /**
             * 使用快取技術bufferedImage,解決畫面交替繪製閃爍問題
             * 1 首先將所有物體繪製於bufferedImage內
             * 2 再將bufferedImage繪製於JFrame內
             */
            //1.建立bufferedImage物件:大小為jf大小,型別為RGB
            BufferedImage bufferedImage = new BufferedImage(jf.getWidth(),jf.getHeight(),BufferedImage.TYPE_INT_BGR);
            //2.獲取bufferedImage物件的畫筆:bg
            Graphics bg = bufferedImage.createGraphics();
            //繪製背景和飛機,於bufferedImage物件上
            bg.drawImage(bgicon.getImage(),0,0,null);
            myPlane.drawPlane(bg);
            //繪製bufferedImage,到JFrame上
            g.drawImage(bufferedImage,0,0,null);

        }
    }
}