mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add movement_utils
This commit is contained in:
parent
06053faed0
commit
ca44497258
@ -10,7 +10,7 @@ use specs::{Component, Entity, FlaggedStorage, HashMapStorage, NullStorage};
|
||||
use sphynx::Uid;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct EcsCharacterState<'a> {
|
||||
pub struct EcsStateData<'a> {
|
||||
pub entity: &'a Entity,
|
||||
pub uid: &'a Uid,
|
||||
pub character: &'a CharacterState,
|
||||
@ -27,7 +27,7 @@ pub struct EcsCharacterState<'a> {
|
||||
pub local_bus: &'a EventBus<LocalEvent>,
|
||||
}
|
||||
|
||||
pub struct EcsStateUpdate {
|
||||
pub struct StateUpdate {
|
||||
pub character: CharacterState,
|
||||
pub pos: Pos,
|
||||
pub vel: Vel,
|
||||
@ -36,52 +36,52 @@ pub struct EcsStateUpdate {
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum MoveState {
|
||||
Stand(StandHandler),
|
||||
Run(RunHandler),
|
||||
Sit(SitHandler),
|
||||
Jump(JumpHandler),
|
||||
Fall(FallHandler),
|
||||
Glide(GlideHandler),
|
||||
Swim(SwimHandler),
|
||||
Climb(ClimbHandler),
|
||||
Stand(StandState),
|
||||
Run(RunState),
|
||||
Sit(SitState),
|
||||
Jump(JumpState),
|
||||
Fall(FallState),
|
||||
Glide(GlideState),
|
||||
Swim(SwimState),
|
||||
Climb(ClimbState),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum ActionState {
|
||||
Idle,
|
||||
Wield(WieldHandler),
|
||||
Idle(IdleState),
|
||||
Wield(WieldState),
|
||||
Attack(AttackKind),
|
||||
Block(BlockKind),
|
||||
Dodge(DodgeKind),
|
||||
// Interact,
|
||||
// Interact?,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum AttackKind {
|
||||
BasicAttack(BasicAttackHandler),
|
||||
Charge(ChargeAttackHandler),
|
||||
BasicAttack(BasicAttackState),
|
||||
Charge(ChargeAttackState),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum BlockKind {
|
||||
BasicBlock(BasicBlockHandler),
|
||||
BasicBlock(BasicBlockState),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum DodgeKind {
|
||||
Roll(RollHandler),
|
||||
Roll(RollState),
|
||||
}
|
||||
|
||||
impl ActionState {
|
||||
pub fn is_equip_finished(&self) -> bool {
|
||||
match self {
|
||||
Wield(WieldHandler { equip_delay }) => *equip_delay == Duration::default(),
|
||||
Wield(WieldState { equip_delay }) => *equip_delay == Duration::default(),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
pub fn get_delay(&self) -> Duration {
|
||||
match self {
|
||||
Wield(WieldHandler { equip_delay }) => *equip_delay,
|
||||
Wield(WieldState { equip_delay }) => *equip_delay,
|
||||
_ => Duration::default(),
|
||||
}
|
||||
}
|
||||
@ -115,7 +115,7 @@ impl ActionState {
|
||||
}
|
||||
}
|
||||
pub fn is_idling(&self) -> bool {
|
||||
if let Idle = self {
|
||||
if let Idle(_) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -125,22 +125,40 @@ impl ActionState {
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct CharacterState {
|
||||
/// __How the character is currently moving, e.g. Running, Standing, Falling.__
|
||||
///
|
||||
/// _Primarily `handle()`s updating `Pos`, `Vel`, `Ori`, and lower body animations.
|
||||
/// Can be overidden by `ActionState`s using `move_disabled` flag. Example: `ChargeAttackState`_
|
||||
pub move_state: MoveState,
|
||||
|
||||
/// __How the character is currently acting, e.g. Wielding, Attacking, Dodging.__
|
||||
///
|
||||
/// _Primarily `handle()`s how character interacts with world, and upper body animations.
|
||||
/// Can be overidden by `MoveState`s using `action_disabled` flag. Example: `GlideState`_
|
||||
pub action_state: ActionState,
|
||||
|
||||
/// Used by `move_state` to disable `action_state` `handle()` calls.
|
||||
pub action_disabled: bool,
|
||||
|
||||
/// Used by `action_state` to disable `move_state` `handle()` calls.
|
||||
pub move_disabled: bool,
|
||||
}
|
||||
|
||||
impl CharacterState {
|
||||
/// __Compares `move_state`s for shallow equality (does not check internal struct equality)__
|
||||
pub fn is_same_move_state(&self, other: &Self) -> bool {
|
||||
// Check if state is the same without looking at the inner data
|
||||
std::mem::discriminant(&self.move_state) == std::mem::discriminant(&other.move_state)
|
||||
}
|
||||
|
||||
/// __Compares `action_state`s for shallow equality (does not check internal struct equality)__
|
||||
pub fn is_same_action_state(&self, other: &Self) -> bool {
|
||||
// Check if state is the same without looking at the inner data
|
||||
std::mem::discriminant(&self.action_state) == std::mem::discriminant(&other.action_state)
|
||||
}
|
||||
|
||||
/// __Compares both `move_state`s and `action_state`a for shallow equality
|
||||
/// (does not check internal struct equality)__
|
||||
pub fn is_same_state(&self, other: &Self) -> bool {
|
||||
self.is_same_move_state(other) && self.is_same_action_state(other)
|
||||
}
|
||||
@ -149,8 +167,8 @@ impl CharacterState {
|
||||
impl Default for CharacterState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
move_state: MoveState::Fall(FallHandler),
|
||||
action_state: ActionState::Idle,
|
||||
move_state: MoveState::Fall(FallState),
|
||||
action_state: ActionState::Idle(IdleState),
|
||||
action_disabled: false,
|
||||
move_disabled: false,
|
||||
}
|
||||
@ -178,3 +196,21 @@ pub struct OverrideMove;
|
||||
impl Component for OverrideMove {
|
||||
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub enum StartAction {
|
||||
Primary,
|
||||
Secondary,
|
||||
Tertiary,
|
||||
Four,
|
||||
Five,
|
||||
}
|
||||
impl Default for StartAction {
|
||||
fn default() -> Self {
|
||||
Self::Primary
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for StartAction {
|
||||
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ pub use body::{
|
||||
quadruped_medium, quadruped_small, Body,
|
||||
};
|
||||
pub use character_state::{
|
||||
ActionState, AttackKind, BlockKind, CharacterState, DodgeKind, EcsCharacterState,
|
||||
EcsStateUpdate, MoveState, OverrideAction, OverrideMove, OverrideState,
|
||||
ActionState, AttackKind, BlockKind, CharacterState, DodgeKind, EcsStateData, MoveState,
|
||||
OverrideAction, OverrideMove, OverrideState, StateUpdate,
|
||||
};
|
||||
pub use controller::{
|
||||
ControlEvent, Controller, ControllerInputs, Input, InputState, InventoryManip, MountState,
|
||||
|
@ -1,22 +1,18 @@
|
||||
use super::TEMP_EQUIP_DELAY;
|
||||
use crate::comp::{
|
||||
ActionState::{Attack, Idle, Wield},
|
||||
AttackKind::BasicAttack,
|
||||
EcsCharacterState, EcsStateUpdate,
|
||||
ItemKind::Tool,
|
||||
StateHandle, WieldHandler,
|
||||
ActionState::Attack, AttackKind::BasicAttack, EcsStateData, StateHandle, StateUpdate,
|
||||
};
|
||||
use crate::util::movement_utils::*;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct BasicAttackHandler {
|
||||
pub struct BasicAttackState {
|
||||
/// How long the state has until exitting
|
||||
remaining_duration: Duration,
|
||||
}
|
||||
|
||||
impl StateHandle for BasicAttackHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for BasicAttackState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
@ -26,21 +22,12 @@ impl StateHandle for BasicAttackHandler {
|
||||
// Check if attack duration has expired
|
||||
if self.remaining_duration == Duration::default() {
|
||||
// If so, go back to wielding or idling
|
||||
update.character.action_state = if let Some(Tool { .. }) =
|
||||
ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind)
|
||||
{
|
||||
Wield(WieldHandler {
|
||||
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
|
||||
})
|
||||
} else {
|
||||
Idle
|
||||
};
|
||||
|
||||
update.character.action_state = attempt_wield(ecs_data.stats);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Otherwise, tick down remaining_duration, and keep rolling
|
||||
update.character.action_state = Attack(BasicAttack(BasicAttackHandler {
|
||||
update.character.action_state = Attack(BasicAttack(BasicAttackState {
|
||||
remaining_duration: self
|
||||
.remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
|
@ -1,22 +1,18 @@
|
||||
use super::{BLOCK_ACCEL, BLOCK_SPEED, TEMP_EQUIP_DELAY};
|
||||
use crate::comp::{
|
||||
ActionState::{Idle, Wield},
|
||||
EcsCharacterState, EcsStateUpdate,
|
||||
ItemKind::Tool,
|
||||
StateHandle, WieldHandler,
|
||||
};
|
||||
use super::{BLOCK_ACCEL, BLOCK_SPEED};
|
||||
use crate::comp::{EcsStateData, StateHandle, StateUpdate};
|
||||
use crate::util::movement_utils::*;
|
||||
use std::time::Duration;
|
||||
use vek::Vec2;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct BasicBlockHandler {
|
||||
pub struct BasicBlockState {
|
||||
/// How long the blocking state has been active
|
||||
active_duration: Duration,
|
||||
}
|
||||
|
||||
impl StateHandle for BasicBlockHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for BasicBlockState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
@ -24,6 +20,7 @@ impl StateHandle for BasicBlockHandler {
|
||||
};
|
||||
|
||||
// TODO: Apply simple move speed debuff instead
|
||||
update.character.move_disabled = true;
|
||||
|
||||
// Update movement
|
||||
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
|
||||
@ -34,16 +31,7 @@ impl StateHandle for BasicBlockHandler {
|
||||
};
|
||||
|
||||
if !ecs_data.inputs.secondary.is_pressed() {
|
||||
update.character.action_state = if let Some(Tool { .. }) =
|
||||
ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind)
|
||||
{
|
||||
Wield(WieldHandler {
|
||||
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
|
||||
})
|
||||
} else {
|
||||
Idle
|
||||
};
|
||||
|
||||
update.character.action_state = attempt_wield(ecs_data.stats);
|
||||
update.character.move_disabled = false;
|
||||
return update;
|
||||
}
|
||||
|
@ -1,26 +1,23 @@
|
||||
use crate::comp::{
|
||||
ActionState::{Attack, Idle, Wield},
|
||||
AttackKind::Charge,
|
||||
EcsCharacterState, EcsStateUpdate, HealthChange, HealthSource,
|
||||
ItemKind::Tool,
|
||||
MoveState::Run,
|
||||
RunHandler, StateHandle, WieldHandler,
|
||||
ActionState::Attack, AttackKind::Charge, EcsStateData, HealthChange, HealthSource,
|
||||
MoveState::Run, RunState, StateHandle, StateUpdate,
|
||||
};
|
||||
use crate::event::ServerEvent;
|
||||
use crate::util::movement_utils::*;
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
use super::{CHARGE_SPEED, TEMP_EQUIP_DELAY};
|
||||
use super::CHARGE_SPEED;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct ChargeAttackHandler {
|
||||
pub struct ChargeAttackState {
|
||||
/// How long the state has until exitting
|
||||
pub remaining_duration: Duration,
|
||||
}
|
||||
|
||||
impl StateHandle for ChargeAttackHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for ChargeAttackState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
@ -30,8 +27,7 @@ impl StateHandle for ChargeAttackHandler {
|
||||
// Prevent move state handling, handled here
|
||||
// ecs_data.updater.insert(*ecs_data.entity, OverrideMove);
|
||||
update.character.action_disabled = true;
|
||||
|
||||
update.character.move_state = Run(RunHandler);
|
||||
update.character.move_state = Run(RunState);
|
||||
|
||||
// Move player
|
||||
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
|
||||
@ -57,17 +53,8 @@ impl StateHandle for ChargeAttackHandler {
|
||||
},
|
||||
});
|
||||
|
||||
// Go back to wielding
|
||||
update.character.action_state = if let Some(Tool { .. }) =
|
||||
ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind)
|
||||
{
|
||||
Wield(WieldHandler {
|
||||
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
|
||||
})
|
||||
} else {
|
||||
Idle
|
||||
};
|
||||
|
||||
// Go back to wielding or idling
|
||||
update.character.action_state = attempt_wield(ecs_data.stats);
|
||||
update.character.move_disabled = false;
|
||||
return update;
|
||||
}
|
||||
@ -75,22 +62,13 @@ impl StateHandle for ChargeAttackHandler {
|
||||
// Check if charge timed out or can't keep moving forward
|
||||
if self.remaining_duration == Duration::default() || update.vel.0.magnitude_squared() < 10.0
|
||||
{
|
||||
update.character.action_state = if let Some(Tool { .. }) =
|
||||
ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind)
|
||||
{
|
||||
Wield(WieldHandler {
|
||||
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
|
||||
})
|
||||
} else {
|
||||
Idle
|
||||
};
|
||||
|
||||
update.character.action_state = attempt_wield(ecs_data.stats);
|
||||
update.character.move_disabled = false;
|
||||
return update;
|
||||
}
|
||||
|
||||
// Tick remaining-duration and keep charging
|
||||
update.character.action_state = Attack(Charge(ChargeAttackHandler {
|
||||
update.character.action_state = Attack(Charge(ChargeAttackState {
|
||||
remaining_duration: self
|
||||
.remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
ActionState::*, EcsCharacterState, EcsStateUpdate, FallHandler, JumpHandler, MoveState::*,
|
||||
StandHandler, StateHandle,
|
||||
ActionState::*, EcsStateData, FallState, IdleState, JumpState, MoveState::*, StandState,
|
||||
StateHandle, StateUpdate,
|
||||
};
|
||||
use super::{CLIMB_SPEED, HUMANOID_CLIMB_ACCEL, HUMANOID_SPEED};
|
||||
use crate::sys::phys::GRAVITY;
|
||||
@ -8,11 +8,11 @@ use vek::vec::{Vec2, Vec3};
|
||||
use vek::Lerp;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct ClimbHandler;
|
||||
pub struct ClimbState;
|
||||
|
||||
impl StateHandle for ClimbHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for ClimbState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
@ -20,7 +20,7 @@ impl StateHandle for ClimbHandler {
|
||||
};
|
||||
|
||||
// Disable actions in this state
|
||||
update.character.action_state = Idle;
|
||||
update.character.action_state = Idle(IdleState);
|
||||
update.character.action_disabled = true;
|
||||
|
||||
// Move player
|
||||
@ -80,13 +80,13 @@ impl StateHandle for ClimbHandler {
|
||||
if let None = ecs_data.physics.on_wall {
|
||||
if ecs_data.inputs.jump.is_pressed() {
|
||||
// They've climbed atop something, give them a boost
|
||||
update.character.move_state = Jump(JumpHandler);
|
||||
update.character.move_state = Jump(JumpState);
|
||||
update.character.action_disabled = false;
|
||||
|
||||
return update;
|
||||
} else {
|
||||
// Just fall off
|
||||
update.character.move_state = Fall(FallHandler);
|
||||
update.character.move_state = Fall(FallState);
|
||||
update.character.action_disabled = false;
|
||||
|
||||
return update;
|
||||
@ -95,7 +95,7 @@ impl StateHandle for ClimbHandler {
|
||||
|
||||
// Remove climb state on ground, otherwise character will get stuck
|
||||
if ecs_data.physics.on_ground {
|
||||
update.character.move_state = Stand(StandHandler);
|
||||
update.character.move_state = Stand(StandState);
|
||||
update.character.action_disabled = false;
|
||||
return update;
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
use super::{
|
||||
EcsCharacterState, EcsStateUpdate, GlideHandler, MoveState::*, RunHandler, StandHandler,
|
||||
StateHandle, SwimHandler,
|
||||
};
|
||||
use super::{HUMANOID_AIR_ACCEL, HUMANOID_AIR_SPEED};
|
||||
use crate::comp::{ClimbState, EcsStateData, GlideState, MoveState::*, StateHandle, StateUpdate};
|
||||
|
||||
use crate::util::movement_utils::*;
|
||||
use vek::{Vec2, Vec3};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct FallHandler;
|
||||
pub struct FallState;
|
||||
|
||||
impl StateHandle for FallHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for FallState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
@ -43,36 +42,22 @@ impl StateHandle for FallHandler {
|
||||
vek::ops::Slerp::slerp(update.ori.0, ori_dir.into(), 2.0 * ecs_data.dt.0);
|
||||
}
|
||||
|
||||
// Check to start climbing
|
||||
if can_climb(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
|
||||
update.character.move_state = Climb(ClimbState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Check gliding
|
||||
if ecs_data.inputs.glide.is_pressed() {
|
||||
update.character.move_state = Glide(GlideHandler);
|
||||
|
||||
update.character.move_state = Glide(GlideState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Not on ground, go to swim or fall
|
||||
if !ecs_data.physics.on_ground {
|
||||
// Check if in fluid to go to swimming or back to falling
|
||||
if ecs_data.physics.in_fluid {
|
||||
update.character.move_state = Swim(SwimHandler);
|
||||
// Else update based on groundedness
|
||||
update.character.move_state =
|
||||
determine_move_from_grounded_state(ecs_data.physics, ecs_data.inputs);
|
||||
|
||||
return update;
|
||||
} else {
|
||||
update.character.move_state = Fall(FallHandler);
|
||||
|
||||
return update;
|
||||
}
|
||||
}
|
||||
// On ground
|
||||
else {
|
||||
// Return to running or standing based on move inputs
|
||||
update.character.move_state = if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
|
||||
Run(RunHandler)
|
||||
} else {
|
||||
Stand(StandHandler)
|
||||
};
|
||||
|
||||
return update;
|
||||
}
|
||||
return update;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
use super::{
|
||||
ActionState::*, ClimbHandler, EcsCharacterState, EcsStateUpdate, FallHandler, MoveState::*,
|
||||
StandHandler, StateHandle,
|
||||
};
|
||||
use super::{GLIDE_ACCEL, GLIDE_ANTIGRAV, GLIDE_SPEED};
|
||||
use crate::comp::{
|
||||
ActionState::*, ClimbState, EcsStateData, FallState, IdleState, MoveState::*, StandState,
|
||||
StateHandle, StateUpdate,
|
||||
};
|
||||
use vek::{Vec2, Vec3};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct GlideHandler;
|
||||
pub struct GlideState;
|
||||
|
||||
impl StateHandle for GlideHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for GlideState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
@ -20,8 +20,9 @@ impl StateHandle for GlideHandler {
|
||||
// Prevent action in this state, set here
|
||||
update.character.action_disabled = true;
|
||||
|
||||
update.character.action_state = Idle;
|
||||
update.character.move_state = Glide(GlideHandler);
|
||||
// Defaults for this state
|
||||
update.character.action_state = Idle(IdleState);
|
||||
update.character.move_state = Glide(GlideState);
|
||||
|
||||
// Move player according to movement direction vector
|
||||
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
|
||||
@ -54,22 +55,21 @@ impl StateHandle for GlideHandler {
|
||||
.max(0.2);
|
||||
}
|
||||
|
||||
// If glide button isn't held
|
||||
// If glide button isn't held, start falling
|
||||
if !ecs_data.inputs.glide.is_pressed() {
|
||||
update.character.move_state = Fall(FallHandler);
|
||||
|
||||
update.character.move_state = Fall(FallState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// If there is a wall in front of character go to climb
|
||||
else if let Some(_wall_dir) = ecs_data.physics.on_wall {
|
||||
update.character.move_state = Climb(ClimbHandler);
|
||||
|
||||
if let Some(_wall_dir) = ecs_data.physics.on_wall {
|
||||
update.character.move_state = Climb(ClimbState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// If on ground go to stand
|
||||
if ecs_data.physics.on_ground {
|
||||
update.character.move_state = Stand(StandHandler);
|
||||
|
||||
update.character.move_state = Stand(StandState);
|
||||
return update;
|
||||
}
|
||||
|
||||
|
35
common/src/comp/states/idle.rs
Normal file
35
common/src/comp/states/idle.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use super::TEMP_EQUIP_DELAY;
|
||||
use crate::comp::{
|
||||
ActionState::Wield, EcsStateData, ItemKind::Tool, StateHandle, StateUpdate, WieldState,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct IdleState;
|
||||
|
||||
impl StateHandle for IdleState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
};
|
||||
|
||||
// Try to wield
|
||||
if ecs_data.inputs.toggle_wield.is_pressed()
|
||||
|| ecs_data.inputs.primary.is_pressed()
|
||||
|| ecs_data.inputs.secondary.is_pressed()
|
||||
{
|
||||
if let Some(Tool { .. }) = ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind) {
|
||||
update.character.action_state = Wield(WieldState {
|
||||
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
|
||||
})
|
||||
}
|
||||
|
||||
// else unarmed stuff?
|
||||
}
|
||||
|
||||
return update;
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
use super::{EcsCharacterState, EcsStateUpdate, FallHandler, MoveState::*, StateHandle};
|
||||
use super::{EcsStateData, FallState, MoveState::*, StateHandle, StateUpdate};
|
||||
use crate::event::LocalEvent;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct JumpHandler;
|
||||
pub struct JumpState;
|
||||
|
||||
impl StateHandle for JumpHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for JumpState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
@ -18,8 +18,8 @@ impl StateHandle for JumpHandler {
|
||||
.emitter()
|
||||
.emit(LocalEvent::Jump(*ecs_data.entity));
|
||||
|
||||
update.character.move_state = Fall(FallHandler);
|
||||
|
||||
// Immediately go to falling state after jump impulse
|
||||
update.character.move_state = Fall(FallState);
|
||||
return update;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ mod charge_attack;
|
||||
mod climb;
|
||||
mod fall;
|
||||
mod glide;
|
||||
mod idle;
|
||||
mod jump;
|
||||
mod roll;
|
||||
mod run;
|
||||
@ -20,6 +21,7 @@ pub use charge_attack::*;
|
||||
pub use climb::*;
|
||||
pub use fall::*;
|
||||
pub use glide::*;
|
||||
pub use idle::*;
|
||||
pub use jump::*;
|
||||
pub use roll::*;
|
||||
pub use run::*;
|
||||
@ -50,35 +52,30 @@ pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
|
||||
|
||||
// Public interface, wires character states to their handlers.
|
||||
use super::{
|
||||
ActionState, ActionState::*, AttackKind::*, BlockKind::*, DodgeKind::*, EcsCharacterState,
|
||||
EcsStateUpdate, MoveState, MoveState::*,
|
||||
ActionState, ActionState::*, AttackKind::*, BlockKind::*, DodgeKind::*, EcsStateData,
|
||||
MoveState, MoveState::*, StateUpdate,
|
||||
};
|
||||
|
||||
pub trait StateHandle {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate;
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate;
|
||||
}
|
||||
|
||||
impl StateHandle for ActionState {
|
||||
/// Passes handle to variant or subvariant handlers
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
match self {
|
||||
Attack(kind) => match kind {
|
||||
BasicAttack(handler) => handler.handle(ecs_data),
|
||||
Charge(handler) => handler.handle(ecs_data),
|
||||
BasicAttack(state) => state.handle(ecs_data),
|
||||
Charge(state) => state.handle(ecs_data),
|
||||
},
|
||||
Block(kind) => match kind {
|
||||
BasicBlock(handler) => handler.handle(ecs_data),
|
||||
BasicBlock(state) => state.handle(ecs_data),
|
||||
},
|
||||
Dodge(kind) => match kind {
|
||||
Roll(handler) => handler.handle(ecs_data),
|
||||
},
|
||||
Wield(handler) => handler.handle(ecs_data),
|
||||
Idle => EcsStateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
ori: *ecs_data.ori,
|
||||
Roll(state) => state.handle(ecs_data),
|
||||
},
|
||||
Wield(state) => state.handle(ecs_data),
|
||||
Idle(state) => state.handle(ecs_data),
|
||||
// All states should be explicitly handled
|
||||
// Do not use default match: _ => {},
|
||||
}
|
||||
@ -87,16 +84,16 @@ impl StateHandle for ActionState {
|
||||
|
||||
impl StateHandle for MoveState {
|
||||
/// Passes handle to variant handlers
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
match self {
|
||||
Stand(handler) => handler.handle(&ecs_data),
|
||||
Run(handler) => handler.handle(&ecs_data),
|
||||
Jump(handler) => handler.handle(&ecs_data),
|
||||
Climb(handler) => handler.handle(&ecs_data),
|
||||
Glide(handler) => handler.handle(&ecs_data),
|
||||
Swim(handler) => handler.handle(&ecs_data),
|
||||
Fall(handler) => handler.handle(&ecs_data),
|
||||
Sit(handler) => handler.handle(&ecs_data),
|
||||
Stand(state) => state.handle(&ecs_data),
|
||||
Run(state) => state.handle(&ecs_data),
|
||||
Jump(state) => state.handle(&ecs_data),
|
||||
Climb(state) => state.handle(&ecs_data),
|
||||
Glide(state) => state.handle(&ecs_data),
|
||||
Swim(state) => state.handle(&ecs_data),
|
||||
Fall(state) => state.handle(&ecs_data),
|
||||
Sit(state) => state.handle(&ecs_data),
|
||||
// All states should be explicitly handled
|
||||
// Do not use default match: _ => {},
|
||||
}
|
||||
|
@ -1,19 +1,18 @@
|
||||
use super::{ROLL_SPEED, TEMP_EQUIP_DELAY};
|
||||
use crate::comp::{
|
||||
ActionState::*, DodgeKind::*, EcsCharacterState, EcsStateUpdate, ItemKind::Tool, OverrideMove,
|
||||
StateHandle, WieldHandler,
|
||||
};
|
||||
use super::ROLL_SPEED;
|
||||
use crate::comp::{ActionState::*, DodgeKind::*, EcsStateData, StateHandle, StateUpdate};
|
||||
use crate::util::movement_utils::*;
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct RollHandler {
|
||||
pub struct RollState {
|
||||
/// How long the state has until exitting
|
||||
remaining_duration: Duration,
|
||||
}
|
||||
|
||||
impl StateHandle for RollHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for RollState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
@ -21,7 +20,7 @@ impl StateHandle for RollHandler {
|
||||
};
|
||||
|
||||
// Prevent move state handling, handled here
|
||||
ecs_data.updater.insert(*ecs_data.entity, OverrideMove);
|
||||
update.character.move_disabled = true;
|
||||
|
||||
// Update velocity
|
||||
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
|
||||
@ -39,28 +38,20 @@ impl StateHandle for RollHandler {
|
||||
// Check if roll duration has expired
|
||||
if self.remaining_duration == Duration::default() {
|
||||
// If so, go back to wielding or idling
|
||||
update.character.action_state = if let Some(Tool { .. }) =
|
||||
ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind)
|
||||
{
|
||||
Wield(WieldHandler {
|
||||
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
|
||||
})
|
||||
} else {
|
||||
Idle
|
||||
};
|
||||
|
||||
ecs_data.updater.remove::<OverrideMove>(*ecs_data.entity);
|
||||
update.character.action_state = attempt_wield(ecs_data.stats);
|
||||
update.character.move_disabled = false;
|
||||
return update;
|
||||
}
|
||||
|
||||
// Otherwise, tick down remaining_duration, and keep rolling
|
||||
update.character.action_state = Dodge(Roll(RollHandler {
|
||||
// Otherwise, tick down remaining_duration
|
||||
update.character.action_state = Dodge(Roll(RollState {
|
||||
remaining_duration: self
|
||||
.remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
}));
|
||||
|
||||
// Keep rolling
|
||||
return update;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,17 @@
|
||||
use super::{
|
||||
ClimbHandler, EcsCharacterState, EcsStateUpdate, FallHandler, GlideHandler, JumpHandler,
|
||||
MoveState::*, SitHandler, StandHandler, StateHandle, SwimHandler,
|
||||
};
|
||||
use super::{HUMANOID_ACCEL, HUMANOID_SPEED};
|
||||
use crate::comp::{
|
||||
ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandle,
|
||||
StateUpdate,
|
||||
};
|
||||
use crate::util::movement_utils::*;
|
||||
use vek::vec::{Vec2, Vec3};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct RunHandler;
|
||||
pub struct RunState;
|
||||
|
||||
impl StateHandle for RunHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for RunState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
@ -44,67 +45,33 @@ impl StateHandle for RunHandler {
|
||||
}
|
||||
|
||||
// Try to sit
|
||||
if ecs_data.inputs.sit.is_pressed()
|
||||
&& ecs_data.physics.on_ground
|
||||
&& ecs_data.body.is_humanoid()
|
||||
{
|
||||
update.character.move_state = Sit(SitHandler);
|
||||
|
||||
if can_sit(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
|
||||
update.character.move_state = Sit(SitState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Try to climb
|
||||
if let (true, Some(_wall_dir)) = (
|
||||
ecs_data.inputs.climb.is_pressed() | ecs_data.inputs.climb_down.is_pressed()
|
||||
&& ecs_data.body.is_humanoid(),
|
||||
ecs_data.physics.on_wall,
|
||||
) {
|
||||
update.character.move_state = Climb(ClimbHandler);
|
||||
|
||||
if can_climb(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
|
||||
update.character.move_state = Climb(ClimbState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Try to swim
|
||||
if !ecs_data.physics.on_ground && ecs_data.physics.in_fluid {
|
||||
update.character.move_state = Swim(SwimHandler);
|
||||
|
||||
// Try to jump
|
||||
if can_jump(ecs_data.physics, ecs_data.inputs) {
|
||||
update.character.move_state = Jump(JumpState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// While on ground ...
|
||||
if ecs_data.physics.on_ground {
|
||||
// Try to jump
|
||||
if ecs_data.inputs.jump.is_pressed() && !ecs_data.inputs.jump.is_held_down() {
|
||||
update.character.move_state = Jump(JumpHandler);
|
||||
|
||||
return update;
|
||||
}
|
||||
}
|
||||
// While not on ground ...
|
||||
else {
|
||||
// Try to glide
|
||||
if ecs_data.physics.on_wall == None
|
||||
&& ecs_data.inputs.glide.is_pressed()
|
||||
&& !ecs_data.inputs.glide.is_held_down()
|
||||
&& ecs_data.body.is_humanoid()
|
||||
{
|
||||
update.character.move_state = Glide(GlideHandler);
|
||||
|
||||
return update;
|
||||
}
|
||||
update.character.move_state = Fall(FallHandler);
|
||||
|
||||
// Try to glide
|
||||
if can_glide(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
|
||||
update.character.move_state = Glide(GlideState);
|
||||
return update;
|
||||
}
|
||||
|
||||
if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
|
||||
update.character.move_state = Run(RunHandler);
|
||||
// Update based on groundedness
|
||||
update.character.move_state =
|
||||
determine_move_from_grounded_state(ecs_data.physics, ecs_data.inputs);
|
||||
|
||||
return update;
|
||||
} else {
|
||||
update.character.move_state = Stand(StandHandler);
|
||||
|
||||
return update;
|
||||
}
|
||||
return update;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
use crate::comp::{
|
||||
ActionState::*, EcsCharacterState, EcsStateUpdate, FallHandler, JumpHandler, MoveState::*,
|
||||
RunHandler, StandHandler, StateHandle, SwimHandler,
|
||||
ActionState::*, EcsStateData, IdleState, JumpState, MoveState::*, RunState, StandState,
|
||||
StateHandle, StateUpdate,
|
||||
};
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct SitHandler;
|
||||
use crate::util::movement_utils::*;
|
||||
|
||||
impl StateHandle for SitHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct SitState;
|
||||
|
||||
impl StateHandle for SitState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
@ -16,46 +18,35 @@ impl StateHandle for SitHandler {
|
||||
|
||||
// Prevent action state handling
|
||||
update.character.action_disabled = true;
|
||||
update.character.action_state = Idle;
|
||||
update.character.move_state = Sit(SitHandler);
|
||||
update.character.action_state = Idle(IdleState);
|
||||
update.character.move_state = Sit(SitState);
|
||||
|
||||
// Falling
|
||||
// Idk, maybe the ground disappears,
|
||||
// Try to Fall
|
||||
// ... maybe the ground disappears,
|
||||
// suddenly maybe a water spell appears.
|
||||
// Can't hurt to be safe :shrug:
|
||||
if !ecs_data.physics.on_ground {
|
||||
if ecs_data.physics.in_fluid {
|
||||
update.character.move_state = Swim(SwimHandler);
|
||||
|
||||
update.character.action_disabled = false;
|
||||
return update;
|
||||
} else {
|
||||
update.character.move_state = Fall(FallHandler);
|
||||
|
||||
update.character.action_disabled = false;
|
||||
return update;
|
||||
}
|
||||
update.character.move_state = determine_fall_or_swim(ecs_data.physics);
|
||||
update.character.move_disabled = false;
|
||||
return update;
|
||||
}
|
||||
// Jumping
|
||||
// Try to jump
|
||||
if ecs_data.inputs.jump.is_pressed() {
|
||||
update.character.move_state = Jump(JumpHandler);
|
||||
|
||||
update.character.move_state = Jump(JumpState);
|
||||
update.character.action_disabled = false;
|
||||
return update;
|
||||
}
|
||||
|
||||
// Moving
|
||||
// Try to Run
|
||||
if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
|
||||
update.character.move_state = Run(RunHandler);
|
||||
|
||||
update.character.move_state = Run(RunState);
|
||||
update.character.action_disabled = false;
|
||||
return update;
|
||||
}
|
||||
|
||||
// Standing back up (unsitting)
|
||||
// Try to Stand
|
||||
if ecs_data.inputs.sit.is_just_pressed() {
|
||||
update.character.move_state = Stand(StandHandler);
|
||||
|
||||
update.character.move_state = Stand(StandState);
|
||||
update.character.action_disabled = false;
|
||||
return update;
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
use super::{
|
||||
ClimbHandler, EcsCharacterState, EcsStateUpdate, FallHandler, GlideHandler, JumpHandler,
|
||||
MoveState::*, RunHandler, SitHandler, StateHandle, SwimHandler,
|
||||
use crate::comp::{
|
||||
ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandle,
|
||||
StateUpdate,
|
||||
};
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct StandHandler;
|
||||
use crate::util::movement_utils::*;
|
||||
|
||||
impl StateHandle for StandHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct StandState;
|
||||
|
||||
impl StateHandle for StandState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
@ -15,66 +17,33 @@ impl StateHandle for StandHandler {
|
||||
};
|
||||
|
||||
// Try to sit
|
||||
if ecs_data.inputs.sit.is_pressed()
|
||||
&& ecs_data.physics.on_ground
|
||||
&& ecs_data.body.is_humanoid()
|
||||
{
|
||||
update.character.move_state = Sit(SitHandler);
|
||||
|
||||
if can_sit(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
|
||||
update.character.move_state = Sit(SitState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Try to climb
|
||||
if let (true, Some(_wall_dir)) = (
|
||||
ecs_data.inputs.climb.is_pressed() | ecs_data.inputs.climb_down.is_pressed()
|
||||
&& ecs_data.body.is_humanoid(),
|
||||
ecs_data.physics.on_wall,
|
||||
) {
|
||||
update.character.move_state = Climb(ClimbHandler);
|
||||
|
||||
if can_climb(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
|
||||
update.character.move_state = Climb(ClimbState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// Try to swim
|
||||
if !ecs_data.physics.on_ground && ecs_data.physics.in_fluid {
|
||||
update.character.move_state = Swim(SwimHandler);
|
||||
|
||||
// Try to jump
|
||||
if can_jump(ecs_data.physics, ecs_data.inputs) {
|
||||
update.character.move_state = Jump(JumpState);
|
||||
return update;
|
||||
}
|
||||
|
||||
// While on ground ...
|
||||
if ecs_data.physics.on_ground {
|
||||
// Try to jump
|
||||
if ecs_data.inputs.jump.is_pressed() {
|
||||
update.character.move_state = Jump(JumpHandler);
|
||||
|
||||
return update;
|
||||
}
|
||||
}
|
||||
// While not on ground ...
|
||||
else {
|
||||
// Try to glide
|
||||
if ecs_data.physics.on_wall == None
|
||||
&& ecs_data.inputs.glide.is_pressed()
|
||||
&& ecs_data.body.is_humanoid()
|
||||
{
|
||||
update.character.move_state = Glide(GlideHandler);
|
||||
|
||||
return update;
|
||||
}
|
||||
update.character.move_state = Fall(FallHandler);
|
||||
|
||||
// Check gliding
|
||||
if can_glide(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
|
||||
update.character.move_state = Glide(GlideState);
|
||||
return update;
|
||||
}
|
||||
|
||||
if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
|
||||
update.character.move_state = Run(RunHandler);
|
||||
// Else update based on groundedness
|
||||
update.character.move_state =
|
||||
determine_move_from_grounded_state(ecs_data.physics, ecs_data.inputs);
|
||||
|
||||
return update;
|
||||
} else {
|
||||
update.character.move_state = Stand(StandHandler);
|
||||
|
||||
return update;
|
||||
}
|
||||
return update;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,14 @@
|
||||
use super::{
|
||||
EcsCharacterState, EcsStateUpdate, MoveState::*, RunHandler, StandHandler, StateHandle,
|
||||
};
|
||||
use super::{HUMANOID_WATER_ACCEL, HUMANOID_WATER_SPEED};
|
||||
use crate::comp::{EcsStateData, MoveState::*, RunState, StandState, StateHandle, StateUpdate};
|
||||
use crate::sys::phys::GRAVITY;
|
||||
use vek::{Vec2, Vec3};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct SwimHandler;
|
||||
pub struct SwimState;
|
||||
|
||||
impl StateHandle for SwimHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for SwimState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
@ -46,24 +44,23 @@ impl StateHandle for SwimHandler {
|
||||
);
|
||||
}
|
||||
|
||||
if ecs_data.inputs.jump.is_pressed() {
|
||||
if ecs_data.inputs.jump.is_pressed() && !ecs_data.inputs.jump.is_held_down() {
|
||||
update.vel.0.z =
|
||||
(update.vel.0.z + ecs_data.dt.0 * GRAVITY * 1.25).min(HUMANOID_WATER_SPEED);
|
||||
}
|
||||
|
||||
// Not on ground
|
||||
if !ecs_data.physics.on_ground {
|
||||
update.character.move_state = Swim(SwimHandler);
|
||||
|
||||
update.character.move_state = Swim(SwimState);
|
||||
return update;
|
||||
}
|
||||
// On ground
|
||||
else {
|
||||
// Return to running or standing based on move inputs
|
||||
update.character.move_state = if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
|
||||
Run(RunHandler)
|
||||
Run(RunState)
|
||||
} else {
|
||||
Stand(StandHandler)
|
||||
Stand(StandState)
|
||||
};
|
||||
|
||||
return update;
|
||||
|
@ -1,16 +1,16 @@
|
||||
use super::{ActionState::*, EcsCharacterState, EcsStateUpdate, StateHandle};
|
||||
use crate::comp::{ActionState::*, EcsStateData, IdleState, StateHandle, StateUpdate};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct WieldHandler {
|
||||
pub struct WieldState {
|
||||
/// How long before a new action can be performed
|
||||
/// after equipping
|
||||
pub equip_delay: Duration,
|
||||
}
|
||||
|
||||
impl StateHandle for WieldHandler {
|
||||
fn handle(&self, ecs_data: &EcsCharacterState) -> EcsStateUpdate {
|
||||
let mut update = EcsStateUpdate {
|
||||
impl StateHandle for WieldState {
|
||||
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *ecs_data.character,
|
||||
pos: *ecs_data.pos,
|
||||
vel: *ecs_data.vel,
|
||||
@ -23,8 +23,7 @@ impl StateHandle for WieldHandler {
|
||||
if ecs_data.inputs.toggle_wield.is_pressed()
|
||||
&& ecs_data.character.action_state.is_equip_finished()
|
||||
{
|
||||
update.character.action_state = Idle;
|
||||
|
||||
update.character.action_state = Idle(IdleState);
|
||||
return update;
|
||||
}
|
||||
|
||||
@ -34,11 +33,10 @@ impl StateHandle for WieldHandler {
|
||||
} else if ecs_data.inputs.secondary.is_pressed() {
|
||||
// TODO: SecondaryStart
|
||||
}
|
||||
}
|
||||
// Equip delay hasn't expired yet
|
||||
else {
|
||||
} else {
|
||||
// Equip delay hasn't expired yet
|
||||
// Update wield delay
|
||||
update.character.action_state = Wield(WieldHandler {
|
||||
update.character.action_state = Wield(WieldState {
|
||||
equip_delay: self
|
||||
.equip_delay
|
||||
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::comp::{
|
||||
Agent, CharacterState, Controller, ControllerInputs, GlideHandler, MountState,
|
||||
MoveState::Glide, Pos, Stats,
|
||||
Agent, CharacterState, Controller, ControllerInputs, GlideState, MountState, MoveState::Glide,
|
||||
Pos, Stats,
|
||||
};
|
||||
use crate::pathfinding::WorldPath;
|
||||
use crate::terrain::TerrainGrid;
|
||||
@ -163,7 +163,7 @@ impl<'a> System<'a> for Sys {
|
||||
inputs.roll.set_state(true);
|
||||
}
|
||||
|
||||
if target_character.move_state == Glide(GlideHandler)
|
||||
if target_character.move_state == Glide(GlideState)
|
||||
&& target_pos.0.z > pos.0.z + 5.0
|
||||
{
|
||||
inputs.glide.set_state(true);
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
Body, CharacterState, Controller, EcsCharacterState, Mounting, MoveState::*, Ori,
|
||||
OverrideAction, OverrideMove, OverrideState, PhysicsState, Pos, SitHandler, StateHandle,
|
||||
Body, CharacterState, Controller, EcsStateData, Mounting, MoveState::*, Ori,
|
||||
OverrideAction, OverrideMove, OverrideState, PhysicsState, Pos, SitState, StateHandle,
|
||||
Stats, Vel,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
@ -110,13 +110,13 @@ impl<'a> System<'a> for Sys {
|
||||
// If mounted, character state is controlled by mount
|
||||
// TODO: Make mounting a state
|
||||
if maybe_mount.is_some() {
|
||||
character.move_state = Sit(SitHandler);
|
||||
character.move_state = Sit(SitState);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine new move state if can move
|
||||
if !maybe_move_override.is_some() && !character.move_disabled {
|
||||
let state_update = character.move_state.handle(&EcsCharacterState {
|
||||
let state_update = character.move_state.handle(&EcsStateData {
|
||||
entity: &entity,
|
||||
uid,
|
||||
character,
|
||||
@ -141,7 +141,7 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// Determine new action if can_act
|
||||
if !maybe_action_override.is_some() && !character.action_disabled {
|
||||
let state_update = character.action_state.handle(&EcsCharacterState {
|
||||
let state_update = character.action_state.handle(&EcsStateData {
|
||||
entity: &entity,
|
||||
uid,
|
||||
character,
|
||||
|
@ -1,8 +1,8 @@
|
||||
use super::phys::GRAVITY;
|
||||
use crate::{
|
||||
comp::{
|
||||
CharacterState, Controller, Mounting, MoveState::*, Ori, PhysicsState, Pos, RunHandler,
|
||||
StandHandler, Stats, Vel,
|
||||
CharacterState, Controller, Mounting, MoveState::*, Ori, PhysicsState, Pos, RunState,
|
||||
StandState, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
state::DeltaTime,
|
||||
@ -106,7 +106,7 @@ impl<'a> System<'a> for Sys {
|
||||
)
|
||||
.join()
|
||||
{
|
||||
// if character.movement == Run(RunHandler) || character.movement == Stand(StandHandler) {
|
||||
// if character.movement == Run(RunState) || character.movement == Stand(StandState) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
|
@ -7,6 +7,9 @@ lazy_static::lazy_static! {
|
||||
|
||||
use vek::{Mat3, Rgb, Rgba, Vec3};
|
||||
|
||||
pub mod movement_utils;
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
/// This is a fast approximation of powf. This should only be used when minor accuracy loss is acceptable.
|
||||
#[inline(always)]
|
||||
#[allow(unsafe_code)]
|
||||
@ -40,6 +43,7 @@ mod approx_powf_tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
#[inline(always)]
|
||||
pub fn srgb_to_linear(col: Rgb<f32>) -> Rgb<f32> {
|
||||
#[inline(always)]
|
||||
@ -52,6 +56,8 @@ pub fn srgb_to_linear(col: Rgb<f32>) -> Rgb<f32> {
|
||||
}
|
||||
col.map(to_linear)
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
#[inline(always)]
|
||||
pub fn linear_to_srgb(col: Rgb<f32>) -> Rgb<f32> {
|
||||
#[inline(always)]
|
||||
@ -64,15 +70,20 @@ pub fn linear_to_srgb(col: Rgb<f32>) -> Rgb<f32> {
|
||||
}
|
||||
col.map(to_srgb)
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
#[inline(always)]
|
||||
pub fn srgba_to_linear(col: Rgba<f32>) -> Rgba<f32> {
|
||||
Rgba::from_translucent(srgb_to_linear(Rgb::from(col)), col.a)
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
#[inline(always)]
|
||||
pub fn linear_to_srgba(col: Rgba<f32>) -> Rgba<f32> {
|
||||
Rgba::from_translucent(linear_to_srgb(Rgb::from(col)), col.a)
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
/// Convert rgb to hsv. Expects rgb to be [0, 1].
|
||||
#[inline(always)]
|
||||
pub fn rgb_to_hsv(rgb: Rgb<f32>) -> Vec3<f32> {
|
||||
@ -104,6 +115,8 @@ pub fn rgb_to_hsv(rgb: Rgb<f32>) -> Vec3<f32> {
|
||||
|
||||
Vec3::new(h, s, v)
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
/// Convert hsv to rgb. Expects h [0, 360], s [0, 1], v [0, 1]
|
||||
#[inline(always)]
|
||||
pub fn hsv_to_rgb(hsv: Vec3<f32>) -> Rgb<f32> {
|
||||
@ -129,6 +142,8 @@ pub fn hsv_to_rgb(hsv: Vec3<f32>) -> Rgb<f32> {
|
||||
|
||||
Rgb::new(r + m, g + m, b + m)
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
/// Convert linear rgb to CIExyY
|
||||
#[inline(always)]
|
||||
pub fn rgb_to_xyy(rgb: Rgb<f32>) -> Vec3<f32> {
|
||||
@ -140,6 +155,8 @@ pub fn rgb_to_xyy(rgb: Rgb<f32>) -> Vec3<f32> {
|
||||
let sum = xyz.sum();
|
||||
Vec3::new(xyz.x / sum, xyz.y / sum, xyz.y)
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
/// Convert to CIExyY to linear rgb
|
||||
#[inline(always)]
|
||||
pub fn xyy_to_rgb(xyy: Vec3<f32>) -> Rgb<f32> {
|
||||
@ -156,6 +173,7 @@ pub fn xyy_to_rgb(xyy: Vec3<f32>) -> Rgb<f32> {
|
||||
)
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
// TO-DO: speed this up
|
||||
#[inline(always)]
|
||||
pub fn saturate_srgb(col: Rgb<f32>, value: f32) -> Rgb<f32> {
|
||||
@ -164,6 +182,7 @@ pub fn saturate_srgb(col: Rgb<f32>, value: f32) -> Rgb<f32> {
|
||||
linear_to_srgb(hsv_to_rgb(hsv).map(|e| e.min(1.0).max(0.0)))
|
||||
}
|
||||
|
||||
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
|
||||
/// Preserves the luma of one color while changing its chromaticty to match the other
|
||||
#[inline(always)]
|
||||
pub fn chromify_srgb(luma: Rgb<f32>, chroma: Rgb<f32>) -> Rgb<f32> {
|
||||
|
89
common/src/util/movement_utils.rs
Normal file
89
common/src/util/movement_utils.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use crate::comp::TEMP_EQUIP_DELAY;
|
||||
use crate::comp::{
|
||||
ActionState, ActionState::*, Body, ControllerInputs, FallState, IdleState, ItemKind::Tool,
|
||||
MoveState, MoveState::*, PhysicsState, RunState, StandState, Stats, SwimState, WieldState,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
/// __Returns a `MoveState` based on `in_fluid` condition__
|
||||
pub fn determine_fall_or_swim(physics: &PhysicsState) -> MoveState {
|
||||
// Check if in fluid to go to swimming or back to falling
|
||||
if physics.in_fluid {
|
||||
Swim(SwimState)
|
||||
} else {
|
||||
Fall(FallState)
|
||||
}
|
||||
}
|
||||
/// __Returns a `MoveState` based on `move_dir` magnitude__
|
||||
pub fn determine_stand_or_run(inputs: &ControllerInputs) -> MoveState {
|
||||
// Return to running or standing based on move inputs
|
||||
if inputs.move_dir.magnitude_squared() > 0.0 {
|
||||
Run(RunState)
|
||||
} else {
|
||||
Stand(StandState)
|
||||
}
|
||||
}
|
||||
|
||||
/// __Returns a `MoveState` based on `on_ground` state.__
|
||||
///
|
||||
/// _`FallState`, or `SwimState` if not `on_ground`,
|
||||
/// `StandState` or `RunState` if is `on_ground`_
|
||||
pub fn determine_move_from_grounded_state(
|
||||
physics: &PhysicsState,
|
||||
inputs: &ControllerInputs,
|
||||
) -> MoveState {
|
||||
// Not on ground, go to swim or fall
|
||||
if !physics.on_ground {
|
||||
determine_fall_or_swim(physics)
|
||||
}
|
||||
// On ground
|
||||
else {
|
||||
determine_stand_or_run(inputs)
|
||||
}
|
||||
}
|
||||
|
||||
/// __Returns an ActionState based on whether character has a weapon equipped.__
|
||||
pub fn attempt_wield(stats: &Stats) -> ActionState {
|
||||
if let Some(Tool { .. }) = stats.equipment.main.as_ref().map(|i| &i.kind) {
|
||||
Wield(WieldState {
|
||||
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
|
||||
})
|
||||
} else {
|
||||
Idle(IdleState)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_climb(physics: &PhysicsState, inputs: &ControllerInputs, body: &Body) -> bool {
|
||||
if let (true, Some(_wall_dir)) = (
|
||||
inputs.climb.is_pressed() | inputs.climb_down.is_pressed() && body.is_humanoid(),
|
||||
physics.on_wall,
|
||||
) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_glide(physics: &PhysicsState, inputs: &ControllerInputs, body: &Body) -> bool {
|
||||
if inputs.glide.is_pressed() && body.is_humanoid() && physics.on_wall == None {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_sit(physics: &PhysicsState, inputs: &ControllerInputs, body: &Body) -> bool {
|
||||
if inputs.sit.is_pressed() && physics.on_ground && body.is_humanoid() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_jump(physics: &PhysicsState, inputs: &ControllerInputs) -> bool {
|
||||
if physics.on_ground && inputs.jump.is_pressed() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
@ -5,9 +5,9 @@ use crate::audio::sfx::{SfxTriggerItem, SfxTriggers};
|
||||
use client::Client;
|
||||
use common::{
|
||||
comp::{
|
||||
ActionState, AttackKind::*, BasicAttackHandler, Body, CharacterState, DodgeKind::*,
|
||||
FallHandler, GlideHandler, ItemKind, MoveState, Pos, RollHandler, RunHandler, StandHandler,
|
||||
Stats,
|
||||
ActionState, AttackKind::*, BasicAttackState, Body, CharacterState, DodgeKind::*,
|
||||
FallState, GlideState, IdleState, ItemKind, MoveState, Pos, RollState, RunState,
|
||||
StandState, Stats,
|
||||
},
|
||||
event::{EventBus, SfxEvent, SfxEventItem},
|
||||
};
|
||||
@ -277,8 +277,10 @@ mod tests {
|
||||
|
||||
let result = SfxEventMapper::map_character_event(
|
||||
&CharacterState {
|
||||
move_state: MoveState::Stand(StandHandler),
|
||||
action_state: ActionState::Idle,
|
||||
move_state: MoveState::Stand(StandState),
|
||||
action_state: ActionState::Idle(IdleState),
|
||||
action_disabled: false,
|
||||
move_disabled: false,
|
||||
},
|
||||
SfxEvent::Idle,
|
||||
&stats,
|
||||
@ -293,8 +295,10 @@ mod tests {
|
||||
|
||||
let result = SfxEventMapper::map_character_event(
|
||||
&CharacterState {
|
||||
move_state: MoveState::Run(RunHandler),
|
||||
action_state: ActionState::Idle,
|
||||
move_state: MoveState::Run(RunState),
|
||||
action_state: ActionState::Idle(IdleState),
|
||||
action_disabled: false,
|
||||
move_disabled: false,
|
||||
},
|
||||
SfxEvent::Idle,
|
||||
&stats,
|
||||
@ -309,8 +313,10 @@ mod tests {
|
||||
|
||||
let result = SfxEventMapper::map_character_event(
|
||||
&CharacterState {
|
||||
action_state: ActionState::Dodge(Roll(RollHandler::default())),
|
||||
move_state: MoveState::Run(RunHandler),
|
||||
action_state: ActionState::Dodge(Roll(RollState::default())),
|
||||
move_state: MoveState::Run(RunState),
|
||||
action_disabled: false,
|
||||
move_disabled: true,
|
||||
},
|
||||
SfxEvent::Run,
|
||||
&stats,
|
||||
@ -325,8 +331,10 @@ mod tests {
|
||||
|
||||
let result = SfxEventMapper::map_character_event(
|
||||
&CharacterState {
|
||||
move_state: MoveState::Fall(FallHandler),
|
||||
action_state: ActionState::Idle,
|
||||
move_state: MoveState::Fall(FallState),
|
||||
action_state: ActionState::Idle(IdleState),
|
||||
action_disabled: false,
|
||||
move_disabled: false,
|
||||
},
|
||||
SfxEvent::Idle,
|
||||
&stats,
|
||||
@ -341,8 +349,10 @@ mod tests {
|
||||
|
||||
let result = SfxEventMapper::map_character_event(
|
||||
&CharacterState {
|
||||
move_state: MoveState::Glide(GlideHandler),
|
||||
action_state: ActionState::Idle,
|
||||
move_state: MoveState::Glide(GlideState),
|
||||
action_state: ActionState::Idle(IdleState),
|
||||
action_disabled: true,
|
||||
move_disabled: false,
|
||||
},
|
||||
SfxEvent::Jump,
|
||||
&stats,
|
||||
@ -357,8 +367,10 @@ mod tests {
|
||||
|
||||
let result = SfxEventMapper::map_character_event(
|
||||
&CharacterState {
|
||||
move_state: MoveState::Glide(GlideHandler),
|
||||
action_state: ActionState::Idle,
|
||||
move_state: MoveState::Glide(GlideState),
|
||||
action_state: ActionState::Idle(IdleState),
|
||||
action_disabled: true,
|
||||
move_disabled: false,
|
||||
},
|
||||
SfxEvent::Glide,
|
||||
&stats,
|
||||
@ -373,8 +385,10 @@ mod tests {
|
||||
|
||||
let result = SfxEventMapper::map_character_event(
|
||||
&CharacterState {
|
||||
move_state: MoveState::Fall(FallHandler),
|
||||
action_state: ActionState::Idle,
|
||||
move_state: MoveState::Fall(FallState),
|
||||
action_state: ActionState::Idle(IdleState),
|
||||
move_disabled: false,
|
||||
action_disabled: false,
|
||||
},
|
||||
SfxEvent::Glide,
|
||||
&stats,
|
||||
@ -394,8 +408,10 @@ mod tests {
|
||||
|
||||
let result = SfxEventMapper::map_character_event(
|
||||
&CharacterState {
|
||||
move_state: MoveState::Stand(StandHandler),
|
||||
action_state: ActionState::Attack(BasicAttack(BasicAttackHandler::default())),
|
||||
move_state: MoveState::Stand(StandState),
|
||||
action_state: ActionState::Attack(BasicAttack(BasicAttackState::default())),
|
||||
move_disabled: false,
|
||||
action_disabled: false,
|
||||
},
|
||||
SfxEvent::Idle,
|
||||
&stats,
|
||||
|
Loading…
Reference in New Issue
Block a user