From 9dda1a1a50584890823854555031ccf2c132b594 Mon Sep 17 00:00:00 2001 From: Christian Nieves Date: Sun, 8 Dec 2024 02:24:46 -0600 Subject: [PATCH] grid movement --- src/snake/main.rs | 114 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 8 deletions(-) diff --git a/src/snake/main.rs b/src/snake/main.rs index 50e6328..95ec0bc 100644 --- a/src/snake/main.rs +++ b/src/snake/main.rs @@ -1,17 +1,99 @@ -use bevy::prelude::*; +use bevy::{prelude::*, window::PrimaryWindow}; use bevy_inspector_egui::quick::WorldInspectorPlugin; +const SNAKE_HEAD_COLOR: Color = Color::srgb(0.7, 1.0, 0.7); +const ARENA_WIDTH: u32 = 20; +const ARENA_HEIGHT: u32 = 15; +const WINDOW_WIDTH: f32 = 1280.0; + #[derive(Component)] struct SnakeHead; -const SNAKE_HEAD_COLOR: Color = Color::srgb(0.7, 0.7, 0.7); +#[derive(Component)] +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, + } + } +} + +fn snake_movement_system( + input: Res>, + + mut head_transforms: Query<(&SnakeHead, &mut Position)>, +) { + for (_, mut pos) in head_transforms.iter_mut() { + if input.pressed(KeyCode::ArrowUp) { + pos.y += 1; + } else if input.pressed(KeyCode::ArrowDown) { + pos.y -= 1; + } else if input.pressed(KeyCode::ArrowLeft) { + pos.x -= 1; + } else if input.pressed(KeyCode::ArrowRight) { + pos.x += 1; + } + } +} + +fn scale_translation( + mut windows: Query<&mut Window, With>, + mut q: Query<(&Size, &mut Transform)>, +) { + let window = windows.single_mut(); + 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( + mut windows: Query<&mut Window, With>, + mut q: Query<(&Position, &mut Transform)>, +) { + // We subtract half the window width because our coordinate system starts at the bottom left, and + // Translation starts from the center. We then add half the size of a single tile, because we want + // our sprites bottom left corner to be at the bottom left of a tile, not the center. + 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.single_mut(); + 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 setup_player(mut commands: Commands) { - commands.spawn(Sprite { - color: SNAKE_HEAD_COLOR, - custom_size: Some(Vec2::new(10.0, 10.0)), - ..default() - }); + commands + .spawn(Sprite { + color: SNAKE_HEAD_COLOR, + custom_size: Some(Vec2::new(10.0, 10.0)), + ..default() + }) + .insert(SnakeHead) + .insert(Position { x: 0, y: 0 }) + .insert(Size::square(1.0)); } fn setup_camera(mut commands: Commands) { @@ -19,9 +101,25 @@ fn setup_camera(mut commands: Commands) { } fn main() { + let systems = snake_movement_system; App::new() - .add_plugins(DefaultPlugins) + .add_plugins( + DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + title: "Snake".to_string(), + resolution: ( + WINDOW_WIDTH, + WINDOW_WIDTH * (ARENA_HEIGHT as f32 / ARENA_WIDTH as f32), + ) + .into(), + ..default() + }), + ..default() + }), + ) .add_plugins(WorldInspectorPlugin::new()) .add_systems(Startup, (setup_camera, setup_player)) + .add_systems(Update, systems) + .add_systems(PostUpdate, (scale_translation, position_translation)) .run(); }