Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #=========================
- # DESCRIPTION
- #=========================
- # Default camera that follows the movement of the player
- extends Camera2D
- # Input names
- const INPUT_MOVE_LEFT: String = "move_left"
- const INPUT_MOVE_RIGHT: String = "move_right"
- const INPUT_MOVE_UP: String = "move_up"
- const INPUT_MOVE_DOWN: String = "move_down"
- @export_range(0.0, 50.0, 0.001, "or_greater") var look_ahead_distance: float = 20.0
- @export_range(0.0, 3.0) var smoothing_duration: float = 1.9
- ## Curve min value should be 1.0.
- ## Max can be modified to suit behavior, but larger value than 15.0 usually causes very quick snapping
- @export var position_smoothing_curve: Curve
- ## Small changes in direction won't slow camera speed too much. Closer to 1.0 means faster snap
- @export_range(0.0, 1.0) var small_angle_smooth_ratio: float = 0.37
- var _player: Player
- var _input_vector: Vector2 = Vector2.ZERO
- var _last_input_vector: Vector2 = Vector2.ZERO
- var _target_position: Vector2 = Vector2.ZERO
- var _smoothing_timer: float = 0.0
- @onready var _small_angle_duration: float = smoothing_duration * small_angle_smooth_ratio
- func _ready() -> void:
- await owner.ready
- _player = get_tree().get_first_node_in_group(GameConstants.PLAYER_GROUP)
- assert(_player != null, "Player is null, Default Camera will not work")
- position = _player.position
- _target_position = _player.position
- func _process(delta: float) -> void:
- if _player == null:
- position = Vector2.ZERO
- return
- _input_vector = get_input_normalize()
- if not _input_vector.is_equal_approx(Vector2.ZERO):
- _target_position = calculate_look_ahead_position()
- set_smoothing_timer(delta)
- var smoothing_curve_domain: float = clampf(_smoothing_timer / smoothing_duration, 0.0 , 1.0)
- var smoothing_weight: float = position_smoothing_curve.sample(smoothing_curve_domain) / 100
- position = position.lerp(_target_position, smoothing_weight)
- func calculate_look_ahead_position() -> Vector2:
- return _player.position + change_to_isometric_coordinates(_last_input_vector * look_ahead_distance)
- func get_input_normalize() -> Vector2:
- var input = Input.get_vector(INPUT_MOVE_LEFT, INPUT_MOVE_RIGHT, INPUT_MOVE_UP, INPUT_MOVE_DOWN)
- return input.normalized()
- # NOTE: The smoothing timer is the most important value to determine the behavior of the camera.
- # The behavior of the camera can be described as follow:
- # 1. If the player releases the input, camera will lerp to the target position based on last directional input
- # 2. When player holds down the input, camera will accelerate ahead of the direction player is moving in
- # 3. When player changes direction, and if the angle is less than 45 degrees, let the camera moves at a higher
- # speed immediately (but not the max speed).
- func set_smoothing_timer(delta: float) -> void:
- if _input_vector.is_equal_approx(Vector2.ZERO):
- if position.is_equal_approx(_target_position):
- _smoothing_timer = 0.0
- else:
- _smoothing_timer += delta
- elif _last_input_vector.is_equal_approx(_input_vector):
- _smoothing_timer += delta
- else:
- if is_angle_less_than_45_degrees(_input_vector.angle_to(_last_input_vector)) \
- and _smoothing_timer > _small_angle_duration:
- _smoothing_timer = _small_angle_duration
- else:
- _smoothing_timer = 0.0
- _last_input_vector = _input_vector
- func change_to_isometric_coordinates(vector: Vector2) -> Vector2:
- return Vector2(vector.x, vector.y / GameConstants.X_TO_Y_RATIO)
- # Performing comparison with angle_to operation of Vector2 can give wrong result bacause of
- # computational error margin, which necessitates check against such margins.
- func is_angle_less_than_45_degrees(angle: float) -> bool:
- return absf(absf(angle) - (PI / 4)) < 0.01
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement