Add movement_utils

This commit is contained in:
AdamWhitehurst 2019-12-28 08:10:39 -08:00
parent 06053faed0
commit ca44497258
23 changed files with 454 additions and 411 deletions

View File

@ -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>>;
}

View File

@ -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,

View File

@ -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))

View File

@ -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;
}

View File

@ -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))

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View 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;
}
}

View File

@ -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;
}
}

View File

@ -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: _ => {},
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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))

View File

@ -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);

View File

@ -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,

View File

@ -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;
// }

View File

@ -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> {

View 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
}
}

View File

@ -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,