iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
Software Development

30天從基礎學起Java,直到做出我的第一個遊戲系列 第 19

Day 19:Java Snake Game 建立遊戲 - 靜態畫面

  • 分享至 

  • xImage
  •  

今天是開始實作我的Snake Game的第一天,會從建立遊戲畫面與靜態畫面生成開始!


一開始先建立視窗(frame)跟畫布(panel)

import javax.swing.JFrame;

public class GameFrame extends JFrame{
    
    GameFrame(){
    this.add(new GamePanel());
    this.setTitle("SnakeGame");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setResizable(false);

    this.pack();
    this.setVisible(true);
    this.setLocationRelativeTo(null);
    }
}

接著是panel,由於我們要讓panel可以畫東西,我們先Override他的繪製函式 (paintComponent)
最一開始設定是1300x750的畫面大小

import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Dimension;
import java.awt.Color;

public class GamePanel extends JPanel{
    static final int PANEL_WIDTH = 1300;
    static final int PANEL_HEIGHT = 750;

    GamePanel(){
        this.setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
        this.setBackground(Color.black);
        this.setOpaque(true);
        this.setFocusable(true);
    }

    @Override
    public void paintComponent(Graphics g){
        Graphics2D g2d = (Graphics2D) g;
        // 將Graphics轉換為Graphics2D
    }
}

接著設定paintComponent的內容,我想讓他在畫布上畫出線條,於是用while迴圈計算並用drawLine進行繪圖

@Override
    public void paintComponent(Graphics g){
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(Color.white);
    int xLine = 0, yLine = 0;
    while(xLine < PANEL_WIDTH){
        g2d.drawLine(xLine, 0, xLine, PANEL_HEIGHT);
        xLine += BLOCK_SIZE;
    }
    while(yLine < PANEL_HEIGHT){
        g2d.drawLine(0, yLine, PANEL_WIDTH, yLine);
        yLine += BLOCK_SIZE;
    }
}

image

可是發現我的背景不如我預期設定好的黑色,因此向gemini詢問,告知我需要在第一行寫上super.paintComponent(g),呼叫預設繪製行為:
image
補上後就正常了

接下來要做的是繪製食物,我的想法是把食物繪製成紅色,貪食蛇繪製成綠色。
食物用random生成,不過在繼續執行之前,我選擇先將任務從paintComponent中分出,我另外寫了幾個method,再傳入paintComponent中,以增加程式的可讀性

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;

    drawGrid(g2d);
    drawFood(g2d);
    drawSnake(g2d);
}

接著稍微修改一下class宣告的變數,屬於各個物件都會固定的就設定為static final
後來我將寬跟高重新設置為800x500,否則畫面會有點太大

public class GamePanel extends JPanel{
    static final int PANEL_WIDTH = 800;
    static final int PANEL_HEIGHT = 500;
    static final int BLOCK_SIZE = 50;
    static final int xBlocks = PANEL_WIDTH / BLOCK_SIZE;
    static final int yBlocks = PANEL_HEIGHT / BLOCK_SIZE;
    int foodX = 0;
    int foodY = 0;
    Color food = Color.red;
}

接著要設定random,用來隨機食物生成位置
但是食物生成的代碼要放在哪裡?
如果將整個代碼放在建構子(constructor)

食物只會在物件建構時生成一次

如果將代碼放在drawFood()內 (也就是paintComponent內)

食物會一直閃爍,因為每次需要重繪頁面時他就會被呼叫,然後食物就會重畫一次

所以正確的做法是再寫一個newFood(),只在偵測到遊戲開始與食物被吃掉後執行

public void newFood(){
    foodX = random.nextInt(xBlocks) * BLOCK_SIZE;
    foodY = random.nextInt(yBlocks) * BLOCK_SIZE;
    // random生成0~xBlocks-1,我們再乘上SIZE就會剛好填滿格子
}

那麼這個newFood()要放在哪呢?
我的想法是我們再寫一個startGame(),用來控制遊戲開始與開始後的操作

public void startGame(){
    newFood();
}

而當我們生成新的食物之後就可以呼叫drawFood()將它畫出來

public void drawFood(Graphics2D g2d){
    g2d.setColor(food);
    g2d.fillRect(foodX, foodY, BLOCK_SIZE, BLOCK_SIZE);
    // 由於只會在發生改變時產生新的食物,因此這個foodX和foodY在通常情況下不會隨意改變數值
    // 因此當畫面需要重繪時,食物仍然在同一個位置,就不會有閃爍的情況發生了
}

接著嘗試之後,newFood()和drawFood()都正常了,就可以來準備設計貪食蛇本體了
我這邊是用LinkedList儲存snake,因為LinkedList非常適合用於需要頻繁插入與刪除的資料

而LinkedList要儲存哪種資料型態呢?
我本來的想法是int,可是gemini告訴我:
image

接著我問它要如何使用point,第一次了解這個型態,發現還蠻好上手的
image

好,所以現在我們知道LinkedList要存point,於是我設計讓他開局的長度為6,且永遠從畫面的中左生成,頭朝右

public void initSnake(){
    for(int i=6; i>0; --i){
        snake.add(new Point(i*BLOCK_SIZE, 4*BLOCK_SIZE));
        // add會把資料往後加 -> index 0 -> index 1 -> index 2 ...
    }
}

初始化完蛇身,我們要把這個蛇身畫在畫布上,這邊使用到enhanced for loop是比較好的選擇

public void drawSnake(Graphics2D g2d){
    g2d.setColor(snakeC);
    for(Point point : snake){
        g2d.fillRect(point.x, point.y, BLOCK_SIZE, BLOCK_SIZE);
    }
}

最後我們就成功把蛇畫在畫布上了!
image


這樣我們就完成第一天的考驗了,成功把內容繪製在畫布上還蠻有成就感的,畢竟這是自己一步一步探索與研究出來的。明天就會進入到動態邏輯的部分了!
天今天也是快樂學習的一天,明天繼續!


上一篇
Day 18:Java GUI (七)
下一篇
Day 20:Java Snake Game 動態邏輯(計時、移動、食物位置判斷)
系列文
30天從基礎學起Java,直到做出我的第一個遊戲20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言