我所知道坦克大戰(單機版)之畫出坦克的實心圓、讓圓動起來、雙緩衝解決閃爍問題

本篇文章目的


  • 畫出坦克的實心圓
  • 讓坦克圓動起來
  • 雙緩衝解決閃爍問題

1、畫出表明坦克的實心圓

咱們須要畫出一個圓,那麼可使用fillOval方法ide

fillOval(int x,int y ,int width ,int  height)

參數的X 和 Y是矩形框的左上角的座標,width和height是寬和高。this

image.png

而咱們重寫paint方法進行畫出坦克的圓spa

@Override
public void paint(Graphics g) {

    //獲取默認的顏色Color
    Color c = g.getColor();
    //將坦克顏色爲紅色
    g.setColor(Color.red);
    //畫一個圓
    g.fillOval(50,50,30,30);
    //將原顏色填充回
    g.setColor(c);
}

image.png

固然也能夠在lauchFrame方法裏添加背景填充色,顯得更外顯眼一些線程

//添加設置背景顏色
this.setBackground(Color.GREEN);

2、讓坦克動起來

咱們使用fillOval方法畫出了圓的實現,那麼怎麼讓這個圓改變位置?code

//畫一個圓
g.fillOval(50,50,30,30);

咱們發現x和y的作標都是50,他們是固定的!圖片

若改變成變量的方式?是否是也是同樣能夠呢?get

int x = 50;//坦克的x座標

int y = 50;//坦克的y座標


@Override
public void paint(Graphics g) {

    //獲取默認的顏色Color
    Color c = g.getColor();
    //將坦克顏色爲紅色
    g.setColor(Color.red);
    //畫一個圓
    g.fillOval(x,y,30,30);
    //將原顏色填充回
    g.setColor(c);
}

image.png

若咱們每次原有的基礎上進行改動,是否是就動起來了?it

咱們採用repaint重繪方法,每隔多少毫秒刷新最新的圓點信息座標io

private class PaintThread implements Runnable {
    @Override
    public void run() {
        while (true) {
            repaint();//重繪方法
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//定義窗口方法
public void lauchFrame() {
    
    //省略其餘關鍵性代碼.....

    //添加設置背景顏色
    this.setBackground(Color.GREEN);

    //使用線程重繪最新圓點信息座標
    new Thread(new PaintThread()).start();
}

@Override
public void paint(Graphics g) {

    //省略其餘關鍵性代碼.....
    
    //刷新圓點位置
    x += 5;//x座標
    y += 5;//y座標
}

這時咱們在main方法運行起來就發現每一個100毫秒就會移動圓點位置了class

image.png

爲何使用線程重面,而不是每按下一個鍵進行一次重畫?

  • 線程重畫更均勻,更能控制重畫的速度。
  • 按鍵重畫不能解決子彈自動飛行的問題。

3、雙緩衝解決閃爍問題

咱們的顯示器通常都是多少hz、多少hz的刷新率,而刷新速度太快,paint方法還沒完成,沒跟上致使會出現閃爍的問題

那麼怎麼解決呢?

1.逐條顯示

2.將全部東西畫在虛擬圖片上,一次性顯示出來

Image offScreenImage = null;//虛擬圖片

@Override
public void update(Graphics g){
    if(offScreenImage == null){
        //若爲null,則建立一張圖片
        offScreenImage = this.createImage(800,600);
    }
    //獲取到虛擬圖片的畫筆
    Graphics gOffScreen = offScreenImage.getGraphics();

    //使用虛擬圖片的畫筆畫圓
    paint(gOffScreen);

    //將虛擬圖片畫下來
    g.drawImage(offScreenImage,0,0,null);
}

可是運行起來會發現,圓動起來後慢慢變成了一條線

image.png

這是怎麼回事呢?

由於當咱們不重寫update方法時,它會本身用背景顏色刷一遍,刷完再畫

而爲何會一條線呢,由於背景沒刷,以前畫出來的圓還在那

因此咱們用虛擬圖片的畫筆畫出一個方框出來代替以前的背景

@Override
public void update(Graphics g){
    if(offScreenImage == null){
        //若爲null,則建立一張圖片
        offScreenImage = this.createImage(800,600);
    }
    //獲取到虛擬圖片的畫筆
    Graphics gOffScreen = offScreenImage.getGraphics();
    //默認黑色,因此須要與效果背景一致獲取原色
    Color c = gOffScreen.getColor();
    gOffScreen.setColor(Color.green);//與原背景色一致
    //使用畫筆畫出一個實現的方框代替原畫的背景效果
    gOffScreen.fillRect(0,0,800,600);
    gOffScreen.setColor(c);//設置原回來
    //使用虛擬圖片的畫筆畫圓
    paint(gOffScreen);
    //將虛擬圖片畫下來
    g.drawImage(offScreenImage,0,0,null);
}

這時再運行就便可

4、使用常量代替固定的尺寸值

因爲咱們的虛擬圖片、框框、以及一些尺寸大小都是固定的值,當須要修改變化的時候,若只有幾個地方,那還比較容易改動

如有幾百個地方、幾千個地方,這就改動的很繁瑣而且很雜亂

public class TankClient extends Frame {

    public static final int GAME_WINDTH = 800;//寬度常量

    public static final int GAME_HEIGHT = 600;//高度常量
    
    @Override
    public void update(Graphics g){
        if(offScreenImage == null){
            //若爲null,則建立一張圖片
            offScreenImage = this.createImage(GAME_WINDTH,GAME_HEIGHT);
        }
        //省略其餘關鍵性代碼......
    }
    //定義窗口方法
    public void lauchFrame() {
        //設置窗口出現的位置
        this.setLocation(400, 300);
        //設置窗口的寬度高度
        this.setSize(GAME_WINDTH, GAME_HEIGHT);
        //省略其餘關鍵性代碼......
    }
}

✧將之後可能須要多處改變的量定義爲常量

✧Frame的寬度和高度

✧常量名通常大寫

參考資料


尚學堂:坦克大戰(馬士兵老師)

相關文章
相關標籤/搜索