学习Bevy练手的Snake
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
||||
5170
Cargo.lock
generated
Normal file
5170
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "snake"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bevy = "0.16.1"
|
||||
rand = "0.9.1"
|
||||
12
README.md
Normal file
12
README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Bevy Snake
|
||||
学习Bevy练手的Snake
|
||||
|
||||
# CHANGELOG
|
||||
## 0.1.0 - [2025.7.7]
|
||||
### ADD
|
||||
- 完成蛇的基本控制和移动系统
|
||||
# TODO
|
||||
[x] 蛇的基本控制和移动系统
|
||||
[ ] 食物生成
|
||||
[ ] 碰撞系统
|
||||
[ ] 分数展示
|
||||
12
src/constant.rs
Normal file
12
src/constant.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use bevy::color::Color;
|
||||
|
||||
pub const SNAKE_HEAD_COLOR: Color = Color::srgb(0.7, 0.7, 0.7);
|
||||
pub const SNAKE_SEGMENT_COLOR: Color = Color::srgb(0.1, 0.7, 0.7);
|
||||
|
||||
pub const SPEED:f32 = 200.;//暂时固定
|
||||
|
||||
pub const SNAKE_SIZE:f32 = 10.;
|
||||
|
||||
|
||||
pub const WINDOWS_WIDTH:f32 = 800.;
|
||||
pub const WINDOWS_HEIGHT:f32 = 600.;
|
||||
83
src/entity.rs
Normal file
83
src/entity.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use std::ops::Not;
|
||||
|
||||
use bevy::{prelude::*};
|
||||
|
||||
use crate::constant::*;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct SnakeHead{pub direction:Direction}
|
||||
impl SnakeHead {
|
||||
pub fn new(d:Direction)->Self{
|
||||
Self{ direction: d }
|
||||
}
|
||||
}
|
||||
impl Default for SnakeHead {
|
||||
fn default() -> Self {
|
||||
Self { direction: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
// 蛇的身体组件
|
||||
#[derive(Component)]
|
||||
pub struct SnakeSegment;
|
||||
|
||||
|
||||
|
||||
#[derive(Component, Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl Default for Direction {
|
||||
fn default() -> Self {
|
||||
Self::Right
|
||||
}
|
||||
}
|
||||
impl Direction {
|
||||
pub fn opposite(&self) -> Self {
|
||||
match self {
|
||||
Direction::Up => Direction::Down,
|
||||
Direction::Down => Direction::Up,
|
||||
Direction::Left => Direction::Right,
|
||||
Direction::Right => Direction::Left,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Resource)]
|
||||
pub struct Positions(pub Vec<Vec2>);
|
||||
|
||||
// 游戏状态
|
||||
#[derive(Resource)]
|
||||
pub struct GameState {
|
||||
pub game_over: bool,
|
||||
pub score: u32,
|
||||
pub highest_score: u32,
|
||||
pub windows_size: (f32, f32),
|
||||
}
|
||||
|
||||
impl Default for GameState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
game_over: false,
|
||||
score: 0,
|
||||
highest_score: 0,
|
||||
windows_size: (WINDOWS_WIDTH, WINDOWS_HEIGHT),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl GameState{
|
||||
pub fn get_windows_size(&self)->(f32,f32){
|
||||
self.windows_size
|
||||
}
|
||||
pub fn get_windows_size_width(&self)->f32{
|
||||
self.windows_size.0
|
||||
}
|
||||
pub fn get_windows_size_height(&self)->f32{
|
||||
self.windows_size.1
|
||||
}
|
||||
}
|
||||
18
src/main.rs
Normal file
18
src/main.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::entity::{GameState, Positions};
|
||||
|
||||
mod system;
|
||||
mod entity;
|
||||
mod constant;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_systems(Startup, (system::setup_camera,system::setup).chain())
|
||||
.init_resource::<GameState>()
|
||||
.init_resource::<Positions>()
|
||||
.add_systems(Startup, (system::spawn))
|
||||
.add_systems(Update, (system::input,system::snake_movement))
|
||||
.run();
|
||||
}
|
||||
84
src/system.rs
Normal file
84
src/system.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use crate::{
|
||||
constant::*,
|
||||
entity::*,
|
||||
};
|
||||
use bevy::prelude::* ;
|
||||
|
||||
pub fn setup_camera(mut commands: Commands) {
|
||||
commands.spawn(Camera2d);
|
||||
}
|
||||
pub fn setup(mut game_state: ResMut<GameState>) {
|
||||
*game_state = GameState::default();
|
||||
}
|
||||
|
||||
pub fn spawn(mut commands: Commands, mut position: ResMut<Positions>) {
|
||||
commands.spawn((
|
||||
SnakeHead::default(),
|
||||
Sprite::from_color(SNAKE_HEAD_COLOR, vec2(SNAKE_SIZE, SNAKE_SIZE)),
|
||||
Transform::from_xyz(0.0, 0.0, 1.0),
|
||||
// Position::new(0.,0.)
|
||||
));
|
||||
position.0.push(vec2(0.0, 0.0));
|
||||
|
||||
for i in 1..=4000 {
|
||||
commands.spawn((
|
||||
SnakeSegment,
|
||||
Sprite {
|
||||
color: SNAKE_SEGMENT_COLOR,
|
||||
custom_size: Some(Vec2::new(SNAKE_SIZE, SNAKE_SIZE)),
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(-i as f32, 0.0, 0.0),
|
||||
));
|
||||
position.0.push(vec2(-i as f32, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn snake_movement(
|
||||
mut head_positions: Query<(&SnakeHead, &mut Transform), With<SnakeHead>>,
|
||||
mut segments: Query<&mut Transform, (With<SnakeSegment>, Without<SnakeHead>)>,
|
||||
time: Res<Time>,
|
||||
mut position: ResMut<Positions>,
|
||||
) {
|
||||
let during = time.delta_secs();
|
||||
if let Ok((head, mut transform)) = head_positions.single_inner() {
|
||||
//头坐标
|
||||
position.0[0] = vec2(transform.translation.x,transform.translation.y);
|
||||
let mut prev = position.0[0];
|
||||
for (i, p) in position.0.iter_mut().enumerate().skip(1) {
|
||||
let new_val = (*p + prev) / 2.;
|
||||
prev = *p;
|
||||
*p = new_val;
|
||||
}
|
||||
match head.direction {
|
||||
Direction::Up => transform.translation.y += SPEED * during,
|
||||
Direction::Down => transform.translation.y -= SPEED * during,
|
||||
Direction::Left => transform.translation.x -= SPEED * during,
|
||||
Direction::Right => transform.translation.x += SPEED * during,
|
||||
}
|
||||
for (i,mut transform) in segments.iter_mut().enumerate(){
|
||||
transform.translation = vec3(position.0[i].x,position.0[i].y,0.);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn input(keyboard_input: Res<ButtonInput<KeyCode>>, mut heads: Query<&mut SnakeHead>) {
|
||||
if let Ok(mut head) = heads.single_mut() {
|
||||
let new_direction = if keyboard_input.pressed(KeyCode::ArrowUp) {
|
||||
Direction::Up
|
||||
} else if keyboard_input.pressed(KeyCode::ArrowDown) {
|
||||
Direction::Down
|
||||
} else if keyboard_input.pressed(KeyCode::ArrowLeft) {
|
||||
Direction::Left
|
||||
} else if keyboard_input.pressed(KeyCode::ArrowRight) {
|
||||
Direction::Right
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
if new_direction != head.direction.opposite() {
|
||||
head.direction = new_direction;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user