• 在Rust用ncurses库创建一个贪吃蛇游戏
  • 发布于 2个月前
  • 399 热度
    0 评论

贪吃蛇是一款经典的电子游戏,深受一代又一代玩家的喜爱。这是一款简单的游戏,玩家在游戏中控制一条蛇,当它吃东西时,它会变得越来越长,并试图避免与墙壁或自己的身体相撞。在这篇文章中,我们将探索如何在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::*;
# 堆代码 duidaima.com
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);
    // 堆代码 duidaima.com
    // 贪吃蛇初始化
    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游戏有了基本的了解。

用户评论