iT邦幫忙

2025 iThome 鐵人賽

DAY 25
0
Software Development

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

Day 25:Java Snake Game 主畫面UI升級(二)

  • 分享至 

  • xImage
  •  

今天要繼續昨天的任務,完成其他的panel
不過首先我們要先處理一些小問題,就是目前主畫面的選單框框如果被選中了會有透明的邊線,很醜!
所以我回顧了一下我的程式碼,發現我並沒有加入這行:

startButton.setFoucsPainted(false);
// 其他按鈕一樣加上

後來我覺得按鈕不應該要有邊界顯示,所以我將按鈕的背景設置成與遊戲背景相同,然後將

startButton.setBackground(backgroundC);
startButton.setBorderPainted(false);
// 其他按鈕一樣加上

這樣就不會有按鈕突兀的問題了,選項變成很直覺美觀地顯示在畫面上
image

然後就是如同GamePanel中,我將設置文字與按鈕的程式碼獨立寫method,再於constructor中呼叫這些method,提高程式碼可讀性

開始今天的工作!
首先,settingPanel的工作打算明天再做,預計會有調整音量,遊戲難度(速度)設置,顏色設定等
今天先完善helpPanel與GameOverPanel

而我們先從helpPanel開始
我想法中helpPanel大概就只是介紹遊戲怎麼玩,然後像之前提醒使用者要切換成英文輸入法而已,比較簡單

import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.*;

public class HelpPanel extends JPanel{
    static final int PANEL_WIDTH = 800;
    static final int PANEL_HEIGHT = 500;

    GameFrame gameFrame;
    JLabel label;
    JButton homeButton;

    HelpPanel(GameFrame frame){
        this.gameFrame = frame;
        this.setBackground(Color.darkGray);
        this.setLayout(null);
        this.setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));

        setButton();
        setLabel();
    }

    private void setButton(){
        homeButton = new JButton("← Home"); // 給一個回到主畫面的按鈕
        homeButton.setFont(new Font("Times New Roman", Font.ITALIC, 30));
        homeButton.setForeground(Color.WHITE);
        homeButton.setBackground(Color.darkGray);
        homeButton.setBorderPainted(false);
        homeButton.setBounds(25, 400, 200, 50);
        homeButton.addActionListener(e->gameFrame.showPanel("Menu"));
        this.add(homeButton);
    }

    private void setLabel(){
        label = new JLabel();
        label.setFont(new Font("MV Boli", Font.BOLD, 50));
        label.setText("<html>HOW TO PLAY:<br>用WASD控制上下左右
                      <br>記得要切成英文輸入法!</html>");
        label.setForeground(Color.WHITE);
        label.setBounds(150, 50, 600, 300);
        label.setVisible(true);
        this.add(label);
    }
}

然後記得要在GameFrame中加入對應的變數與名稱

public class GameFrame extends JFrame{
    HelpPanel helpPanel;
    
    private void setPanel(){
        helpPanel = new HelpPanel(this);
        mainPanel.add(helpPanel, "Help");
    }
}

image

接下來是遊戲結束的畫面,由於我們會在遊戲結束時展示成績分數,所以我們需要想辦法傳遞這個變數
我的想法是在GameFrame, GamePanel, GameOverPanel中各宣告score變數用於儲存與傳遞這個數值
我們首先要在GameFrame中宣告setScore和getScore,讓另外兩個Panel可以對其做操作

public class GameFrame extends JFrame{
    private int score = 0;

    public void setScore(int score){
        if(score >= 0) this.score = score;
    }

    public void getScore(){return this.score;}
}

思考完傳遞數值的方式後,我們可以來建置GameOverPanel了,我打算在這個畫面除了展示結束、成績以外,可以提供兩個選擇:回主畫面或開始下一把遊戲

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

public class GameOverPanel extends JPanel{
    static final int PANEL_WIDTH = 800;
    static final int PANEL_HEIGHT = 500;

    // 用於存放更新的score數值
    int score = 0;

    GameFrame gameFrame;
    JButton homeButton; // 回到主畫面
    JButton newGameButton; // 開始下一把遊戲

    JLabel gameOverLabel;
    JLabel gameOverLabel2;

    GameOverPanel(GameFrame frame){
        this.gameFrame = frame;
        this.setBackground(Color.darkGray);
        this.setLayout(null);
        this.setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));

        setButton();
    }

    public void setScore(){ 
        // 這個setScore設為public,用意是當GameFrame在showPanel需要呼叫GameOverPanel時
        // 會先呼叫setScore()修改其分數,然後再呼叫GameOverPanel顯示結束畫面
        // 否則會因為修改時間與展示時間不對,導致例如score永遠為0的情況
        this.score = gameFrame.getScore();
        gameOverLabel2.setText("<html>Your Final Score Is: " + score + "</html>");
        // 得到新的score後再將其加入label的text內
    }

    private void setButton(){
        gameOverLabel = new JLabel();
        gameOverLabel.setFont(new Font("MV Boli", Font.BOLD, 100));
        gameOverLabel.setText("GAME OVER!");
        gameOverLabel.setForeground(Color.WHITE);
        gameOverLabel.setBounds(50, 50, 700, 100);
        gameOverLabel.setVisible(true);

        gameOverLabel2 = new JLabel();
        gameOverLabel2.setFont(new Font("MV Boli", Font.BOLD, 50));
        gameOverLabel2.setForeground(Color.WHITE);
        gameOverLabel2.setBounds(100, 150, 600, 100);
        gameOverLabel2.setVisible(true);

        homeButton = new JButton("回主畫面 Menu");
        homeButton.setFont(new Font("宋体", Font.PLAIN, 30));
        homeButton.setForeground(Color.WHITE);
        homeButton.setBackground(Color.darkGray);
        homeButton.setBorderPainted(false);
        homeButton.setFocusPainted(false);
        homeButton.setBounds(200, 350, 400, 50);
        homeButton.addActionListener(e->gameFrame.showPanel("Menu"));
        // 這邊使用e,是Lambda Expression的用法
        // 對於ActionListener這樣的Anonymous Inner Class可以省去很多程式碼
        // 前面的Anonymous Inner Class也會大部分改成e,用於簡短程式碼

        newGameButton = new JButton("新遊戲 New Game");
        newGameButton.setFont(new Font("宋体", Font.PLAIN, 30));
        newGameButton.setForeground(Color.WHITE);
        newGameButton.setBackground(Color.darkGray);
        newGameButton.setBorderPainted(false);
        newGameButton.setBounds(200, 280, 400, 50);
        newGameButton.addActionListener(e->gameFrame.showPanel("Game"));

        this.add(gameOverLabel);
        this.add(gameOverLabel2);
        this.add(newGameButton);
        this.add(homeButton);
    }
}

接著是回到GameFrame做設定

public class GameFrame extends JFrame{
    GameOverPanel gameOverPanel;
    
    private void setPanel(){
        gameOverPanel = new GameOverPanel(this);
        mainPanel.add(gameOverPanel, "GameOver");
    }
    
    // 重要的是我們要在這裡修改GameOverPanel的分數
    public void showPanel(String panelName){
        cardLayout.show(mainPanel, panelName);
        if("Game".equals(panelName)){gamePanel.startGame();}
        else if("GameOver".equals(panelName)){gameOverPanel.setScore();} // 增加這行
    }
}

image

這樣就完成HelpPanel的幫助頁面與GameOverPanel的結束頁面以及分數顯示了


上一篇
Day 24:Java Snake Game 主畫面UI升級(一)
系列文
30天從基礎學起Java,直到做出我的第一個遊戲25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言