rust语言写的贪吃蛇游戏

Posted 福大大架构师每日一题

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了rust语言写的贪吃蛇游戏相关的知识,希望对你有一定的参考价值。

首先新建工程,然后用vscode打开,命令如下:

cargo new snake --bin

文件结构如下:

Cargo.Toml文件内容如下:

[package]
name = "snake"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.4.6"
piston_window="0.74.0"
[profile.release]
opt-level = 0
lto = true
codegen-units = 1
panic = "abort"

src/draw.rs文件内容如下:

use piston_window::types::Color;
use piston_window::rectangle, Context, G2d;
const BLOCK_SIZE: f64 = 25.0;
pub fn to_coord(game_coord: i32) -> f64 
    (game_coord as f64) * BLOCK_SIZE

pub fn to_coord_u32(game_coord: i32) -> u32 
    to_coord(game_coord) as u32

pub fn draw_block(color: Color, x: i32, y: i32, con: &Context, g: &mut G2d) 
    let gui_x = to_coord(x);
    let gui_y = to_coord(y);
    rectangle(
        color,
        [gui_x, gui_y, BLOCK_SIZE, BLOCK_SIZE],
        con.transform,
        g,
    );

pub fn draw_rectangle(
    color: Color,
    x: i32,
    y: i32,
    width: i32,
    height: i32,
    con: &Context,
    g: &mut G2d,
) 
    let x = to_coord(x);
    let y = to_coord(y);
    rectangle(
        color,
        [
            x,
            y,
            BLOCK_SIZE * (width as f64),
            BLOCK_SIZE * (height as f64),
        ],
        con.transform,
        g,
    );


game.rs文件内容如下:

use crate::draw::draw_block, draw_rectangle;
use piston_window::types::Color;
use piston_window::*;
use rand::thread_rng, Rng;
use crate::snake::Direction, Snake;
const FOOD_COLOR: Color = [0.80, 0.00, 0.00, 1.0];
const BORDER_COLOR: Color = [0.80, 0.00, 0.00, 1.0];
const GAMEOVER_COLOR: Color = [0.90, 0.00, 0.00, 0.5];
const MOVING_PERIOD: f64 = 0.1;
const RESTART_TIME: f64 = 1.0;

pub struct Game 
    snake: Snake,
    food_exists: bool,
    food_x: i32,
    food_y: i32,
    width: i32,
    height: i32,
    game_over: bool,
    waiting_time: f64,

impl Game 
    pub fn new(width: i32, height: i32) -> Game 
        Game 
            snake: Snake::new(2, 2),
            food_exists: true,
            food_x: 6,
            food_y: 4,
            width,
            height,
            game_over: false,
            waiting_time: 0.0,
        
    
    pub fn key_pressed(&mut self, key: Key) 
        if self.game_over 
            return;
        
        let dir = match key 
            Key::Up => Some(Direction::Up),
            Key::Down => Some(Direction::Down),
            Key::Left => Some(Direction::Left),
            Key::Right => Some(Direction::Right),
            _ => None,
        ;
        if dir.unwrap() == self.snake.head_direction().opposite() 
            return;
        
        self.update_snake(dir);
    
    pub fn draw(&self, con: &Context, g: &mut G2d) 
        self.snake.draw(con, g);
        if self.food_exists 
            draw_block(FOOD_COLOR, self.food_x, self.food_y, con, g);
        
        draw_rectangle(BORDER_COLOR, 0, 0, self.width, 1, con, g);
        draw_rectangle(BORDER_COLOR, 0, self.height - 1, self.width, 1, con, g);
        draw_rectangle(BORDER_COLOR, 0, 0, 1, self.height, con, g);
        draw_rectangle(BORDER_COLOR, self.width - 1, 0, 1, self.height, con, g);
        if self.game_over 
            draw_rectangle(GAMEOVER_COLOR, 0, 0, self.width, self.height, con, g);
        
    
    pub fn update(&mut self, delta_time: f64) 
        self.waiting_time += delta_time;
        if self.game_over 
            if self.waiting_time > RESTART_TIME 
                self.restart();
            
            return;
        
        if !self.food_exists 
            self.add_food();
        
        if self.waiting_time > MOVING_PERIOD 
            self.update_snake(None);
        
    
    fn check_eating(&mut self) 
        let (head_x, head_y): (i32, i32) = self.snake.head_position();
        if self.food_exists && self.food_x == head_x && self.food_y == head_y 
            self.food_exists = false;
            self.snake.restore_tail();
        
    
    fn check_if_snake_alive(&self, dir: Option<Direction>) -> bool 
        let (next_x, next_y) = self.snake.next_head(dir);
        if self.snake.overlap_tail(next_x, next_y) 
            return false;
        
        next_x > 0 && next_y > 0 && next_x < self.width - 1 && next_y < self.height - 1
    
    fn add_food(&mut self) 
        let mut rng = thread_rng();
        let mut new_x = rng.gen_range(1, self.width - 1);
        let mut new_y = rng.gen_range(1, self.width - 1);
        while self.snake.overlap_tail(new_x, new_y) 
            new_x = rng.gen_range(1, self.width - 1);
            new_y = rng.gen_range(1, self.width - 1);
        
        self.food_x = new_x;
        self.food_y = new_y;
        self.food_exists = true;
    
    fn update_snake(&mut self, dir: Option<Direction>) 
        if self.check_if_snake_alive(dir) 
            self.snake.move_forward(dir);
            self.check_eating();
         else 
            self.game_over = true;
        
        self.waiting_time = 0.0;
    
    fn restart(&mut self) 
        self.snake = Snake::new(2, 2);
        self.waiting_time = 0.0;
        self.food_exists = true;
        self.food_x = 6;
        self.food_y = 4;
        self.game_over = false;
    


main.rs文件内容如下:

extern crate piston_window;
extern crate rand;
mod draw;
mod game;
mod snake;
use draw::to_coord_u32;
use game::Game;
use piston_window::types::Color;
use piston_window::*;
const BACK_COLOR: Color = [0.5, 0.5, 0.5, 1.0];
fn main() 
    //https://magiclen.org/rust-compile-optimize/
    let (width, height) = (30, 30);
    let mut window: PistonWindow =
        WindowSettings::new("Snake", [to_coord_u32(width), to_coord_u32(height)])
            .exit_on_esc(true)
            .build()
            .unwrap();
    let mut game = Game::new(width, height);
    while let Some(event) = window.next() 
        if let Some(Button::Keyboard(key)) = event.press_args() 
            game.key_pressed(key);
        
        window.draw_2d(&event, |c, g| 
            clear(BACK_COLOR, g);
            game.draw(&c, g);
        );
        event.update(|arg| 
            game.update(arg.dt);
        );
    


snake.rs文件内容如下:

use piston_window::types::Color;
use piston_window::Context, G2d;
use std::collections::LinkedList;

use crate::draw::draw_block;
const SNAKE_COLOR: Color = [0.00, 0.80, 0.00, 1.0];
#[derive(Copy, Clone, PartialEq)]
pub enum Direction 
    Up,
    Down,
    Left,
    Right,

impl Direction 
    pub fn opposite(&self) -> Direction 
        match *self 
            Direction::Up => Direction::Down,
            Direction::Down => Direction::Up,
            Direction::Left => Direction::Right,
            Direction::Right => Direction::Left,
        
    

#[derive(Debug, Clone)]
struct Block 
    x: i32,
    y: i32,

pub struct Snake 
    direction: Direction,
    body: LinkedList<Block>,
    tail: Option<Block>,

impl Snake 
    pub fn new(x: i32, y: i32) -> Snake 
        let mut body: LinkedList<Block> = LinkedList::new();
        body.push_back(Block  x: x + 2, y );
        body.push_back(Block  x: x + 1, y );
        body.push_back(Block  x, y );
        Snake 
            direction: Direction::Right,
            body,
            tail: None,
        
    
    pub fn draw(&self, con: &Context, g: &mut G2d) 
        for block in &self.body 
            draw_block(SNAKE_COLOR, block.x, block.y, con, g);
        
    
    pub fn head_position(&self) -> (i32, i32) 
        let head_block = self.body.front().unwrap();
        (head_block.x, head_block.y)
    
    pub fn move_forward(&mut self, dir: Option<Direction>) 
        match dir 
            Some(d) => self.direction = d,
            None => (),
        
        let (last_x, last_y): (i32, i32) = self.head_position();
        let new_block = match self以上是关于rust语言写的贪吃蛇游戏的主要内容,如果未能解决你的问题,请参考以下文章

JavaScrip写的贪吃蛇

贪吃蛇小游戏程序(C语言)

C语言之贪吃蛇(ncurses)

c语言 贪吃蛇 程序

贪吃蛇游戏改运行背景颜色的C语言代码。

纯原生JS面向对象构造函数方法实现贪吃蛇小游戏