cyber_rider/src/camera.rs
Joe Ardent 4708eabdd9 ok, the wheels keep going through the planet and getting stuck
I'm going to need to do like raycasting from each wheel or something to do this right.
2023-01-26 17:16:05 -08:00

131 lines
3.6 KiB
Rust

use bevy::prelude::*;
use crate::{bike::CyberBikeModel, input::InputState};
// 85 degrees in radians
const MAX_PITCH: f32 = 1.48353;
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash, Component)]
enum CyberCameras {
Hero,
Debug,
}
#[derive(Debug, Resource)]
pub struct DebugCamOffset {
pub rot: f32,
pub dist: f32,
pub alt: f32,
}
impl Default for DebugCamOffset {
fn default() -> Self {
DebugCamOffset {
rot: 60.0,
dist: 10.0,
alt: 4.0,
}
}
}
impl CyberCameras {
fn next(self) -> Self {
match self {
CyberCameras::Debug => CyberCameras::Hero,
CyberCameras::Hero => CyberCameras::Debug,
}
}
}
fn setup_cybercams(mut commands: Commands) {
let hero_projection = PerspectiveProjection {
fov: std::f32::consts::FRAC_PI_3,
..Default::default()
};
commands
.spawn(Camera3dBundle {
projection: bevy::render::camera::Projection::Perspective(hero_projection),
..Default::default()
})
.insert(CyberCameras::Hero);
commands
.spawn(Camera3dBundle::default())
.insert(CyberCameras::Debug);
}
fn follow_cyberbike(
mut query: ParamSet<(
// 0: the bike
Query<&Transform, With<CyberBikeModel>>,
// 1: the cameras
Query<(&mut Transform, &CyberCameras)>,
)>,
input: Res<InputState>,
offset: Res<DebugCamOffset>,
) {
let bike_xform = *query.p0().single();
let up = bike_xform.translation.normalize();
for (mut cam_xform, cam_type) in query.p1().iter_mut() {
match *cam_type {
CyberCameras::Hero => {
let look_at = bike_xform.translation + (bike_xform.forward() * 200.0);
let cam_pos = bike_xform.translation + (bike_xform.back() * 1.05) + (up * 1.08);
cam_xform.translation = cam_pos;
cam_xform.look_at(look_at, up);
// handle input pitch
let angle = input.pitch.powi(3) * MAX_PITCH;
let axis = cam_xform.right();
cam_xform.rotate(Quat::from_axis_angle(axis, angle));
}
CyberCameras::Debug => {
let mut ncx = bike_xform.to_owned();
ncx.rotate(Quat::from_axis_angle(up, offset.rot.to_radians()));
ncx.translation += ncx.forward() * offset.dist;
ncx.translation += ncx.up() * offset.alt;
*cam_xform = ncx;
cam_xform.look_at(bike_xform.translation, up);
}
}
}
}
fn update_active_camera(
state: Res<State<CyberCameras>>,
mut query: Query<(&mut Camera, &CyberCameras)>,
) {
// find the camera with the current state, set it as the ActiveCamera
query.iter_mut().for_each(|(mut cam, cyber)| {
if cyber.eq(state.current()) {
cam.is_active = true;
} else {
cam.is_active = false;
}
});
}
fn cycle_cam_state(mut state: ResMut<State<CyberCameras>>, mut keys: ResMut<Input<KeyCode>>) {
if keys.just_pressed(KeyCode::D) {
let new_state = state.current().next();
info!("{:?}", new_state);
state.set(new_state).unwrap();
keys.reset(KeyCode::D);
}
}
pub struct CyberCamPlugin;
impl Plugin for CyberCamPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
// common stuff
app.insert_resource(DebugCamOffset::default())
.add_startup_system(setup_cybercams)
.add_state(CyberCameras::Hero)
.add_system(cycle_cam_state)
.add_system(update_active_camera)
.add_system(follow_cyberbike);
}
}