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 ...
随机推荐
- 将map转成vo实体
//将map转成vo实体 AssetManagementProductsVO param= JSON.parseObject(JSON.toJSONString(map), AssetManageme ...
- nginx配置https详细过程
准备工作 需要先准备好你域名对应的证书和私钥,也就是cert证书和key.我部署是很常见的ng+tomcat双层配置,ng作为前端的代理,所以tomcat就不需要自己处理https,ng作为代理以ht ...
- 解决margin合并问题
一.什么是外边距合并 外边距合并(叠加)是一个相当简单的概念.但是,在实践中对网页进行布局时,它会造成许多混淆. 所谓的外边距合并就是,当两个垂直外边距相遇时,它们将形成一个外边距.合并的外边距的高度 ...
- Vue基础语法整理
vue基础用法&基础原理整理 1. vue基础知识和原理 1.1 初识Vue 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象 demo容器里的代码依然符合html规范,只不过混 ...
- 【LeetCode动态规划#05】背包问题的理论分析(基于代码随想录的个人理解,多图)
背包问题 问题描述 背包问题是一系列问题的统称,具体包括:01背包.完全背包.多重背包.分组背包等(仅需掌握前两种,后面的为竞赛级题目) 下面来研究01背包 实际上即使是最经典的01背包,也不会直接出 ...
- MYSQL DQL语句(基础)
MySQL引入 数据库的好处 持久化数据到本地 可以实现结构化查询,方便管理 数据库的相关概念 DB:数据库(database):存储数据的"仓库",它保存了一系列有组织的数据. ...
- el-tree组件过来吧默认打开全部子节点
//搜索到节点必须打开此节点所有子节点,因为默认是不会打开子节点的,所以手动设置打开的最高层级.本次我设置了最大四个层级 filterNode(value,data,node) { if(!value ...
- 字符串常见API(charCodeAt\fromCharCode)
1.myStr.charCodeAt(num) 返回指定位置的字符的Unicode(是字符编码的一种模式)编码. 2.String.fromCharCode() String的意思就是不能用自己定义的 ...
- ChatGPT 与 Midjourney 强强联手,让先秦阿房宫重现辉煌!
Midjourney 是一款非常特殊的 AI 绘画聊天机器人,它并不是软件,也不用安装,而是直接搭载在 Discord 平台之上,所有的功能都是通过调用 Discord 的聊天机器人程序实现的.要想使 ...
- 华为云 OpenTiny 跨端、跨框架企业级开源组件库项目落地实践直播即将开启!
大家好,我是 Kagol,公众号:前端开源星球. "你们这个产品怎么只能在电脑上适配呀?我想在手机上看都不行,太麻烦了!!" "你们这个产品看起来太简单了,我想要@@功能 ...