mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'timo-rebase-slipped-on-midge' into 'master'
ECS organization + Rolling animation See merge request veloren/veloren!235
This commit is contained in:
commit
ceff450233
@ -29,7 +29,7 @@ fn main() {
|
||||
client.send_chat("Hello!".to_string());
|
||||
|
||||
loop {
|
||||
let events = match client.tick(comp::Control::default(), clock.get_last_delta()) {
|
||||
let events = match client.tick(comp::Controller::default(), clock.get_last_delta()) {
|
||||
Ok(events) => events,
|
||||
Err(err) => {
|
||||
error!("Error: {:?}", err);
|
||||
|
@ -153,7 +153,7 @@ impl Client {
|
||||
pub fn current_chunk(&self) -> Option<Arc<TerrainChunk>> {
|
||||
let chunk_pos = Vec2::from(
|
||||
self.state
|
||||
.read_storage::<comp::phys::Pos>()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(self.entity)
|
||||
.cloned()?
|
||||
.0,
|
||||
@ -171,52 +171,6 @@ impl Client {
|
||||
self.postbox.send_message(ClientMsg::Chat(msg))
|
||||
}
|
||||
|
||||
/// Jump locally, the new positions will be synced to the server
|
||||
#[allow(dead_code)]
|
||||
pub fn jump(&mut self) {
|
||||
if self.client_state != ClientState::Character {
|
||||
return;
|
||||
}
|
||||
self.state.write_component(self.entity, comp::Jumping);
|
||||
}
|
||||
|
||||
/// Start to glide locally, animation will be synced
|
||||
#[allow(dead_code)]
|
||||
pub fn glide(&mut self, state: bool) {
|
||||
if self.client_state != ClientState::Character {
|
||||
return;
|
||||
}
|
||||
if state {
|
||||
self.state.write_component(self.entity, comp::Gliding);
|
||||
} else {
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Gliding>()
|
||||
.remove(self.entity);
|
||||
}
|
||||
}
|
||||
|
||||
/// Start to attack
|
||||
#[allow(dead_code)]
|
||||
pub fn attack(&mut self) {
|
||||
if self.client_state != ClientState::Character {
|
||||
return;
|
||||
}
|
||||
// TODO: Test if attack is possible using timeout
|
||||
self.state
|
||||
.write_component(self.entity, comp::Attacking::start());
|
||||
self.postbox.send_message(ClientMsg::Attack);
|
||||
}
|
||||
|
||||
/// Tell the server the client wants to respawn.
|
||||
#[allow(dead_code)]
|
||||
pub fn respawn(&mut self) {
|
||||
if self.client_state != ClientState::Dead {
|
||||
return;
|
||||
}
|
||||
self.postbox.send_message(ClientMsg::Respawn)
|
||||
}
|
||||
|
||||
/// Remove all cached terrain
|
||||
#[allow(dead_code)]
|
||||
pub fn clear_terrain(&mut self) {
|
||||
@ -226,7 +180,11 @@ impl Client {
|
||||
|
||||
/// Execute a single client tick, handle input and update the game state by the given duration.
|
||||
#[allow(dead_code)]
|
||||
pub fn tick(&mut self, control: comp::Control, dt: Duration) -> Result<Vec<Event>, Error> {
|
||||
pub fn tick(
|
||||
&mut self,
|
||||
controller: comp::Controller,
|
||||
dt: Duration,
|
||||
) -> Result<Vec<Event>, Error> {
|
||||
// This tick function is the centre of the Veloren universe. Most client-side things are
|
||||
// managed from here, and as such it's important that it stays organised. Please consult
|
||||
// the core developers before making significant changes to this code. Here is the
|
||||
@ -243,10 +201,8 @@ impl Client {
|
||||
|
||||
// 1) Handle input from frontend.
|
||||
// Pass character actions from frontend input to the player's entity.
|
||||
// TODO: Only do this if the entity already has a Inputs component!
|
||||
if self.client_state == ClientState::Character {
|
||||
self.state.write_component(self.entity, control.clone());
|
||||
}
|
||||
self.state.write_component(self.entity, controller.clone());
|
||||
self.postbox.send_message(ClientMsg::Controller(controller));
|
||||
|
||||
// 2) Build up a list of events for this frame, to be passed to the frontend.
|
||||
let mut frontend_events = Vec::new();
|
||||
@ -262,7 +218,7 @@ impl Client {
|
||||
// 5) Terrain
|
||||
let pos = self
|
||||
.state
|
||||
.read_storage::<comp::phys::Pos>()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(self.entity)
|
||||
.cloned();
|
||||
if let (Some(pos), Some(view_distance)) = (pos, self.view_distance) {
|
||||
@ -336,19 +292,6 @@ impl Client {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Update the server about the player's current animation.
|
||||
if let Some(animation_info) = self
|
||||
.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::AnimationInfo>()
|
||||
.get_mut(self.entity)
|
||||
{
|
||||
if animation_info.changed {
|
||||
self.postbox
|
||||
.send_message(ClientMsg::PlayerAnimation(animation_info.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
// Output debug metrics
|
||||
if log_enabled!(log::Level::Info) && self.tick % 600 == 0 {
|
||||
let metrics = self
|
||||
|
@ -7,6 +7,9 @@ pub enum Animation {
|
||||
Jump,
|
||||
Gliding,
|
||||
Attack,
|
||||
Roll,
|
||||
Crun,
|
||||
Cidle,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
|
16
common/src/comp/controller.rs
Normal file
16
common/src/comp/controller.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use specs::{Component, FlaggedStorage, VecStorage};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Controller {
|
||||
pub move_dir: Vec2<f32>,
|
||||
pub jump: bool,
|
||||
pub attack: bool,
|
||||
pub roll: bool,
|
||||
pub glide: bool,
|
||||
pub respawn: bool,
|
||||
}
|
||||
|
||||
impl Component for Controller {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
}
|
@ -1,29 +1,33 @@
|
||||
use specs::{Component, FlaggedStorage, NullStorage, VecStorage};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Control {
|
||||
pub move_dir: Vec2<f32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct Respawning;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MoveDir(pub Vec2<f32>);
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Attacking {
|
||||
pub time: f32,
|
||||
pub applied: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Rolling {
|
||||
pub time: f32,
|
||||
pub applied: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct OnGround;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Jumping;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Gliding;
|
||||
|
||||
impl Component for Control {
|
||||
type Storage = VecStorage<Self>;
|
||||
}
|
||||
|
||||
impl Component for Respawning {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
@ -36,14 +40,36 @@ impl Attacking {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rolling {
|
||||
pub fn start() -> Self {
|
||||
Self {
|
||||
time: 0.0,
|
||||
applied: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for MoveDir {
|
||||
type Storage = VecStorage<Self>;
|
||||
}
|
||||
|
||||
impl Component for Attacking {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
}
|
||||
|
||||
impl Component for Rolling {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
}
|
||||
|
||||
impl Component for OnGround {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
||||
impl Component for Jumping {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
||||
impl Component for Gliding {
|
||||
type Storage = NullStorage<Self>;
|
||||
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
|
||||
}
|
||||
|
@ -1,26 +1,18 @@
|
||||
pub mod actor;
|
||||
pub mod agent;
|
||||
pub mod animation;
|
||||
pub mod inputs;
|
||||
pub mod phys;
|
||||
pub mod player;
|
||||
pub mod stats;
|
||||
mod agent;
|
||||
mod animation;
|
||||
mod controller;
|
||||
mod inputs;
|
||||
mod phys;
|
||||
mod player;
|
||||
mod stats;
|
||||
|
||||
// Reexports
|
||||
pub use actor::Actor;
|
||||
pub use actor::Body;
|
||||
pub use actor::HumanoidBody;
|
||||
pub use actor::QuadrupedBody;
|
||||
pub use actor::QuadrupedMediumBody;
|
||||
pub use actor::{Actor, Body, HumanoidBody, QuadrupedBody, QuadrupedMediumBody};
|
||||
pub use agent::Agent;
|
||||
pub use animation::Animation;
|
||||
pub use animation::AnimationInfo;
|
||||
pub use inputs::Attacking;
|
||||
pub use inputs::Control;
|
||||
pub use inputs::Gliding;
|
||||
pub use inputs::Jumping;
|
||||
pub use inputs::Respawning;
|
||||
pub use animation::{Animation, AnimationInfo};
|
||||
pub use controller::Controller;
|
||||
pub use inputs::{Attacking, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling};
|
||||
pub use phys::{ForceUpdate, Ori, Pos, Vel};
|
||||
pub use player::Player;
|
||||
pub use stats::Dying;
|
||||
pub use stats::HealthSource;
|
||||
pub use stats::Stats;
|
||||
pub use stats::{Dying, HealthSource, Stats};
|
||||
|
@ -2,7 +2,6 @@ use specs::{Component, NullStorage, VecStorage};
|
||||
use vek::*;
|
||||
|
||||
// Position
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Pos(pub Vec3<f32>);
|
||||
|
||||
@ -11,7 +10,6 @@ impl Component for Pos {
|
||||
}
|
||||
|
||||
// Velocity
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Vel(pub Vec3<f32>);
|
||||
|
||||
@ -20,7 +18,6 @@ impl Component for Vel {
|
||||
}
|
||||
|
||||
// Orientation
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Ori(pub Vec3<f32>);
|
||||
|
||||
@ -29,7 +26,6 @@ impl Component for Ori {
|
||||
}
|
||||
|
||||
// ForceUpdate
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct ForceUpdate;
|
||||
|
||||
|
@ -11,18 +11,16 @@ pub enum ClientMsg {
|
||||
name: String,
|
||||
body: comp::Body,
|
||||
},
|
||||
Attack,
|
||||
Respawn,
|
||||
Controller(comp::Controller),
|
||||
RequestState(ClientState),
|
||||
SetViewDistance(u32),
|
||||
Ping,
|
||||
Pong,
|
||||
Chat(String),
|
||||
PlayerAnimation(comp::AnimationInfo),
|
||||
PlayerPhysics {
|
||||
pos: comp::phys::Pos,
|
||||
vel: comp::phys::Vel,
|
||||
ori: comp::phys::Ori,
|
||||
pos: comp::Pos,
|
||||
vel: comp::Vel,
|
||||
ori: comp::Ori,
|
||||
},
|
||||
TerrainChunkRequest {
|
||||
key: Vec2<i32>,
|
||||
|
@ -17,13 +17,15 @@ impl sphynx::ResPacket for EcsResPacket {}
|
||||
sphynx::sum_type! {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum EcsCompPacket {
|
||||
Pos(comp::phys::Pos),
|
||||
Vel(comp::phys::Vel),
|
||||
Ori(comp::phys::Ori),
|
||||
Pos(comp::Pos),
|
||||
Vel(comp::Vel),
|
||||
Ori(comp::Ori),
|
||||
Actor(comp::Actor),
|
||||
Player(comp::Player),
|
||||
Stats(comp::Stats),
|
||||
Attacking(comp::Attacking),
|
||||
Rolling(comp::Rolling),
|
||||
Gliding(comp::Gliding),
|
||||
}
|
||||
}
|
||||
// Automatically derive From<T> for EcsCompPhantom
|
||||
@ -31,13 +33,15 @@ sphynx::sum_type! {
|
||||
sphynx::sum_type! {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum EcsCompPhantom {
|
||||
Pos(PhantomData<comp::phys::Pos>),
|
||||
Vel(PhantomData<comp::phys::Vel>),
|
||||
Ori(PhantomData<comp::phys::Ori>),
|
||||
Pos(PhantomData<comp::Pos>),
|
||||
Vel(PhantomData<comp::Vel>),
|
||||
Ori(PhantomData<comp::Ori>),
|
||||
Actor(PhantomData<comp::Actor>),
|
||||
Player(PhantomData<comp::Player>),
|
||||
Stats(PhantomData<comp::Stats>),
|
||||
Attacking(PhantomData<comp::Attacking>),
|
||||
Rolling(PhantomData<comp::Rolling>),
|
||||
Gliding(PhantomData<comp::Gliding>),
|
||||
}
|
||||
}
|
||||
impl sphynx::CompPacket for EcsCompPacket {
|
||||
|
@ -32,9 +32,9 @@ pub enum ServerMsg {
|
||||
EcsSync(sphynx::SyncPackage<EcsCompPacket, EcsResPacket>),
|
||||
EntityPhysics {
|
||||
entity: u64,
|
||||
pos: comp::phys::Pos,
|
||||
vel: comp::phys::Vel,
|
||||
ori: comp::phys::Ori,
|
||||
pos: comp::Pos,
|
||||
vel: comp::Vel,
|
||||
ori: comp::Ori,
|
||||
},
|
||||
EntityAnimation {
|
||||
entity: u64,
|
||||
|
@ -98,28 +98,31 @@ impl State {
|
||||
|
||||
// Create a new Sphynx ECS world.
|
||||
fn setup_sphynx_world(ecs: &mut sphynx::World<EcsCompPacket, EcsResPacket>) {
|
||||
// Register synced components.
|
||||
// Register server->client synced components.
|
||||
ecs.register_synced::<comp::Actor>();
|
||||
ecs.register_synced::<comp::Player>();
|
||||
ecs.register_synced::<comp::Stats>();
|
||||
ecs.register_synced::<comp::Attacking>(); // TODO: Don't send this to the client?
|
||||
ecs.register::<comp::phys::ForceUpdate>();
|
||||
ecs.register_synced::<comp::Attacking>();
|
||||
ecs.register_synced::<comp::Rolling>();
|
||||
ecs.register_synced::<comp::Gliding>();
|
||||
|
||||
// Register components synced by other means
|
||||
ecs.register::<comp::phys::Pos>();
|
||||
ecs.register::<comp::phys::Vel>();
|
||||
ecs.register::<comp::phys::Ori>();
|
||||
ecs.register::<comp::Pos>();
|
||||
ecs.register::<comp::Vel>();
|
||||
ecs.register::<comp::Ori>();
|
||||
ecs.register::<comp::MoveDir>();
|
||||
ecs.register::<comp::OnGround>();
|
||||
ecs.register::<comp::AnimationInfo>();
|
||||
ecs.register::<comp::Controller>();
|
||||
|
||||
// Register client-local components
|
||||
ecs.register::<comp::Control>();
|
||||
ecs.register::<comp::Jumping>();
|
||||
|
||||
// Register server-local components
|
||||
ecs.register::<comp::Agent>();
|
||||
ecs.register::<comp::Respawning>();
|
||||
ecs.register::<comp::Gliding>();
|
||||
ecs.register::<comp::Dying>();
|
||||
ecs.register::<comp::ForceUpdate>();
|
||||
ecs.register::<inventory::Inventory>();
|
||||
|
||||
// Register synced resources used by the ECS.
|
||||
|
@ -1,29 +0,0 @@
|
||||
use crate::{comp::Attacking, state::DeltaTime};
|
||||
use specs::{Entities, Join, Read, System, WriteStorage};
|
||||
|
||||
// Basic ECS AI agent system
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, DeltaTime>,
|
||||
WriteStorage<'a, Attacking>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (entities, dt, mut attacks): Self::SystemData) {
|
||||
for attack in (&mut attacks).join() {
|
||||
attack.time += dt.0;
|
||||
}
|
||||
|
||||
let finished_attacks = (&entities, &mut attacks)
|
||||
.join()
|
||||
.filter(|(_, a)| a.time > 0.25) // TODO: constant
|
||||
.map(|(e, _)| e)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for entity in finished_attacks {
|
||||
attacks.remove(entity);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +1,27 @@
|
||||
use crate::comp::{phys::Pos, Agent, Attacking, Control, Jumping};
|
||||
use crate::comp::{Agent, Attacking, Controller, Jumping, Pos};
|
||||
use log::warn;
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use specs::{Entities, Join, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Basic ECS AI agent system
|
||||
/// This system will allow NPCs to modify their controller
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
WriteStorage<'a, Agent>,
|
||||
ReadStorage<'a, Pos>,
|
||||
WriteStorage<'a, Control>,
|
||||
WriteStorage<'a, Controller>,
|
||||
WriteStorage<'a, Jumping>,
|
||||
WriteStorage<'a, Attacking>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(entities, mut agents, positions, mut controls, mut jumps, mut attacks): Self::SystemData,
|
||||
(entities, mut agents, positions, mut controllers, mut jumps, mut attacks): Self::SystemData,
|
||||
) {
|
||||
for (entity, agent, pos, control) in
|
||||
(&entities, &mut agents, &positions, &mut controls).join()
|
||||
for (entity, agent, pos, controller) in
|
||||
(&entities, &mut agents, &positions, &mut controllers).join()
|
||||
{
|
||||
match agent {
|
||||
Agent::Wanderer(bearing) => {
|
||||
@ -32,7 +31,7 @@ impl<'a> System<'a> for Sys {
|
||||
- pos.0 * 0.0002;
|
||||
|
||||
if bearing.magnitude_squared() != 0.0 {
|
||||
control.move_dir = bearing.normalized();
|
||||
controller.move_dir = bearing.normalized();
|
||||
}
|
||||
}
|
||||
Agent::Pet { target, offset } => {
|
||||
@ -49,7 +48,7 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// Move towards the target.
|
||||
let dist: f32 = Vec2::from(tgt_pos - pos.0).magnitude();
|
||||
control.move_dir = if dist > 5.0 {
|
||||
controller.move_dir = if dist > 5.0 {
|
||||
Vec2::from(tgt_pos - pos.0).normalized()
|
||||
} else if dist < 1.5 && dist > 0.0 {
|
||||
Vec2::from(pos.0 - tgt_pos).normalized()
|
||||
@ -57,7 +56,7 @@ impl<'a> System<'a> for Sys {
|
||||
Vec2::zero()
|
||||
};
|
||||
}
|
||||
_ => control.move_dir = Vec2::zero(),
|
||||
_ => controller.move_dir = Vec2::zero(),
|
||||
}
|
||||
|
||||
// Change offset occasionally.
|
||||
@ -72,7 +71,7 @@ impl<'a> System<'a> for Sys {
|
||||
Some(tgt_pos) => {
|
||||
let dist = Vec2::<f32>::from(tgt_pos.0 - pos.0).magnitude();
|
||||
if dist < 2.0 {
|
||||
control.move_dir = Vec2::zero();
|
||||
controller.move_dir = Vec2::zero();
|
||||
|
||||
if rand::random::<f32>() < 0.2 {
|
||||
attacks
|
||||
@ -82,7 +81,7 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
false
|
||||
} else if dist < 60.0 {
|
||||
control.move_dir =
|
||||
controller.move_dir =
|
||||
Vec2::<f32>::from(tgt_pos.0 - pos.0).normalized() * 0.96;
|
||||
|
||||
false
|
||||
@ -91,7 +90,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
control.move_dir = Vec2::one();
|
||||
controller.move_dir = Vec2::one();
|
||||
true
|
||||
}
|
||||
};
|
||||
|
@ -1,15 +1,87 @@
|
||||
use crate::{comp::AnimationInfo, state::DeltaTime};
|
||||
use specs::{Join, Read, System, WriteStorage};
|
||||
use crate::{
|
||||
comp::{
|
||||
Animation, AnimationInfo, Attacking, ForceUpdate, Gliding, Jumping, OnGround, Ori, Pos,
|
||||
Rolling, Vel,
|
||||
},
|
||||
state::DeltaTime,
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
|
||||
// Basic ECS AI agent system
|
||||
/// This system will apply the animation that fits best to the users actions
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (Read<'a, DeltaTime>, WriteStorage<'a, AnimationInfo>);
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, Vel>,
|
||||
ReadStorage<'a, OnGround>,
|
||||
ReadStorage<'a, Jumping>,
|
||||
ReadStorage<'a, Gliding>,
|
||||
ReadStorage<'a, Attacking>,
|
||||
ReadStorage<'a, Rolling>,
|
||||
WriteStorage<'a, AnimationInfo>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (dt, mut animation_infos): Self::SystemData) {
|
||||
for mut animation_info in (&mut animation_infos).join() {
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
dt,
|
||||
velocities,
|
||||
on_grounds,
|
||||
jumpings,
|
||||
glidings,
|
||||
attackings,
|
||||
rollings,
|
||||
mut animation_infos,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
for (entity, vel, on_ground, jumping, gliding, attacking, rolling, mut animation_info) in (
|
||||
&entities,
|
||||
&velocities,
|
||||
on_grounds.maybe(),
|
||||
jumpings.maybe(),
|
||||
glidings.maybe(),
|
||||
attackings.maybe(),
|
||||
rollings.maybe(),
|
||||
&mut animation_infos,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
animation_info.time += dt.0 as f64;
|
||||
|
||||
fn impossible_animation(message: &str) -> Animation {
|
||||
warn!("{}", message);
|
||||
Animation::Idle
|
||||
}
|
||||
|
||||
let animation = match (
|
||||
on_ground.is_some(),
|
||||
vel.0.magnitude() > 3.0, // Moving
|
||||
attacking.is_some(),
|
||||
gliding.is_some(),
|
||||
rolling.is_some(),
|
||||
) {
|
||||
(_, _, true, true, _) => impossible_animation("Attack while gliding"),
|
||||
(_, _, true, _, true) => impossible_animation("Roll while attacking"),
|
||||
(_, _, _, true, true) => impossible_animation("Roll while gliding"),
|
||||
(_, false, _, _, true) => impossible_animation("Roll without moving"),
|
||||
(_, true, false, false, true) => Animation::Roll,
|
||||
(true, false, false, false, false) => Animation::Idle,
|
||||
(true, true, false, false, false) => Animation::Run,
|
||||
(false, _, false, false, false) => Animation::Jump,
|
||||
(_, _, false, true, false) => Animation::Gliding,
|
||||
(_, _, true, false, false) => Animation::Attack,
|
||||
};
|
||||
|
||||
let last = animation_info.clone();
|
||||
let changed = last.animation != animation;
|
||||
|
||||
*animation_info = AnimationInfo {
|
||||
animation,
|
||||
time: if changed { 0.0 } else { last.time },
|
||||
changed,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
77
common/src/sys/combat.rs
Normal file
77
common/src/sys/combat.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
Attacking, HealthSource, Stats, {ForceUpdate, Ori, Pos, Vel},
|
||||
},
|
||||
state::{DeltaTime, Uid},
|
||||
};
|
||||
use log::warn;
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
|
||||
/// This system is responsible for handling accepted inputs like moving or attacking
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, Uid>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Ori>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, Attacking>,
|
||||
WriteStorage<'a, Stats>,
|
||||
WriteStorage<'a, ForceUpdate>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
uids,
|
||||
dt,
|
||||
positions,
|
||||
orientations,
|
||||
mut velocities,
|
||||
mut attackings,
|
||||
mut stats,
|
||||
mut force_updates,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
// Attacks
|
||||
(&entities, &uids, &positions, &orientations, &mut attackings)
|
||||
.join()
|
||||
.filter_map(|(entity, uid, pos, ori, mut attacking)| {
|
||||
if !attacking.applied {
|
||||
// Go through all other entities
|
||||
for (b, pos_b, mut vel_b, mut stat_b) in
|
||||
(&entities, &positions, &mut velocities, &mut stats).join()
|
||||
{
|
||||
// Check if it is a hit
|
||||
if entity != b
|
||||
&& !stat_b.is_dead
|
||||
&& pos.0.distance_squared(pos_b.0) < 50.0
|
||||
&& ori.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0
|
||||
{
|
||||
// Deal damage
|
||||
stat_b.hp.change_by(-10, HealthSource::Attack { by: *uid }); // TODO: variable damage and weapon
|
||||
vel_b.0 += (pos_b.0 - pos.0).normalized() * 10.0;
|
||||
vel_b.0.z = 15.0;
|
||||
let _ = force_updates.insert(b, ForceUpdate);
|
||||
}
|
||||
}
|
||||
attacking.applied = true;
|
||||
}
|
||||
|
||||
if attacking.time > 0.5 {
|
||||
Some(entity)
|
||||
} else {
|
||||
attacking.time += dt.0;
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.for_each(|e| {
|
||||
attackings.remove(e);
|
||||
});
|
||||
}
|
||||
}
|
117
common/src/sys/controller.rs
Normal file
117
common/src/sys/controller.rs
Normal file
@ -0,0 +1,117 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
Animation, AnimationInfo, Attacking, Controller, Gliding, HealthSource, Jumping, MoveDir,
|
||||
OnGround, Respawning, Rolling, Stats, {ForceUpdate, Ori, Pos, Vel},
|
||||
},
|
||||
state::DeltaTime,
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
|
||||
/// This system is responsible for validating controller inputs
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, Controller>,
|
||||
ReadStorage<'a, Stats>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Vel>,
|
||||
ReadStorage<'a, Ori>,
|
||||
ReadStorage<'a, OnGround>,
|
||||
WriteStorage<'a, MoveDir>,
|
||||
WriteStorage<'a, Jumping>,
|
||||
WriteStorage<'a, Attacking>,
|
||||
WriteStorage<'a, Rolling>,
|
||||
WriteStorage<'a, Respawning>,
|
||||
WriteStorage<'a, Gliding>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
dt,
|
||||
controllers,
|
||||
stats,
|
||||
positions,
|
||||
velocities,
|
||||
orientations,
|
||||
on_grounds,
|
||||
mut move_dirs,
|
||||
mut jumpings,
|
||||
mut attackings,
|
||||
mut rollings,
|
||||
mut respawns,
|
||||
mut glidings,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
for (entity, controller, stats, pos, vel, ori, on_ground) in (
|
||||
&entities,
|
||||
&controllers,
|
||||
&stats,
|
||||
&positions,
|
||||
&velocities,
|
||||
&orientations,
|
||||
on_grounds.maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
if stats.is_dead {
|
||||
// Respawn
|
||||
if controller.respawn {
|
||||
respawns.insert(entity, Respawning);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Move dir
|
||||
if rollings.get(entity).is_none() {
|
||||
move_dirs.insert(
|
||||
entity,
|
||||
MoveDir(if controller.move_dir.magnitude() > 1.0 {
|
||||
controller.move_dir.normalized()
|
||||
} else {
|
||||
controller.move_dir
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Glide
|
||||
if controller.glide
|
||||
&& on_ground.is_none()
|
||||
&& attackings.get(entity).is_none()
|
||||
&& rollings.get(entity).is_none()
|
||||
{
|
||||
glidings.insert(entity, Gliding);
|
||||
} else {
|
||||
glidings.remove(entity);
|
||||
}
|
||||
|
||||
// Attack
|
||||
if controller.attack
|
||||
&& attackings.get(entity).is_none()
|
||||
&& glidings.get(entity).is_none()
|
||||
&& rollings.get(entity).is_none()
|
||||
{
|
||||
attackings.insert(entity, Attacking::start());
|
||||
}
|
||||
|
||||
// Jump
|
||||
if controller.jump && on_ground.is_some() && vel.0.z <= 0.0 {
|
||||
jumpings.insert(entity, Jumping);
|
||||
}
|
||||
|
||||
// Roll
|
||||
if controller.roll
|
||||
&& rollings.get(entity).is_none()
|
||||
&& attackings.get(entity).is_none()
|
||||
&& glidings.get(entity).is_none()
|
||||
&& on_ground.is_some()
|
||||
&& vel.0.magnitude() > 5.0
|
||||
{
|
||||
rollings.insert(entity, Rolling::start());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
phys::{ForceUpdate, Ori, Pos, Vel},
|
||||
Animation, AnimationInfo, Attacking, Control, Gliding, HealthSource, Jumping, Stats,
|
||||
},
|
||||
state::{DeltaTime, Uid},
|
||||
terrain::TerrainMap,
|
||||
vol::{ReadVol, Vox},
|
||||
};
|
||||
use log::warn;
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Basic ECS AI agent system
|
||||
pub struct Sys;
|
||||
|
||||
const HUMANOID_ACCEL: f32 = 100.0;
|
||||
const HUMANOID_SPEED: f32 = 500.0;
|
||||
const HUMANOID_AIR_ACCEL: f32 = 10.0;
|
||||
const HUMANOID_AIR_SPEED: f32 = 100.0;
|
||||
const HUMANOID_JUMP_ACCEL: f32 = 16.0;
|
||||
const GLIDE_ACCEL: f32 = 15.0;
|
||||
const GLIDE_SPEED: f32 = 45.0;
|
||||
// Gravity is 9.81 * 4, so this makes gravity equal to .15
|
||||
const GLIDE_ANTIGRAV: f32 = 9.81 * 3.95;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, Uid>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadExpect<'a, TerrainMap>,
|
||||
ReadStorage<'a, Pos>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, Ori>,
|
||||
WriteStorage<'a, AnimationInfo>,
|
||||
WriteStorage<'a, Stats>,
|
||||
ReadStorage<'a, Control>,
|
||||
WriteStorage<'a, Jumping>,
|
||||
WriteStorage<'a, Gliding>,
|
||||
WriteStorage<'a, Attacking>,
|
||||
WriteStorage<'a, ForceUpdate>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
uids,
|
||||
dt,
|
||||
terrain,
|
||||
positions,
|
||||
mut velocities,
|
||||
mut orientations,
|
||||
mut animation_infos,
|
||||
mut stats,
|
||||
controls,
|
||||
mut jumps,
|
||||
glides,
|
||||
mut attacks,
|
||||
mut force_updates,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
for (entity, pos, control, stats, mut ori, mut vel) in (
|
||||
&entities,
|
||||
&positions,
|
||||
&controls,
|
||||
&stats,
|
||||
&mut orientations,
|
||||
&mut velocities,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
// Disable while dead TODO: Replace with client states
|
||||
if stats.is_dead {
|
||||
continue;
|
||||
}
|
||||
|
||||
let on_ground = terrain
|
||||
.get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32))
|
||||
.map(|vox| !vox.is_empty())
|
||||
.unwrap_or(false)
|
||||
&& vel.0.z <= 0.0;
|
||||
|
||||
let gliding = glides.get(entity).is_some() && vel.0.z < 0.0;
|
||||
let move_dir = if control.move_dir.magnitude() > 1.0 {
|
||||
control.move_dir.normalized()
|
||||
} else {
|
||||
control.move_dir
|
||||
};
|
||||
|
||||
if on_ground {
|
||||
// Move player according to move_dir
|
||||
if vel.0.magnitude() < HUMANOID_SPEED {
|
||||
vel.0 += Vec2::broadcast(dt.0) * move_dir * HUMANOID_ACCEL;
|
||||
}
|
||||
|
||||
// Jump
|
||||
if jumps.get(entity).is_some() && vel.0.z <= 0.0 {
|
||||
vel.0.z = HUMANOID_JUMP_ACCEL;
|
||||
jumps.remove(entity);
|
||||
}
|
||||
} else if gliding && vel.0.magnitude() < GLIDE_SPEED {
|
||||
let anti_grav = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2;
|
||||
vel.0.z += dt.0 * anti_grav * Vec2::<f32>::from(vel.0 * 0.15).magnitude().min(1.0);
|
||||
vel.0 += Vec2::broadcast(dt.0) * move_dir * GLIDE_ACCEL;
|
||||
} else if vel.0.magnitude() < HUMANOID_AIR_SPEED {
|
||||
vel.0 += Vec2::broadcast(dt.0) * move_dir * HUMANOID_AIR_ACCEL;
|
||||
}
|
||||
|
||||
// Set direction based on velocity
|
||||
if vel.0.magnitude_squared() != 0.0 {
|
||||
ori.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
let animation = if on_ground {
|
||||
if control.move_dir.magnitude() > 0.01 {
|
||||
Animation::Run
|
||||
} else if attacks.get(entity).is_some() {
|
||||
Animation::Attack
|
||||
} else {
|
||||
Animation::Idle
|
||||
}
|
||||
} else if glides.get(entity).is_some() {
|
||||
Animation::Gliding
|
||||
} else {
|
||||
Animation::Jump
|
||||
};
|
||||
|
||||
let last = animation_infos
|
||||
.get_mut(entity)
|
||||
.cloned()
|
||||
.unwrap_or(AnimationInfo::default());
|
||||
let changed = last.animation != animation;
|
||||
|
||||
if let Err(err) = animation_infos.insert(
|
||||
entity,
|
||||
AnimationInfo {
|
||||
animation,
|
||||
time: if changed { 0.0 } else { last.time },
|
||||
changed,
|
||||
},
|
||||
) {
|
||||
warn!("Inserting AnimationInfo for an entity failed: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
for (entity, &uid, pos, ori, attacking) in
|
||||
(&entities, &uids, &positions, &orientations, &mut attacks).join()
|
||||
{
|
||||
if !attacking.applied {
|
||||
for (b, pos_b, stat_b, mut vel_b) in
|
||||
(&entities, &positions, &mut stats, &mut velocities).join()
|
||||
{
|
||||
// Check if it is a hit
|
||||
if entity != b
|
||||
&& !stat_b.is_dead
|
||||
&& pos.0.distance_squared(pos_b.0) < 50.0
|
||||
&& ori.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0
|
||||
{
|
||||
// Deal damage
|
||||
stat_b.hp.change_by(-10, HealthSource::Attack { by: uid }); // TODO: variable damage and weapon
|
||||
vel_b.0 += (pos_b.0 - pos.0).normalized() * 10.0;
|
||||
vel_b.0.z = 15.0;
|
||||
if let Err(err) = force_updates.insert(b, ForceUpdate) {
|
||||
warn!("Inserting ForceUpdate for an entity failed: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
attacking.applied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
pub mod actions;
|
||||
pub mod agent;
|
||||
pub mod animation;
|
||||
pub mod inputs;
|
||||
pub mod combat;
|
||||
pub mod controller;
|
||||
pub mod phys;
|
||||
mod stats;
|
||||
|
||||
@ -10,17 +10,17 @@ use specs::DispatcherBuilder;
|
||||
|
||||
// System names
|
||||
const AGENT_SYS: &str = "agent_sys";
|
||||
const INPUTS_SYS: &str = "inputs_sys";
|
||||
const ACTIONS_SYS: &str = "actions_sys";
|
||||
const CONTROLLER_SYS: &str = "controller_sys";
|
||||
const PHYS_SYS: &str = "phys_sys";
|
||||
const COMBAT_SYS: &str = "combat_sys";
|
||||
const ANIMATION_SYS: &str = "animation_sys";
|
||||
const STATS_SYS: &str = "stats_sys";
|
||||
|
||||
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
|
||||
dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[]);
|
||||
dispatch_builder.add(phys::Sys, PHYS_SYS, &[]);
|
||||
dispatch_builder.add(actions::Sys, ACTIONS_SYS, &[]);
|
||||
dispatch_builder.add(inputs::Sys, INPUTS_SYS, &[]);
|
||||
dispatch_builder.add(combat::Sys, COMBAT_SYS, &[]);
|
||||
dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[]);
|
||||
dispatch_builder.add(stats::Sys, STATS_SYS, &[INPUTS_SYS]);
|
||||
dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]);
|
||||
}
|
||||
|
@ -1,21 +1,26 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
phys::{Pos, Vel},
|
||||
Stats,
|
||||
},
|
||||
comp::{Gliding, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, Stats, Vel},
|
||||
state::DeltaTime,
|
||||
terrain::TerrainMap,
|
||||
vol::{ReadVol, Vox},
|
||||
};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Basic ECS physics system
|
||||
pub struct Sys;
|
||||
|
||||
const GRAVITY: f32 = 9.81 * 4.0;
|
||||
const FRIC_GROUND: f32 = 0.15;
|
||||
const FRIC_AIR: f32 = 0.015;
|
||||
const HUMANOID_ACCEL: f32 = 70.0;
|
||||
const HUMANOID_SPEED: f32 = 120.0;
|
||||
const HUMANOID_AIR_ACCEL: f32 = 10.0;
|
||||
const HUMANOID_AIR_SPEED: f32 = 100.0;
|
||||
const HUMANOID_JUMP_ACCEL: f32 = 16.0;
|
||||
const ROLL_ACCEL: f32 = 160.0;
|
||||
const ROLL_SPEED: f32 = 550.0;
|
||||
const GLIDE_ACCEL: f32 = 15.0;
|
||||
const GLIDE_SPEED: f32 = 45.0;
|
||||
// Gravity is 9.81 * 4, so this makes gravity equal to .15
|
||||
const GLIDE_ANTIGRAV: f32 = 9.81 * 3.95;
|
||||
|
||||
// Integrates forces, calculates the new velocity based off of the old velocity
|
||||
// dt = delta time
|
||||
@ -38,34 +43,128 @@ fn integrate_forces(dt: f32, mut lv: Vec3<f32>, damp: f32) -> Vec3<f32> {
|
||||
lv
|
||||
}
|
||||
|
||||
/// This system applies forces and calculates new positions and velocities.
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadExpect<'a, TerrainMap>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, MoveDir>,
|
||||
ReadStorage<'a, Gliding>,
|
||||
ReadStorage<'a, Stats>,
|
||||
WriteStorage<'a, Jumping>,
|
||||
WriteStorage<'a, Rolling>,
|
||||
WriteStorage<'a, OnGround>,
|
||||
WriteStorage<'a, Pos>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, Ori>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (terrain, dt, stats, mut positions, mut velocities): Self::SystemData) {
|
||||
for (stats, pos, vel) in (&stats, &mut positions, &mut velocities).join() {
|
||||
// Disable while dead TODO: Replace with client states
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
terrain,
|
||||
dt,
|
||||
move_dirs,
|
||||
glidings,
|
||||
stats,
|
||||
mut jumpings,
|
||||
mut rollings,
|
||||
mut on_grounds,
|
||||
mut positions,
|
||||
mut velocities,
|
||||
mut orientations,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
// Apply movement inputs
|
||||
for (entity, stats, move_dir, gliding, mut pos, mut vel, mut ori) in (
|
||||
&entities,
|
||||
&stats,
|
||||
move_dirs.maybe(),
|
||||
glidings.maybe(),
|
||||
&mut positions,
|
||||
&mut velocities,
|
||||
&mut orientations,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
// Disable while dead TODO: Replace with client states?
|
||||
if stats.is_dead {
|
||||
continue;
|
||||
}
|
||||
|
||||
let on_ground = terrain
|
||||
.get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32))
|
||||
.map(|vox| !vox.is_empty())
|
||||
.unwrap_or(false)
|
||||
&& vel.0.z <= 0.0;
|
||||
// Move player according to move_dir
|
||||
if let Some(move_dir) = move_dir {
|
||||
vel.0 += Vec2::broadcast(dt.0)
|
||||
* move_dir.0
|
||||
* match (
|
||||
on_grounds.get(entity).is_some(),
|
||||
glidings.get(entity).is_some(),
|
||||
rollings.get(entity).is_some(),
|
||||
) {
|
||||
(true, false, false) if vel.0.magnitude() < HUMANOID_SPEED => {
|
||||
HUMANOID_ACCEL
|
||||
}
|
||||
(false, true, false) if vel.0.magnitude() < GLIDE_SPEED => GLIDE_ACCEL,
|
||||
(false, false, false) if vel.0.magnitude() < HUMANOID_AIR_SPEED => {
|
||||
HUMANOID_AIR_ACCEL
|
||||
}
|
||||
(true, false, true) if vel.0.magnitude() < ROLL_SPEED => ROLL_ACCEL,
|
||||
|
||||
_ => 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
// Jump
|
||||
if jumpings.get(entity).is_some() {
|
||||
vel.0.z = HUMANOID_JUMP_ACCEL;
|
||||
jumpings.remove(entity);
|
||||
}
|
||||
|
||||
// Glide
|
||||
if gliding.is_some() && vel.0.magnitude() < GLIDE_SPEED && vel.0.z < 0.0 {
|
||||
let lift = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2;
|
||||
vel.0.z += dt.0 * lift * Vec2::<f32>::from(vel.0 * 0.15).magnitude().min(1.0);
|
||||
}
|
||||
|
||||
// Roll
|
||||
if let Some(time) = rollings.get_mut(entity).map(|r| &mut r.time) {
|
||||
*time += dt.0;
|
||||
if *time > 0.55 {
|
||||
rollings.remove(entity);
|
||||
}
|
||||
}
|
||||
|
||||
// Set direction based on velocity
|
||||
if vel.0.magnitude_squared() != 0.0 {
|
||||
ori.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
// Movement
|
||||
pos.0 += vel.0 * dt.0;
|
||||
|
||||
// Update OnGround component
|
||||
if terrain
|
||||
.get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32))
|
||||
.map(|vox| !vox.is_empty())
|
||||
.unwrap_or(false)
|
||||
&& vel.0.z <= 0.0
|
||||
{
|
||||
on_grounds.insert(entity, OnGround);
|
||||
} else {
|
||||
on_grounds.remove(entity);
|
||||
}
|
||||
|
||||
// Integrate forces
|
||||
// Friction is assumed to be a constant dependent on location
|
||||
let friction = 50.0 * if on_ground { FRIC_GROUND } else { FRIC_AIR };
|
||||
let friction = 50.0
|
||||
* if on_grounds.get(entity).is_some() {
|
||||
FRIC_GROUND
|
||||
} else {
|
||||
FRIC_AIR
|
||||
};
|
||||
vel.0 = integrate_forces(dt.0, vel.0, friction);
|
||||
|
||||
// Basic collision with terrain
|
||||
|
@ -5,9 +5,8 @@ use crate::{
|
||||
use log::warn;
|
||||
use specs::{Entities, Join, Read, System, WriteStorage};
|
||||
|
||||
// Basic ECS AI agent system
|
||||
/// This system kills players
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
|
@ -100,18 +100,12 @@ fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
||||
let (opt_x, opt_y, opt_z) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32);
|
||||
match (opt_x, opt_y, opt_z) {
|
||||
(Some(x), Some(y), Some(z)) => {
|
||||
match server
|
||||
.state
|
||||
.read_component_cloned::<comp::phys::Pos>(entity)
|
||||
{
|
||||
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
||||
Some(current_pos) => {
|
||||
server.state.write_component(
|
||||
entity,
|
||||
comp::phys::Pos(current_pos.0 + Vec3::new(x, y, z)),
|
||||
);
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::ForceUpdate);
|
||||
.write_component(entity, comp::Pos(current_pos.0 + Vec3::new(x, y, z)));
|
||||
server.state.write_component(entity, comp::ForceUpdate);
|
||||
}
|
||||
None => server.clients.notify(
|
||||
entity,
|
||||
@ -131,10 +125,8 @@ fn handle_goto(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
||||
(Some(x), Some(y), Some(z)) => {
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::Pos(Vec3::new(x, y, z)));
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::ForceUpdate);
|
||||
.write_component(entity, comp::Pos(Vec3::new(x, y, z)));
|
||||
server.state.write_component(entity, comp::ForceUpdate);
|
||||
}
|
||||
_ => server
|
||||
.clients
|
||||
@ -173,20 +165,15 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
|
||||
match opt_alias {
|
||||
Some(alias) => {
|
||||
let ecs = server.state.ecs();
|
||||
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::player::Player>())
|
||||
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||
.join()
|
||||
.find(|(_, player)| player.alias == alias)
|
||||
.map(|(entity, _)| entity);
|
||||
match opt_player {
|
||||
Some(player) => match server
|
||||
.state
|
||||
.read_component_cloned::<comp::phys::Pos>(player)
|
||||
{
|
||||
Some(player) => match server.state.read_component_cloned::<comp::Pos>(player) {
|
||||
Some(pos) => {
|
||||
server.state.write_component(entity, pos);
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::ForceUpdate);
|
||||
server.state.write_component(entity, comp::ForceUpdate);
|
||||
}
|
||||
None => server.clients.notify(
|
||||
entity,
|
||||
@ -222,10 +209,7 @@ fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &C
|
||||
|
||||
match (opt_agent, opt_id, opt_amount) {
|
||||
(Some(agent), Some(id), Some(amount)) => {
|
||||
match server
|
||||
.state
|
||||
.read_component_cloned::<comp::phys::Pos>(entity)
|
||||
{
|
||||
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
||||
Some(mut pos) => {
|
||||
pos.0.x += 1.0; // Temp fix TODO: Solve NaN issue with positions of pets
|
||||
let body = kind_to_body(id);
|
||||
|
@ -135,7 +135,7 @@ impl Server {
|
||||
#[allow(dead_code)]
|
||||
pub fn create_npc(
|
||||
&mut self,
|
||||
pos: comp::phys::Pos,
|
||||
pos: comp::Pos,
|
||||
name: String,
|
||||
body: comp::Body,
|
||||
) -> EcsEntityBuilder {
|
||||
@ -143,13 +143,13 @@ impl Server {
|
||||
.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(comp::phys::Vel(Vec3::zero()))
|
||||
.with(comp::phys::Ori(Vec3::unit_y()))
|
||||
.with(comp::Control::default())
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori(Vec3::unit_y()))
|
||||
.with(comp::Controller::default())
|
||||
.with(comp::AnimationInfo::default())
|
||||
.with(comp::Actor::Character { name, body })
|
||||
.with(comp::Stats::default())
|
||||
.with(comp::phys::ForceUpdate)
|
||||
.with(comp::ForceUpdate)
|
||||
}
|
||||
|
||||
pub fn create_player_character(
|
||||
@ -164,11 +164,12 @@ impl Server {
|
||||
state.write_component(entity, comp::Actor::Character { name, body });
|
||||
state.write_component(entity, comp::Stats::default());
|
||||
state.write_component(entity, comp::AnimationInfo::default());
|
||||
state.write_component(entity, comp::phys::Pos(spawn_point));
|
||||
state.write_component(entity, comp::phys::Vel(Vec3::zero()));
|
||||
state.write_component(entity, comp::phys::Ori(Vec3::unit_y()));
|
||||
state.write_component(entity, comp::Controller::default());
|
||||
state.write_component(entity, comp::Pos(spawn_point));
|
||||
state.write_component(entity, comp::Vel(Vec3::zero()));
|
||||
state.write_component(entity, comp::Ori(Vec3::unit_y()));
|
||||
// Make sure physics are accepted.
|
||||
state.write_component(entity, comp::phys::ForceUpdate);
|
||||
state.write_component(entity, comp::ForceUpdate);
|
||||
|
||||
// Tell the client its request was successful.
|
||||
client.allow_state(ClientState::Character);
|
||||
@ -245,9 +246,8 @@ impl Server {
|
||||
// Actually kill them
|
||||
for entity in todo_kill {
|
||||
if let Some(client) = self.clients.get_mut(&entity) {
|
||||
self.state
|
||||
.write_component(entity, comp::phys::Vel(Vec3::zero()));
|
||||
self.state.write_component(entity, comp::phys::ForceUpdate);
|
||||
self.state.write_component(entity, comp::Vel(Vec3::zero()));
|
||||
self.state.write_component(entity, comp::ForceUpdate);
|
||||
client.force_state(ClientState::Dead);
|
||||
} else {
|
||||
if let Err(err) = self.state.ecs_mut().delete_entity_synced(entity) {
|
||||
@ -272,12 +272,11 @@ impl Server {
|
||||
self.state.write_component(entity, comp::Stats::default());
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::phys::Pos>()
|
||||
.write_storage::<comp::Pos>()
|
||||
.get_mut(entity)
|
||||
.map(|pos| pos.0.z += 100.0);
|
||||
self.state
|
||||
.write_component(entity, comp::phys::Vel(Vec3::zero()));
|
||||
self.state.write_component(entity, comp::phys::ForceUpdate);
|
||||
self.state.write_component(entity, comp::Vel(Vec3::zero()));
|
||||
self.state.write_component(entity, comp::ForceUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +287,7 @@ impl Server {
|
||||
for (entity, view_distance, pos) in (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<comp::Player>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||
&self.state.ecs().read_storage::<comp::Pos>(),
|
||||
)
|
||||
.join()
|
||||
.filter_map(|(entity, player, pos)| {
|
||||
@ -323,7 +322,7 @@ impl Server {
|
||||
// For each player with a position, calculate the distance.
|
||||
for (player, pos) in (
|
||||
&self.state.ecs().read_storage::<comp::Player>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||
&self.state.ecs().read_storage::<comp::Pos>(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -492,24 +491,16 @@ impl Server {
|
||||
}
|
||||
ClientState::Pending => {}
|
||||
},
|
||||
ClientMsg::Attack => match client.client_state {
|
||||
ClientState::Character => {
|
||||
if state
|
||||
.ecs()
|
||||
.read_storage::<comp::Attacking>()
|
||||
.get(entity)
|
||||
.is_none()
|
||||
{
|
||||
state.write_component(entity, comp::Attacking::start());
|
||||
}
|
||||
ClientMsg::Controller(controller) => match client.client_state {
|
||||
ClientState::Connected
|
||||
| ClientState::Registered
|
||||
| ClientState::Spectator => {
|
||||
client.error_state(RequestStateError::Impossible)
|
||||
}
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
},
|
||||
ClientMsg::Respawn => match client.client_state {
|
||||
ClientState::Dead => {
|
||||
state.write_component(entity, comp::Respawning);
|
||||
ClientState::Dead | ClientState::Character => {
|
||||
state.write_component(entity, controller);
|
||||
}
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
ClientState::Pending => {}
|
||||
},
|
||||
ClientMsg::Chat(msg) => match client.client_state {
|
||||
ClientState::Connected => {
|
||||
@ -521,15 +512,6 @@ impl Server {
|
||||
| ClientState::Character => new_chat_msgs.push((Some(entity), msg)),
|
||||
ClientState::Pending => {}
|
||||
},
|
||||
ClientMsg::PlayerAnimation(animation_info) => {
|
||||
match client.client_state {
|
||||
ClientState::Character => {
|
||||
state.write_component(entity, animation_info)
|
||||
}
|
||||
// Only characters can send animations.
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
}
|
||||
}
|
||||
ClientMsg::PlayerPhysics { pos, vel, ori } => match client.client_state {
|
||||
ClientState::Character => {
|
||||
state.write_component(entity, pos);
|
||||
@ -639,9 +621,9 @@ impl Server {
|
||||
// Sync physics
|
||||
for (&uid, &pos, &vel, &ori) in (
|
||||
&state.ecs().read_storage::<Uid>(),
|
||||
&state.ecs().read_storage::<comp::phys::Pos>(),
|
||||
&state.ecs().read_storage::<comp::phys::Vel>(),
|
||||
&state.ecs().read_storage::<comp::phys::Ori>(),
|
||||
&state.ecs().read_storage::<comp::Pos>(),
|
||||
&state.ecs().read_storage::<comp::Vel>(),
|
||||
&state.ecs().read_storage::<comp::Ori>(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -680,13 +662,10 @@ impl Server {
|
||||
for (entity, &uid, &pos, &vel, &ori, force_update) in (
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<Uid>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Vel>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Ori>(),
|
||||
self.state
|
||||
.ecs()
|
||||
.read_storage::<comp::phys::ForceUpdate>()
|
||||
.maybe(),
|
||||
&self.state.ecs().read_storage::<comp::Pos>(),
|
||||
&self.state.ecs().read_storage::<comp::Vel>(),
|
||||
&self.state.ecs().read_storage::<comp::Ori>(),
|
||||
self.state.ecs().read_storage::<comp::ForceUpdate>().maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -702,7 +681,7 @@ impl Server {
|
||||
|
||||
let in_vd = |entity| {
|
||||
// Get client position.
|
||||
let client_pos = match state.ecs().read_storage::<comp::phys::Pos>().get(entity) {
|
||||
let client_pos = match state.ecs().read_storage::<comp::Pos>().get(entity) {
|
||||
Some(pos) => pos.0,
|
||||
None => return false,
|
||||
};
|
||||
@ -733,10 +712,7 @@ impl Server {
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<Uid>(),
|
||||
&self.state.ecs().read_storage::<comp::AnimationInfo>(),
|
||||
self.state
|
||||
.ecs()
|
||||
.read_storage::<comp::phys::ForceUpdate>()
|
||||
.maybe(),
|
||||
self.state.ecs().read_storage::<comp::ForceUpdate>().maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -755,7 +731,7 @@ impl Server {
|
||||
// Remove all force flags.
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::phys::ForceUpdate>()
|
||||
.write_storage::<comp::ForceUpdate>()
|
||||
.clear();
|
||||
}
|
||||
|
||||
|
@ -46,11 +46,11 @@ impl Animation for AttackAnimation {
|
||||
-8.0 + wave_quicken_slow * 10.0,
|
||||
4.0 + wave_quicken_double * 3.0,
|
||||
9.0,
|
||||
) / 11.0;
|
||||
);
|
||||
next.l_hand.ori = Quaternion::rotation_z(-0.8)
|
||||
* Quaternion::rotation_x(0.0 + wave_quicken * -0.8)
|
||||
* Quaternion::rotation_y(0.0 + wave_quicken * -0.4);
|
||||
next.l_hand.scale = Vec3::one() / 11.0;
|
||||
next.l_hand.scale = Vec3::one();
|
||||
|
||||
next.r_hand.offset = Vec3::new(0.0, -2.0, 6.5) / 11.0;
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.0);
|
||||
|
104
voxygen/src/anim/character/cidle.rs
Normal file
104
voxygen/src/anim/character/cidle.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use super::{super::Animation, CharacterSkeleton};
|
||||
use std::{f32::consts::PI, ops::Mul};
|
||||
use vek::*;
|
||||
|
||||
pub struct CidleAnimation;
|
||||
|
||||
impl Animation for CidleAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = f64;
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: f64,
|
||||
anim_time: f64,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin();
|
||||
let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos();
|
||||
|
||||
let head_look = Vec2::new(
|
||||
((global_time + anim_time) as f32 / 8.0)
|
||||
.floor()
|
||||
.mul(7331.0)
|
||||
.sin()
|
||||
* 0.5,
|
||||
((global_time + anim_time) as f32 / 8.0)
|
||||
.floor()
|
||||
.mul(1337.0)
|
||||
.sin()
|
||||
* 0.25,
|
||||
);
|
||||
next.head.offset = Vec3::new(0.0, 2.0, 11.0 + wave_ultra_slow * 0.3);
|
||||
next.head.ori = Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y);
|
||||
next.head.scale = Vec3::one();
|
||||
|
||||
next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_ultra_slow * 0.3);
|
||||
next.chest.ori = Quaternion::rotation_x(0.0);
|
||||
next.chest.scale = Vec3::one();
|
||||
|
||||
next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + wave_ultra_slow * 0.3);
|
||||
next.belt.ori = Quaternion::rotation_x(0.0);
|
||||
next.belt.scale = Vec3::one();
|
||||
|
||||
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + wave_ultra_slow * 0.3);
|
||||
next.shorts.ori = Quaternion::rotation_x(0.0);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-7.5,
|
||||
-2.0 + wave_ultra_slow_cos * 0.15,
|
||||
8.0 + wave_ultra_slow * 0.5,
|
||||
) / 11.0;
|
||||
|
||||
next.l_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * 0.06);
|
||||
next.l_hand.scale = Vec3::one() / 11.0;
|
||||
|
||||
next.r_hand.offset = Vec3::new(
|
||||
7.5,
|
||||
-2.0 + wave_ultra_slow_cos * 0.15,
|
||||
8.0 + wave_ultra_slow * 0.5,
|
||||
) / 11.0;
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * 0.06);
|
||||
next.r_hand.scale = Vec3::one() / 11.;
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, -0.1, 8.0);
|
||||
next.l_foot.ori = Quaternion::identity();
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, -0.1, 8.0);
|
||||
next.r_foot.ori = Quaternion::identity();
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.weapon.offset = Vec3::new(-7.0, -5.0, 15.0);
|
||||
next.weapon.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
||||
next.weapon.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.l_shoulder.offset = Vec3::new(-10.0, -3.2, 2.5);
|
||||
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.l_shoulder.scale = Vec3::one() * 1.04;
|
||||
|
||||
next.r_shoulder.offset = Vec3::new(0.0, -3.2, 2.5);
|
||||
next.r_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.04;
|
||||
|
||||
next.draw.offset = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.draw.ori = Quaternion::rotation_y(0.0);
|
||||
next.draw.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.left_equip.offset = Vec3::new(0.0, 0.0, 5.0) / 11.0;
|
||||
next.left_equip.ori = Quaternion::rotation_x(0.0);;
|
||||
next.left_equip.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.right_equip.offset = Vec3::new(0.0, 0.0, 5.0) / 11.0;
|
||||
next.right_equip.ori = Quaternion::rotation_x(0.0);;
|
||||
next.right_equip.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, -0.2, 0.1);
|
||||
next.torso.ori = Quaternion::rotation_x(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0;
|
||||
|
||||
next
|
||||
}
|
||||
}
|
97
voxygen/src/anim/character/crun.rs
Normal file
97
voxygen/src/anim/character/crun.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use super::{super::Animation, CharacterSkeleton};
|
||||
use std::ops::Mul;
|
||||
use vek::*;
|
||||
|
||||
pub struct CrunAnimation;
|
||||
|
||||
impl Animation for CrunAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = (f32, f64);
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
(velocity, global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave = (anim_time as f32 * 14.0).sin();
|
||||
let wave_cos = (anim_time as f32 * 14.0).cos();
|
||||
|
||||
let head_look = Vec2::new(
|
||||
((global_time + anim_time) as f32 / 2.0)
|
||||
.floor()
|
||||
.mul(7331.0)
|
||||
.sin()
|
||||
* 0.2,
|
||||
((global_time + anim_time) as f32 / 2.0)
|
||||
.floor()
|
||||
.mul(1337.0)
|
||||
.sin()
|
||||
* 0.1,
|
||||
);
|
||||
|
||||
next.head.offset = Vec3::new(0.0, 3.0, 12.0 + wave_cos * 1.3);
|
||||
next.head.ori = Quaternion::rotation_z(head_look.x + wave * 0.1)
|
||||
* Quaternion::rotation_x(head_look.y + 0.35);
|
||||
next.head.scale = Vec3::one();
|
||||
|
||||
next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_cos * 1.1);
|
||||
next.chest.ori = Quaternion::rotation_z(wave * 0.1);
|
||||
next.chest.scale = Vec3::one();
|
||||
|
||||
next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + wave_cos * 1.1);
|
||||
next.belt.ori = Quaternion::rotation_z(wave * 0.25);
|
||||
next.belt.scale = Vec3::one();
|
||||
|
||||
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + wave_cos * 1.1);
|
||||
next.shorts.ori = Quaternion::rotation_z(wave * 0.6);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
next.l_hand.offset = Vec3::new(-9.0, 3.0 + wave_cos * 8.0, 12.0 - wave * 1.0) / 11.0;
|
||||
next.l_hand.ori = Quaternion::rotation_x(wave_cos * 1.1);
|
||||
next.l_hand.scale = Vec3::one() / 11.0;
|
||||
|
||||
next.r_hand.offset = Vec3::new(9.0, 3.0 - wave_cos * 8.0, 12.0 + wave * 1.0) / 11.0;
|
||||
next.r_hand.ori = Quaternion::rotation_x(wave_cos * -1.1);
|
||||
next.r_hand.scale = Vec3::one() / 11.0;
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave_cos * 1.0, 6.0);
|
||||
next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave_cos * 1.5);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, 0.0 - wave_cos * 1.0, 6.0);
|
||||
next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.5);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.weapon.offset = Vec3::new(-7.0, -5.0, 15.0);
|
||||
next.weapon.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
||||
next.weapon.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.l_shoulder.offset = Vec3::new(-10.0, -3.2, 2.5);
|
||||
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.l_shoulder.scale = Vec3::one() * 1.04;
|
||||
|
||||
next.r_shoulder.offset = Vec3::new(0.0, -3.2, 2.5);
|
||||
next.r_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.04;
|
||||
|
||||
next.draw.offset = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.draw.ori = Quaternion::rotation_y(0.0);
|
||||
next.draw.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.left_equip.offset = Vec3::new(0.0, 0.0, 5.0) / 11.0;
|
||||
next.left_equip.ori = Quaternion::rotation_x(0.0);;
|
||||
next.left_equip.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.right_equip.offset = Vec3::new(0.0, 0.0, 5.0) / 11.0;
|
||||
next.right_equip.ori = Quaternion::rotation_x(0.0);;
|
||||
next.right_equip.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, -0.2, 0.4);
|
||||
next.torso.ori = Quaternion::rotation_x(-velocity * 0.04 - wave_cos * 0.10);
|
||||
next.torso.scale = Vec3::one() / 11.0;
|
||||
|
||||
next
|
||||
}
|
||||
}
|
@ -6,11 +6,11 @@ pub struct GlidingAnimation;
|
||||
|
||||
impl Animation for GlidingAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = f64;
|
||||
type Dependency = (f32, f64);
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: f64,
|
||||
(velocity, global_time): Self::Dependency,
|
||||
anim_time: f64,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
@ -35,48 +35,40 @@ impl Animation for GlidingAnimation {
|
||||
.sin()
|
||||
* 0.25,
|
||||
);
|
||||
next.head.offset = Vec3::new(0.0, 2.0, 12.0);
|
||||
next.head.offset = Vec3::new(0.0, 2.0, 2.0);
|
||||
next.head.ori = Quaternion::rotation_x(0.35 - wave_very_slow * 0.10 + head_look.y)
|
||||
* Quaternion::rotation_z(head_look.x + wave_very_slow_cos * 0.15);
|
||||
next.head.scale = Vec3::one();
|
||||
|
||||
next.chest.offset = Vec3::new(0.0, 0.0, 8.0);
|
||||
next.chest.offset = Vec3::new(0.0, 0.0, -2.0);
|
||||
next.chest.ori = Quaternion::rotation_z(wave_very_slow_cos * 0.15);
|
||||
next.chest.scale = Vec3::one();
|
||||
|
||||
next.belt.offset = Vec3::new(0.0, 0.0, 6.0);
|
||||
next.belt.offset = Vec3::new(0.0, 0.0, -4.0);
|
||||
next.belt.ori = Quaternion::rotation_z(wave_very_slow_cos * 0.20);
|
||||
next.belt.scale = Vec3::one();
|
||||
|
||||
next.shorts.offset = Vec3::new(0.0, 0.0, 3.0);
|
||||
next.shorts.offset = Vec3::new(0.0, 0.0, -7.0);
|
||||
next.shorts.ori = Quaternion::rotation_z(wave_very_slow_cos * 0.25);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-10.0,
|
||||
6.0 - wave_very_slow * 1.50,
|
||||
15.0 + wave_very_slow * 0.50,
|
||||
) / 11.0;
|
||||
next.l_hand.ori = Quaternion::rotation_x(0.2 + wave_very_slow_cos * 0.05);
|
||||
next.l_hand.scale = Vec3::one() / 11.0;
|
||||
next.l_hand.offset = Vec3::new(-10.0, -2.0 + wave_very_slow * 0.10, 10.5);
|
||||
next.l_hand.ori = Quaternion::rotation_x(1.0 + wave_very_slow_cos * -0.10);
|
||||
next.l_hand.scale = Vec3::one();
|
||||
|
||||
next.r_hand.offset = Vec3::new(
|
||||
10.0,
|
||||
6.0 - wave_very_slow * 1.50,
|
||||
14.5 + wave_very_slow * 0.50,
|
||||
) / 11.0;
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.1 + wave_very_slow * 0.05);
|
||||
next.r_hand.scale = Vec3::one() / 11.0;
|
||||
next.r_hand.offset = Vec3::new(10.0, -2.0 + wave_very_slow * 0.10, 10.5);
|
||||
next.r_hand.ori = Quaternion::rotation_x(1.0 + wave_very_slow_cos * -0.10);
|
||||
next.r_hand.scale = Vec3::one();
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, 1.0, 8.0);
|
||||
next.l_foot.offset = Vec3::new(-3.4, 1.0, -2.0);
|
||||
next.l_foot.ori = Quaternion::rotation_x(
|
||||
wave_stop * -0.7 - wave_slow_cos * -0.21 + wave_very_slow * 0.19,
|
||||
(wave_stop * -0.7 - wave_slow_cos * -0.21 + wave_very_slow * 0.19) * velocity * 0.07,
|
||||
);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, 1.0, 8.0);
|
||||
next.r_foot.offset = Vec3::new(3.4, 1.0, -2.0);
|
||||
next.r_foot.ori = Quaternion::rotation_x(
|
||||
wave_stop * -0.8 + wave_slow * -0.25 + wave_very_slow_alt * 0.13,
|
||||
(wave_stop * -0.8 + wave_slow * -0.25 + wave_very_slow_alt * 0.13) * velocity * 0.07,
|
||||
);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
@ -92,21 +84,21 @@ impl Animation for GlidingAnimation {
|
||||
next.r_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.04;
|
||||
|
||||
next.draw.offset = Vec3::new(0.0, -9.0 + wave_very_slow * 0.10, 18.0);
|
||||
next.draw.ori = Quaternion::rotation_x(0.95 - wave_very_slow * 0.15)
|
||||
next.draw.offset = Vec3::new(0.0, -9.0 + wave_very_slow * 0.10, 8.0);
|
||||
next.draw.ori = Quaternion::rotation_x(1.0)//0.95 - wave_very_slow * 0.08)
|
||||
* Quaternion::rotation_y(wave_very_slow_cos * 0.04);
|
||||
next.draw.scale = Vec3::one();
|
||||
|
||||
next.left_equip.offset = Vec3::new(0.0, 0.0, 5.0) / 11.0;
|
||||
next.left_equip.offset = Vec3::new(0.0, 0.0, -5.0) / 11.0;
|
||||
next.left_equip.ori = Quaternion::rotation_x(0.0);;
|
||||
next.left_equip.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.right_equip.offset = Vec3::new(0.0, 0.0, 5.0) / 11.0;
|
||||
next.right_equip.offset = Vec3::new(0.0, 0.0, -5.0) / 11.0;
|
||||
next.right_equip.ori = Quaternion::rotation_x(0.0);;
|
||||
next.right_equip.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, -0.2, 0.0);
|
||||
next.torso.ori = Quaternion::rotation_x(-0.8 + wave_very_slow * 0.10);
|
||||
next.torso.offset = Vec3::new(0.0, -0.2, 10.0) / 11.0;
|
||||
next.torso.ori = Quaternion::rotation_x(-0.05 * velocity + wave_very_slow * 0.10);
|
||||
next.torso.scale = Vec3::one() / 11.0;
|
||||
|
||||
next
|
||||
|
@ -51,20 +51,20 @@ impl Animation for IdleAnimation {
|
||||
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-7.5,
|
||||
-2.0 + wave_ultra_slow_cos * 0.15,
|
||||
8.0 + wave_ultra_slow * 0.5,
|
||||
) / 11.0;
|
||||
0.0 + wave_ultra_slow_cos * 0.15,
|
||||
7.0 + wave_ultra_slow * 0.5,
|
||||
);
|
||||
|
||||
next.l_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * 0.06);
|
||||
next.l_hand.scale = Vec3::one() / 11.0;
|
||||
next.l_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * -0.06);
|
||||
next.l_hand.scale = Vec3::one();
|
||||
|
||||
next.r_hand.offset = Vec3::new(
|
||||
7.5,
|
||||
-2.0 + wave_ultra_slow_cos * 0.15,
|
||||
8.0 + wave_ultra_slow * 0.5,
|
||||
) / 11.0;
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * 0.06);
|
||||
next.r_hand.scale = Vec3::one() / 11.;
|
||||
0.0 + wave_ultra_slow_cos * 0.15,
|
||||
7.0 + wave_ultra_slow * 0.5,
|
||||
);
|
||||
next.r_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * -0.06);
|
||||
next.r_hand.scale = Vec3::one();
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, -0.1, 8.0);
|
||||
next.l_foot.ori = Quaternion::identity();
|
||||
|
@ -39,17 +39,17 @@ impl Animation for JumpAnimation {
|
||||
-8.0,
|
||||
0.0 + wave_stop * 3.8,
|
||||
7.0 + wave_stop * 3.2 - wave * 0.4,
|
||||
) / 11.0;
|
||||
);
|
||||
next.l_hand.ori = Quaternion::rotation_x(wave_stop_alt * 0.6);
|
||||
next.l_hand.scale = Vec3::one() / 11.0;
|
||||
next.l_hand.scale = Vec3::one();
|
||||
|
||||
next.r_hand.offset = Vec3::new(
|
||||
8.0,
|
||||
0.0 + wave_stop * -3.8,
|
||||
7.0 + wave_stop * 3.2 - wave * 0.4,
|
||||
) / 11.0;
|
||||
);
|
||||
next.r_hand.ori = Quaternion::rotation_x(-wave_stop_alt * 0.6);
|
||||
next.r_hand.scale = Vec3::one() / 11.0;
|
||||
next.r_hand.scale = Vec3::one();
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, 1.0, 6.0);
|
||||
next.l_foot.ori = Quaternion::rotation_x(wave_stop * -1.2 - wave_slow * 0.2);
|
||||
|
@ -1,14 +1,20 @@
|
||||
pub mod attack;
|
||||
pub mod cidle;
|
||||
pub mod crun;
|
||||
pub mod gliding;
|
||||
pub mod idle;
|
||||
pub mod jump;
|
||||
pub mod roll;
|
||||
pub mod run;
|
||||
|
||||
// Reexports
|
||||
pub use self::attack::AttackAnimation;
|
||||
pub use self::cidle::CidleAnimation;
|
||||
pub use self::crun::CrunAnimation;
|
||||
pub use self::gliding::GlidingAnimation;
|
||||
pub use self::idle::IdleAnimation;
|
||||
pub use self::jump::JumpAnimation;
|
||||
pub use self::roll::RollAnimation;
|
||||
pub use self::run::RunAnimation;
|
||||
|
||||
use super::{Bone, Skeleton};
|
||||
@ -68,8 +74,8 @@ impl Skeleton for CharacterSkeleton {
|
||||
FigureBoneData::new(torso_mat * chest_mat),
|
||||
FigureBoneData::new(torso_mat * self.belt.compute_base_matrix()),
|
||||
FigureBoneData::new(torso_mat * self.shorts.compute_base_matrix()),
|
||||
FigureBoneData::new(l_hand_mat),
|
||||
FigureBoneData::new(self.r_hand.compute_base_matrix()),
|
||||
FigureBoneData::new(torso_mat * l_hand_mat),
|
||||
FigureBoneData::new(torso_mat * self.r_hand.compute_base_matrix()),
|
||||
FigureBoneData::new(torso_mat * self.l_foot.compute_base_matrix()),
|
||||
FigureBoneData::new(torso_mat * self.r_foot.compute_base_matrix()),
|
||||
FigureBoneData::new(torso_mat * chest_mat * weapon_mat),
|
||||
|
98
voxygen/src/anim/character/roll.rs
Normal file
98
voxygen/src/anim/character/roll.rs
Normal file
@ -0,0 +1,98 @@
|
||||
use super::{super::Animation, CharacterSkeleton};
|
||||
use std::{f32::consts::PI, ops::Mul};
|
||||
use vek::*;
|
||||
|
||||
pub struct RollAnimation;
|
||||
|
||||
impl Animation for RollAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = f64;
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
global_time: f64,
|
||||
anim_time: f64,
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave = (anim_time as f32 * 5.5).sin();
|
||||
let wave_quick = (anim_time as f32 * 9.5).sin();
|
||||
let wave_quick_cos = (anim_time as f32 * 9.5).cos();
|
||||
let wave_cos = (anim_time as f32 * 5.5).cos();
|
||||
let wave_slow = (anim_time as f32 * 2.8 + PI).sin();
|
||||
let wave_dub = (anim_time as f32 * 5.5).sin();
|
||||
|
||||
next.head.offset = Vec3::new(0.0, 0.0 + wave_slow * -3.0, 9.0 + wave_dub * -5.0);
|
||||
next.head.ori = Quaternion::rotation_x(wave_dub * -0.4);
|
||||
next.head.scale = Vec3::one();
|
||||
|
||||
next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_dub * -2.5);
|
||||
next.chest.ori = Quaternion::rotation_x(wave_dub * -0.5);
|
||||
next.chest.scale = Vec3::one() * 1.01;
|
||||
|
||||
next.belt.offset = Vec3::new(0.0, 0.0, 5.0);
|
||||
next.belt.ori = Quaternion::rotation_x(0.0);
|
||||
next.belt.scale = Vec3::one();
|
||||
|
||||
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0);
|
||||
next.shorts.ori = Quaternion::rotation_x(0.0);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-5.5 + wave * -0.5,
|
||||
-2.0 + wave_quick_cos * -5.5,
|
||||
8.0 + wave_quick * 0.5,
|
||||
);
|
||||
|
||||
next.l_hand.ori =
|
||||
Quaternion::rotation_x(wave_slow * 6.5) * Quaternion::rotation_y(wave * 0.3);
|
||||
next.l_hand.scale = Vec3::one();
|
||||
|
||||
next.r_hand.offset = Vec3::new(
|
||||
5.5 + wave * 0.5,
|
||||
-2.0 + wave_quick_cos * 2.5,
|
||||
8.0 + wave_quick * 3.0,
|
||||
);
|
||||
next.r_hand.ori =
|
||||
Quaternion::rotation_x(wave_slow * 6.5) * Quaternion::rotation_y(wave * 0.3);
|
||||
next.r_hand.scale = Vec3::one();
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, -0.1, 9.0 - 0.0 + wave_dub * -1.2 + wave_slow * 4.0);
|
||||
next.l_foot.ori = Quaternion::rotation_x(wave * 0.6);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, -0.1, 9.0 - 0.0 + wave_dub * -1.0 + wave_slow * 4.0);
|
||||
next.r_foot.ori = Quaternion::rotation_x(wave * -0.4);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.weapon.offset = Vec3::new(-7.0, -7.0, 15.0);
|
||||
next.weapon.ori =
|
||||
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + wave_quick * 1.0);
|
||||
next.weapon.scale = Vec3::one();
|
||||
|
||||
next.l_shoulder.offset = Vec3::new(-10.0, -3.2, 2.5);
|
||||
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.l_shoulder.scale = Vec3::one() * 1.04;
|
||||
|
||||
next.r_shoulder.offset = Vec3::new(0.0, -3.2, 2.5);
|
||||
next.r_shoulder.ori = Quaternion::rotation_x(0.0);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.04;
|
||||
|
||||
next.draw.offset = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.draw.ori = Quaternion::rotation_y(0.0);
|
||||
next.draw.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.left_equip.offset = Vec3::new(0.0, 0.0, 5.0) / 11.0;
|
||||
next.left_equip.ori = Quaternion::rotation_x(0.0);;
|
||||
next.left_equip.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.right_equip.offset = Vec3::new(0.0, 0.0, 5.0) / 11.0;
|
||||
next.right_equip.ori = Quaternion::rotation_x(0.0);;
|
||||
next.right_equip.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, -2.2, 0.1 + wave_dub * 16.0) / 11.0;
|
||||
next.torso.ori = Quaternion::rotation_x(wave_slow * 6.0);
|
||||
next.torso.scale = Vec3::one() / 11.0;
|
||||
next
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
use super::{super::Animation, CharacterSkeleton};
|
||||
use std::f32::consts::PI;
|
||||
use std::ops::Mul;
|
||||
use vek::*;
|
||||
|
||||
@ -15,8 +16,11 @@ impl Animation for RunAnimation {
|
||||
) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave = (anim_time as f32 * 14.0).sin();
|
||||
let wave_cos = (anim_time as f32 * 14.0).cos();
|
||||
let wave = (anim_time as f32 * 12.0).sin();
|
||||
let wave_cos = (anim_time as f32 * 12.0).cos();
|
||||
let wave_diff = (anim_time as f32 * 12.0 + PI / 2.0).sin();
|
||||
let wave_cos_dub = (anim_time as f32 * 24.0).cos();
|
||||
let wave_stop = (anim_time as f32 * 2.6).min(PI / 2.0).sin();
|
||||
|
||||
let head_look = Vec2::new(
|
||||
((global_time + anim_time) as f32 / 2.0)
|
||||
@ -48,24 +52,33 @@ impl Animation for RunAnimation {
|
||||
next.shorts.ori = Quaternion::rotation_z(wave * 0.6);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
next.l_hand.offset = Vec3::new(-9.0, 3.0 + wave_cos * 8.0, 12.0 - wave * 1.0) / 11.0;
|
||||
next.l_hand.ori = Quaternion::rotation_x(wave_cos * 1.1);
|
||||
next.l_hand.scale = Vec3::one() / 11.0;
|
||||
next.l_hand.offset = Vec3::new(
|
||||
-7.5 + wave_cos_dub * 1.0,
|
||||
2.0 + wave_cos * 5.0,
|
||||
7.0 - wave * 1.5,
|
||||
);
|
||||
next.l_hand.ori = Quaternion::rotation_x(wave_cos * 0.8);
|
||||
next.l_hand.scale = Vec3::one() * 1.0;
|
||||
|
||||
next.r_hand.offset = Vec3::new(9.0, 3.0 - wave_cos * 8.0, 12.0 + wave * 1.0) / 11.0;
|
||||
next.r_hand.ori = Quaternion::rotation_x(wave_cos * -1.1);
|
||||
next.r_hand.scale = Vec3::one() / 11.0;
|
||||
next.r_hand.offset = Vec3::new(
|
||||
7.5 - wave_cos_dub * 1.0,
|
||||
2.0 - wave_cos * 5.0,
|
||||
7.0 + wave * 1.5,
|
||||
);
|
||||
next.r_hand.ori = Quaternion::rotation_x(wave_cos * -0.8);
|
||||
next.r_hand.scale = Vec3::one() * 1.0;
|
||||
|
||||
next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave_cos * 1.0, 6.0);
|
||||
next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave_cos * 1.5);
|
||||
next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave_cos * 1.0, 7.0);
|
||||
next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave_cos * 1.3);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.offset = Vec3::new(3.4, 0.0 - wave_cos * 1.0, 6.0);
|
||||
next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.5);
|
||||
next.r_foot.offset = Vec3::new(3.4, 0.0 - wave_cos * 1.0, 7.0);
|
||||
next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.3);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.weapon.offset = Vec3::new(-7.0, -5.0, 15.0);
|
||||
next.weapon.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
|
||||
next.weapon.ori =
|
||||
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + wave_cos * 0.25);
|
||||
next.weapon.scale = Vec3::one();
|
||||
|
||||
next.l_shoulder.offset = Vec3::new(-10.0, -3.2, 2.5);
|
||||
@ -89,7 +102,8 @@ impl Animation for RunAnimation {
|
||||
next.right_equip.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.torso.offset = Vec3::new(0.0, -0.2, 0.4);
|
||||
next.torso.ori = Quaternion::rotation_x(-velocity * 0.04 - wave_cos * 0.10);
|
||||
next.torso.ori =
|
||||
Quaternion::rotation_x(wave_stop * velocity * -0.06 + wave_diff * velocity * -0.005);
|
||||
next.torso.scale = Vec3::one() / 11.0;
|
||||
|
||||
next
|
||||
|
@ -103,7 +103,7 @@ font_ids! {
|
||||
pub struct DebugInfo {
|
||||
pub tps: f64,
|
||||
pub ping_ms: f64,
|
||||
pub coordinates: Option<comp::phys::Pos>,
|
||||
pub coordinates: Option<comp::Pos>,
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
@ -312,7 +312,7 @@ impl Hud {
|
||||
if self.show.ingame {
|
||||
let ecs = client.state().ecs();
|
||||
let actor = ecs.read_storage::<comp::Actor>();
|
||||
let pos = ecs.read_storage::<comp::phys::Pos>();
|
||||
let pos = ecs.read_storage::<comp::Pos>();
|
||||
let stats = ecs.read_storage::<comp::Stats>();
|
||||
let player = ecs.read_storage::<comp::Player>();
|
||||
let entities = ecs.entities();
|
||||
@ -322,7 +322,7 @@ impl Hud {
|
||||
let player_pos = client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<comp::phys::Pos>()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(client.entity())
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
let mut name_id_walker = self.ids.name_tags.walk();
|
||||
|
@ -108,7 +108,7 @@ impl PlayState for CharSelectionState {
|
||||
if let Err(err) = self
|
||||
.client
|
||||
.borrow_mut()
|
||||
.tick(comp::Control::default(), clock.get_last_delta())
|
||||
.tick(comp::Controller::default(), clock.get_last_delta())
|
||||
{
|
||||
error!("Failed to tick the scene: {:?}", err);
|
||||
return PlayStateResult::Pop;
|
||||
|
@ -477,15 +477,15 @@ impl FigureMgr {
|
||||
let player_pos = client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<comp::phys::Pos>()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(client.entity())
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
for (entity, pos, vel, ori, actor, animation_info, stats) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::phys::Pos>(),
|
||||
&ecs.read_storage::<comp::phys::Vel>(),
|
||||
&ecs.read_storage::<comp::phys::Ori>(),
|
||||
&ecs.read_storage::<comp::Pos>(),
|
||||
&ecs.read_storage::<comp::Vel>(),
|
||||
&ecs.read_storage::<comp::Ori>(),
|
||||
&ecs.read_storage::<comp::Actor>(),
|
||||
&ecs.read_storage::<comp::AnimationInfo>(),
|
||||
ecs.read_storage::<comp::Stats>().maybe(),
|
||||
@ -556,10 +556,25 @@ impl FigureMgr {
|
||||
time,
|
||||
animation_info.time,
|
||||
),
|
||||
comp::Animation::Roll => character::RollAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
time,
|
||||
animation_info.time,
|
||||
),
|
||||
comp::Animation::Crun => character::CrunAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
(vel.0.magnitude(), time),
|
||||
animation_info.time,
|
||||
),
|
||||
comp::Animation::Cidle => character::CidleAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
time,
|
||||
animation_info.time,
|
||||
),
|
||||
comp::Animation::Gliding => {
|
||||
character::GlidingAnimation::update_skeleton(
|
||||
state.skeleton_mut(),
|
||||
time,
|
||||
(vel.0.magnitude(), time),
|
||||
animation_info.time,
|
||||
)
|
||||
}
|
||||
@ -661,15 +676,15 @@ impl FigureMgr {
|
||||
let player_pos = client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<comp::phys::Pos>()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(client.entity())
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
for (entity, _, _, _, actor, _, _) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::phys::Pos>(),
|
||||
&ecs.read_storage::<comp::phys::Vel>(),
|
||||
&ecs.read_storage::<comp::phys::Ori>(),
|
||||
&ecs.read_storage::<comp::Pos>(),
|
||||
&ecs.read_storage::<comp::Vel>(),
|
||||
&ecs.read_storage::<comp::Ori>(),
|
||||
&ecs.read_storage::<comp::Actor>(),
|
||||
&ecs.read_storage::<comp::AnimationInfo>(),
|
||||
ecs.read_storage::<comp::Stats>().maybe(),
|
||||
|
@ -110,7 +110,7 @@ impl Scene {
|
||||
let player_pos = client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage::<comp::phys::Pos>()
|
||||
.read_storage::<comp::Pos>()
|
||||
.get(client.entity())
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{clock::Clock, comp, comp::phys::Pos, msg::ClientState};
|
||||
use common::{clock::Clock, comp, comp::Pos, msg::ClientState};
|
||||
use log::{error, warn};
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use vek::*;
|
||||
@ -16,8 +16,9 @@ use vek::*;
|
||||
pub struct SessionState {
|
||||
scene: Scene,
|
||||
client: Rc<RefCell<Client>>,
|
||||
key_state: KeyState,
|
||||
hud: Hud,
|
||||
key_state: KeyState,
|
||||
controller: comp::Controller,
|
||||
}
|
||||
|
||||
/// Represents an active game session (i.e., the one being played).
|
||||
@ -30,6 +31,7 @@ impl SessionState {
|
||||
scene,
|
||||
client,
|
||||
key_state: KeyState::new(),
|
||||
controller: comp::Controller::default(),
|
||||
hud: Hud::new(window),
|
||||
}
|
||||
}
|
||||
@ -45,22 +47,8 @@ const BG_COLOR: Rgba<f32> = Rgba {
|
||||
|
||||
impl SessionState {
|
||||
/// Tick the session (and the client attached to it).
|
||||
pub fn tick(&mut self, dt: Duration) -> Result<(), Error> {
|
||||
// Calculate the movement input vector of the player from the current key presses
|
||||
// and the camera direction.
|
||||
let ori = self.scene.camera().get_orientation();
|
||||
let unit_vecs = (
|
||||
Vec2::new(ori[0].cos(), -ori[0].sin()),
|
||||
Vec2::new(ori[0].sin(), ori[0].cos()),
|
||||
);
|
||||
let dir_vec = self.key_state.dir_vec();
|
||||
let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
|
||||
|
||||
for event in self
|
||||
.client
|
||||
.borrow_mut()
|
||||
.tick(comp::Control { move_dir }, dt)?
|
||||
{
|
||||
fn tick(&mut self, dt: Duration) -> Result<(), Error> {
|
||||
for event in self.client.borrow_mut().tick(self.controller.clone(), dt)? {
|
||||
match event {
|
||||
client::Event::Chat(msg) => {
|
||||
self.hud.new_message(msg);
|
||||
@ -127,19 +115,22 @@ impl PlayState for SessionState {
|
||||
Event::Close => {
|
||||
return PlayStateResult::Shutdown;
|
||||
}
|
||||
Event::InputUpdate(GameInput::Attack, true) => {
|
||||
self.client.borrow_mut().attack();
|
||||
self.client.borrow_mut().respawn();
|
||||
Event::InputUpdate(GameInput::Attack, state) => {
|
||||
self.controller.attack = state;
|
||||
self.controller.respawn = state; // TODO: Don't do both
|
||||
}
|
||||
Event::InputUpdate(GameInput::Jump, true) => {
|
||||
self.client.borrow_mut().jump();
|
||||
Event::InputUpdate(GameInput::Roll, state) => {
|
||||
self.controller.roll = state;
|
||||
}
|
||||
Event::InputUpdate(GameInput::Jump, state) => {
|
||||
self.controller.jump = state;
|
||||
}
|
||||
Event::InputUpdate(GameInput::MoveForward, state) => self.key_state.up = state,
|
||||
Event::InputUpdate(GameInput::MoveBack, state) => self.key_state.down = state,
|
||||
Event::InputUpdate(GameInput::MoveLeft, state) => self.key_state.left = state,
|
||||
Event::InputUpdate(GameInput::MoveRight, state) => self.key_state.right = state,
|
||||
Event::InputUpdate(GameInput::Glide, state) => {
|
||||
self.client.borrow_mut().glide(state)
|
||||
self.controller.glide = state;
|
||||
}
|
||||
|
||||
// Pass all other events to the scene
|
||||
@ -149,6 +140,16 @@ impl PlayState for SessionState {
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the movement input vector of the player from the current key presses
|
||||
// and the camera direction.
|
||||
let ori = self.scene.camera().get_orientation();
|
||||
let unit_vecs = (
|
||||
Vec2::new(ori[0].cos(), -ori[0].sin()),
|
||||
Vec2::new(ori[0].sin(), ori[0].cos()),
|
||||
);
|
||||
let dir_vec = self.key_state.dir_vec();
|
||||
self.controller.move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
|
||||
|
||||
// Perform an in-game tick.
|
||||
if let Err(err) = self.tick(clock.get_last_delta()) {
|
||||
error!("Failed to tick the scene: {:?}", err);
|
||||
|
@ -31,6 +31,7 @@ pub struct ControlSettings {
|
||||
pub screenshot: KeyMouse,
|
||||
pub toggle_ingame_ui: KeyMouse,
|
||||
pub attack: KeyMouse,
|
||||
pub roll: KeyMouse,
|
||||
}
|
||||
|
||||
impl Default for ControlSettings {
|
||||
@ -59,6 +60,7 @@ impl Default for ControlSettings {
|
||||
screenshot: KeyMouse::Key(VirtualKeyCode::F4),
|
||||
toggle_ingame_ui: KeyMouse::Key(VirtualKeyCode::F6),
|
||||
attack: KeyMouse::Mouse(MouseButton::Left),
|
||||
roll: KeyMouse::Mouse(MouseButton::Middle),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ pub enum GameInput {
|
||||
Screenshot,
|
||||
ToggleIngameUi,
|
||||
Attack,
|
||||
Roll,
|
||||
Respawn,
|
||||
}
|
||||
|
||||
@ -134,6 +135,7 @@ impl Window {
|
||||
GameInput::ToggleIngameUi,
|
||||
);
|
||||
key_map.insert(settings.controls.attack, GameInput::Attack);
|
||||
key_map.insert(settings.controls.roll, GameInput::Roll);
|
||||
|
||||
Ok(Self {
|
||||
events_loop,
|
||||
|
Loading…
Reference in New Issue
Block a user