Skip to content

with bevy 0.9.1 there are 8 errors + crash with closed the window #13

@syapk

Description

@syapk

error[E0432]: unresolved import bevy::core::FixedTimestep
error[E0277]: the trait bound SnakeSegments: Resource is not satisfied
error[E0277]: the trait bound LastTailPosition: Resource is not satisfied
error[E0277]: the trait bound SnakeSegments: Resource is not satisfied
error[E0277]: the trait bound SnakeSegments: Resource is not satisfied
error[E0277]: the trait bound LastTailPosition: Resource is not satisfied
error[E0277]: the trait bound SnakeSegments: Resource is not satisfied
error[E0433]: failed to resolve: use of undeclared type OrthographicCameraBundle

here is the fix with a correct program close:

use bevy::prelude::*;
use bevy::time::FixedTimestep;

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.set(WindowPlugin {
window: WindowDescriptor {
title: "Snake!".to_string(),
width: 500.,
height: 300.,
..default()
},
..default()
}))
.add_startup_system(setup_camera)
.add_startup_system(spawn_snake)
.insert_resource(SnakeSegments::default())
.insert_resource(LastTailPosition::default())
.add_event::()
.add_system(snake_movement_input.before(snake_movement))
.add_event::()
.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::window::close_on_esc)
.run();
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions