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()
|
.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
|
/// Clean client ECS state
|
||||||
fn clean_state(&mut self) {
|
fn clean_state(&mut self) {
|
||||||
let client_uid = self
|
let client_uid = self
|
||||||
|
@ -8,6 +8,7 @@ const FAR_PLANE: f32 = 100000.0;
|
|||||||
|
|
||||||
const FIRST_PERSON_INTERP_TIME: f32 = 0.1;
|
const FIRST_PERSON_INTERP_TIME: f32 = 0.1;
|
||||||
const THIRD_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;
|
const LERP_ORI_RATE: f32 = 15.0;
|
||||||
pub const MIN_ZOOM: f32 = 0.1;
|
pub const MIN_ZOOM: f32 = 0.1;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ pub const MIN_ZOOM: f32 = 0.1;
|
|||||||
pub enum CameraMode {
|
pub enum CameraMode {
|
||||||
FirstPerson = 0,
|
FirstPerson = 0,
|
||||||
ThirdPerson = 1,
|
ThirdPerson = 1,
|
||||||
|
Freefly = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CameraMode {
|
impl Default for CameraMode {
|
||||||
@ -73,15 +75,7 @@ impl Camera {
|
|||||||
/// and position of the camera.
|
/// and position of the camera.
|
||||||
pub fn compute_dependents(&mut self, terrain: &impl ReadVol) {
|
pub fn compute_dependents(&mut self, terrain: &impl ReadVol) {
|
||||||
let dist = {
|
let dist = {
|
||||||
let (start, end) = (
|
let (start, end) = (self.focus - self.forward() * self.dist, self.focus);
|
||||||
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,
|
|
||||||
);
|
|
||||||
|
|
||||||
match terrain
|
match terrain
|
||||||
.ray(start, end)
|
.ray(start, end)
|
||||||
@ -155,13 +149,10 @@ impl Camera {
|
|||||||
|
|
||||||
/// Zoom the camera by the given delta, limiting the input accordingly.
|
/// Zoom the camera by the given delta, limiting the input accordingly.
|
||||||
pub fn zoom_by(&mut self, delta: f32) {
|
pub fn zoom_by(&mut self, delta: f32) {
|
||||||
match self.mode {
|
if self.mode == CameraMode::ThirdPerson {
|
||||||
CameraMode::ThirdPerson => {
|
|
||||||
// Clamp camera dist to the 2 <= x <= infinity range
|
// Clamp camera dist to the 2 <= x <= infinity range
|
||||||
self.tgt_dist = (self.tgt_dist + delta).max(2.0);
|
self.tgt_dist = (self.tgt_dist + delta).max(2.0);
|
||||||
},
|
}
|
||||||
CameraMode::FirstPerson => {},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zoom with the ability to switch between first and third-person mode.
|
/// Zoom with the ability to switch between first and third-person mode.
|
||||||
@ -181,6 +172,7 @@ impl Camera {
|
|||||||
self.set_mode(CameraMode::ThirdPerson);
|
self.set_mode(CameraMode::ThirdPerson);
|
||||||
self.tgt_dist = MIN_THIRD_PERSON;
|
self.tgt_dist = MIN_THIRD_PERSON;
|
||||||
},
|
},
|
||||||
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,6 +236,7 @@ impl Camera {
|
|||||||
match self.mode {
|
match self.mode {
|
||||||
CameraMode::FirstPerson => FIRST_PERSON_INTERP_TIME,
|
CameraMode::FirstPerson => FIRST_PERSON_INTERP_TIME,
|
||||||
CameraMode::ThirdPerson => THIRD_PERSON_INTERP_TIME,
|
CameraMode::ThirdPerson => THIRD_PERSON_INTERP_TIME,
|
||||||
|
CameraMode::Freefly => FREEFLY_INTERP_TIME,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +280,9 @@ impl Camera {
|
|||||||
CameraMode::FirstPerson => {
|
CameraMode::FirstPerson => {
|
||||||
self.set_distance(MIN_ZOOM);
|
self.set_distance(MIN_ZOOM);
|
||||||
},
|
},
|
||||||
|
CameraMode::Freefly => {
|
||||||
|
self.zoom_by(0.0);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,4 +297,45 @@ impl Camera {
|
|||||||
mode => mode,
|
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 {
|
match camera_mode {
|
||||||
CameraMode::ThirdPerson => {
|
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||||
Some(humanoid_head_spec.mesh_head(&body, generate_mesh))
|
Some(humanoid_head_spec.mesh_head(&body, generate_mesh))
|
||||||
},
|
},
|
||||||
CameraMode::FirstPerson => None,
|
CameraMode::FirstPerson => None,
|
||||||
},
|
},
|
||||||
match camera_mode {
|
match camera_mode {
|
||||||
CameraMode::ThirdPerson => Some(humanoid_armor_chest_spec.mesh_chest(
|
CameraMode::ThirdPerson | CameraMode::Freefly => Some(
|
||||||
&body,
|
humanoid_armor_chest_spec.mesh_chest(&body, loadout, generate_mesh),
|
||||||
loadout,
|
),
|
||||||
generate_mesh,
|
|
||||||
)),
|
|
||||||
CameraMode::FirstPerson => None,
|
CameraMode::FirstPerson => None,
|
||||||
},
|
},
|
||||||
match camera_mode {
|
match camera_mode {
|
||||||
CameraMode::ThirdPerson => {
|
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||||
Some(humanoid_armor_belt_spec.mesh_belt(&body, loadout, generate_mesh))
|
Some(humanoid_armor_belt_spec.mesh_belt(&body, loadout, generate_mesh))
|
||||||
},
|
},
|
||||||
CameraMode::FirstPerson => None,
|
CameraMode::FirstPerson => None,
|
||||||
},
|
},
|
||||||
match camera_mode {
|
match camera_mode {
|
||||||
CameraMode::ThirdPerson => {
|
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||||
Some(humanoid_armor_back_spec.mesh_back(&body, loadout, generate_mesh))
|
Some(humanoid_armor_back_spec.mesh_back(&body, loadout, generate_mesh))
|
||||||
},
|
},
|
||||||
CameraMode::FirstPerson => None,
|
CameraMode::FirstPerson => None,
|
||||||
},
|
},
|
||||||
match camera_mode {
|
match camera_mode {
|
||||||
CameraMode::ThirdPerson => Some(humanoid_armor_pants_spec.mesh_pants(
|
CameraMode::ThirdPerson | CameraMode::Freefly => Some(
|
||||||
&body,
|
humanoid_armor_pants_spec.mesh_pants(&body, loadout, generate_mesh),
|
||||||
loadout,
|
),
|
||||||
generate_mesh,
|
|
||||||
)),
|
|
||||||
CameraMode::FirstPerson => None,
|
CameraMode::FirstPerson => None,
|
||||||
},
|
},
|
||||||
Some(humanoid_armor_hand_spec.mesh_left_hand(&body, loadout, generate_mesh)),
|
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_left_foot(&body, loadout, generate_mesh)),
|
||||||
Some(humanoid_armor_foot_spec.mesh_right_foot(&body, loadout, generate_mesh)),
|
Some(humanoid_armor_foot_spec.mesh_right_foot(&body, loadout, generate_mesh)),
|
||||||
match camera_mode {
|
match camera_mode {
|
||||||
CameraMode::ThirdPerson => {
|
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||||
Some(humanoid_armor_shoulder_spec.mesh_left_shoulder(
|
Some(humanoid_armor_shoulder_spec.mesh_left_shoulder(
|
||||||
&body,
|
&body,
|
||||||
loadout,
|
loadout,
|
||||||
@ -168,7 +164,7 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
|||||||
CameraMode::FirstPerson => None,
|
CameraMode::FirstPerson => None,
|
||||||
},
|
},
|
||||||
match camera_mode {
|
match camera_mode {
|
||||||
CameraMode::ThirdPerson => {
|
CameraMode::ThirdPerson | CameraMode::Freefly => {
|
||||||
Some(humanoid_armor_shoulder_spec.mesh_right_shoulder(
|
Some(humanoid_armor_shoulder_spec.mesh_right_shoulder(
|
||||||
&body,
|
&body,
|
||||||
loadout,
|
loadout,
|
||||||
|
@ -239,10 +239,17 @@ impl Scene {
|
|||||||
},
|
},
|
||||||
CameraMode::ThirdPerson if scene_data.is_aiming => player_scale * 2.1,
|
CameraMode::ThirdPerson if scene_data.is_aiming => player_scale * 2.1,
|
||||||
CameraMode::ThirdPerson => player_scale * 1.65,
|
CameraMode::ThirdPerson => player_scale * 1.65,
|
||||||
|
CameraMode::Freefly => 0.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.camera
|
match self.camera.get_mode() {
|
||||||
.set_focus_pos(player_pos + Vec3::unit_z() * (up - tilt.min(0.0).sin() * dist * 0.6));
|
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.
|
// Tick camera for interpolation.
|
||||||
self.camera.update(
|
self.camera.update(
|
||||||
|
@ -173,7 +173,9 @@ impl PlayState for SessionState {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.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 free_look = false;
|
||||||
let mut auto_walk = 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 {
|
Event::AnalogGameInput(input) => match input {
|
||||||
AnalogGameInput::MovementX(v) => {
|
AnalogGameInput::MovementX(v) => {
|
||||||
self.key_state.analog_matrix.x = v;
|
self.key_state.analog_matrix.x = v;
|
||||||
@ -543,17 +553,60 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !free_look {
|
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();
|
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.
|
// Get the current state of movement related inputs
|
||||||
let unit_vecs = (
|
let input_vec = self.key_state.dir_vec();
|
||||||
Vec2::new(ori[0].cos(), -ori[0].sin()),
|
let (axis_right, axis_up) = (input_vec[0], input_vec[1]);
|
||||||
Vec2::new(ori[0].sin(), ori[0].cos()),
|
|
||||||
);
|
match self.scene.camera().get_mode() {
|
||||||
let dir_vec = self.key_state.dir_vec();
|
camera::CameraMode::FirstPerson | camera::CameraMode::ThirdPerson => {
|
||||||
self.inputs.move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
|
// 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();
|
self.inputs.climb = self.key_state.climb();
|
||||||
|
|
||||||
|
@ -142,6 +142,7 @@ impl ControlSettings {
|
|||||||
//GameInput::Charge => KeyMouse::Key(VirtualKeyCode::Key1),
|
//GameInput::Charge => KeyMouse::Key(VirtualKeyCode::Key1),
|
||||||
GameInput::FreeLook => KeyMouse::Key(VirtualKeyCode::L),
|
GameInput::FreeLook => KeyMouse::Key(VirtualKeyCode::L),
|
||||||
GameInput::AutoWalk => KeyMouse::Key(VirtualKeyCode::Period),
|
GameInput::AutoWalk => KeyMouse::Key(VirtualKeyCode::Period),
|
||||||
|
GameInput::CycleCamera => KeyMouse::Key(VirtualKeyCode::Key0),
|
||||||
GameInput::Slot1 => KeyMouse::Key(VirtualKeyCode::Key1),
|
GameInput::Slot1 => KeyMouse::Key(VirtualKeyCode::Key1),
|
||||||
GameInput::Slot2 => KeyMouse::Key(VirtualKeyCode::Key2),
|
GameInput::Slot2 => KeyMouse::Key(VirtualKeyCode::Key2),
|
||||||
GameInput::Slot3 => KeyMouse::Key(VirtualKeyCode::Key3),
|
GameInput::Slot3 => KeyMouse::Key(VirtualKeyCode::Key3),
|
||||||
@ -204,6 +205,7 @@ impl Default for ControlSettings {
|
|||||||
//GameInput::Charge,
|
//GameInput::Charge,
|
||||||
GameInput::FreeLook,
|
GameInput::FreeLook,
|
||||||
GameInput::AutoWalk,
|
GameInput::AutoWalk,
|
||||||
|
GameInput::CycleCamera,
|
||||||
GameInput::Slot1,
|
GameInput::Slot1,
|
||||||
GameInput::Slot2,
|
GameInput::Slot2,
|
||||||
GameInput::Slot3,
|
GameInput::Slot3,
|
||||||
|
@ -65,6 +65,7 @@ pub enum GameInput {
|
|||||||
SwapLoadout,
|
SwapLoadout,
|
||||||
FreeLook,
|
FreeLook,
|
||||||
AutoWalk,
|
AutoWalk,
|
||||||
|
CycleCamera,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameInput {
|
impl GameInput {
|
||||||
@ -89,6 +90,7 @@ impl GameInput {
|
|||||||
GameInput::Mount => "gameinput.mount",
|
GameInput::Mount => "gameinput.mount",
|
||||||
GameInput::Enter => "gameinput.enter",
|
GameInput::Enter => "gameinput.enter",
|
||||||
GameInput::Command => "gameinput.command",
|
GameInput::Command => "gameinput.command",
|
||||||
|
GameInput::CycleCamera => "gameinput.cyclecamera",
|
||||||
GameInput::Escape => "gameinput.escape",
|
GameInput::Escape => "gameinput.escape",
|
||||||
GameInput::Map => "gameinput.map",
|
GameInput::Map => "gameinput.map",
|
||||||
GameInput::Bag => "gameinput.bag",
|
GameInput::Bag => "gameinput.bag",
|
||||||
|
Loading…
Reference in New Issue
Block a user