Skip to content

Commit

Permalink
feat: Jellyfish v2 (#898)
Browse files Browse the repository at this point in the history
Take 2 🎬 this is the second iteration of the Jellyfish item, based on
Duck Game's [RC
Controller](https://duckgame.fandom.com/wiki/RC_Controller).

More tweaks may come in follow-up PRs

## Notable Changes from [v1](#895)

- The camera follows any entity with the new `CameraSubject` component
- Entity must also have a `Transform` and `KinematicBody` to work
properly
- The flappy jellyfish collides with solids
- The flappy is now much more jerky and overly responsive to user input,
I may add acceleration to the left/right movement so that it floats
around more to give it a more natural feel
- Control the jellyfish like Duck Game's RC Controller
- The flappy is tied to the jellyfish hat, not the player
- If the driver dies/drops the jellyfish the flappy doesn't explode,
another player can pick it up and take control
- Despawn & dehydrate the jellyfish item when the flappy explodes

## ToDo

- ~Try to get the jellyfish on the player's head~ (will handle in
another PR for cosmetic changes)
  • Loading branch information
nelson137 authored Jan 12, 2024
1 parent 744411f commit 7a6c0fb
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 257 deletions.
4 changes: 2 additions & 2 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ use crate::{prelude::*, settings::PlayerControlMapping};
pub mod prelude {
pub use super::{
attachment::*, audio::*, bullet::*, camera::*, damage::*, debug::*, editor::*, editor::*,
elements::prelude::*, globals::*, input::*, item::*, lifetime::*, map::*,
map_constructor::*, metadata::*, physics::*, player::*, random::*, utils::*, FPS,
elements::prelude::*, flappy_jellyfish::*, globals::*, input::*, item::*, lifetime::*,
map::*, map_constructor::*, metadata::*, physics::*, player::*, random::*, utils::*, FPS,
MAX_PLAYERS,
};
}
Expand Down
58 changes: 29 additions & 29 deletions src/core/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,24 @@ pub struct ParallaxBackgroundSprite {
pub meta: ParallaxLayerMeta,
}

/// A subject of the camera.
///
/// The camera will move and zoom to ensure that all subjects remain visible. Entities must also
/// have a `Transform` component and a `KinematicBody` component for this to work properly.
#[derive(Clone, Copy, Debug, Default, HasSchema)]
pub struct CameraSubject {
/// A rectangle around the subject that is larger than the subject, and will always move to
/// contain it. The camera will seek to contain this rectangle, instead of the subject itself.
///
/// The advantage of this processing method is that the larger rect doesn't move as much as the
/// subject, because, for instance, a player jumping up and down in place will still be inside
/// of their camera rect, so the camera will not move around annoyingly.
rect: Rect,
}

/// The state of the camera.
#[derive(Clone, Debug, HasSchema, Default)]
pub struct CameraState {
/// A rectangle around the player that is larger than the player, and will always move to
/// contain the player. The camra will seek to contain this rectangle, instead of the player
/// itself.
///
/// The advantage of this processing method is that the larger rect doesn't move as much as the
/// player, because, for instance, while jumping up and down in place, the player will still be
/// inside of their camera rect, so the camera will not move around annoyingly.
pub player_camera_rects: [Rect; MAX_PLAYERS],
/// Disables the default camera controller. Useful, for example, when taking over the camera
/// from the editor.
pub disable_controller: bool,
Expand All @@ -45,16 +52,16 @@ fn camera_controller(
map: Res<LoadedMap>,
mut cameras: CompMut<Camera>,
mut camera_shakes: CompMut<CameraShake>,
mut camera_states: CompMut<CameraState>,
camera_states: Comp<CameraState>,
mut camera_subjects: CompMut<CameraSubject>,
transforms: Comp<Transform>,
player_indexes: Comp<PlayerIdx>,
bodies: Comp<KinematicBody>,
window: Res<Window>,
) {
let meta = &meta.core.camera;

let Some((_ent, (camera, camera_shake, camera_state))) = entities
.iter_with((&mut cameras, &mut camera_shakes, &mut camera_states))
.iter_with((&mut cameras, &mut camera_shakes, &camera_states))
.next()
else {
return;
Expand All @@ -64,13 +71,13 @@ fn camera_controller(
}

// Update player camera rects
for (_ent, (transform, player_idx, body)) in
entities.iter_with((&transforms, &player_indexes, &bodies))
for (_ent, (camera_subj, transform, body)) in
entities.iter_with((&mut camera_subjects, &transforms, &bodies))
{
let camera_box_size = meta.player_camera_box_size;

// Get the player's camera box
let camera_box = &mut camera_state.player_camera_rects[player_idx.0 as usize];
let camera_box = &mut camera_subj.rect;

// If it's not be initialized.
if camera_box.min == Vec2::ZERO && camera_box.max == Vec2::ZERO {
Expand Down Expand Up @@ -112,27 +119,19 @@ fn camera_controller(
.unwrap_or(window.size);
let viewport_aspect = viewport_size.x / viewport_size.y;
let default_height = meta.default_height;
let camera_height = if let CameraSize::FixedHeight(height) = &camera.size {
*height
let default_width = viewport_aspect * default_height;
let camera_height = if let CameraSize::FixedHeight(height) = camera.size {
height
} else {
400.0
};
let mut scale = camera_height / default_height;
let default_width = viewport_aspect * default_height;
let map_size = map.grid_size.as_vec2() * map.tile_size;

let mut min = Vec2::new(f32::MAX, f32::MAX);
let mut max = Vec2::new(f32::MIN, f32::MIN);

let players: Vec<u32> = entities
.iter_with(&player_indexes)
.map(|x| x.1 .0)
.collect();
let player_count = players.len();

for player_idx in players {
let rect = camera_state.player_camera_rects[player_idx as usize];
let mut min = Vec2::MAX;
let mut max = Vec2::MIN;

for CameraSubject { rect } in camera_subjects.iter_mut() {
min = (rect.min - vec2(meta.border_left, meta.border_bottom))
.min(min)
.max(Vec2::ZERO);
Expand All @@ -142,7 +141,8 @@ fn camera_controller(

let camera_pos = &mut camera_shake.center;

let mut middle_point = if player_count == 0 {
let subject_count = camera_subjects.iter().count();
let mut middle_point = if subject_count == 0 {
camera_pos.truncate()
} else {
Rect { min, max }.center()
Expand Down
Loading

0 comments on commit 7a6c0fb

Please sign in to comment.