use bevy::prelude::*; use bevy::render::pass::ClearColor; use rand::prelude::random; use std::time::Duration; const ARENA_WIDTH: u32 = 10; const ARENA_HEIGHT: u32 = 10; #[derive(Default, Copy, Clone, Eq, PartialEq, Hash)] struct Position { x: i32, y: i32, } struct Size { width: f32, height: f32, } impl Size { pub fn square(x: f32) -> Self { Self { width: x, height: x, } } } struct SnakeHead; struct Materials { head_material: Handle, food_material: Handle, } struct Food; struct FoodSpawnTimer(Timer); impl Default for FoodSpawnTimer { fn default() -> Self { Self(Timer::new(Duration::from_millis(1000), true)) } } fn setup(commands: &mut Commands, mut materials: ResMut>) { commands.spawn(Camera2dBundle::default()); commands.insert_resource(Materials { head_material: materials.add(Color::rgb(0.7, 0.7, 0.7).into()), food_material: materials.add(Color::rgb(1.0, 0.0, 1.0).into()), }); } fn spawn_snake(commands: &mut Commands, materials: Res) { commands .spawn(SpriteBundle { material: materials.head_material.clone(), sprite: Sprite::new(Vec2::new(10.0, 10.0)), ..Default::default() }) .with(SnakeHead) .with(Position { x: 3, y: 3 }) .with(Size::square(0.8)); } fn snake_movement( keyboard_input: Res>, mut head_positions: Query<&mut Position, With>, ) { for mut pos in head_positions.iter_mut() { if keyboard_input.pressed(KeyCode::Left) { pos.x -= 1; } if keyboard_input.pressed(KeyCode::Right) { pos.x += 1; } if keyboard_input.pressed(KeyCode::Down) { pos.y -= 1; } if keyboard_input.pressed(KeyCode::Up) { pos.y += 1; } } } fn size_scaling(windows: Res, mut q: Query<(&Size, &mut Sprite)>) { let window = windows.get_primary().unwrap(); for (sprite_size, mut sprite) in q.iter_mut() { sprite.size = Vec2::new( sprite_size.width / ARENA_WIDTH as f32 * window.width() as f32, sprite_size.height / ARENA_HEIGHT as f32 * window.height() as f32, ); } } 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.) } let window = windows.get_primary().unwrap(); for (pos, mut transform) in q.iter_mut() { transform.translation = Vec3::new( convert(pos.x as f32, window.width() as f32, ARENA_WIDTH as f32), convert(pos.y as f32, window.height() as f32, ARENA_HEIGHT as f32), 0.0, ); } } fn food_spawner( commands: &mut Commands, materials: Res, time: Res