veloren/common/src/states/climb.rs

103 lines
3.5 KiB
Rust
Raw Normal View History

2020-02-24 18:17:16 +00:00
use crate::{
comp::{CharacterState, EcsStateData, EnergySource, StateUpdate},
states::StateHandler,
sys::phys::GRAVITY,
};
2020-02-03 10:54:50 +00:00
use std::collections::VecDeque;
2020-02-24 18:17:16 +00:00
use vek::{
vec::{Vec2, Vec3},
Lerp,
};
2019-12-26 14:43:59 +00:00
2020-01-07 15:49:08 +00:00
const HUMANOID_CLIMB_ACCEL: f32 = 5.0;
const CLIMB_SPEED: f32 = 5.0;
2020-01-05 18:19:09 +00:00
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
2020-01-08 16:56:36 +00:00
pub struct State;
2019-12-26 14:43:59 +00:00
2020-01-08 16:56:36 +00:00
impl StateHandler for State {
2020-02-24 18:17:16 +00:00
fn new(_ecs_data: &EcsStateData) -> Self { Self {} }
2020-01-05 23:17:22 +00:00
2019-12-28 16:10:39 +00:00
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
2019-12-26 14:43:59 +00:00
pos: *ecs_data.pos,
vel: *ecs_data.vel,
ori: *ecs_data.ori,
character: *ecs_data.character,
2020-02-24 18:17:16 +00:00
energy: *ecs_data.energy,
2020-02-03 10:54:50 +00:00
local_events: VecDeque::new(),
server_events: VecDeque::new(),
2019-12-26 14:43:59 +00:00
};
2020-02-24 18:17:16 +00:00
if let Err(_) = update.energy.try_change_by(-5, EnergySource::Climb) {
update.character = CharacterState::Idle(None);
}
2020-01-07 15:49:08 +00:00
// If no wall is in front of character ...
2020-02-03 19:43:36 +00:00
if ecs_data.physics.on_wall.is_none() || ecs_data.physics.on_ground {
2020-01-07 15:49:08 +00:00
if ecs_data.inputs.jump.is_pressed() {
// They've climbed atop something, give them a boost
//TODO: JUMP EVENT
2020-01-07 15:49:08 +00:00
}
update.character = CharacterState::Idle(None);
2020-02-03 19:43:36 +00:00
return update;
2020-01-07 15:49:08 +00:00
}
2019-12-26 18:01:19 +00:00
// Move player
2019-12-26 14:43:59 +00:00
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
* ecs_data.inputs.move_dir
2020-01-07 15:49:08 +00:00
* if update.vel.0.magnitude_squared() < CLIMB_SPEED.powf(2.0) {
2019-12-26 14:43:59 +00:00
HUMANOID_CLIMB_ACCEL
} else {
0.0
};
2019-12-26 18:01:19 +00:00
// Set orientation direction based on wall direction
2019-12-26 14:43:59 +00:00
let ori_dir = if let Some(wall_dir) = ecs_data.physics.on_wall {
if Vec2::<f32>::from(wall_dir).magnitude_squared() > 0.001 {
Vec2::from(wall_dir).normalized()
} else {
Vec2::from(update.vel.0)
}
} else {
Vec2::from(update.vel.0)
};
// Smooth orientation
2019-12-26 14:43:59 +00:00
if ori_dir.magnitude_squared() > 0.0001
&& (update.ori.0.normalized() - Vec3::from(ori_dir).normalized()).magnitude_squared()
> 0.001
{
update.ori.0 = vek::ops::Slerp::slerp(
update.ori.0,
ori_dir.into(),
if ecs_data.physics.on_ground { 9.0 } else { 2.0 } * ecs_data.dt.0,
);
}
// Apply Vertical Climbing Movement
if let (true, Some(_wall_dir)) = (
(ecs_data.inputs.climb.is_pressed() | ecs_data.inputs.climb_down.is_pressed())
&& update.vel.0.z <= CLIMB_SPEED,
ecs_data.physics.on_wall,
) {
if ecs_data.inputs.climb_down.is_pressed() && !ecs_data.inputs.climb.is_pressed() {
update.vel.0 -=
ecs_data.dt.0 * update.vel.0.map(|e| e.abs().powf(1.5) * e.signum() * 6.0);
} else if ecs_data.inputs.climb.is_pressed() && !ecs_data.inputs.climb_down.is_pressed()
{
update.vel.0.z = (update.vel.0.z + ecs_data.dt.0 * GRAVITY * 1.25).min(CLIMB_SPEED);
} else {
update.vel.0.z = update.vel.0.z + ecs_data.dt.0 * GRAVITY * 1.5;
update.vel.0 = Lerp::lerp(
update.vel.0,
Vec3::zero(),
30.0 * ecs_data.dt.0 / (1.0 - update.vel.0.z.min(0.0) * 5.0),
);
}
}
2020-01-12 23:14:08 +00:00
update
2019-12-26 14:43:59 +00:00
}
}