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.direction {
Direction::Up => Block {
x: last_x,
y: last_y - 1,
},
Direction::Down => Block {
x: last_x,
y: last_y + 1,
},
Direction::Left => Block {
x: last_x - 1,
y: last_y,
},
Direction::Right => Block {
x: last_x + 1,
y: last_y,
},
};
self.body.push_front(new_block);
let removed_block = self.body.pop_back().unwrap();
self.tail = Some(removed_block);
}
pub fn head_direction(&self) -> Direction {
self.direction
}
pub fn next_head(&self, dir: Option<Direction>) -> (i32, i32) {
let (head_x, head_y): (i32, i32) = self.head_position();
let mut moving_dir = self.direction;
match dir {
Some(d) => moving_dir = d,
None => {}
}
match moving_dir {
Direction::Up => (head_x, head_y - 1),
Direction::Down => (head_x, head_y + 1),
Direction::Left => (head_x - 1, head_y),
Direction::Right => (head_x + 1, head_y),
}
}
pub fn restore_tail(&mut self) {
let blk = self.tail.clone().unwrap();
self.body.push_back(blk);
}
pub fn overlap_tail(&self, x: i32, y: i32) -> bool {
let mut ch = 0;
for block in &self.body {
if x == block.x && y == block.y {
return true;
}
ch += 1;
if ch == self.body.len() - 1 {
break;
}
}
return false;
}
}
cargo build --release
./target/release/snake.exe
结果如下:
rust语言写的贪吃蛇游戏的更多相关文章
- 【C语言项目】贪吃蛇游戏(上)
目录 00. 目录 01. 开发背景 02. 功能介绍 03. 欢迎界面设计 3.1 常用终端控制函数 3.2 设置文本颜色函数 3.3 设置光标位置函数 3.4 绘制字符画(蛇) 3.5 欢迎界面函 ...
- 关于用Java写的贪吃蛇游戏的一些感想
学习Java有那么一个月了,兴趣还是挺高的.然而最近老师布置的一个迷宫问题,着实让我头疼了一两个礼拜,以至于身心疲惫,困扰不安.无奈,暂且先放下这个迷宫问题,写个简单点的贪吃蛇程序,以此来提高低落的情 ...
- Python写的贪吃蛇游戏例子
第一次用Python写这种比较实用且好玩的东西,权当练手吧 游戏说明: * P键控制“暂停/开始”* 方向键控制贪吃蛇的方向 源代码如下: 复制代码代码如下: from Tkinter import ...
- 【C语言项目】贪吃蛇游戏(下)
目录 00. 目录 07. 游戏逻辑 7.5 按下ESC键结束游戏 7.6 判断是否撞到墙 7.7 判断是否咬到自己 08. 游戏失败界面设计 8.1 游戏失败界面边框设计 8.2 撞墙失败界面 8. ...
- 用最少的JS代码写出贪吃蛇游戏---迷你版
游戏进行页面展示 GAME OVER 页面展示 代码如下: <!doctype html> <html> <body> <canvas id=&q ...
- python 写一个贪吃蛇游戏
#!usr/bin/python #-*- coding:utf-8 -*- import random import curses s = curses.initscr() curses.curs_ ...
- 原生js写的贪吃蛇网页版游戏特效
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <bo ...
- 「JavaScript」手起刀落-一起来写经典的贪吃蛇游戏
回味 小时候玩的经典贪吃蛇游戏我们印象仍然深刻,谋划了几天,小时候喜欢玩的游戏,长大了终于有能力把他做出来(从来都没有通关过,不知道自己写的程序,是不是能通关了...),好了,闲话不多谈,先来看一下效 ...
- 贪吃蛇游戏——C语言双向链表实现
采用了双向链表结点来模拟蛇身结点: 通过C语言光标控制函数来打印地图.蛇身和食物: /************************** *************************** 贪吃 ...
- 贪吃蛇游戏(printf输出C语言版本)
这一次我们应用printf输出实现一个经典的小游戏—贪吃蛇,主要难点是小蛇数据如何存储.如何实现转弯的效果.吃到食物后如何增加长度. 1 构造小蛇 首先,在画面中显示一条静止的小蛇.二维数组canva ...
随机推荐
- springboot条件注册Condition注解
环境识别 import org.springframework.context.annotation.Condition; import org.springframework.context.ann ...
- Thingsboard3.2.2本地部署
Thingboard3.2.2本地安装编译详细教程!!! 一:拉取源码. 创建一个空的文件夹 在此处使用git拉取源码. git clone https://github.com/thingsboar ...
- 项目构建node-sass源码报错 SyntaxError:Unexpectedtoken"?"
背景 vue2项目,之前一直构建正常.今天改了代码,构建时报错,报错原因显示编译node-sass源码时出错. 报错信息: Modulebuild failed:/node_modules/node- ...
- CosineWarmup理论与代码实战
摘要:CosineWarmup是一种非常实用的训练策略,本次教程将带领大家实现该训练策略.教程将从理论和代码实战两个方面进行. 本文分享自华为云社区<CosineWarmup理论介绍与代码实战& ...
- SpringBoot——定制错误页面及原理
更多内容,前往 IT-BLOG 一.SpringBoot 默认的错误处理机制 [1]浏览器返回的默认错误页面如下: ☞ 浏览器发送请求的请求头信息如下:text/html 会在后面的源码分析中说到 ...
- 命令行启动kate||cmd启动kate|| 一行命令用kate编辑文件
命令行启动kate||cmd启动kate|| 一行命令用kate编辑文件 先看: 在得知可以在命令行中输入code以启用vscode编辑器后 例 code D:\dLevel\Lenovo\Deskt ...
- Teamcenter_NX集成开发:UF_UGMGR函数的使用
最近工作中经常使用Teamcenter.NX集成开发的情况,因此在这里记录UF_UGMGR函数的使用.使用UF_UGMGR相关函数需要有Teamcenter使用经验,理解Teamcenter中文件夹. ...
- 用Python基于Google Bard做一个交互式的聊天机器人
用Python基于Google Bard做一个交互式的聊天机器人 之前已经通过浏览器试过了 Google Bard ,更多细节请看: Try out Google Bard, Will Google ...
- 微软开源了一个 助力开发LLM 加持的应用的 工具包 semantic-kernel
在首席执行官萨蒂亚·纳德拉(Satya Nadella)的支持下,微软似乎正在迅速转变为一家以人工智能为中心的公司.最近微软的众多产品线都采用GPT-4加持,从Microsoft 365等商业产品到& ...
- PHP微信三方平台-序章
一 微信三方平台准备工作 参数说明: 1.登录授权的发起页域名:提供登录授权公众号的域名地址主开发地址 2.测试公众号列表:未全网发布之前只能添加测试公众号 3.授权事件后的接收URL: 这个地址只要 ...