Comments (2)
Tip: Format this code with the code
block
My fork has bevy 0.9 support. I've already made a pull request
from bevy_snake.
use bevy::prelude::*;
use bevy::time::FixedTimestep;
use bevy::window::close_on_esc;
use rand::prelude::random;
const SNAKE_HEAD_COLOR: Color = Color::rgb(0.7, 0.7, 0.7);
const FOOD_COLOR: Color = Color::rgb(1.0, 0.0, 1.0);
const SNAKE_SEGMENT_COLOR: Color = Color::rgb(0.3, 0.3, 0.3);
const ARENA_HEIGHT: u32 = 10;
const ARENA_WIDTH: u32 = 10;
#[derive(Component, Clone, Copy, PartialEq, Eq)]
struct Position {
x: i32,
y: i32,
}
#[derive(Component)]
struct Size {
width: f32,
height: f32,
}
impl Size {
pub fn square(x: f32) -> Self {
Self {
width: x,
height: x,
}
}
}
#[derive(Component)]
struct SnakeHead {
direction: Direction,
}
struct GameOverEvent;
struct GrowthEvent;
#[derive(Resource, Default)]
struct LastTailPosition(Option);
#[derive(Component)]
struct SnakeSegment;
#[derive(Resource, Default, Deref, DerefMut)]
struct SnakeSegments(Vec);
#[derive(Component)]
struct Food;
#[derive(PartialEq, Copy, Clone)]
enum Direction {
Left,
Up,
Right,
Down,
}
impl Direction {
fn opposite(self) -> Self {
match self {
Self::Left => Self::Right,
Self::Right => Self::Left,
Self::Up => Self::Down,
Self::Down => Self::Up,
}
}
}
fn setup_camera(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
}
fn spawn_snake(mut commands: Commands, mut segments: ResMut) {
*segments = SnakeSegments(vec![
commands
.spawn(SpriteBundle {
sprite: Sprite {
color: SNAKE_HEAD_COLOR,
..default()
},
..default()
})
.insert(SnakeHead {
direction: Direction::Up,
})
.insert(SnakeSegment)
.insert(Position { x: 3, y: 3 })
.insert(Size::square(0.8))
.id(),
spawn_segment(commands, Position { x: 3, y: 2 }),
]);
}
fn spawn_segment(mut commands: Commands, position: Position) -> Entity {
commands
.spawn(SpriteBundle {
sprite: Sprite {
color: SNAKE_SEGMENT_COLOR,
..default()
},
..default()
})
.insert(SnakeSegment)
.insert(position)
.insert(Size::square(0.65))
.id()
}
fn snake_movement(
mut last_tail_position: ResMut,
mut game_over_writer: EventWriter,
segments: ResMut,
mut heads: Query<(Entity, &SnakeHead)>,
mut positions: Query<&mut Position>,
) {
if let Some((head_entity, head)) = heads.iter_mut().next() {
let segment_positions = segments
.iter()
.map(|e| *positions.get_mut(*e).unwrap())
.collect::<Vec>();
let mut head_pos = positions.get_mut(head_entity).unwrap();
match &head.direction {
Direction::Left => {
head_pos.x -= 1;
}
Direction::Right => {
head_pos.x += 1;
}
Direction::Up => {
head_pos.y += 1;
}
Direction::Down => {
head_pos.y -= 1;
}
};
if head_pos.x < 0
|| head_pos.y < 0
|| head_pos.x as u32 >= ARENA_WIDTH
|| head_pos.y as u32 >= ARENA_HEIGHT
{
game_over_writer.send(GameOverEvent);
}
if segment_positions.contains(&head_pos) {
game_over_writer.send(GameOverEvent);
}
segment_positions
.iter()
.zip(segments.iter().skip(1))
.for_each(|(pos, segment)| {
*positions.get_mut(*segment).unwrap() = *pos;
});
*last_tail_position = LastTailPosition(Some(*segment_positions.last().unwrap()));
}
}
fn snake_movement_input(keyboard_input: Res<Input>, mut heads: Query<&mut SnakeHead>) {
if let Some(mut head) = heads.iter_mut().next() {
let dir: Direction = if keyboard_input.pressed(KeyCode::Left) {
Direction::Left
} else if keyboard_input.pressed(KeyCode::Down) {
Direction::Down
} else if keyboard_input.pressed(KeyCode::Up) {
Direction::Up
} else if keyboard_input.pressed(KeyCode::Right) {
Direction::Right
} else {
head.direction
};
if dir != head.direction.opposite() {
head.direction = dir;
}
}
}
fn game_over(
mut commands: Commands,
mut reader: EventReader,
segments_res: ResMut,
food: Query<Entity, With>,
segments: Query<Entity, With>,
) {
if reader.iter().next().is_some() {
for ent in food.iter().chain(segments.iter()) {
commands.entity(ent).despawn();
}
spawn_snake(commands, segments_res);
}
}
fn snake_eating(
mut commands: Commands,
mut growth_writer: EventWriter,
food_positions: Query<(Entity, &Position), With>,
head_positions: Query<&Position, With>,
) {
for head_pos in head_positions.iter() {
for (ent, food_pos) in food_positions.iter() {
if food_pos == head_pos {
commands.entity(ent).despawn();
growth_writer.send(GrowthEvent);
}
}
}
}
fn snake_growth(
commands: Commands,
last_tail_position: Res,
mut segments: ResMut,
mut growth_reader: EventReader,
) {
if growth_reader.iter().next().is_some() {
segments.push(spawn_segment(commands, last_tail_position.0.unwrap()));
}
}
fn size_scaling(windows: Res, mut q: Query<(&Size, &mut Transform)>) {
if let Some(window) = windows.get_primary() {
for (sprite_size, mut transform) in q.iter_mut() {
transform.scale = Vec3::new(
sprite_size.width / ARENA_WIDTH as f32 * window.width(),
sprite_size.height / ARENA_HEIGHT as f32 * window.height(),
1.0,
);
}
}
}
fn position_translation(windows: Res, mut q: Query<(&Position, &mut Transform)>) {
fn convert(pos: f32, bound_window: f32, bound_game: f32) -> f32 {
let tile_size = bound_window / bound_game;
pos / bound_game * bound_window - (bound_window / 2.) + (tile_size / 2.)
}
if let Some(window) = windows.get_primary() {
for (pos, mut transform) in q.iter_mut() {
transform.translation = Vec3::new(
convert(pos.x as f32, window.width(), ARENA_WIDTH as f32),
convert(pos.y as f32, window.height(), ARENA_HEIGHT as f32),
0.0,
);
}
}
}
fn food_spawner(mut commands: Commands) {
commands
.spawn(SpriteBundle {
sprite: Sprite {
color: FOOD_COLOR,
..default()
},
..default()
})
.insert(Food)
.insert(Position {
x: (random() * ARENA_WIDTH as f32) as i32,
y: (random() * ARENA_HEIGHT as f32) as i32,
})
.insert(Size::square(0.8));
}
fn main() {
App::new()
.insert_resource(ClearColor(Color::rgb(0.04, 0.04, 0.04)))
.add_plugins(DefaultPlugins)
.add_startup_system(setup_camera)
.add_startup_system(spawn_snake)
.insert_resource(SnakeSegments::default())
.insert_resource(LastTailPosition::default())
.add_system(snake_movement_input.before(snake_movement))
.add_system_set(
SystemSet::new()
.with_run_criteria(FixedTimestep::step(0.150))
.with_system(snake_movement)
.with_system(snake_eating.after(snake_movement))
.with_system(snake_growth.after(snake_eating)),
)
.add_system(game_over.after(snake_movement))
.add_system_set(
SystemSet::new()
.with_run_criteria(FixedTimestep::step(1.0))
.with_system(food_spawner),
)
.add_system_set_to_stage(
CoreStage::PostUpdate,
SystemSet::new()
.with_system(position_translation)
.with_system(size_scaling),
)
.add_system(bevy::close_on_esc)
.run();
}
Formatted with a code block and rust format for you all.
from bevy_snake.
Related Issues (11)
- Problem in SnakeSegments struct HOT 1
- Website is down HOT 2
- technically no licence HOT 1
- responsiveness HOT 6
- System Order HOT 1
- There is a possibility to ignore opposite direction check HOT 2
- Missing .add_system(game_over.system()) on the website HOT 1
- mismatched types: &Handle<ColorMaterial>
- More idiomatic startup setup HOT 2
- thanks for writing the post! it's extremely solid :D HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bevy_snake.