Skip to content

Commit

Permalink
minor fixes and improved the first person controller with new mechanics
Browse files Browse the repository at this point in the history
  • Loading branch information
ninetailsrabbit committed Dec 31, 2024
1 parent 7bee026 commit 544f434
Show file tree
Hide file tree
Showing 18 changed files with 395 additions and 52 deletions.
1 change: 1 addition & 0 deletions autoload/general/game_globals.gd
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const interactables_collision_layer: int = 32
const grabbables_collision_layer: int = 64
const bullets_collision_layer: int = 128
const playing_cards_collision_layer: int = 256
const ladders_collision_layer: int = 512
#endregion


Expand Down
81 changes: 68 additions & 13 deletions autoload/general/global_day_night_clock.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
extends Node

signal time_tick(day: int, hour: int, minute: int)
signal hour_passed
signal day_passed

const MinutesPerDay: int = 1440
const MinutesPerHour: int = 60
const DayHourLength: int = MinutesPerDay / MinutesPerHour
const InGameToRealMinuteDuration := TAU / MinutesPerDay

@export var emit_tick_signal: bool = false
## This value when it's 1.0 means that one minute in real time translates into one second in-game, so modify this value as is needed
@export var in_game_speed: float = 1.0
@export var initial_day: int = 0
Expand All @@ -18,27 +22,44 @@ const InGameToRealMinuteDuration := TAU / MinutesPerDay
initial_hour = clampi(hour, 0, 23)
time = InGameToRealMinuteDuration * MinutesPerHour * initial_hour

var is_running: bool = false
var time: float = 0.0
var past_minute: int = -1
## Get the current value time to use on gradient color curves and change the environment tempererature according to the day time
var curve_value: float = 0.0

var curve_value: float = 0.0:
set(value):
if value != curve_value:
curve_value = clampf(value, 0.0, 1.0)
var current_period: String = "AM"
var current_day: int = 0
var current_hour: int = 0
var current_minute: int = 0

var current_day: int = 0:
set(value):
if value != current_day:
current_day = maxi(0, value)
day_passed.emit()
var current_hour: int = 0:
set(value):
if value != current_hour:
current_hour = value
current_hour = clampi(value, 0, 23)
hour_passed.emit()
var current_minute: int = 0:
set(value):
if value != current_minute:
current_minute = value
current_minute = clampi(value, 0, 59)

func _ready() -> void:
set_process(false)



func _process(delta: float) -> void:
time += delta * InGameToRealMinuteDuration * in_game_speed
_recalculate_time()

curve_value = (sin(time - PI / 2.0) + 1.0) / 2.0
curve_value = get_curve_value()

_recalculate_time()
if curve_value >= 1.0:
curve_value = 0.0


func start(day: int = initial_day, hour: int = initial_hour, minute: int = initial_minute) -> void:
Expand All @@ -53,13 +74,46 @@ func start(day: int = initial_day, hour: int = initial_hour, minute: int = initi

time = InGameToRealMinuteDuration * MinutesPerHour * current_hour

is_running = true
set_process(true)


func stop() -> void:
is_running = false
set_process(false)


func total_seconds() -> int:
if current_day > 0:
current_day * seconds()

return seconds()


func seconds(hour: int = current_hour, minute: int = current_minute) -> int:
return (hour * MinutesPerHour * MinutesPerHour) + minute * MinutesPerHour


func get_curve_value(hour: int = current_hour, minute: int = current_minute) -> float:
var current_time_fraction = (seconds(hour, minute) * 1000) / (DayHourLength * MinutesPerHour * MinutesPerHour * 1000.0)


return clampf(current_time_fraction, 0.0, 1.0)


func time_display() -> String:
var hour: int = current_hour
var minute: int = current_minute

if hour < 10:
"0" + str(hour)

if minute < 10:
"0" + str(minute)

return "%s:%s" % [hour, minute]


func change_day_to(new_day: int) -> void:
initial_day = new_day

Expand All @@ -73,16 +127,17 @@ func change_minute_to(new_minute: int) -> void:


func _recalculate_time() -> void:
var total_minutes = int(time / InGameToRealMinuteDuration)
var current_day_minutes = fmod(total_minutes, MinutesPerDay)
var total_minutes = int(time / InGameToRealMinuteDuration) + initial_minute
var current_day_minutes = fmod(total_minutes, MinutesPerDay) + initial_minute

current_day = initial_day + int(total_minutes / MinutesPerDay)
current_hour = int(current_day_minutes / MinutesPerHour)
current_minute = initial_minute + int(fmod(current_day_minutes, MinutesPerHour))
current_minute = int(fmod(current_day_minutes, MinutesPerHour))

if past_minute != current_minute:
past_minute = current_minute

current_period = "AM" if current_hour < 12 else "PM"

time_tick.emit(current_day, current_hour, current_minute)
if emit_tick_signal:
time_tick.emit(current_day, current_hour, current_minute)
4 changes: 4 additions & 0 deletions autoload/persistence/settings/input_controls.gd
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@ const ToggleInventory: StringName = &"toggle_inventory"

const Drag: StringName = &"drag"

const ClimbLadder: StringName = &"climb_ladder"

const VehicleAccelerate: StringName = &"vehicle_accelerate"
const VehicleReverseAccelerate: StringName = &"vehicle_reverse_accelerate"
const VehicleSteerRight: StringName = &"vehicle_steer_right"
const VehicleSteerLeft: StringName = &"vehicle_steer_left"
const VehicleHandBrake: StringName = &"vehicle_hand_brake"
const StartVehicleEngine: StringName = &"start_vehicle_engine"

const StopDrivingBoat: StringName = &"stop_driving_boat"

const PerformanceMetrics: StringName = &"performance_metrics"
const PauseGame: StringName = &"pause"
2 changes: 1 addition & 1 deletion components/interaction/3D/interactables/interactable_3d.gd
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,4 @@ func on_canceled_interaction() -> void:

GlobalGameEvents.interactable_canceled_interaction.emit(self)

#endregion
#endregion
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ func unfocus(interactable: Interactable3D = current_interactable):
interacting = false
enabled = true

interactable.unfocused.emit()
interactable.unfocused.emit()
9 changes: 5 additions & 4 deletions components/interaction/3D/ui/interactable_information.gd
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ var current_interactable: Interactable3D
func _enter_tree() -> void:
mouse_filter = MouseFilter.MOUSE_FILTER_IGNORE

GlobalGameEvents.interactable_focused.connect(on_interactable_focused)
GlobalGameEvents.interactable_unfocused.connect(on_interactable_unfocused)
GlobalGameEvents.interactable_canceled_interaction.connect(on_interactable_unfocused)


func _ready() -> void:
information_label.text = ""
information_label.hide()

GlobalGameEvents.interactable_focused.connect(on_interactable_focused)
GlobalGameEvents.interactable_unfocused.connect(on_interactable_unfocused)
GlobalGameEvents.interactable_canceled_interaction.connect(on_interactable_unfocused)
GlobalGameEvents.interactable_interacted.connect(on_interactable_unfocused)


func on_interactable_focused(interactable: Interactable3D) -> void:
current_interactable = interactable
Expand Down
57 changes: 43 additions & 14 deletions components/motion/3D/boat/boat_3d.gd
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
## Recommended to set linear damp to 1 and angular damp to 2
class_name Boat3D extends RigidBody3D

const GroupName: StringName = &"boats"

signal started_engine
signal stopped_engine

@export var boat_mesh: MeshInstance3D
@export var boat_mesh: Node3D
@export var water_level: float = 0.0
@export_category("Engine")
@export var boat_engine_force: float = 20.0
Expand All @@ -26,11 +28,13 @@ signal stopped_engine
@export var boat_rudder: Node3D
@export var boat_rudder_maximum_rotation: Vector3 = Vector3.ZERO
@export var boat_rudder_idle_rotation: Vector3 = Vector3.ZERO
@export var boat_rudder_lerp_factor: float = 15.0
@export var boat_rudder_lerp_factor: float = 5.0
@export var boat_rudder_idle_lerp_factor: float = 2.0

var motion_input: TransformedInput = TransformedInput.new(self)
var current_engine_force: float = 0.0
var buoyancy_spots: Array[Node3D] = []

var is_being_driven: bool = false
var engine_on: bool = false:
set(value):
if value != engine_on:
Expand All @@ -43,13 +47,41 @@ var engine_on: bool = false:
stopped_engine.emit()


func _enter_tree() -> void:
add_to_group(GroupName)


func _ready() -> void:
if buoyancy_root:
buoyancy_spots.assign(buoyancy_root.get_children())


func start_engine() -> void:
engine_on = true


func stop_engine() -> void:
engine_on = false


func drive() -> void:
is_being_driven = true


func stop_drive() -> void:
is_being_driven = false


func _physics_process(delta: float) -> void:
if engine_on:
if engine_on and is_being_driven:
if boat_rudder:
motion_input.update()
var steering_input: float = -motion_input.input_direction_horizontal_axis

if is_zero_approx(steering_input):
boat_rudder.rotation_degrees = boat_rudder.rotation_degrees.lerp(boat_rudder_idle_rotation, delta * boat_rudder_idle_lerp_factor)
else:
boat_rudder.rotation_degrees = boat_rudder.rotation_degrees.lerp(sign(steering_input) * boat_rudder_maximum_rotation, delta * boat_rudder_lerp_factor)

if Input.is_action_pressed(InputControls.VehicleAccelerate):
if boat_acceleration > 0:
Expand All @@ -58,13 +90,7 @@ func _physics_process(delta: float) -> void:
current_engine_force = boat_engine_force

apply_central_force(global_transform.basis * (Vector3.FORWARD * current_engine_force) )

if Input.is_action_pressed(InputControls.VehicleSteerLeft):
apply_torque(Vector3.UP * boat_steering_force)

if Input.is_action_pressed(InputControls.VehicleSteerRight):
apply_torque(Vector3.DOWN * boat_steering_force)


elif Input.is_action_pressed(InputControls.VehicleReverseAccelerate):
if boat_acceleration > 0:
current_engine_force = lerp(current_engine_force, boat_reverse_engine_force, boat_reverse_acceleration * delta)
Expand All @@ -73,13 +99,16 @@ func _physics_process(delta: float) -> void:

apply_central_force(global_transform.basis * (Vector3.BACK * current_engine_force) )

if not is_zero_approx(current_engine_force):
if Input.is_action_pressed(InputControls.VehicleSteerLeft):
apply_torque(Vector3.UP * boat_steering_force)

if Input.is_action_pressed(InputControls.VehicleSteerRight):
apply_torque(Vector3.DOWN * boat_steering_force)


else:
if boat_rudder:
boat_rudder.rotation_degrees = boat_rudder.rotation_degrees.lerp(boat_rudder_idle_rotation, delta * boat_rudder_idle_lerp_factor)

for buoyancy_spot: Node3D in buoyancy_spots:
if buoyancy_spot.global_position.y <= water_level:
apply_force(Vector3.UP * randf_range(buoyancy_force - buoyancy_force_variation, buoyancy_force) * -buoyancy_spot.global_position, buoyancy_spot.global_position - global_position)
apply_force(mass * Vector3.UP * randf_range(buoyancy_force - buoyancy_force_variation, buoyancy_force) * -buoyancy_spot.global_position, buoyancy_spot.global_position - global_position)
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@icon("res://components/motion/3D/first-person/controller/first_person_controller.svg")
class_name FirstPersonController extends CharacterBody3D

const GroupName: StringName = &"player"

@export var mouse_mode_switch_input_actions: Array[String] = ["ui_cancel"]
@export_group("Camera FOV")
@export var dinamic_camera_fov: bool = true
Expand Down Expand Up @@ -30,6 +32,7 @@ class_name FirstPersonController extends CharacterBody3D
if value != stairs:
stairs = value
_update_wall_checkers()
@export var ladder_climb: bool = false
@onready var debug_ui: CanvasLayer = $DebugUI
@onready var finite_state_machine: FiniteStateMachine = $FiniteStateMachine
@onready var camera: CameraShake3D = $CameraController/Head/CameraShake3D
Expand All @@ -45,6 +48,8 @@ class_name FirstPersonController extends CharacterBody3D
@onready var left_wall_checker_2: RayCast3D = %LeftWallChecker2

@onready var ceil_shape_cast: ShapeCast3D = $CeilShapeCast
@onready var ladder_cast_detector: ShapeCast3D = $LadderCastDetector

@onready var footsteps_manager_3d: FootstepsManager3D = $FootstepsManager3D

@onready var animation_player: AnimationPlayer = $AnimationPlayer
Expand All @@ -55,7 +60,6 @@ class_name FirstPersonController extends CharacterBody3D
@onready var original_camera_fov = camera.fov
@onready var fire_arm_weapon_holder: FireArmWeaponHolder = $CameraController/Head/CameraShake3D/FireArmWeaponHolder

const group_name = "player"

var was_grounded: bool = false
var is_grounded: bool = false
Expand All @@ -66,10 +70,10 @@ var last_direction: Vector3 = Vector3.ZERO
func _unhandled_key_input(_event: InputEvent) -> void:
if InputHelper.is_any_action_just_pressed(mouse_mode_switch_input_actions):
switch_mouse_capture_mode()


func _enter_tree() -> void:
add_to_group(group_name)
add_to_group(GroupName)


func _ready() -> void:
Expand All @@ -86,7 +90,8 @@ func _ready() -> void:
RunToWalkTransition.new(),
AnyToWallRunTransition.new(),
WallRunToFallTransition.new(),
WallRunToWallJumpTransition.new()
WallRunToWallJumpTransition.new(),
AnyToLadderClimbTransition.new()
])

finite_state_machine.state_changed.connect(on_state_changed)
Expand Down Expand Up @@ -150,11 +155,17 @@ func get_current_wall_side() -> Vector3:

func lock_movement() -> void:
finite_state_machine.lock_state_machine()
camera_controller.lock()


func unlock_movement() -> void:
finite_state_machine.unlock_state_machine()


func lock_camera() -> void:
camera_controller.lock()


func unlock_camera() -> void:
camera_controller.unlock()


Expand Down Expand Up @@ -216,7 +227,7 @@ func on_state_changed(_from: MachineState, to: MachineState) -> void:
#if interactable.lock_player_on_interact:
#lock_movement()
#
#

#func on_interactable_canceled_interaction(_interactable: Interactable3D) -> void:
#unlock_movement()
#camera.make_current()
Expand Down
Loading

0 comments on commit 544f434

Please sign in to comment.