使用 Rust 開發一個貪喫蛇遊戲

貪喫蛇是一款經典的電子遊戲,深受一代又一代玩家的喜愛。這是一款簡單的遊戲,玩家在遊戲中控制一條蛇,當它喫東西時,它會變得越來越長,並試圖避免與牆壁或自己的身體相撞。在這篇文章中,我們將探索如何在 Rust 中使用 ncurses 庫創建一個貪喫蛇遊戲。

ncurses 是什麼?

ncurses 是一個用於在終端中創建基於文本的用戶界面 (gui) 的庫。它提供了一組功能,用於在屏幕上繪製字符和顏色、讀取鍵盤輸入和管理終端顯示。ncurses 可用於大多數類 unix 系統,包括 Linux 和 macOS。

創建項目

創建一個新的 Rust 項目:

cargo new snake --bin

接下來,將 ncurses 庫添加到 Cargo.toml 文件中:

[dependencies]
ncurses = "5.100.0"

現在,運行 cargo build 以下載 ncurses 庫並構建項目。

繪製蛇

爲了在屏幕上繪製蛇,我們將創建一個結構體來表示蛇的身體。我們將使用 LinkedList 來存儲蛇身體的每個部分的座標。

在 src/main.rs 中寫入如下代碼:

use std::collections::LinkedList;

struct Snake {
    body: LinkedList<(i32, i32)>,
}

我們還將創建一個函數來在屏幕上繪製蛇。這個函數將遍歷蛇身體的每個部分,並在相應的位置繪製一個角色。

use ncurses::*;

fn draw_snake(snake: &Snake) {
    for &(x, y) in &snake.body {
        mvaddch(x, y, '@' as u32);
    }
}

這裏,mvaddch 是一個 ncurses 庫函數,它將光標移動到指定位置,並將指定的字符添加到屏幕上。@字符用來表示蛇的身體。

移動蛇

爲了移動蛇,我們將在 snake 結構體中添加一個方向字段,表示蛇移動的方向。我們還將添加 move_forward 方法,該方法基於當前方向更新蛇身體每個部分的座標。

#[derive(Clone, Copy, PartialEq)]
enum Direction {
    Left,
    Right,
    Up,
    Down,
}

struct Snake {
    body: LinkedList<(i32, i32)>,
    direction: Direction,
}

impl Snake {
    fn move_forward(&mut self) {
        let (mut x, mut y) = *self.body.front().unwrap();
        match self.direction {
            Direction::Left => y -= 1,
            Direction::Right =y += 1,
            Direction::Up => x -= 1,
            Direction::Down =x += 1,
        }
        self.body.push_front((x, y));
        self.body.pop_back();
    }
}

這裏,self.body.front().unwrap() 獲取蛇身體前部的座標。然後我們根據當前方向更新座標,並將新座標添加到身體前部,並刪除身體後部的座標。

接下來,我們將添加一個函數來處理鍵盤輸入,這個函數將根據方向鍵更新蛇的方向。

fn handle_input(snake: &mut Snake) {
    let input = getch();

    match input {
        // 'a' 鍵
        97 ={
            snake.direction = Direction::Left
        },
        // 'd' 鍵
        100 ={
            snake.direction = Direction::Right
        },
        // 'w' 鍵
        119 ={
            snake.direction = Direction::Up
        },
        // 's' 鍵
        115 ={
            snake.direction = Direction::Down
        },
        _ =(),
    }
}

這裏,getch 是一個 ncurses 庫函數,它等待鍵盤輸入並返回相應的鍵代碼。KEY_* 常量表示方向鍵。

貪喫蛇喫食物

impl Snake {
    ......

    fn eat_food(&mut self, food: &mut Vec<(i32, i32)>) {
        for (i, v) in food.clone().iter().enumerate() {
            let head = *self.body.front().unwrap();
            if head.0 == v.0 && head.1 == v.1 {
                self.body.push_back(head);
                food.remove(i);
                break;
            }
        }
    } 
}

當貪喫蛇的頭部座標與食物座標一致時,貪喫蛇變長,即列表加一。同時刪除該食物。

創造遊戲循環

最後,我們將創建更新遊戲狀態並重新繪製屏幕的遊戲循環。

fn main() {
    initscr();
    noecho();
    cbreak();
    curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);

    // 貪喫蛇初始化
    let mut snake = Snake {
        body: LinkedList::from_iter(vec![(10, 10)(10, 9)(10, 8)]),
        direction: Direction::Right,
    };

    // 食物初始化
    let mut food = vec![(13, 13)(16, 8)(5, 20)(9, 30)(11, 40)];

    loop {
        clear();
        draw_snake(&snake);
        draw_food(&food);
        handle_input(&mut snake);
        snake.move_forward();
        snake.eat_food(&mut food);
        refresh();
        napms(100);
    }
    // endwin();
}

這裏,initscr 函數用於初始化 ncurses 庫,noecho 函數用於禁用鍵回顯,cbreak 函數用於將終端設置爲 cbreak 模式,curs_set 函數用於設置光標可見性。

在遊戲循環中,我們首先使用 clear 清除屏幕,並使用我們之前定義的函數繪製貪喫蛇,然後處理輸入,移動貪喫蛇。Refresh 用於更新屏幕,napms 在繼續之前等待指定的毫秒數。

最後,我們使用 endwin 清理 ncurses 庫。

運行

執行 cargo build 後,進入 snake/target/debug 目錄,執行命令:

./snake

在鍵盤上按 w、s、a、d 健就可以上下左右移動貪喫蛇並可以貪喫食物了。

如圖:

總結

在這篇文章中,我們探討了如何在 Rust 中使用 ncurses 庫創建一個簡單的貪喫蛇遊戲。我們介紹了在屏幕上繪圖、處理輸入和創建遊戲循環的基礎知識。你現在應該對如何在 Rust 中使用 ncurses 庫創建簡單的 TUI 遊戲有了基本的瞭解。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/5UIMFFf67rAyfJQjq1sC2w