~starkingdoms/starkingdoms

71ade52ef032a59f7fc96e236eefa00dbc6285d7 — ghostly_zsh 28 days ago dc538d5
even better animation
1 files changed, 33 insertions(+), 15 deletions(-)

M crates/unified/src/client/parts.rs
M crates/unified/src/client/parts.rs => crates/unified/src/client/parts.rs +33 -15
@@ 1,3 1,5 @@
use std::f32::consts::PI;

use crate::attachment::{Joint, JointOf, Joints, PartInShip, Peer, SnapOf, SnapOfJoint};
use crate::client::Me;
use crate::client::colors::GREEN;


@@ 115,9 117,11 @@ struct SnapResource(Option<Entity>, Option<Entity>);
#[derive(Component)]
struct DragGhost;
#[derive(Component)]
struct GhostTarget(pub Quat);
#[derive(Component)]
struct GhostVelocity(pub Vec3);
struct Ghost {
    pub rot: Quat,
    pub last_target_pos: Vec3,
    pub vel: Vec3,
}

const TRANSLATION_SMOOTH: f32 = 0.3;
const ROTATION_SMOOTH: f32 = 0.1;


@@ 147,7 151,11 @@ fn on_part_click(
    }
    let mut s = sprite.0.clone();
    s.color = Color::srgba(0.7, 0.7, 0.7, 1.0);
    commands.spawn((DragGhost, GhostVelocity(Vec3::ZERO), GhostTarget(sprite.1.rotation), *sprite.1, s));
    commands.spawn((DragGhost, Ghost {
        rot: sprite.1.rotation,
        last_target_pos: sprite.1.translation,
        vel: Vec3::ZERO,
    }, *sprite.1, s));

    drag.0 = Some(ev.event().event_target());
}


@@ 191,7 199,7 @@ fn on_part_release(
/// This code is super cursed, and it will break at the lightest breeze
fn update_drag_ghosts(
    ghost: Single<
        (&mut Transform, &mut GhostVelocity, &mut GhostTarget),
        (&mut Transform, &mut Ghost),
        (
            With<DragGhost>,
            Without<SnapOf>,


@@ 213,12 221,12 @@ fn update_drag_ghosts(
) {
    const CUTOFF: f32 = 25.0; // px

    let (mut ghost, mut ghost_velocity, mut ghost_target) = ghost.into_inner();
    let (mut ghost, mut ghost_info) = ghost.into_inner();
    let Some(cursor) = cursor.0 else { return };

    let mut best_distance = f32::INFINITY;
    let mut best_target = Transform::from_xyz(cursor.x, cursor.y, 0.0);
    best_target.rotation = ghost_target.0;
    best_target.rotation = ghost_info.rot;
    let mut snap = None;
    let mut best_parent_position = None;
    let mut best_snap_position = None;


@@ 345,14 353,24 @@ fn update_drag_ghosts(
            -180.0_f32.to_radians() * time.delta_secs(),
        ));
    }
    ghost_target.0 = best_target.rotation;
    ghost.rotation = ghost.rotation.slerp(ghost_target.0, ROTATION_SMOOTH);
    let disp = ghost.translation - best_target.translation;
    const K: f32 = 0.07;
    const C: f32 = 0.5;
    let a = (-K*disp - C*ghost_velocity.0)/2.0;
    ghost.translation += ghost_velocity.0;
    ghost_velocity.0 += a;
    ghost_info.rot = best_target.rotation;
    ghost.rotation = ghost.rotation.slerp(ghost_info.rot, ROTATION_SMOOTH);
    let target_vel = (best_target.translation - ghost_info.last_target_pos)
        /time.delta_secs();
    const F: f32 = 2.0; // frequency (Hz)
    // 0.0 is undamped, 0.0-1.0 is underdamped, 1.0 is critical, and >1.0 is over
    const ZETA: f32 = 0.7; // damping
    const R: f32 = -0.6; // initial response speed
    const K1: f32 = ZETA/(PI*F);
    const K2: f32 = 1.0/((2.0*PI*F)*(2.0*PI*F));
    const K3: f32 = (R*ZETA)/(2.0*PI*F);
    let a = (best_target.translation - ghost.translation
        + K3*target_vel - K1*ghost_info.vel)/K2;

    ghost.translation += ghost_info.vel*time.delta_secs();
    ghost_info.vel += a*time.delta_secs();

    ghost_info.last_target_pos = best_target.translation;

    rsnap.0 = snap;
    rsnap.1 = best_self_snap;