首頁 > 軟體

Java實現簡單的迷宮遊戲詳解

2022-02-10 13:01:14

前言

人類建造迷宮已有5000年的歷史。在世界的不同文化發展時期,這些奇特的建築物始終吸引人們沿著彎彎曲曲、困難重重的小路吃力地行走,尋找真相。迷宮類小遊戲應運而生。在遊戲中,迷宮被表現為冒險舞臺裡,藏有各式各樣奇妙與謎題或寶藏的危險區域。型態有洞窟、人工建築物、怪物巢穴、密林或山路等。迷宮內有惡徒或凶猛的生物(真實存在或想像物體都有)徘徊,其中可能會有陷阱、不明設施、遺蹟等。

《簡單迷宮》遊戲是用java語言實現,採用了swing技術進行了介面化處理,設計思路用了物件導向思想。

主要需求

方向鍵控制移動,角色走出迷宮,遊戲勝利。

主要設計

1、構建遊戲地圖面板

2、設定迷宮地圖,包含可走的通道,不可走的牆體,還有出口位置

3、鍵盤的上下左右按鍵,來控制角色的移動

4、角色移動的演演算法,通道可走,遇到牆體不可走

5、走到終點,有成功通關的提示。

功能截圖

遊戲開始頁面

移動介面

通關的介面

程式碼實現

視窗佈局

public class MainApp extends JFrame {
    public MainApp(){
        // 設定表單名稱
        setTitle("簡易迷宮遊戲");
        // 獲取自定義的遊戲地圖面板的範例物件
        MapPanel panel=new MapPanel();
        Container contentPane = getContentPane();
        contentPane.add(panel);
        // 執行並構建表單設定
        pack();
    }

    public static void main(String[] args) {
        MainApp app=new MainApp();
        // 允許表單關閉操作
        app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 顯示錶單
        app.setVisible(true);
    }
}

核心演演算法

public class MapPanel extends JPanel implements KeyListener {
    // 表單的寬和高
    private static final int WIDTH = 450;
    private static final int HEIGHT = 450;
    // 設定背景方格預設行數和列數
    private static final int ROW = 15;
    private static final int COLUMN = 15;
    // 設定表單單個影象,採用30x30大小的圖形,一行設定15個,即450畫素,即表單預設大小
    private static final int SIZE = 30;

    // 設定迷宮地圖
    private static final byte FLOOR = 0;// 0表示通道地板
    private static final byte WALL = 1;// 1表示牆
    private static final byte END = 2;// 2表示終點
    private byte[][] map = {
            {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
            {1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1},
            {1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1},
            {1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1},
            {1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1},
            {1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1},
            {1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
            {1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1},
            {1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
            {1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1},
            {1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1},
            {1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1},
            {1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1},
            {1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1},
            {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 2, 1}
    };

    // 設定顯示的影象物件
    private Image floorImage;
    private Image wallImage;
    private Image heroImage;
    private Image endImage;

    // 角色座標
    private int x, y;

    // 區分上下左右按鍵的移動
    private static final byte LEFT = 0;
    private static final byte RIGHT = 1;
    private static final byte UP = 2;
    private static final byte DOWN = 3;

    public MapPanel() {
        // 設定面板大小
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        // 載入圖片
        loadImage();
        // 初始化角色座標
        this.x = 1;
        this.y = 1;
        // 設定焦點在本表單並且監聽鍵盤事件
        setFocusable(true);
        addKeyListener(this);
    }

    /**
     * 畫地圖和角色
     *
     * @param g 畫筆
     */
    public void paintComponent(Graphics g) {
        drawMap(g);
        drawRole(g);
    }

    /**
     * 畫角色(英雄)
     *
     * @param g 畫筆
     */
    private void drawRole(Graphics g) {
        g.drawImage(heroImage, x * SIZE, y * SIZE, SIZE, SIZE, this);
    }

    private void loadImage() {
        // 獲取當前類對應相對位置image資料夾下的地板影象
        ImageIcon icon = new ImageIcon(getClass().getResource("images/floor.png"));
        // 將地板影象範例賦給floorImage變數
        floorImage = icon.getImage();
        // 獲取牆體影象
        icon = new ImageIcon(getClass().getResource("images/wall.gif"));
        wallImage = icon.getImage();
        // 獲取英雄影象
        icon = new ImageIcon(getClass().getResource("images/hero.png"));
        heroImage = icon.getImage();
        // 獲取終點影象
        icon = new ImageIcon(getClass().getResource("images/end.png"));
        endImage = icon.getImage();
    }

    /**
     * 根據map[i][j]中記錄的地圖資訊繪製圖案畫出地圖
     * 標記0為地板,標記1為牆
     *
     * @param g
     */
    private void drawMap(Graphics g) {
        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COLUMN; j++) {
                switch (map[i][j]) {
                    case 0:
                        // 標記為0時畫出地板,在指定位置載入影象
                        g.drawImage(floorImage, j * SIZE, i * SIZE, this);
                        break;
                    case 1:
                        // 標記為1時畫出城牆
                        g.drawImage(wallImage, j * SIZE, i * SIZE, this);
                        break;
                    case 2:
                        // 標記為2時畫出終點
                        g.drawImage(endImage, j * SIZE, i * SIZE, SIZE, SIZE, this);
                    default:
                        break;
                }
            }
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        // 根據按鍵進行移動
        int keyCode = e.getKeyCode();// 獲取按鍵編碼
        switch (keyCode) {
            // 左方向鍵或'A'鍵,都可以左移
            case KeyEvent.VK_LEFT:
                move(LEFT);
                break;
            case KeyEvent.VK_A:
                move(LEFT);
                break;
            // 右方向鍵或'D'鍵,都可以右移
            case KeyEvent.VK_RIGHT:
                move(RIGHT);
                break;
            case KeyEvent.VK_D:
                move(RIGHT);
                break;
            // 上方向鍵或'W'鍵,都可以上移
            case KeyEvent.VK_UP:
                move(UP);
                break;
            case KeyEvent.VK_W:
                move(UP);
                break;
            // 下方向鍵或'S'鍵,都可以下移
            case KeyEvent.VK_DOWN:
                move(DOWN);
                break;
            case KeyEvent.VK_S:
                move(DOWN);
                break;
            default:
                break;
        }
        // 重新繪製表單影象
        repaint();
        if (isFinish(x, y)) {
            // 移動到出口
            JOptionPane.showMessageDialog(this, "恭喜通關!");
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    /**
     * 判斷是否允許移動,如果傳入的座標不是牆則可以移動
     *
     * @param x
     * @param y
     * @return 允許移動則返回true,否則返回false
     */
    private boolean isAllowMove(int x, int y) {
        // 以判斷(x,y)是WALL還是FLOOR來作為是否能移動的根據
        // 1表示牆,不能移動;0表示地板,可以移動
        if (x < COLUMN && y < ROW) {// 進行引數校驗,不能超過陣列的長度
            return map[y][x] != 1;
        }
        return false;
    }

    /**
     * 移動角色人物
     *
     * @param event 傳入移動方向,分別可以是LEFT、RIGHT、UP、DOWN
     */
    private void move(int event) {
        switch (event) {
            case LEFT:// 左移
                if (isAllowMove(x - 1, y)) {// 判斷左移一步後的位置是否允許移動(不是牆就可以移動)
                    x--;
                }
                break;
            case RIGHT:// 右移
                if (isAllowMove(x + 1, y)) {
                    x++;
                }
                break;
            case UP:// 上移
                if (isAllowMove(x, y - 1)) {
                    y--;
                }
                break;
            case DOWN:// 下移
                if (isAllowMove(x, y + 1)) {
                    y++;
                }
            default:
                break;
        }
    }

    /**
     * 傳入人物的座標來判斷是否到達終點
     *
     * @param x
     * @param y
     * @return
     */
    private boolean isFinish(int x, int y) {
        // 2表示終點影象
        // 注意:x座標表示第幾列,y座標表示第幾行,所以是map[y][x]而不是map[x][y]
        return map[y][x] == END;
    }
}

總結

通過此次的《簡易迷宮》遊戲實現,讓我對swing的相關知識有了進一步的瞭解,對java這門語言也有了比以前更深刻的認識。

java的一些基本語法,比如資料型別、運運算元、程式流程控制和陣列等,理解更加透徹。java最核心的核心就是物件導向思想,對於這一個概念,終於悟到了一些。

到此這篇關於Java實現簡單的迷宮遊戲詳解的文章就介紹到這了,更多相關Java迷宮遊戲內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com