use gizmo_core::world::World;
use gizmo_math::{Quat, Vec3};
use gizmo_physics_core::Transform;
#[derive(Debug, Clone, Copy)]
pub struct Spin {
pub axis: Vec3,
pub angular_velocity: f32,
pub rest_rotation: Quat,
pub angle: f32,
}
impl Spin {
pub fn new(axis: Vec3, angular_velocity: f32) -> Self {
let axis = if axis.length_squared() > 1e-9 {
axis.normalize()
} else {
Vec3::X
};
Self {
axis,
angular_velocity,
rest_rotation: Quat::IDENTITY,
angle: 0.0,
}
}
pub fn with_rest_rotation(mut self, rest: Quat) -> Self {
self.rest_rotation = rest;
self
}
}
gizmo_core::impl_component!(Spin);
pub struct SpinSystem;
impl gizmo_core::system::System for SpinSystem {
fn access_info(&self) -> gizmo_core::system::AccessInfo {
let mut info = gizmo_core::system::AccessInfo::new();
info.is_exclusive = true; info
}
fn run(&mut self, world: &World, dt: f32) {
if let Some(mut q) = unsafe {
world.query_unchecked::<(
gizmo_core::query::Mut<Spin>,
gizmo_core::query::Mut<Transform>,
)>()
} {
for (_id, (mut spin, mut t)) in q.iter_mut() {
spin.angle += spin.angular_velocity * dt;
t.rotation = spin.rest_rotation * Quat::from_axis_angle(spin.axis, spin.angle);
t.update_local_matrix();
}
}
}
}
pub struct SpinPlugin;
impl<State: 'static> crate::app::Plugin<State> for SpinPlugin {
fn build(&self, app: &mut crate::app::App<State>) {
app.schedule.add_di_system(
gizmo_core::system::SystemConfig::new(Box::new(SpinSystem)).label("spin"),
);
}
}
#[cfg(test)]
mod tests {
use super::*;
use gizmo_core::system::System;
use gizmo_core::world::World;
#[test]
fn spin_system_rotates_transform_over_rest() {
let mut world = World::new();
let e = world.spawn();
let rest = Quat::from_rotation_y(0.5);
world.add_component(e, Transform::new(Vec3::ZERO));
world.add_component(e, Spin::new(Vec3::X, 2.0).with_rest_rotation(rest));
let mut sys = SpinSystem;
for _ in 0..60 {
sys.run(&world, 1.0 / 60.0);
}
let t = world.borrow::<Transform>();
let rot = t.get(e.id()).unwrap().rotation;
let expected = rest * Quat::from_axis_angle(Vec3::X, 2.0);
assert!(
rot.dot(expected).abs() > 0.9999,
"Spin rest'in üzerine ~2 rad döndürmeli"
);
let spins = world.borrow::<Spin>();
assert!((spins.get(e.id()).unwrap().angle - 2.0).abs() < 1e-3);
}
}