Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add slippery tile. #673

Merged
merged 7 commits into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions assets/default.core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ map_elements:
- /elements/environment/snail/snail.element.yaml
- /elements/environment/player_spawner/player_spawner.element.yaml
- /elements/environment/sproinger/sproinger.element.yaml
- /elements/environment/slippery/slippery.element.yaml
- /elements/environment/slippery_seaweed/slippery_seaweed.element.yaml
- /elements/item/crate/crate.element.yaml
- /elements/item/grenade/grenade.element.yaml
- /elements/item/kick_bomb/kick_bomb.element.yaml
Expand Down
4 changes: 4 additions & 0 deletions assets/elements/environment/slippery/slippery.atlas.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
image: ./slippery.png
tile_size: [33, 12]
rows: 1
columns: 1
10 changes: 10 additions & 0 deletions assets/elements/environment/slippery/slippery.element.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: Slippery
category: Gameplay
editor:
grab_size: [33, 10]
show_name: false
builtin: !Slippery
atlas: ./slippery.atlas.yaml
body_size: [33, 18]
player_slide: 4
body_friction: 0.95
Binary file added assets/elements/environment/slippery/slippery.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: Slippery Seaweed
category: Gameplay
editor:
grab_size: [40, 51]
show_name: false
builtin: !SlipperySeaweed
atlas: ./slippery_seaweed.atlas.yaml
body_size: [8, 8]
Expand Down
2 changes: 2 additions & 0 deletions core/src/elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod kick_bomb;
pub mod mine;
pub mod musket;
pub mod player_spawner;
pub mod slippery;
pub mod slippery_seaweed;
pub mod snail;
pub mod sproinger;
Expand Down Expand Up @@ -55,6 +56,7 @@ pub fn install(session: &mut GameSession) {
stomp_boots::install(session);
crate_item::install(session);
slippery_seaweed::install(session);
slippery::install(session);
}

fn handle_out_of_bounds_items(
Expand Down
80 changes: 80 additions & 0 deletions core/src/elements/slippery.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use crate::prelude::*;

pub fn install(session: &mut GameSession) {
session
.stages
.add_system_to_stage(CoreStage::PreUpdate, hydrate)
.add_system_to_stage(CoreStage::PreUpdate, update);
}

#[derive(Clone, Debug, TypeUlid, Default)]
#[ulid = "01GTF77BGTAPJNTYEXKP6A2862"]
pub struct Slippery {
pub player_slide: f32,
pub body_friction: f32,
}

fn hydrate(
entities: Res<Entities>,
mut hydrated: CompMut<MapElementHydrated>,
element_handles: Comp<ElementHandle>,
element_assets: BevyAssets<ElementMeta>,
mut slippery: CompMut<Slippery>,
mut atlas_sprites: CompMut<AtlasSprite>,
mut bodies: CompMut<KinematicBody>,
) {
let mut not_hydrated_bitset = hydrated.bitset().clone();
not_hydrated_bitset.bit_not();
not_hydrated_bitset.bit_and(element_handles.bitset());

for entity in entities.iter_with_bitset(&not_hydrated_bitset) {
let element_handle = element_handles.get(entity).unwrap();
let Some(element_meta) = element_assets.get(&element_handle.get_bevy_handle()) else {
continue;
};

if let BuiltinElementKind::Slippery {
atlas,
body_size,
player_slide,
body_friction,
} = &element_meta.builtin
{
hydrated.insert(entity, MapElementHydrated);
atlas_sprites.insert(entity, AtlasSprite::new(atlas.clone()));
bodies.insert(
entity,
KinematicBody {
shape: ColliderShape::Rectangle { size: *body_size },
has_mass: false,
..default()
},
);
slippery.insert(
entity,
Slippery {
player_slide: *player_slide,
body_friction: *body_friction,
},
);
}
}
}

pub fn update(
entities: Res<Entities>,
slippery: CompMut<Slippery>,
collision_world: CollisionWorld,
mut bodies: CompMut<KinematicBody>,
) {
for (slippery_ent, slippery) in entities.iter_with(&slippery) {
for (p_ent, body) in entities.iter_with(&mut bodies) {
if collision_world
.actor_collisions(p_ent)
.contains(&slippery_ent)
{
body.frame_friction_override = Some(slippery.body_friction);
}
}
}
}
6 changes: 6 additions & 0 deletions core/src/metadata/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,4 +303,10 @@ pub enum BuiltinElementKind {
fps: f32,
body_size: Vec2,
},
Slippery {
atlas: Handle<Atlas>,
body_size: Vec2,
player_slide: f32,
body_friction: f32,
},
}
13 changes: 12 additions & 1 deletion core/src/physics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ pub struct KinematicBody {
pub angular_velocity: f32,
pub gravity: f32,
pub bounciness: f32,
/// Sets a 1 frame override for the body friction. It will be re-set to `None` every frame so if
/// you wish to apply a continuous friction change, you must re-set it every frame.
///
/// This is useful for things like slippery blocks or other things that want to modify a body's
/// friction while it is on the block.
pub frame_friction_override: Option<f32>,
zicklag marked this conversation as resolved.
Show resolved Hide resolved
pub is_on_ground: bool,
pub was_on_ground: bool,
/// Will be `true` if the body is currently on top of a platform/jumpthrough tile
Expand Down Expand Up @@ -259,7 +265,12 @@ fn update_kinematic_bodies(

if body.is_on_ground {
if body.has_friction {
body.velocity.x *= game.physics.friction_lerp;
body.velocity.x *= if let Some(friction) = body.frame_friction_override {
friction
} else {
game.physics.friction_lerp
};
body.frame_friction_override = None;

if body.velocity.x.abs() <= game.physics.stop_threshold {
body.velocity.x = 0.0;
Expand Down
19 changes: 16 additions & 3 deletions core/src/player/state/states/idle.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use crate::player::slippery::Slippery;

pub const ID: Key = key!("core::idle");

Expand Down Expand Up @@ -43,9 +44,11 @@ pub fn handle_player_state(
mut sprites: CompMut<AnimationBankSprite>,
mut bodies: CompMut<KinematicBody>,
mut audio_events: ResMut<AudioEvents>,
collision_world: CollisionWorld,
slippery: CompMut<Slippery>,
) {
let players = entities.iter_with((&player_states, &player_indexes, &mut sprites, &mut bodies));
for (_player_ent, (player_state, player_idx, animation, body)) in players {
for (player_ent, (player_state, player_idx, animation, body)) in players {
if player_state.current != ID {
continue;
}
Expand Down Expand Up @@ -73,12 +76,22 @@ pub fn handle_player_state(
body.velocity.y = meta.stats.jump_speed;
}

let mut slide_factor = 1.;
for (slippery_ent, slippery_meta) in entities.iter_with(&slippery) {
if collision_world
.actor_collisions(player_ent)
.contains(&slippery_ent)
{
slide_factor = 1. / slippery_meta.player_slide;
}
}

// Since we are idling, slide
if body.velocity.x != 0.0 {
if body.velocity.x.is_sign_positive() {
body.velocity.x = (body.velocity.x - meta.stats.slowdown).max(0.0);
body.velocity.x = (body.velocity.x - meta.stats.slowdown * slide_factor).max(0.0);
} else {
body.velocity.x = (body.velocity.x + meta.stats.slowdown).min(0.0);
body.velocity.x = (body.velocity.x + meta.stats.slowdown * slide_factor).min(0.0);
}
}
}
Expand Down