use crate::engine::ecs::ComponentId;
use crate::engine::ecs::component::{Component, ComponentRef};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CollisionResponseMode {
Slide,
Push,
}
#[derive(Debug, Clone)]
pub struct CollisionResponseComponent {
pub enabled: bool,
pub mode: CollisionResponseMode,
pub max_iterations: u32,
pub push_out_epsilon: f32,
pub push_strength: f32,
pub friction: f32,
pub friction_y: f32,
pub max_speed: f32,
pub velocity: [f32; 3],
pub gravity_coefficient: f32,
pub movement_target_source: Option<ComponentRef>,
pub movement_target_id: Option<ComponentId>,
pub(crate) movement_target_required: bool,
component: Option<ComponentId>,
}
impl CollisionResponseComponent {
pub fn new(mode: CollisionResponseMode) -> Self {
Self {
enabled: true,
mode,
max_iterations: 6,
push_out_epsilon: 0.001,
push_strength: 4.0,
friction: 0.0,
friction_y: 0.0,
max_speed: 6.0,
velocity: [0.0, 0.0, 0.0],
gravity_coefficient: 0.0,
movement_target_source: None,
movement_target_id: None,
movement_target_required: false,
component: None,
}
}
pub fn slide() -> Self {
let mut c = Self::new(CollisionResponseMode::Slide);
c.push_strength = 0.0;
c.friction = 0.0;
c.max_speed = 0.0;
c
}
pub fn push() -> Self {
Self::new(CollisionResponseMode::Push)
}
pub fn with_push_strength(mut self, push_strength: f32) -> Self {
self.push_strength = push_strength;
self
}
pub fn with_friction(mut self, friction: f32) -> Self {
self.friction = friction.max(0.0);
self
}
pub fn with_friction_y(mut self, friction_y: f32) -> Self {
self.friction_y = friction_y.max(0.0);
self
}
pub fn movement_target(mut self, target: ComponentRef) -> Self {
self.movement_target_source = Some(target);
self
}
pub(crate) fn with_runtime_movement_target(mut self, target: Option<ComponentId>) -> Self {
self.movement_target_id = target;
self.movement_target_required = true;
self
}
}
impl Default for CollisionResponseComponent {
fn default() -> Self {
Self::slide()
}
}
impl Component for CollisionResponseComponent {
fn name(&self) -> &'static str {
"collision_response"
}
fn set_id(&mut self, component: ComponentId) {
self.component = Some(component);
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn init(&mut self, emit: &mut dyn crate::engine::ecs::SignalEmitter, component: ComponentId) {
emit.push_intent_now(
component,
crate::engine::ecs::IntentValue::RegisterCollisionResponse {
component_id: component,
},
);
}
fn cleanup(
&mut self,
emit: &mut dyn crate::engine::ecs::SignalEmitter,
component: ComponentId,
) {
emit.push_intent_now(
component,
crate::engine::ecs::IntentValue::RemoveCollisionResponse {
component_id: component,
},
);
}
fn to_mms_ast(
&self,
_world: &crate::engine::ecs::World,
) -> crate::scripting::ast::ComponentExpression {
use crate::engine::ecs::component::ce_helpers::*;
let ctor = match self.mode {
CollisionResponseMode::Slide => "slide",
CollisionResponseMode::Push => "push",
};
let mut ce = ce_call("CollisionResponse", ctor, vec![])
.with_call("enabled", vec![b(self.enabled)])
.with_call("max_iterations", vec![num(self.max_iterations as f64)])
.with_call("push_out_epsilon", vec![num(self.push_out_epsilon as f64)])
.with_call("push_strength", vec![num(self.push_strength as f64)])
.with_call("friction", vec![num(self.friction as f64)])
.with_call("friction_y", vec![num(self.friction_y as f64)])
.with_call("max_speed", vec![num(self.max_speed as f64)]);
if let Some(target) = &self.movement_target_source {
let expr = match target {
ComponentRef::Guid(guid) => {
crate::scripting::ast::Expression::String(format!("@uuid:{guid}"))
}
ComponentRef::Query(query) => {
crate::scripting::ast::Expression::String(query.clone())
}
};
ce = ce.with_call("movement_target", vec![expr]);
}
ce
}
}