use std::any::TypeId;
use atomic_refcell::{AtomicRef, AtomicRefMut};
use cgmath::{Matrix4, Vector2, Vector3};
use gilrs::{Axis, Button, GamepadId};
use super::{
dispatcher::{EventDispatcher, EventType, SubEventType},
super::{
ecs::{resource::ResourceRefMut, component::{ComponentRefMut, Component}, world:: World, query::Query},
physics::{transform::{Transform, Position}, collision::Collision, velocity::Velocity, gravity::Gravity, rigid_body::{RigidBody, BodyType}},
managers::render::{manager::RenderState, cache},
text::{text::TextHolder, font::Font},
color::color::Color,
camera::camera2d::Camera2d,
animation::{animation::Animation, looping_state::LoopingState, animation_state::AnimationState},
bindings::gamepad::{gamepad_input::GamepadInput, gamepad_instance::GamepadInstance}
}
};
pub(crate) fn events(world: &mut World, render_state: &RenderState) {
let mut event_dispatcher: ResourceRefMut<'_, EventDispatcher> = world.get_resource_mut::<EventDispatcher>().unwrap();
let events: Vec<_> = event_dispatcher.drain().into();
for event in events {
match &event.event_type {
EventType::Transform(sub_event_type) => {
let mut transform: ComponentRefMut<'_, Transform> = world.get_entity_component_mut::<Transform>(&event.entity).unwrap();
if let Some(value) = event.get::<Vector2<f32>>() {
if sub_event_type == &SubEventType::UpdatePixelatedPosition {
transform.position.x = value.x;
transform.position.y = value.y;
transform.dirty_position = false;
} else {
transform.scale.x = value.x;
transform.scale.y = value.y;
transform.dirty_scale = false;
}
}
},
EventType::Text(sub_event_type) => {
let mut text_holder: ResourceRefMut<'_, TextHolder> = world.get_resource_mut::<TextHolder>().unwrap();
if let Some(text_renderer) = text_holder.text_renderers.get_mut(&event.entity.0) {
match sub_event_type {
SubEventType::UpdateTextFont => {
if let Some(font) = event.get::<Font>() {
text_renderer.font(
font.clone(),
render_state.queue.clone(),
render_state.physical_size.clone()
);
}
},
SubEventType::UpdateTextPosition => {
if let Some(position) = event.get::<Position>() {
text_renderer.position(
position.clone(),
render_state.queue.clone(),
render_state.physical_size.clone()
);
}
},
SubEventType::UpdateTextContent => {
if let Some(content) = event.get::<String>() {
text_renderer.content(
content.clone(),
render_state.queue.clone(),
render_state.physical_size.clone()
);
}
},
SubEventType::UpdateTextColor => {
if let Some(color) = event.get::<Color>() {
text_renderer.color(
color.clone(),
render_state.queue.clone(),
render_state.physical_size.clone()
);
}
},
_ => {}
}
}
},
EventType::Gamepad(sub_event_type) => {
let mut gamepad_input: ResourceRefMut<'_, GamepadInput> = world.get_resource_mut::<GamepadInput>().unwrap();
match sub_event_type {
SubEventType::GamepadConnected => {
let id: &GamepadId = event.get::<GamepadId>().unwrap();
if gamepad_input.instances.get_mut(id).is_some() {
gamepad_input.instances.get_mut(id).unwrap().connect();
} else {
gamepad_input.instances.insert(id.clone(), GamepadInstance::default());
}
},
SubEventType::GamepadDisconnected => {
gamepad_input.instances.get_mut(event.get::<GamepadId>().unwrap()).map(|instance| instance.disconnect());
},
SubEventType::GamepadButtonPressed => {
let (id, button): &(GamepadId, Button) = event.get::<(GamepadId, Button)>().unwrap();
gamepad_input.instances.get_mut(id).map(|instance| instance.pressed.insert(button.clone()));
},
SubEventType::GamepadButtonReleased => {
let (id, button): &(GamepadId, Button) = event.get::<(GamepadId, Button)>().unwrap();
gamepad_input.instances.get_mut(id).map(|instance| instance.pressed.remove(button));
},
SubEventType::GamepadAxisChanged => {
let (id, axis, direction): &(GamepadId, Axis, f32) = event.get::<(GamepadId, Axis, f32)>().unwrap();
gamepad_input.instances.get_mut(id).map(|instance| instance.joystick(axis, direction));
}
_ => {}
}
}
}
}
}
pub(crate) fn camera(world: &mut World, render_state: &mut RenderState) {
let (target_entity, target_position) = {
let camera2d: ResourceRefMut<'_, Camera2d> = world.get_resource_mut::<Camera2d>().unwrap();
if let Some(entity) = camera2d.target {
if let Some(transform) = world.get_entity_component::<Transform>(&entity) {
(Some(entity), Some(transform.position.clone()))
} else {
(None, None)
}
} else {
(None, None)
}
};
if let (Some(entity), Some(position)) = (target_entity, target_position) {
let mut camera2d: ResourceRefMut<'_, Camera2d> = world.get_resource_mut::<Camera2d>().unwrap();
camera2d.transform.position = position.clone();
camera2d.view_matrix = Matrix4::from_translation(Vector3::new(
-position.x.clone(),
-position.y,
0.0
));
let _ = cache::buffer::get_projection_or_view_buffer(
render_state,
true,
Some(&entity),
&camera2d
);
let _ = cache::buffer::get_projection_or_view_buffer(
render_state,
false,
Some(&entity),
&camera2d
);
}
}
pub(crate) fn animations(world: &mut World, delta: f32) {
let mut query: Query<'_> = Query::new(&world).with::<Animation>();
for entity in query.entities_with_components().unwrap() {
if let Some(mut animation) = world.get_entity_component_mut::<Animation>(&entity) {
let mut to_remove_from_stack: Vec<String> = Vec::new();
for (title, sprite_sheet) in animation.sprite_sheets.iter_mut() {
if sprite_sheet.animation_state != AnimationState::Playing {
continue;
}
sprite_sheet.timer.tick(delta);
if sprite_sheet.timer.is_finished() {
sprite_sheet.current_index = (sprite_sheet.current_index + 1) % sprite_sheet.indices.len() as u32;
if &sprite_sheet.current_index == sprite_sheet.indices.last().unwrap() && sprite_sheet.looping_state != LoopingState::Repeat {
sprite_sheet.animation_state = AnimationState::Finished;
to_remove_from_stack.push(title.clone());
}
}
}
for title in to_remove_from_stack {
animation.playing_stack.retain(|t| *t != title);
}
}
}
}
pub(crate) fn gravity(world: &mut World, render_state: &mut RenderState, delta: f32) {
let mut query: Query<'_> = Query::new(world).with::<Gravity>()
.with::<Transform>()
.with::<Velocity>()
.with::<RigidBody>();
for entity in query.entities_with_components().unwrap() {
if let (Some(gravity), Some(mut transform), Some(mut velocity), Some(rigid_body)) = (
world.get_entity_component::<Gravity>(&entity),
world.get_entity_component_mut::<Transform>(&entity),
world.get_entity_component_mut::<Velocity>(&entity),
world.get_entity_component::<RigidBody>(&entity)
) {
if rigid_body.body_type == BodyType::Dynamic && rigid_body.rest == false {
velocity.y -= gravity.value * rigid_body.friction * delta;
let new_y: f32 = transform.position.y + velocity.y * delta;
transform.set_position_y(render_state, new_y);
}
}
}
}
pub(crate) fn collisions(world: &mut World) {
for archetype in world.archetypes.values_mut() {
if let (Some(transforms), Some(collisions)) = (
archetype.components.get(&TypeId::of::<Transform>()),
archetype.components.get(&TypeId::of::<Collision>())
) {
for (transform, collision) in transforms.iter().zip(collisions) {
let transform_ref: AtomicRef<'_, Box<dyn Component>> = transform.borrow();
let mut collision_ref: AtomicRefMut<'_, Box<dyn Component>> = collision.borrow_mut();
if let (Some(transform), Some(collision)) = (
transform_ref.as_any().downcast_ref::<Transform>(),
collision_ref.as_any_mut().downcast_mut::<Collision>()
) {
collision.collider.position = transform.position.to_vec();
collision.collider.scale = transform.scale;
}
}
}
}
}