Skip to content

Commit

Permalink
Implement first version of camera stopping
Browse files Browse the repository at this point in the history
Define points in the levels, where all the enemies (spawned) until then must be defeated before continuing.

The camera logic needs refinements (extra complexity) because for example, as of now, when there is a stop point, the players can't cross it, leaving a small part of the screen unusable by them.
  • Loading branch information
64kramsystem committed Jul 28, 2022
1 parent 1f7dd5f commit e6d6e50
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 8 deletions.
14 changes: 11 additions & 3 deletions src/attack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ use crate::{
self, ATTACK_HEIGHT, ATTACK_LAYER, ATTACK_WIDTH, ITEM_BOTTLE_NAME, ITEM_HEIGHT, ITEM_LAYER,
ITEM_WIDTH, THROW_ITEM_ROTATION_SPEED,
},
enemy::SpawnLocationX,
input::PlayerAction,
item::item_carried_by_player,
metadata::{FighterMeta, GameMeta, ItemMeta},
metadata::{FighterMeta, GameMeta, ItemMeta, LevelMeta},
movement::{
clamp_player_movements, LeftMovementBoundary, MoveInArc, MoveInDirection, Rotate, Target,
},
Expand Down Expand Up @@ -296,6 +297,8 @@ fn player_flop(
),
With<Player>,
>,
enemy_spawn_locations_query: Query<&SpawnLocationX>,
level_meta: Res<LevelMeta>,
fighter_assets: Res<Assets<FighterMeta>>,
time: Res<Time>,
left_movement_boundary: Res<LeftMovementBoundary>,
Expand Down Expand Up @@ -384,8 +387,13 @@ fn player_flop(
)
.collect::<Vec<_>>();

let players_movement =
clamp_player_movements(players_movement, &left_movement_boundary, &game_meta);
let players_movement = clamp_player_movements(
players_movement,
&enemy_spawn_locations_query,
&level_meta,
&left_movement_boundary,
&game_meta,
);

for ((_, _, mut transform, _, _, _, _), player_dir) in query.iter_mut().zip(players_movement) {
if let Some(player_dir) = player_dir {
Expand Down
60 changes: 55 additions & 5 deletions src/movement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use leafwing_input_manager::prelude::ActionState;
use crate::{
animation::Facing,
consts::{self, LEFT_BOUNDARY_MAX_DISTANCE},
enemy::SpawnLocationX,
input::PlayerAction,
metadata::GameMeta,
metadata::{GameMeta, LevelMeta},
state::State,
ArrivedEvent, DespawnMarker, Player, Stats,
};
Expand Down Expand Up @@ -40,6 +41,8 @@ pub struct Knockback {
pub fn knockback_system(
mut commands: Commands,
mut query: Query<(Entity, &mut Transform, &mut Knockback, Option<&Player>)>,
enemy_spawn_locations_query: Query<&SpawnLocationX>,
level_meta: Res<LevelMeta>,
time: Res<Time>,
game_meta: Res<GameMeta>,
left_movement_boundary: Res<LeftMovementBoundary>,
Expand Down Expand Up @@ -85,7 +88,13 @@ pub fn knockback_system(
})
.collect::<Vec<_>>();

let player_dirs = clamp_player_movements(player_movements, &left_movement_boundary, &game_meta);
let player_dirs = clamp_player_movements(
player_movements,
&enemy_spawn_locations_query,
&level_meta,
&left_movement_boundary,
&game_meta,
);

for ((_, transform, _, _), player_dir) in player_knockbacks.iter_mut().zip(player_dirs) {
transform.translation += player_dir.unwrap().extend(0.);
Expand All @@ -103,6 +112,8 @@ pub fn player_controller(
),
With<Player>,
>,
enemy_spawn_locations_query: Query<&SpawnLocationX>,
level_meta: Res<LevelMeta>,
time: Res<Time>,
game_meta: Res<GameMeta>,
left_movement_boundary: Res<LeftMovementBoundary>,
Expand Down Expand Up @@ -130,7 +141,13 @@ pub fn player_controller(
})
.collect::<Vec<_>>();

let player_dirs = clamp_player_movements(player_movements, &left_movement_boundary, &game_meta);
let player_dirs = clamp_player_movements(
player_movements,
&enemy_spawn_locations_query,
&level_meta,
&left_movement_boundary,
&game_meta,
);

for ((mut state, _, mut transform, mut facing, _), dir) in
query.iter_mut().zip(player_dirs.iter())
Expand Down Expand Up @@ -291,18 +308,51 @@ pub fn update_left_movement_boundary(
/// Not a system, but a utility method!.
///
/// player_movements: array of (location, direction vector).
/// enemy_spawn_location_query: spawn locations of _alive_ enemies.
///
/// WATCH OUT! All players must be included, even if they don't move, in which case, pass
/// None as direction. This is because clamping is based on the position of _all_ the
/// players.
/// It's possible to pass an empty array; this can happen if the system doesn't guard the case
/// where all the players are dead; an empty array will be returned.
pub fn clamp_player_movements(
player_movements: Vec<(Vec3, Option<Vec2>)>,
mut player_movements: Vec<(Vec3, Option<Vec2>)>,
enemy_spawn_locations_query: &Query<&SpawnLocationX>,
level_meta: &LevelMeta,
left_movement_boundary: &LeftMovementBoundary,
game_meta: &GameMeta,
) -> Vec<Option<Vec2>> {
// In the first pass, we perform the absolute clamping (screen limits), and we collect the data
// In the first pass, we check the camera stop points. If a player is moving across a stop
// point, all the enemies up to that point must have been defeated, in order to move.

let current_stop_point = level_meta.stop_points.iter().find(|point_x| {
player_movements.iter().any(|(location, dir)| {
if let Some(dir) = dir {
location.x < **point_x && **point_x <= location.x + dir.x
} else {
false
}
})
});

if let Some(current_stop_point) = current_stop_point {
let any_enemy_behind_stop_point = enemy_spawn_locations_query
.iter()
.any(|SpawnLocationX(spawn_x)| spawn_x <= current_stop_point);

if any_enemy_behind_stop_point {
for (location, movement) in player_movements.iter_mut() {
if let Some(movement) = movement.as_mut() {
// Can be simplified, but it's harder to understand.
if location.x + movement.x > *current_stop_point {
movement.x = 0.;
}
}
}
}
}

// Then, we perform the absolute clamping (screen top/left/bottom), and we collect the data
// required for the relative clamping.

let mut min_new_player_x = f32::MAX;
Expand Down

0 comments on commit e6d6e50

Please sign in to comment.