reorganize binaries

This commit is contained in:
Christian Nieves
2024-12-09 19:14:04 -06:00
parent 390c4e9603
commit 3f38a6f0fe
3 changed files with 1 additions and 3 deletions

49
src/bin/first_app.rs Normal file
View File

@@ -0,0 +1,49 @@
use bevy::prelude::*;
#[derive(Component)]
struct Person;
#[derive(Component)]
struct Name(String);
fn add_people(mut commands: Commands) {
commands.spawn((Person, Name("Elaina Proctor".to_string())));
commands.spawn((Person, Name("Renzo Hume".to_string())));
commands.spawn((Person, Name("Zayna Nieves".to_string())));
}
#[derive(Resource)]
struct GreetTimer(Timer);
fn greet_people(time: Res<Time>, mut timer: ResMut<GreetTimer>, query: Query<&Name, With<Person>>) {
// update our timer with the time elapsed since the last update
// if that caused the timer to finish, we say hello to everyone
if timer.0.tick(time.delta()).just_finished() {
for name in &query {
println!("hello {}!", name.0);
}
}
}
fn change_names(mut query: Query<&mut Name, With<Person>>) {
for mut name in &mut query {
if name.0 == "Elaina Proctor" {
name.0 = "Elain Hume".to_string();
break;
}
}
}
pub struct HelloPlugin;
impl Plugin for HelloPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(GreetTimer(Timer::from_seconds(2.0, TimerMode::Repeating)));
app.add_systems(Startup, add_people);
app.add_systems(Update, (change_names, greet_people).chain());
}
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(HelloPlugin)
.run();
}

322
src/bin/snake.rs Normal file
View File

@@ -0,0 +1,322 @@
use std::time::Duration;
use bevy::{prelude::*, time::common_conditions::on_timer, window::PrimaryWindow};
use bevy_inspector_egui::quick::WorldInspectorPlugin;
use rand::prelude::random;
const SNAKE_HEAD_COLOR: Color = Color::srgb(0.5, 0.7, 0.5);
const SNAKE_SEGMENT_COLOR: Color = Color::srgb(0.3, 0.5, 0.3);
const FOOD_COLOR: Color = Color::srgb(0.7, 0.5, 0.7);
const ARENA_WIDTH: u32 = 15;
const ARENA_HEIGHT: u32 = 10;
const WINDOW_WIDTH: f32 = 1280.0;
#[derive(Eq, PartialEq, Copy, Clone)]
enum Direction {
Up,
Down,
Left,
Right,
}
impl Direction {
fn opposite(self) -> Self {
match self {
Self::Left => Self::Right,
Self::Right => Self::Left,
Self::Up => Self::Down,
Self::Down => Self::Up,
}
}
}
#[derive(Component)]
struct SnakeHead {
direction: Direction,
}
#[derive(Component)]
struct SnakeSegment;
#[derive(Resource, Default)]
struct SnakeSegments(Vec<Entity>);
#[derive(Resource, Default)]
struct LastTailPosition(Option<Position>);
#[derive(Component)]
struct Food;
#[derive(Component, Clone, Copy, Eq, PartialEq, Debug)]
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_input(input: Res<ButtonInput<KeyCode>>, mut heads: Query<&mut SnakeHead>) {
if let Some(mut head) = heads.iter_mut().next() {
let dir: Direction = if input.pressed(KeyCode::ArrowUp) {
Direction::Up
} else if input.pressed(KeyCode::ArrowDown) {
Direction::Down
} else if input.pressed(KeyCode::ArrowLeft) {
Direction::Left
} else if input.pressed(KeyCode::ArrowRight) {
Direction::Right
} else {
head.direction
};
// allow all inputs except turning around
if dir != head.direction.opposite() {
head.direction = dir;
}
}
}
fn snake_movement(
segments: Res<SnakeSegments>,
heads: Query<(Entity, &SnakeHead)>,
mut positions: Query<&mut Position>,
mut last_tail_position: ResMut<LastTailPosition>,
mut game_over_writer: EventWriter<GameOverEvent>,
) {
// Filter positions to just the segments
let segment_positions = segments
.0
.iter()
.map(|entity| *positions.get_mut(*entity).unwrap())
.collect::<Vec<Position>>();
let (head_entity, head) = heads.single();
let mut head_pos = positions.get_mut(head_entity).unwrap();
match &head.direction {
Direction::Up => head_pos.y += 1,
Direction::Down => head_pos.y -= 1,
Direction::Left => head_pos.x -= 1,
Direction::Right => head_pos.x += 1,
}
// Before we move the tail, check if the head has collided with a wall.
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);
}
// Before we move the tail, check if the head has collided with the tail.
if segment_positions.contains(&head_pos) {
println!("triggering GAME OVER tail hit {:?}", &head_pos);
game_over_writer.send(GameOverEvent);
}
segment_positions
.iter()
.zip(segments.0.iter().skip(1))
.for_each(|(pos, segment)| {
*positions.get_mut(*segment).unwrap() = *pos;
});
last_tail_position.0 = Some(*segment_positions.last().unwrap());
}
fn game_over(
mut commands: Commands,
mut game_over_reader: EventReader<GameOverEvent>,
segments_resource: ResMut<SnakeSegments>,
segments: Query<Entity, With<SnakeSegment>>,
head: Query<Entity, With<SnakeHead>>,
food: Query<Entity, With<Food>>,
) {
if game_over_reader.read().next().is_some() {
println!("GAME OVER");
for e in food.iter().chain(segments.iter()).chain(head.iter()) {
commands.entity(e).despawn();
}
spawn_snake(commands, segments_resource);
}
}
fn scale_translation(
mut windows: Query<&mut Window, With<PrimaryWindow>>,
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<PrimaryWindow>>,
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 spawn_segment(commands: &mut Commands, pos: Position) -> Entity {
commands
.spawn(Sprite {
color: SNAKE_SEGMENT_COLOR,
..Default::default()
})
.insert(SnakeSegment)
.insert(Name::new(String::from("SnakeSegment")))
.insert(pos)
.insert(Size::square(0.77))
.id()
}
fn spawn_food(mut commands: Commands) {
commands
.spawn(Sprite {
color: FOOD_COLOR,
..default()
})
.insert(Position {
x: (random::<f32>() * ARENA_WIDTH as f32) as i32,
y: (random::<f32>() * ARENA_HEIGHT as f32) as i32,
})
.insert(Name::new(String::from("Food")))
.insert(Size::square(0.8))
.insert(Food);
}
fn spawn_snake(mut commands: Commands, mut segments: ResMut<SnakeSegments>) {
*segments = SnakeSegments(vec![
commands
.spawn(Sprite {
color: SNAKE_HEAD_COLOR,
..default()
})
.insert(SnakeHead {
direction: Direction::Right,
})
.insert(Size::square(1.0))
.insert(Name::new(String::from("Snake Head")))
.insert(Position { x: 1, y: 0 })
.id(),
spawn_segment(&mut commands, Position { x: 0, y: 0 }),
])
}
#[derive(Event)]
struct GrowthEvent;
#[derive(Event)]
struct GameOverEvent;
fn snake_eating(
mut commands: Commands,
mut growth_writer: EventWriter<GrowthEvent>,
food_positions: Query<(Entity, &Position), With<Food>>,
head_positions: Query<&Position, With<SnakeHead>>,
) {
let head_pos = head_positions.single();
for (ent, food_pos) in food_positions.iter() {
if food_pos == head_pos {
commands.entity(ent).despawn();
growth_writer.send(GrowthEvent);
}
}
}
fn snake_growth(
mut commands: Commands,
last_tail_position: Res<LastTailPosition>,
mut segments: ResMut<SnakeSegments>,
mut growth_reader: EventReader<GrowthEvent>,
) {
if growth_reader.read().next().is_some() {
segments
.0
.push(spawn_segment(&mut commands, last_tail_position.0.unwrap()));
}
}
fn setup_camera(mut commands: Commands) {
commands.spawn((Camera2d {},));
}
pub struct SnakePlugin;
impl Plugin for SnakePlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, (setup_camera, spawn_snake))
.add_systems(
Update,
(
snake_movement_input,
(spawn_food).run_if(on_timer(Duration::from_secs(3))),
),
)
.add_systems(
FixedUpdate,
(snake_movement, snake_eating, snake_growth, game_over)
.chain()
.run_if(on_timer(Duration::from_millis(500))),
)
.add_systems(PostUpdate, (scale_translation, position_translation));
app.insert_resource(SnakeSegments::default())
.insert_resource(LastTailPosition::default());
// Events must be added to the app before they can be used
// using the 'add_event' method
app.add_event::<GrowthEvent>();
app.add_event::<GameOverEvent>();
}
}
fn main() {
App::new()
.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_plugins(SnakePlugin)
.run();
}