mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'fexii/freefly-camera' into 'master'
Add freefly camera mode and cycle camera mode keybind See merge request veloren/veloren!1188
This commit is contained in:
commit
930e0028bc
@ -1083,6 +1083,18 @@ impl Client {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Return true if this client is an admin on the server
|
||||
pub fn is_admin(&self) -> bool {
|
||||
let client_uid = self
|
||||
.state
|
||||
.read_component_cloned::<Uid>(self.entity)
|
||||
.expect("Client doesn't have a Uid!!!");
|
||||
|
||||
self.player_list
|
||||
.get(&client_uid)
|
||||
.map_or(false, |info| info.is_admin)
|
||||
}
|
||||
|
||||
/// Clean client ECS state
|
||||
fn clean_state(&mut self) {
|
||||
let client_uid = self
|
||||
|
@ -8,6 +8,7 @@ const FAR_PLANE: f32 = 100000.0;
|
||||
|
||||
const FIRST_PERSON_INTERP_TIME: f32 = 0.1;
|
||||
const THIRD_PERSON_INTERP_TIME: f32 = 0.1;
|
||||
const FREEFLY_INTERP_TIME: f32 = 0.0;
|
||||
const LERP_ORI_RATE: f32 = 15.0;
|
||||
pub const MIN_ZOOM: f32 = 0.1;
|
||||
|
||||
@ -16,6 +17,7 @@ pub const MIN_ZOOM: f32 = 0.1;
|
||||
pub enum CameraMode {
|
||||
FirstPerson = 0,
|
||||
ThirdPerson = 1,
|
||||
Freefly = 2,
|
||||
}
|
||||
|
||||
impl Default for CameraMode {
|
||||
@ -73,15 +75,7 @@ impl Camera {
|
||||
/// and position of the camera.
|
||||
pub fn compute_dependents(&mut self, terrain: &impl ReadVol) {
|
||||
let dist = {
|
||||
let (start, end) = (
|
||||
self.focus
|
||||
+ (Vec3::new(
|
||||
-f32::sin(self.ori.x) * f32::cos(self.ori.y),
|
||||
-f32::cos(self.ori.x) * f32::cos(self.ori.y),
|
||||
f32::sin(self.ori.y),
|
||||
) * self.dist),
|
||||
self.focus,
|
||||
);
|
||||
let (start, end) = (self.focus - self.forward() * self.dist, self.focus);
|
||||
|
||||
match terrain
|
||||
.ray(start, end)
|
||||
@ -155,13 +149,10 @@ impl Camera {
|
||||
|
||||
/// Zoom the camera by the given delta, limiting the input accordingly.
|
||||
pub fn zoom_by(&mut self, delta: f32) {
|
||||
match self.mode {
|
||||
CameraMode::ThirdPerson => {
|
||||
if self.mode == CameraMode::ThirdPerson {
|
||||
// Clamp camera dist to the 2 <= x <= infinity range
|
||||
self.tgt_dist = (self.tgt_dist + delta).max(2.0);
|
||||
},
|
||||
CameraMode::FirstPerson => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Zoom with the ability to switch between first and third-person mode.
|
||||
@ -181,6 +172,7 @@ impl Camera {
|
||||
self.set_mode(CameraMode::ThirdPerson);
|
||||
self.tgt_dist = MIN_THIRD_PERSON;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -244,6 +236,7 @@ impl Camera {
|
||||
match self.mode {
|
||||
CameraMode::FirstPerson => FIRST_PERSON_INTERP_TIME,
|
||||
CameraMode::ThirdPerson => THIRD_PERSON_INTERP_TIME,
|
||||
CameraMode::Freefly => FREEFLY_INTERP_TIME,
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,6 +280,9 @@ impl Camera {
|
||||
CameraMode::FirstPerson => {
|
||||
self.set_distance(MIN_ZOOM);
|
||||
},
|
||||
CameraMode::Freefly => {
|
||||
self.zoom_by(0.0);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -301,4 +297,45 @@ impl Camera {
|
||||
mode => mode,
|
||||
}
|
||||
}
|
||||
|
||||
/// Cycle the camera to its next valid mode. If is_admin is false then only
|
||||
/// modes which are accessible without admin access will be cycled to.
|
||||
pub fn next_mode(&mut self, is_admin: bool) {
|
||||
self.set_mode(match self.mode {
|
||||
CameraMode::ThirdPerson => CameraMode::FirstPerson,
|
||||
CameraMode::FirstPerson => {
|
||||
if is_admin {
|
||||
CameraMode::Freefly
|
||||
} else {
|
||||
CameraMode::ThirdPerson
|
||||
}
|
||||
},
|
||||
CameraMode::Freefly => CameraMode::ThirdPerson,
|
||||
});
|
||||
}
|
||||
|
||||
/// Return a unit vector in the forward direction for the current camera
|
||||
/// orientation
|
||||
pub fn forward(&self) -> Vec3<f32> {
|
||||
Vec3::new(
|
||||
f32::sin(self.ori.x) * f32::cos(self.ori.y),
|
||||
f32::cos(self.ori.x) * f32::cos(self.ori.y),
|
||||
-f32::sin(self.ori.y),
|
||||
)
|
||||
}
|
||||
|
||||
/// Return a unit vector in the right direction for the current camera
|
||||
/// orientation
|
||||
pub fn right(&self) -> Vec3<f32> {
|
||||
const UP: Vec3<f32> = Vec3::new(0.0, 0.0, 1.0);
|
||||
self.forward().cross(UP).normalized()
|
||||
}
|
||||
|
||||
/// Return a unit vector in the forward direction on the XY plane for
|
||||
/// the current camera orientation
|
||||
pub fn forward_xy(&self) -> Vec2<f32> { Vec2::new(f32::sin(self.ori.x), f32::cos(self.ori.x)) }
|
||||
|
||||
/// Return a unit vector in the right direction on the XY plane for
|
||||
/// the current camera orientation
|
||||
pub fn right_xy(&self) -> Vec2<f32> { Vec2::new(f32::cos(self.ori.x), -f32::sin(self.ori.x)) }
|
||||
}
|
||||
|
@ -120,37 +120,33 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
||||
|
||||
[
|
||||
match camera_mode {
|
||||
CameraMode::ThirdPerson => {
|
||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||
Some(humanoid_head_spec.mesh_head(&body, generate_mesh))
|
||||
},
|
||||
CameraMode::FirstPerson => None,
|
||||
},
|
||||
match camera_mode {
|
||||
CameraMode::ThirdPerson => Some(humanoid_armor_chest_spec.mesh_chest(
|
||||
&body,
|
||||
loadout,
|
||||
generate_mesh,
|
||||
)),
|
||||
CameraMode::ThirdPerson | CameraMode::Freefly => Some(
|
||||
humanoid_armor_chest_spec.mesh_chest(&body, loadout, generate_mesh),
|
||||
),
|
||||
CameraMode::FirstPerson => None,
|
||||
},
|
||||
match camera_mode {
|
||||
CameraMode::ThirdPerson => {
|
||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||
Some(humanoid_armor_belt_spec.mesh_belt(&body, loadout, generate_mesh))
|
||||
},
|
||||
CameraMode::FirstPerson => None,
|
||||
},
|
||||
match camera_mode {
|
||||
CameraMode::ThirdPerson => {
|
||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||
Some(humanoid_armor_back_spec.mesh_back(&body, loadout, generate_mesh))
|
||||
},
|
||||
CameraMode::FirstPerson => None,
|
||||
},
|
||||
match camera_mode {
|
||||
CameraMode::ThirdPerson => Some(humanoid_armor_pants_spec.mesh_pants(
|
||||
&body,
|
||||
loadout,
|
||||
generate_mesh,
|
||||
)),
|
||||
CameraMode::ThirdPerson | CameraMode::Freefly => Some(
|
||||
humanoid_armor_pants_spec.mesh_pants(&body, loadout, generate_mesh),
|
||||
),
|
||||
CameraMode::FirstPerson => None,
|
||||
},
|
||||
Some(humanoid_armor_hand_spec.mesh_left_hand(&body, loadout, generate_mesh)),
|
||||
@ -158,7 +154,7 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
||||
Some(humanoid_armor_foot_spec.mesh_left_foot(&body, loadout, generate_mesh)),
|
||||
Some(humanoid_armor_foot_spec.mesh_right_foot(&body, loadout, generate_mesh)),
|
||||
match camera_mode {
|
||||
CameraMode::ThirdPerson => {
|
||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||
Some(humanoid_armor_shoulder_spec.mesh_left_shoulder(
|
||||
&body,
|
||||
loadout,
|
||||
@ -168,7 +164,7 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
||||
CameraMode::FirstPerson => None,
|
||||
},
|
||||
match camera_mode {
|
||||
CameraMode::ThirdPerson => {
|
||||
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||
Some(humanoid_armor_shoulder_spec.mesh_right_shoulder(
|
||||
&body,
|
||||
loadout,
|
||||
|
@ -239,10 +239,17 @@ impl Scene {
|
||||
},
|
||||
CameraMode::ThirdPerson if scene_data.is_aiming => player_scale * 2.1,
|
||||
CameraMode::ThirdPerson => player_scale * 1.65,
|
||||
CameraMode::Freefly => 0.0,
|
||||
};
|
||||
|
||||
self.camera
|
||||
.set_focus_pos(player_pos + Vec3::unit_z() * (up - tilt.min(0.0).sin() * dist * 0.6));
|
||||
match self.camera.get_mode() {
|
||||
CameraMode::FirstPerson | CameraMode::ThirdPerson => {
|
||||
self.camera.set_focus_pos(
|
||||
player_pos + Vec3::unit_z() * (up - tilt.min(0.0).sin() * dist * 0.6),
|
||||
);
|
||||
},
|
||||
CameraMode::Freefly => {},
|
||||
};
|
||||
|
||||
// Tick camera for interpolation.
|
||||
self.camera.update(
|
||||
|
@ -173,7 +173,9 @@ impl PlayState for SessionState {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut ori = self.scene.camera().get_orientation();
|
||||
let mut walk_forward_dir = self.scene.camera().forward_xy();
|
||||
let mut walk_right_dir = self.scene.camera().right_xy();
|
||||
let mut freefly_vel = Vec3::zero();
|
||||
let mut free_look = false;
|
||||
let mut auto_walk = false;
|
||||
|
||||
@ -517,6 +519,14 @@ impl PlayState for SessionState {
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
Event::InputUpdate(GameInput::CycleCamera, true) => {
|
||||
// Prevent accessing camera modes which aren't available in multiplayer
|
||||
// unless you are an admin. This is an easily bypassed clientside check.
|
||||
// The server should do its own filtering of which entities are sent to
|
||||
// clients to prevent abuse.
|
||||
let camera = self.scene.camera_mut();
|
||||
camera.next_mode(self.client.borrow().is_admin());
|
||||
},
|
||||
Event::AnalogGameInput(input) => match input {
|
||||
AnalogGameInput::MovementX(v) => {
|
||||
self.key_state.analog_matrix.x = v;
|
||||
@ -543,17 +553,60 @@ impl PlayState for SessionState {
|
||||
}
|
||||
|
||||
if !free_look {
|
||||
ori = self.scene.camera().get_orientation();
|
||||
walk_forward_dir = self.scene.camera().forward_xy();
|
||||
walk_right_dir = self.scene.camera().right_xy();
|
||||
self.inputs.look_dir = Dir::from_unnormalized(cam_dir + aim_dir_offset).unwrap();
|
||||
}
|
||||
// Calculate the movement input vector of the player from the current key
|
||||
// presses and the camera direction.
|
||||
let unit_vecs = (
|
||||
Vec2::new(ori[0].cos(), -ori[0].sin()),
|
||||
Vec2::new(ori[0].sin(), ori[0].cos()),
|
||||
);
|
||||
let dir_vec = self.key_state.dir_vec();
|
||||
self.inputs.move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
|
||||
|
||||
// Get the current state of movement related inputs
|
||||
let input_vec = self.key_state.dir_vec();
|
||||
let (axis_right, axis_up) = (input_vec[0], input_vec[1]);
|
||||
|
||||
match self.scene.camera().get_mode() {
|
||||
camera::CameraMode::FirstPerson | camera::CameraMode::ThirdPerson => {
|
||||
// Move the player character based on their walking direction.
|
||||
// This could be different from the camera direction if free look is enabled.
|
||||
self.inputs.move_dir = walk_right_dir * axis_right + walk_forward_dir * axis_up;
|
||||
freefly_vel = Vec3::zero();
|
||||
},
|
||||
|
||||
camera::CameraMode::Freefly => {
|
||||
// Move the camera freely in 3d space. Apply acceleration so that
|
||||
// the movement feels more natural and controlled.
|
||||
const FREEFLY_ACCEL: f32 = 120.0;
|
||||
const FREEFLY_DAMPING: f32 = 80.0;
|
||||
const FREEFLY_MAX_SPEED: f32 = 50.0;
|
||||
|
||||
let forward = self.scene.camera().forward();
|
||||
let right = self.scene.camera().right();
|
||||
let dir = right * axis_right + forward * axis_up;
|
||||
|
||||
let dt = clock.get_last_delta().as_secs_f32();
|
||||
if freefly_vel.magnitude_squared() > 0.01 {
|
||||
let new_vel =
|
||||
freefly_vel - freefly_vel.normalized() * (FREEFLY_DAMPING * dt);
|
||||
if freefly_vel.dot(new_vel) > 0.0 {
|
||||
freefly_vel = new_vel;
|
||||
} else {
|
||||
freefly_vel = Vec3::zero();
|
||||
}
|
||||
}
|
||||
if dir.magnitude_squared() > 0.01 {
|
||||
freefly_vel += dir * (FREEFLY_ACCEL * dt);
|
||||
if freefly_vel.magnitude() > FREEFLY_MAX_SPEED {
|
||||
freefly_vel = freefly_vel.normalized() * FREEFLY_MAX_SPEED;
|
||||
}
|
||||
}
|
||||
|
||||
let pos = self.scene.camera().get_focus_pos();
|
||||
self.scene
|
||||
.camera_mut()
|
||||
.set_focus_pos(pos + freefly_vel * dt);
|
||||
|
||||
// Do not apply any movement to the player character
|
||||
self.inputs.move_dir = Vec2::zero();
|
||||
},
|
||||
};
|
||||
|
||||
self.inputs.climb = self.key_state.climb();
|
||||
|
||||
|
@ -142,6 +142,7 @@ impl ControlSettings {
|
||||
//GameInput::Charge => KeyMouse::Key(VirtualKeyCode::Key1),
|
||||
GameInput::FreeLook => KeyMouse::Key(VirtualKeyCode::L),
|
||||
GameInput::AutoWalk => KeyMouse::Key(VirtualKeyCode::Period),
|
||||
GameInput::CycleCamera => KeyMouse::Key(VirtualKeyCode::Key0),
|
||||
GameInput::Slot1 => KeyMouse::Key(VirtualKeyCode::Key1),
|
||||
GameInput::Slot2 => KeyMouse::Key(VirtualKeyCode::Key2),
|
||||
GameInput::Slot3 => KeyMouse::Key(VirtualKeyCode::Key3),
|
||||
@ -204,6 +205,7 @@ impl Default for ControlSettings {
|
||||
//GameInput::Charge,
|
||||
GameInput::FreeLook,
|
||||
GameInput::AutoWalk,
|
||||
GameInput::CycleCamera,
|
||||
GameInput::Slot1,
|
||||
GameInput::Slot2,
|
||||
GameInput::Slot3,
|
||||
|
@ -65,6 +65,7 @@ pub enum GameInput {
|
||||
SwapLoadout,
|
||||
FreeLook,
|
||||
AutoWalk,
|
||||
CycleCamera,
|
||||
}
|
||||
|
||||
impl GameInput {
|
||||
@ -89,6 +90,7 @@ impl GameInput {
|
||||
GameInput::Mount => "gameinput.mount",
|
||||
GameInput::Enter => "gameinput.enter",
|
||||
GameInput::Command => "gameinput.command",
|
||||
GameInput::CycleCamera => "gameinput.cyclecamera",
|
||||
GameInput::Escape => "gameinput.escape",
|
||||
GameInput::Map => "gameinput.map",
|
||||
GameInput::Bag => "gameinput.bag",
|
||||
|
Loading…
Reference in New Issue
Block a user