diff --git a/src/game.rs b/src/game.rs index ef051cb..8e9f5da 100644 --- a/src/game.rs +++ b/src/game.rs @@ -6,7 +6,7 @@ use crate::AppState; use bevy::{ input::{keyboard::KeyCode, Input}, prelude::{shape::Quad, *}, - sprite::Mesh2dHandle, + sprite::Mesh2dHandle, ecs::system::EntityCommands, }; use bevy_rapier2d::prelude::*; use std::collections::BTreeSet; @@ -34,13 +34,14 @@ impl Plugin for GamePlugin { .add_system_set( SystemSet::on_update(AppState::Game) .with_system(crate::levels::post_setup_level) - .with_system(keyboard_input_system) + .with_system(player_movement_system) .with_system(move_camera) .with_system(character_particle_effect_system), ) .add_system_set( SystemSet::on_update(AppState::Win) - .with_system(keyboard_input_system) + .with_system(change_character_system) + .with_system(player_movement_system) .with_system(move_camera) .with_system(character_particle_effect_system), ) @@ -79,18 +80,12 @@ impl FromWorld for CharacterMeshes { #[derive(Component)] pub struct Level; -#[derive(Clone, Component, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct CharacterId(pub u32); - -#[derive(Clone, Component, Copy, Eq, Hash, PartialEq)] -pub struct SelectedCharacterId(pub Option); - -#[derive(Component)] -pub struct CharacterIdList(pub BTreeSet); - #[derive(Clone, Component, PartialEq)] pub struct CharacterColor(pub Color); +#[derive(Component)] +pub struct Player; + // Systems fn setup( @@ -109,36 +104,60 @@ fn setup( ); } +pub fn spawn_characters( + commands: &mut Commands, + character_meshes: &Res, + materials: &mut ResMut>, + audio: &Res>, + + transforms: &mut Vec, + colors: &Vec, +) { + spawn_character( + commands, + character_meshes, + materials, + audio, + transforms[0], + colors[0], + true, + ); + + for c in 1 .. transforms.len() { + spawn_character( + commands, + character_meshes, + materials, + audio, + transforms[c], + colors[c], + false, + ); + } +} + pub fn spawn_character( commands: &mut Commands, character_meshes: &Res, materials: &mut ResMut>, - selected_character_id: &mut Mut, - character_id_list: &mut Mut, audio: &Res>, mut transform: Transform, color: Color, + is_player: bool, ) { transform.translation.z = transform.translation.z.max(1.0); - let character_id = CharacterId( - character_id_list - .0 - .iter() - .last() - .map_or(0, |last_character_id| last_character_id.0 + 1), - ); - character_id_list.0.insert(character_id); + let color_mesh_2d_bundle: ColorMesh2dBundle = ColorMesh2dBundle { + mesh: character_meshes.square.clone(), + material: materials.add(ColorMaterial::from(color)), + transform, + ..default() + }; - commands - .spawn_bundle(ColorMesh2dBundle { - mesh: character_meshes.square.clone(), - material: materials.add(ColorMaterial::from(color)), - transform, - ..default() - }) + let mut entity_commands: EntityCommands = commands.spawn_bundle(color_mesh_2d_bundle); + + entity_commands .insert(Level) - .insert(character_id) .insert(CharacterColor(color)) .insert(RigidBody::Dynamic) .insert(Collider::cuboid(32., 32.)) @@ -154,9 +173,8 @@ pub fn spawn_character( .insert(ExternalImpulse::default()) .insert(ActiveEvents::COLLISION_EVENTS); - // If no character is selected, then select this one - if selected_character_id.0.is_none() { - selected_character_id.0 = Some(character_id); + if is_player { + entity_commands.insert(Player); audio .send(AudioMsg::Color([color.r(), color.g(), color.b()])) .ok(); @@ -168,23 +186,16 @@ fn collision_event_system( character_meshes: Res, mut materials: ResMut>, mut collision_events: EventReader, - character_query: Query<(&CharacterId, &CharacterColor, &Transform)>, - mut level_query: Query<(&mut SelectedCharacterId, &mut CharacterIdList)>, + character_query: Query<(&CharacterColor, &Transform)>, mut app_state: ResMut>, audio: Res>, ) { for collision_event in collision_events.iter() { if let CollisionEvent::Started(e1, e2, flags) = collision_event { if flags.is_empty() { - if let (Ok((c1_id, c1_color, c1_transform)), Ok((c2_id, c2_color, _c2_transform))) = + if let (Ok((c1_color, c1_transform)), Ok((c2_color, _c2_transform))) = (character_query.get(*e1), character_query.get(*e2)) { - let (mut selected_character_id, mut character_id_list) = - level_query.single_mut(); - character_id_list.0.remove(c1_id); - character_id_list.0.remove(c2_id); - selected_character_id.0 = None; - // TODO completely remove particles commands.entity(*e1).despawn_recursive(); commands.entity(*e2).despawn_recursive(); @@ -203,11 +214,10 @@ fn collision_event_system( &mut commands, &character_meshes, &mut materials, - &mut selected_character_id, - &mut character_id_list, &audio, *c1_transform, new_color.into(), + true, ); } } @@ -215,56 +225,67 @@ fn collision_event_system( } } -fn keyboard_input_system( +fn change_character_system( + mut commands: Commands, + keyboard_input: Res>, - mut characters: Query<(&CharacterId, &mut Velocity, &CharacterColor)>, - mut level_query: Query<(&mut SelectedCharacterId, &CharacterIdList)>, + characters: Query<(Entity, &Transform, &CharacterColor, Option<&Player>)>, + audio: Res>, +) { + if !keyboard_input.just_pressed(KeyCode::Tab) { return; } + + let mut player_idx: usize = 0; + let mut player_count: usize = 0; + + // find player idx + for (_entity, _transform, _color, player) in characters.iter() { + if let Some(_player) = player { + player_idx = player_count; + } + player_count += 1; + } + + // calculate next player index + let next_player_idx = (player_idx + 1) % player_count; + player_count = 0; + + // exchange `Player` component from old `player_idx` to new `next_player_idx` + for (entity, _transform, color, _player) in characters.iter() { + if player_count == player_idx { + commands.entity(entity).remove::(); + } + + if player_count == next_player_idx { + commands.entity(entity).insert(Player); + audio + .send(AudioMsg::Color([color.0.r(), color.0.g(), color.0.b()])) + .ok(); + } + + player_count += 1; + } +} + +fn player_movement_system( + keyboard_input: Res>, + mut characters: Query<&mut Velocity, With>, mut app_state: ResMut>, audio: Res>, ) { - if let Ok((mut selected_character_id, character_id_list)) = level_query.get_single_mut() { - if keyboard_input.just_pressed(KeyCode::Tab) { - let selected = if let Some(selected_character_id) = &mut selected_character_id.0 { - *selected_character_id = *character_id_list - .0 - .range(*selected_character_id..) - .nth(1) - .unwrap_or_else(|| character_id_list.0.iter().next().unwrap()); - *selected_character_id - } else { - selected_character_id.0 = Some(CharacterId(0)); - CharacterId(0) - }; - if let Some((_character_id, _velocity, color)) = characters - .iter_mut() - .find(|(character_id, _velocity, _color)| **character_id == selected) - { - audio - .send(AudioMsg::Color([color.0.r(), color.0.g(), color.0.b()])) - .ok(); - } - } + let right_pressed: bool = + keyboard_input.pressed(KeyCode::Right) || keyboard_input.pressed(KeyCode::D); + let left_pressed: bool = + keyboard_input.pressed(KeyCode::Left) || keyboard_input.pressed(KeyCode::A); - let right_pressed: bool = - keyboard_input.pressed(KeyCode::Right) || keyboard_input.pressed(KeyCode::D); - let left_pressed: bool = - keyboard_input.pressed(KeyCode::Left) || keyboard_input.pressed(KeyCode::A); + for mut velocity in characters.iter_mut() { + velocity.linvel.x = 200. * (right_pressed as i8 - left_pressed as i8) as f32; - if let Some(selected_character_id) = &selected_character_id.0 { - if let Some((_character_id, mut velocity, _color)) = characters - .iter_mut() - .find(|(character_id, _velocity, _color)| *character_id == selected_character_id) - { - velocity.linvel.x = 200. * (right_pressed as i8 - left_pressed as i8) as f32; - - if keyboard_input.just_pressed(KeyCode::Space) { - audio.send(AudioMsg::Jump).ok(); - velocity.linvel.y = 500.; - } - } - } - } + if keyboard_input.just_pressed(KeyCode::Space) { + audio.send(AudioMsg::Jump).ok(); + velocity.linvel.y = 500.; + } + } if app_state.current() == &AppState::Win && keyboard_input.just_pressed(KeyCode::Return) { app_state.replace(AppState::Game).unwrap(); @@ -272,20 +293,12 @@ fn keyboard_input_system( } fn character_particle_effect_system( - mut characters: Query<(&CharacterId, &Transform, &CharacterColor)>, + characters: Query<(&Transform, &CharacterColor), With>, mut particle_effect: ResMut, - mut level_query: Query<&SelectedCharacterId>, ) { - if let Ok(selected_character_id) = level_query.get_single_mut() { - if let Some(selected_character_id) = &selected_character_id.0 { - if let Some((_character_id, transform, color)) = characters - .iter_mut() - .find(|(character_id, _transform, _color)| *character_id == selected_character_id) - { - particle_effect.translation = transform.translation; - particle_effect.color = color.0; - } - } + for (transform, color) in characters.iter() { + particle_effect.translation = transform.translation; + particle_effect.color = color.0; } } @@ -309,29 +322,25 @@ fn win_setup(mut commands: Commands, asset_server: Res) { fn move_camera( mut camera_query: Query<(&Camera, &mut Transform)>, - characters: Query<(&CharacterId, &Transform), Without>, - level_query: Query<&SelectedCharacterId>, + characters: Query<&Transform, (Without, With)>, time: Res