Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added camera zoom #35

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 77 additions & 8 deletions addons/fpc/character.gd
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ extends CharacterBody3D
@export var sprint_speed : float = 6.0
## The speed that the character moves at when crouching.
@export var crouch_speed : float = 1.0
## The speed at which the camera zooms.
@export var zoom_speed : float = 8.0

## How fast the character speeds up and slows down when Motion Smoothing is on.
@export var acceleration : float = 10.0
## How high the player jumps.
@export var jump_velocity : float = 4.5
## How far the player turns when the mouse is moved.
@export var mouse_sensitivity : float = 0.1
## The level of camera zoom when character is zoomed in.
@export var zoom_multiplier : float = 2.0
## Automatically adjust mouse sensitivty when zoomed in to keep relative sensitivity equal.
@export var zoom_sensitivity_compensation : bool = true
## Invert the X axis input for the camera.
@export var invert_camera_x_axis : bool = false
## Invert the Y axis input for the camera.
Expand Down Expand Up @@ -65,7 +71,8 @@ extends CharacterBody3D
JUMP = "ui_accept",
CROUCH = "crouch",
SPRINT = "sprint",
PAUSE = "ui_cancel"
PAUSE = "ui_cancel",
ZOOM = "zoom"
}
@export_subgroup("Controller Specific")
## This only affects how the camera is handled, the rest should be covered by adding controller inputs to the existing actions in the Input Map.
Expand Down Expand Up @@ -93,12 +100,16 @@ extends CharacterBody3D
@export var motion_smoothing : bool = true
## Enables or disables sprinting.
@export var sprint_enabled : bool = true
## Enable camera zoom
@export var zoom_enabled: bool = true
## Toggles the sprinting state when button is pressed or requires the player to hold the button down to remain sprinting.
@export_enum("Hold to Sprint", "Toggle Sprint") var sprint_mode : int = 0
## Enables or disables crouching.
@export var crouch_enabled : bool = true
## Toggles the crouch state when button is pressed or requires the player to hold the button down to remain crouched.
@export_enum("Hold to Crouch", "Toggle Crouch") var crouch_mode : int = 0
## Toggles the camera zoom when button is pressed or requires the player to hold the botton down to remain zoomed in.
@export_enum("Hold to Zoom", "Toggle Zoom") var zoom_mode : int = 0
## Wether sprinting should effect FOV.
@export var dynamic_fov : bool = true
## If the player holds down the jump button, should the player keep hopping.
Expand Down Expand Up @@ -126,6 +137,11 @@ var state : String = "normal"
var low_ceiling : bool = false # This is for when the ceiling is too low and the player needs to crouch.
var was_on_floor : bool = true # Was the player on the floor last frame (for landing animation)

# Get the default fov of the camera so zoom multiplication is consistent across different fov values.
var default_fov : float
# The zoom_fov is calculated as (default_fov / zoom_multiplier)
var zoom_fov : float

# The reticle should always have a Control node as the root
var RETICLE : Control

Expand All @@ -135,6 +151,9 @@ var gravity : float = ProjectSettings.get_setting("physics/3d/default_gravity")
# Stores mouse input for rotating the camera in the physics process
var mouseInput : Vector2 = Vector2(0,0)

var default_mouse_sensitivity : float
var zoom_compensated_mouse_sensitivity : float

#endregion


Expand All @@ -148,7 +167,10 @@ func _ready():
# If the controller is rotated in a certain direction for game design purposes, redirect this rotation into the head.
HEAD.rotation.y = rotation.y
rotation.y = 0


if zoom_enabled:
calculate_fov()

if default_reticle:
change_reticle(default_reticle)

Expand Down Expand Up @@ -181,13 +203,16 @@ func _physics_process(delta): # Most things happen here.
handle_movement(delta, input_dir)

handle_head_rotation()

if zoom_enabled:
handle_zoom()

# The player is not able to stand up if the ceiling is too low
low_ceiling = $CrouchCeilingDetection.is_colliding()

handle_state(input_dir)
if dynamic_fov: # This may be changed to an AnimationPlayer
update_camera_fov()

update_camera_fov(delta)

if view_bobbing:
play_headbob_animation(input_dir)
Expand Down Expand Up @@ -265,6 +290,18 @@ func handle_head_rotation():
mouseInput = Vector2(0,0)
HEAD.rotation.x = clamp(HEAD.rotation.x, deg_to_rad(-90), deg_to_rad(90))

func handle_zoom():
if zoom_enabled:
if zoom_mode == 0:
if Input.is_action_just_pressed(controls.ZOOM) and state != "zooming":
enter_zoom_state()
elif Input.is_action_just_released(controls.ZOOM) and state == "zooming":
enter_normal_state()
elif zoom_mode == 1:
if Input.is_action_just_pressed(controls.ZOOM) and state == "normal":
enter_zoom_state()
elif Input.is_action_just_pressed(controls.ZOOM) and state == "zooming":
enter_normal_state()

func check_controls(): # If you add a control, you might want to add a check for it here.
# The actions are being disabled so the engine doesn't halt the entire project in debug mode
Expand All @@ -286,6 +323,9 @@ func check_controls(): # If you add a control, you might want to add a check for
if !InputMap.has_action(controls.PAUSE):
push_error("No control mapped for pause. Please add an input map control. Disabling pausing.")
pausing_enabled = false
if !InputMap.has_action(controls.ZOOM):
push_error("No control mapped for zoom. Please add an input map control. Disabling zooming.")
zoom_enabled = false
if !InputMap.has_action(controls.CROUCH):
push_error("No control mapped for crouch. Please add an input map control. Disabling crouching.")
crouch_enabled = false
Expand Down Expand Up @@ -348,6 +388,8 @@ func enter_normal_state():
CROUCH_ANIMATION.play_backwards("crouch")
state = "normal"
speed = base_speed
if zoom_sensitivity_compensation:
mouse_sensitivity = default_mouse_sensitivity

func enter_crouch_state():
#print("entering crouch state")
Expand All @@ -363,6 +405,15 @@ func enter_sprint_state():
state = "sprinting"
speed = sprint_speed

func enter_zoom_state():
#print("entering zoom state")
var prev_state = state
state = "zooming"
speed = crouch_speed

if zoom_sensitivity_compensation:
mouse_sensitivity = zoom_compensated_mouse_sensitivity

#endregion

#region Animation Handling
Expand Down Expand Up @@ -466,10 +517,28 @@ func change_reticle(reticle): # Yup, this function is kinda strange
RETICLE = load(reticle).instantiate()
RETICLE.character = self
$UserInterface.add_child(RETICLE)


func update_camera_fov():
if state == "sprinting":

func calculate_fov():
# Retrieve the camera fov settings so the zoom amount scales correctly with different player fov.
# Dividing by zoom_multiplier instead of sqrt(zoom_multiplier) for more accurate size rather than accurate area.
default_fov = CAMERA.fov
zoom_fov = default_fov / sqrt(zoom_multiplier)

# Determine the modified mouse sensitivity such that it feels the same when zoomed in.
if zoom_sensitivity_compensation:
default_mouse_sensitivity = mouse_sensitivity
var screen_size = get_viewport().size

var fovy = 2 * atan(1.0/screen_size[1] * tan(zoom_fov/2 * PI/180.0)) * 180.0/PI
var fovx = 2 * atan(1.0/screen_size[0] * tan(default_fov/2.0 * PI/180.0)) * 180.0/PI
var zoom_sense_modifier = fovy/fovx
zoom_compensated_mouse_sensitivity = default_mouse_sensitivity * zoom_sense_modifier


func update_camera_fov(delta):
if state == "zooming":
CAMERA.fov = lerp(CAMERA.fov, zoom_fov, delta * zoom_speed)
elif state == "sprinting" and dynamic_fov:
CAMERA.fov = lerp(CAMERA.fov, 85.0, 0.3)
else:
CAMERA.fov = lerp(CAMERA.fov, 75.0, 0.3)
Expand Down