#[cfg(feature = "physics")]
use crate::runner::{CAMERA_FIRST_PERSON, PLAYER_NAME, lookup_named, register_named};
use crate::runner::{CAMERA_FIXED, CAMERA_FLY, CAMERA_NAME_PREFIX, CAMERA_ORBIT};
#[cfg(feature = "physics")]
use nightshade::ecs::physics::commands::spawn_first_person_player;
use nightshade::prelude::*;
pub fn orbit_camera(world: &mut World, focus: Vec3, radius: f32) -> Entity {
despawn_api_camera(world);
let camera = spawn_pan_orbit_camera(world, focus, radius, 0.6, 0.4, CAMERA_ORBIT.to_string());
activate_camera(world, camera);
camera
}
pub fn fly_camera(world: &mut World, position: Vec3) -> Entity {
despawn_api_camera(world);
let camera = spawn_camera(world, position, CAMERA_FLY.to_string());
activate_camera(world, camera);
camera
}
#[cfg(feature = "physics")]
pub fn first_person(world: &mut World, position: Vec3) -> Entity {
despawn_api_camera(world);
let (player, camera) = spawn_first_person_player(world, position);
world.core.set_name(player, Name(PLAYER_NAME.to_string()));
register_named(world, PLAYER_NAME, player);
world
.core
.set_name(camera, Name(CAMERA_FIRST_PERSON.to_string()));
activate_camera(world, camera);
set_cursor_locked(world, true);
set_cursor_visible(world, false);
player
}
pub fn fixed_camera(world: &mut World, eye: Vec3, target: Vec3) -> Entity {
despawn_api_camera(world);
let camera = spawn_camera(world, eye, CAMERA_FIXED.to_string());
if let Some(transform) = mutate_local_transform(world, camera) {
transform.rotation = camera_look_rotation(eye, target, 0.0);
}
activate_camera(world, camera);
camera
}
#[cfg(feature = "physics")]
#[inline]
pub fn set_player_speed(world: &mut World, player: Entity, speed: f32) {
if let Some(controller) = world.core.get_character_controller_mut(player) {
controller.max_speed = speed;
}
}
#[cfg(feature = "physics")]
#[inline]
pub fn set_player_jump(world: &mut World, player: Entity, impulse: f32) {
if let Some(controller) = world.core.get_character_controller_mut(player) {
controller.jump_impulse = impulse;
}
}
pub fn look_at(world: &mut World, eye: Vec3, target: Vec3) {
let Some(camera) = world.resources.active_camera else {
return;
};
if let Some(transform) = mutate_local_transform(world, camera) {
transform.translation = eye;
transform.rotation = camera_look_rotation(eye, target, 0.0);
}
}
pub fn set_orbit_focus(world: &mut World, focus: Vec3) {
let Some(camera) = world.resources.active_camera else {
return;
};
if let Some(orbit) = world.core.get_pan_orbit_camera_mut(camera) {
orbit.target_focus = focus;
}
}
pub fn camera_position(world: &World) -> Vec3 {
world
.resources
.active_camera
.map(|camera| crate::placement::position(world, camera))
.unwrap_or_else(Vec3::zeros)
}
pub fn camera_forward(world: &World) -> Vec3 {
let Some(camera) = world.resources.active_camera else {
return Vec3::new(0.0, 0.0, -1.0);
};
let matrix = crate::placement::world_matrix(world, camera);
nalgebra_glm::vec3(-matrix[(0, 2)], -matrix[(1, 2)], -matrix[(2, 2)]).normalize()
}
fn despawn_api_camera(world: &mut World) {
#[cfg(feature = "physics")]
if let Some(player) = lookup_named(world, PLAYER_NAME) {
despawn_recursive_immediate(world, player);
world.resources.entities.names.remove(PLAYER_NAME);
set_cursor_locked(world, false);
set_cursor_visible(world, true);
}
let api_camera = world.resources.active_camera.filter(|&camera| {
world
.core
.get_name(camera)
.is_some_and(|name| name.0.starts_with(CAMERA_NAME_PREFIX))
});
if let Some(camera) = api_camera {
despawn_recursive_immediate(world, camera);
}
world.resources.active_camera = None;
}
fn activate_camera(world: &mut World, camera: Entity) {
world.resources.active_camera = Some(camera);
#[cfg(feature = "audio")]
{
world.core.add_components(camera, AUDIO_LISTENER);
world.core.set_audio_listener(camera, AudioListener);
}
}