Compare commits
4 Commits
2a60380258
...
a4100e3026
| Author | SHA1 | Date | |
|---|---|---|---|
| a4100e3026 | |||
| 31363b1d52 | |||
| 8a5373c340 | |||
| b3b73433a2 |
@ -62,6 +62,20 @@ folder_colors={
|
||||
|
||||
[input]
|
||||
|
||||
ui_accept={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194309,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194310,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
|
||||
]
|
||||
}
|
||||
ui_cancel={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194305,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":true,"script":null)
|
||||
]
|
||||
}
|
||||
move_forward={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
class_name InteractiveLoader
|
||||
extends Node
|
||||
|
||||
@export var auto_free: bool = false
|
||||
|
||||
var load_progress: Array = []
|
||||
|
||||
|
||||
@ -26,4 +28,7 @@ func load_threaded(path: String) -> Resource:
|
||||
else:
|
||||
SPrint.print_msg("[Interactive Loader] is no longer in the scene tree. We can't wait for a process frame anymore, resulting in a freeze.", -1.0, SPrint.WARNING)
|
||||
|
||||
if auto_free:
|
||||
queue_free()
|
||||
|
||||
return ResourceLoader.load_threaded_get(path)
|
||||
|
||||
@ -10,6 +10,7 @@ func _enter_tree() -> void:
|
||||
for spawnpoint: PlayerSpawnPoint in loaded_if_spawnpoint:
|
||||
if GameGlobals.spawn_id == spawnpoint.spawn_id:
|
||||
var was_threaded: bool = level_loader.load_threaded
|
||||
level_loader.load_threaded = false
|
||||
load_level()
|
||||
level_loader.load_threaded = was_threaded
|
||||
return
|
||||
@ -34,14 +35,14 @@ func unload_level() -> void:
|
||||
if keep_loaded_duration > 0.0:
|
||||
var duration: float = keep_loaded_duration
|
||||
|
||||
while is_inside_tree() and duration > 0.0:
|
||||
while duration > 0.0:
|
||||
if has_overlapping_bodies():
|
||||
return
|
||||
|
||||
duration -= get_process_delta_time() * float(not get_tree().paused)
|
||||
await get_tree().process_frame
|
||||
|
||||
if not is_instance_valid(get_tree()):
|
||||
if not is_inside_tree() or not is_instance_valid(get_tree()):
|
||||
return
|
||||
|
||||
level_loader.unload_level()
|
||||
|
||||
@ -5,22 +5,36 @@ extends Marker3D
|
||||
signal level_loaded
|
||||
signal level_unloaded
|
||||
|
||||
static var initial_level_reference: PackedScene
|
||||
|
||||
@export_file("*.tscn", "*.scn") var scene_path: String
|
||||
@export var load_threaded: bool = true
|
||||
@export_tool_button("Load Level", "Slot") var editor_load: Callable = load_level
|
||||
@export_tool_button("Unload Level", "Clear") var editor_unload: Callable = unload_level
|
||||
@export_group("Level ID")
|
||||
@export var override_level_id: bool = true
|
||||
@export var level_id: StringName = &""
|
||||
|
||||
var level: Node
|
||||
var is_loading: bool = false
|
||||
|
||||
|
||||
func load_level() -> void:
|
||||
if is_loading:
|
||||
return
|
||||
|
||||
if not Engine.is_editor_hint() and override_level_id:
|
||||
GameGlobals.set_level(level_id)
|
||||
|
||||
if is_instance_valid(level):
|
||||
if level.scene_file_path == scene_path:
|
||||
if _get_uid(level.scene_file_path) == _get_uid(scene_path):
|
||||
push_warning("Level already loaded")
|
||||
return
|
||||
|
||||
unload_level()
|
||||
|
||||
is_loading = true
|
||||
|
||||
var scene: PackedScene
|
||||
|
||||
if load_threaded:
|
||||
@ -33,6 +47,8 @@ func load_level() -> void:
|
||||
level = scene.instantiate()
|
||||
add_child(level)
|
||||
|
||||
is_loading = false
|
||||
initial_level_reference = null
|
||||
level_loaded.emit()
|
||||
|
||||
|
||||
@ -45,11 +61,21 @@ func unload_level() -> void:
|
||||
if child.owner == null:
|
||||
child.queue_free()
|
||||
|
||||
initial_level_reference = null
|
||||
level_unloaded.emit()
|
||||
|
||||
|
||||
func _load_level_threaded() -> PackedScene:
|
||||
var interactive_loader := InteractiveLoader.new()
|
||||
interactive_loader.auto_free = true
|
||||
add_child(interactive_loader)
|
||||
|
||||
return await interactive_loader.load_threaded(scene_path)
|
||||
var resource: Resource = await interactive_loader.load_threaded(scene_path)
|
||||
#interactive_loader.queue_free()
|
||||
return resource
|
||||
|
||||
|
||||
func _get_uid(path: String) -> int:
|
||||
var uid: int = ResourceUID.text_to_id(ResourceUID.path_to_uid(path))
|
||||
#print("UID: ", uid, " Path: ", path)
|
||||
return uid
|
||||
|
||||
31
source/src/core/level/load_threshold_area.gd
Normal file
31
source/src/core/level/load_threshold_area.gd
Normal file
@ -0,0 +1,31 @@
|
||||
class_name LevelThresholdArea
|
||||
extends Area3D
|
||||
|
||||
static var is_level_loading: bool = false
|
||||
|
||||
@export var level_loaders: Array[LevelLoader] = []
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
body_entered.connect(prevent_if_any_loading.unbind(1))
|
||||
|
||||
|
||||
func prevent_if_any_loading() -> bool:
|
||||
for loader: LevelLoader in level_loaders:
|
||||
if not loader.is_loading:
|
||||
continue
|
||||
|
||||
get_tree().paused = true
|
||||
is_level_loading = true
|
||||
SceneFader.set_loading_hints_visible(true)
|
||||
|
||||
while loader.is_loading:
|
||||
await get_tree().process_frame
|
||||
|
||||
SceneFader.set_loading_hints_visible(false)
|
||||
get_tree().paused = false
|
||||
is_level_loading = false
|
||||
return true
|
||||
|
||||
return false
|
||||
1
source/src/core/level/load_threshold_area.gd.uid
Normal file
1
source/src/core/level/load_threshold_area.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dhrqjudaignuc
|
||||
139
source/src/core/vibration_component.gd
Normal file
139
source/src/core/vibration_component.gd
Normal file
@ -0,0 +1,139 @@
|
||||
@tool
|
||||
class_name VibrationComponent
|
||||
extends Node
|
||||
|
||||
## A small helper node to quickly perform controller vibrations.
|
||||
|
||||
|
||||
## If [code]false[/code], calling [method vibrate] will not start a controller vibration.
|
||||
@export var enabled: bool = true:
|
||||
get = is_enabled,
|
||||
set = set_enabled
|
||||
## [param duration] is the duration of the effect in seconds
|
||||
## (a duration of [code]0[/code] will try to play the vibration indefinitely).[br]
|
||||
## The vibration can be stopped early by calling [method stop_vibration].
|
||||
@export var duration: float = 0.15:
|
||||
get = get_duration,
|
||||
set = set_duration
|
||||
## The device index to perform the vibration on.
|
||||
@export var device: int = 0:
|
||||
get = get_device,
|
||||
set = set_device
|
||||
## The delay the vibration by this amount.
|
||||
@export var delay: float = 0.0
|
||||
|
||||
@warning_ignore_start("unused_private_class_variable")
|
||||
@export_tool_button("Test Vibration", "InputEventJoypadMotion")
|
||||
var _editor_test_vibration: Callable = vibrate
|
||||
@export_tool_button("Stop Vibration", "MissingNode")
|
||||
var _editor_stop_test_vibration: Callable = stop_vibration
|
||||
@warning_ignore_restore("unused_private_class_variable")
|
||||
|
||||
@export_group("Magnitude")
|
||||
## [param weak_magnitude] is the strength of the weak motor
|
||||
## (between [code]0[/code] and [code]1[/code]).
|
||||
@export_range(0.0, 1.0) var weak_magnitude: float = 0.1:
|
||||
get = get_weak_magnitude,
|
||||
set = set_weak_magnitude
|
||||
## [param strong_magnitude] is the strength of the strong motor
|
||||
## (between [code]0[/code] and [code]1[/code]).
|
||||
@export_range(0.0, 1.0) var strong_magnitude: float = 0.2:
|
||||
get = get_strong_magnitude,
|
||||
set = set_strong_magnitude
|
||||
## Multiplies [member weak_magnitude] and [member strong_magnitude] by this amount.
|
||||
@export var magnitude_multiplier: float = 1.0:
|
||||
get = get_magnitude_multiplier,
|
||||
set = set_magnitude_multiplier
|
||||
|
||||
var animated_weak_magnitude: float = 0.0:
|
||||
set(value):
|
||||
animated_weak_magnitude = clampf(value, 0.0, 1.0)
|
||||
var animated_strong_magnitude: float = 0.0:
|
||||
set(value):
|
||||
animated_strong_magnitude = clampf(value, 0.0, 1.0)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not is_zero_approx(animated_weak_magnitude + animated_strong_magnitude):
|
||||
Input.start_joy_vibration.call_deferred(
|
||||
device, animated_weak_magnitude, animated_strong_magnitude, delta
|
||||
)
|
||||
animated_weak_magnitude = 0.0
|
||||
animated_strong_magnitude = 0.0
|
||||
|
||||
|
||||
## Performs the controller vibration based on given parameters of the component.[br]
|
||||
## [b]Info[/b]: The [member enabled] parameter must be [code]true[/code].
|
||||
func vibrate() -> void:
|
||||
# Don't vibrate if the user has it turned off.
|
||||
if not Engine.is_editor_hint():
|
||||
if (
|
||||
not InputManager.using_controller
|
||||
#or not ProjectSettings.get_setting("game/input/controller_vibrations", true)
|
||||
):
|
||||
return
|
||||
|
||||
if enabled:
|
||||
if delay > 0.0:
|
||||
await get_tree().create_timer(delay).timeout
|
||||
|
||||
Input.start_joy_vibration(
|
||||
device,
|
||||
clampf(weak_magnitude * magnitude_multiplier, 0.0, 1.0),
|
||||
clampf(strong_magnitude * magnitude_multiplier, 0.0, 1.0),
|
||||
duration
|
||||
)
|
||||
|
||||
|
||||
## Stops the vibration of the joypad, based on the [member device] parameter,
|
||||
## started with [method vibrate].
|
||||
func stop_vibration() -> void:
|
||||
Input.stop_joy_vibration(device)
|
||||
|
||||
|
||||
func set_enabled(value: bool) -> void:
|
||||
enabled = value
|
||||
|
||||
|
||||
func is_enabled() -> bool:
|
||||
return enabled
|
||||
|
||||
|
||||
func set_device(device_id: int) -> void:
|
||||
device = device_id
|
||||
|
||||
|
||||
func get_device() -> int:
|
||||
return device
|
||||
|
||||
|
||||
func set_duration(length: float) -> void:
|
||||
duration = length
|
||||
|
||||
|
||||
func get_duration() -> float:
|
||||
return duration
|
||||
|
||||
|
||||
func set_magnitude_multiplier(multiplier_value: float) -> void:
|
||||
magnitude_multiplier = multiplier_value
|
||||
|
||||
|
||||
func get_magnitude_multiplier() -> float:
|
||||
return magnitude_multiplier
|
||||
|
||||
|
||||
func set_weak_magnitude(weak_value: float) -> void:
|
||||
weak_magnitude = weak_value
|
||||
|
||||
|
||||
func get_weak_magnitude() -> float:
|
||||
return weak_magnitude
|
||||
|
||||
|
||||
func set_strong_magnitude(strong_value: float) -> void:
|
||||
strong_magnitude = strong_value
|
||||
|
||||
|
||||
func get_strong_magnitude() -> float:
|
||||
return strong_magnitude
|
||||
1
source/src/core/vibration_component.gd.uid
Normal file
1
source/src/core/vibration_component.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bbwtct3hoxwws
|
||||
@ -3,6 +3,8 @@ extends Node
|
||||
|
||||
const PLAYER: PackedScene = preload(GameGlobals.PLAYER_PATH)
|
||||
|
||||
@export_group("Debug", "debug_")
|
||||
@export_custom(PROPERTY_HINT_GROUP_ENABLE, "checkbox_only") var debug_enabled: bool = false
|
||||
@export var debug_spawn_point: StringName = &""
|
||||
@export_range(-1, 0, 1, "or_greater") var debug_chapter_idx: int = -1
|
||||
|
||||
@ -10,14 +12,17 @@ var player_character: PlayerCharacter
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
if OS.has_feature("editor") and not debug_spawn_point.is_empty():
|
||||
GameGlobals.game = self
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
if OS.has_feature("editor") and debug_enabled:
|
||||
if not debug_spawn_point.is_empty():
|
||||
GameGlobals.set_spawn_id(debug_spawn_point)
|
||||
|
||||
if debug_chapter_idx >= 0:
|
||||
GameGlobals.set_chapter_index(debug_chapter_idx)
|
||||
|
||||
GameGlobals.game = self
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
class_name Character3D
|
||||
extends CharacterBody3D
|
||||
extends StairsCharacter3D
|
||||
|
||||
@export var movement: CharacterMovement
|
||||
@export var speed_scale: float = 1.0
|
||||
@ -12,11 +12,11 @@ var air_control: float = 1.0
|
||||
var freeze_air_control: bool = false
|
||||
var last_platform_velocity := Vector3.ZERO
|
||||
var _was_on_floor: bool = false
|
||||
var _previous_velocity: Vector3
|
||||
var previous_velocity: Vector3
|
||||
|
||||
|
||||
func move(direction: Vector3, delta: float) -> void:
|
||||
direction *= (speed * speed_scale)
|
||||
direction *= speed * speed_scale
|
||||
|
||||
var on_floor: bool = is_on_floor()
|
||||
|
||||
@ -56,7 +56,7 @@ func move(direction: Vector3, delta: float) -> void:
|
||||
velocity = velocity.move_toward(direction, speed_change * delta)
|
||||
|
||||
await get_tree().physics_frame
|
||||
_previous_velocity = velocity
|
||||
previous_velocity = velocity
|
||||
#DebugDraw3D.draw_arrow(global_position, global_position + velocity, Color.BLUE, 0.5, true)
|
||||
#SPrint.print_msg("%s Velocity: %s" % [self , velocity], 0.02)
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
class_name GameCamera3D
|
||||
class_name PlayerHead
|
||||
extends Node3D
|
||||
|
||||
const ACTION_CAMERA_UP: StringName = &"camera_up"
|
||||
@ -38,13 +38,24 @@ const CONTROLLER_INVERT_Y_PATH: StringName = &"game/input/camera_controller_inve
|
||||
@export var headbob_frequency: float = 0.5
|
||||
@export var headbob_multiplier: float = 1.0
|
||||
@export var headbob_character: Character3D
|
||||
@export var headbob_target: Node3D
|
||||
|
||||
@export_group("Step Smoothing", "step_")
|
||||
@export var step_smoothing_target: Node3D
|
||||
@export var step_speed: float = 8.0
|
||||
|
||||
var rotational_direction: Vector2
|
||||
var rotational_velocity: Vector2
|
||||
var input_event: InputEvent
|
||||
var using_controller: bool = false
|
||||
# Headbobbing
|
||||
var headbob_time: float = 0.0
|
||||
var headbob_enabled: bool = true
|
||||
# Stair smooting
|
||||
var stair_camera_offset_height: float = 0.0
|
||||
var _previous_position: Vector3
|
||||
var _stair_camera_target_height: float = 0.0
|
||||
var _stair_camera_step_smoothing: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@ -62,18 +73,23 @@ func _ready() -> void:
|
||||
ProjectSettings.settings_changed.connect(_update_settings)
|
||||
_update_settings.call()
|
||||
|
||||
_setup_step_smoothing()
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not GameGlobals.in_cutscene:
|
||||
_process_input(delta)
|
||||
_perform_head_bob(delta)
|
||||
|
||||
_process_step_smoothing(delta)
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion or event is InputEventJoypadMotion:
|
||||
input_event = event
|
||||
|
||||
|
||||
#region Mouse/Controller rotation
|
||||
func apply_rotation(rot: Vector2) -> void:
|
||||
rotate_y(-rot.x)
|
||||
rotation.x = rotation.x - rot.y
|
||||
@ -156,12 +172,14 @@ func _process_controller(delta: float) -> void:
|
||||
|
||||
func _lerp_rotational_velocity(sensitivity: float, friction: float, delta: float) -> Vector2:
|
||||
return rotational_velocity.lerp(rotational_direction * sensitivity, friction * delta)
|
||||
#endregion
|
||||
|
||||
|
||||
#region Headbobbing
|
||||
func _perform_head_bob(delta: float) -> void:
|
||||
if not headbob_enabled:
|
||||
camera.position = Vector3.ZERO
|
||||
camera.rotation.z = 0.0
|
||||
headbob_target.position = Vector3.ZERO
|
||||
headbob_target.rotation.z = 0.0
|
||||
headbob_time = 0.0
|
||||
return
|
||||
|
||||
@ -172,7 +190,38 @@ func _perform_head_bob(delta: float) -> void:
|
||||
headbob_time += delta * headbob_speed * headbob_multiplier
|
||||
headbob_time = fposmod(headbob_time, TAU)
|
||||
|
||||
camera.position.y = sin(headbob_time * headbob_frequency) * headbob_range
|
||||
camera.position.x = cos(headbob_time * headbob_frequency / 2) * headbob_range
|
||||
camera.rotation.z = deg_to_rad(lerp(camera.position.x, camera.position.y, 0.5)) * TAU
|
||||
SPrint.print_msgf(str("Head Z-Rotation: ", camera.rotation.z), true)
|
||||
headbob_target.position.y = sin(headbob_time * headbob_frequency) * headbob_range
|
||||
headbob_target.position.x = cos(headbob_time * headbob_frequency / 2) * headbob_range
|
||||
headbob_target.rotation.z = deg_to_rad(lerp(headbob_target.position.x, headbob_target.position.y, 0.5)) * TAU
|
||||
SPrint.print_msgf(str("Head Z-Rotation: ", headbob_target.rotation.z), true)
|
||||
#endregion
|
||||
|
||||
|
||||
#region Step Smoothing
|
||||
func smooth_step(height_change: float) -> void:
|
||||
_stair_camera_target_height -= height_change
|
||||
_stair_camera_step_smoothing = true
|
||||
|
||||
|
||||
func _setup_step_smoothing() -> void:
|
||||
headbob_character.on_stair_step.connect(_on_stair_step)
|
||||
stair_camera_offset_height = step_smoothing_target.position.y
|
||||
|
||||
|
||||
func _on_stair_step() -> void:
|
||||
smooth_step(global_position.y - _previous_position.y)
|
||||
|
||||
|
||||
func _process_step_smoothing(delta: float) -> void:
|
||||
if _stair_camera_step_smoothing and is_instance_valid(step_smoothing_target):
|
||||
_stair_camera_target_height = lerp(_stair_camera_target_height, 0.0, step_speed * delta)
|
||||
|
||||
if absf(_stair_camera_target_height) < 0.0025:
|
||||
_stair_camera_target_height = 0.0
|
||||
_stair_camera_step_smoothing = false
|
||||
|
||||
var target_pos := Vector3.UP * (stair_camera_offset_height + _stair_camera_target_height)
|
||||
step_smoothing_target.position = target_pos.rotated(Vector3.LEFT, rotation.x)
|
||||
|
||||
_previous_position = global_position
|
||||
#endregion
|
||||
|
||||
@ -25,9 +25,10 @@ var has_control: bool = true
|
||||
var is_crouching: bool = false
|
||||
var crouch_speed_affection: float = 0.0
|
||||
|
||||
@onready var head: GameCamera3D = $Head
|
||||
@onready var collision_shape: CollisionShape3D = $CollisionShape3D
|
||||
@onready var head: PlayerHead = $Head
|
||||
@onready var collision_shape: CollisionShape3D = $CylinderCollider
|
||||
@onready var standup_checker: Area3D = $StandupChecker
|
||||
@onready var stair_stepper: StairStepper = $StairStepper
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@ -51,12 +52,15 @@ func _physics_process(delta: float) -> void:
|
||||
if not is_on_floor():
|
||||
apply_gravity(delta)
|
||||
elif not _was_on_floor:
|
||||
if _previous_velocity.y <= -2.0:
|
||||
if previous_velocity.y <= -2.0:
|
||||
head.camera.shake(0.025, 0.175)
|
||||
|
||||
if not has_control:
|
||||
move(Vector3.ZERO, delta)
|
||||
move_and_slide()
|
||||
move_and_stair_step()
|
||||
|
||||
#if is_on_floor():
|
||||
#stair_stepper.handle_step_climbing()
|
||||
return
|
||||
|
||||
# Handle jump.
|
||||
@ -78,8 +82,15 @@ func _physics_process(delta: float) -> void:
|
||||
speed *= remap(crouch_speed_affection, 0.0, 1.0, 1.0, standup_speed_affection)
|
||||
|
||||
move(movement_direction, delta)
|
||||
move_and_stair_step()
|
||||
|
||||
move_and_slide()
|
||||
SPrint.print_msgf(
|
||||
"Player Horizontal-Velocity: %s\nPlayer Vertical-Velocity: %s"
|
||||
% [(velocity * Utils.VEC3_HOR).length(), velocity.y], true
|
||||
)
|
||||
|
||||
#if is_on_floor():
|
||||
#stair_stepper.handle_step_climbing()
|
||||
|
||||
|
||||
func apply_gravity(delta: float) -> void:
|
||||
@ -119,4 +130,8 @@ func handle_crouching(delta: float) -> void:
|
||||
head.position.y = lerp(head.position.y, target_camera_height, weight)
|
||||
|
||||
crouch_speed_affection = lerp(crouch_speed_affection, float(is_crouching), weight * standup_speed_affection_speed_multiplier if not is_crouching else 1.0)
|
||||
SPrint.print_msgf("Crouching Speed Affection: %s\n%s" % [crouch_speed_affection, is_crouching], true)
|
||||
|
||||
if crouch_speed_affection <= 0.05:
|
||||
crouch_speed_affection = 0.0
|
||||
|
||||
SPrint.print_msgf("Crouching Speed Affection: %s\nIs Crouching: %s" % [crouch_speed_affection, is_crouching], true)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=9 format=3 uid="uid://clhy3kiceqf2o"]
|
||||
[gd_scene load_steps=10 format=3 uid="uid://clhy3kiceqf2o"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://day6rhxicaxqf" path="res://src/gameplay/characters/player/player_character.gd" id="1_hqu6r"]
|
||||
[ext_resource type="Script" uid="uid://dsjlv8midt2g2" path="res://src/gameplay/characters/character_movement.gd" id="2_1ixuj"]
|
||||
@ -13,14 +13,24 @@ max_turning_speed = 70.0
|
||||
peak_gravity_multiplier = 0.3
|
||||
metadata/_custom_type_script = "uid://dsjlv8midt2g2"
|
||||
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_fjt7c"]
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_bdj5f"]
|
||||
margin = 0.01
|
||||
radius = 0.46
|
||||
height = 1.8
|
||||
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_gy1j0"]
|
||||
height = 1.59
|
||||
radius = 0.49
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_bdj5f"]
|
||||
margin = 0.01
|
||||
height = 1.8
|
||||
radius = 0.46
|
||||
|
||||
[node name="PlayerCharacter" type="CharacterBody3D"]
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_ntkcp"]
|
||||
height = 1.59
|
||||
radius = 0.45
|
||||
|
||||
[node name="PlayerCharacter" type="StairsCharacter3D"]
|
||||
collider = NodePath("CylinderCollider")
|
||||
step_height_up = 0.7
|
||||
step_height_down = 0.7
|
||||
collision_layer = 2
|
||||
script = ExtResource("1_hqu6r")
|
||||
standup_speed_affection = 0.15
|
||||
@ -28,30 +38,43 @@ standup_speed_affection_speed_multiplier = 0.5
|
||||
movement = SubResource("Resource_vq0uu")
|
||||
metadata/_custom_type_script = "uid://day6rhxicaxqf"
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
[node name="CapsuleCollider" type="CollisionShape3D" parent="."]
|
||||
process_mode = 4
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9, 0)
|
||||
shape = SubResource("CylinderShape3D_fjt7c")
|
||||
visible = false
|
||||
shape = SubResource("CapsuleShape3D_bdj5f")
|
||||
disabled = true
|
||||
|
||||
[node name="Head" type="Node3D" parent="." node_paths=PackedStringArray("camera", "headbob_character")]
|
||||
[node name="CylinderCollider" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9, 0)
|
||||
shape = SubResource("CylinderShape3D_bdj5f")
|
||||
|
||||
[node name="Head" type="Node3D" parent="." node_paths=PackedStringArray("camera", "headbob_character", "headbob_target", "step_smoothing_target")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
|
||||
script = ExtResource("2_fjt7c")
|
||||
camera = NodePath("ShakingCamera")
|
||||
camera = NodePath("Headbobbing/StairStepping/ShakingCamera")
|
||||
headbob_range = 0.05
|
||||
headbob_frequency = 2.0
|
||||
headbob_character = NodePath("..")
|
||||
headbob_target = NodePath("Headbobbing")
|
||||
step_smoothing_target = NodePath("Headbobbing/StairStepping")
|
||||
|
||||
[node name="ShakingCamera" type="Camera3D" parent="Head"]
|
||||
[node name="Headbobbing" type="Node3D" parent="Head"]
|
||||
|
||||
[node name="StairStepping" type="Node3D" parent="Head/Headbobbing"]
|
||||
|
||||
[node name="ShakingCamera" type="Camera3D" parent="Head/Headbobbing/StairStepping"]
|
||||
current = true
|
||||
fov = 85.0
|
||||
script = ExtResource("4_ci1ud")
|
||||
metadata/_custom_type_script = "uid://44s0v8mukxk4"
|
||||
|
||||
[node name="FootstepComponent" type="Node" parent="." node_paths=PackedStringArray("character")]
|
||||
script = ExtResource("4_vq0uu")
|
||||
character = NodePath("..")
|
||||
|
||||
[node name="StandupChecker" type="Area3D" parent="."]
|
||||
input_ray_pickable = false
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StandupChecker"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.99, 0)
|
||||
shape = SubResource("CylinderShape3D_gy1j0")
|
||||
shape = SubResource("CylinderShape3D_ntkcp")
|
||||
|
||||
[node name="FootstepComponent" type="Node" parent="."]
|
||||
script = ExtResource("4_vq0uu")
|
||||
|
||||
@ -3,15 +3,21 @@ extends Node
|
||||
signal player_died(death_type: DeathTypes)
|
||||
|
||||
const MAIN_MENU_PATH: String = "uid://dwd8wf02j2epn"
|
||||
const INITIAL_LEVEL_ID: StringName = &"OutsideArea"
|
||||
const GAME_PATH: String = "uid://s7cw6ulb7kh7"
|
||||
const PLAYER_PATH: String = "uid://clhy3kiceqf2o"
|
||||
const CHAPTER_LIST: ChapterList = preload("uid://d2mcwotliowv7")
|
||||
const LEVELS: Dictionary[StringName, String] = {
|
||||
&"OutsideArea": "uid://lraild3yetsh",
|
||||
&"EntranceHall": "uid://cmdy6f6kesmbj",
|
||||
}
|
||||
|
||||
enum DeathTypes {
|
||||
SAW,
|
||||
}
|
||||
|
||||
var game: Game
|
||||
var level: StringName = &""
|
||||
var player: PlayerCharacter
|
||||
var player_alive: bool = true
|
||||
var spawn_id: StringName = &"": set = set_spawn_id
|
||||
@ -26,6 +32,7 @@ func get_player() -> PlayerCharacter:
|
||||
func reset_game() -> void:
|
||||
player_alive = true
|
||||
spawn_id = &""
|
||||
level = INITIAL_LEVEL_ID
|
||||
chapter_index = 0
|
||||
in_cutscene = false
|
||||
|
||||
@ -36,6 +43,7 @@ func load_from_save() -> void:
|
||||
var data: Dictionary[StringName, Variant] = SaveManager.persistent_data
|
||||
spawn_id = data.get(&"spawn_id")
|
||||
chapter_index = data.get(&"chapter_index")
|
||||
level = data.get(&"level", &"")
|
||||
|
||||
|
||||
func set_spawn_id(id: StringName) -> void:
|
||||
@ -50,6 +58,12 @@ func set_chapter_index(index: int) -> void:
|
||||
SaveManager.persistent_data[&"chapter_index"] = chapter_index
|
||||
|
||||
|
||||
func set_level(level_id: StringName) -> void:
|
||||
level = level_id
|
||||
|
||||
SaveManager.persistent_data[&"level"] = level
|
||||
|
||||
|
||||
func kill_player(death_type: DeathTypes) -> void:
|
||||
if not player_alive:
|
||||
return
|
||||
|
||||
@ -8,6 +8,7 @@ var persistent_data: Dictionary[StringName, Variant] = {
|
||||
&"spawn_id": &"",
|
||||
&"sequence_index": 0,
|
||||
&"chapter_index": 0,
|
||||
&"level": &"",
|
||||
&"level_data": {
|
||||
|
||||
}
|
||||
|
||||
@ -12,24 +12,33 @@ var is_loading: bool = false
|
||||
@onready var color_rect: ColorRect = %ColorRect
|
||||
@onready var loading_hint_animations: AnimationPlayer = %LoadingHintAnimations
|
||||
@onready var loading_hint: TextureRect = %LoadingHint
|
||||
@onready var loading_label: RichTextLabel = $LoadingLabel
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
loading_label.hide()
|
||||
color_rect.hide()
|
||||
color_rect.color.a = 0.0
|
||||
|
||||
|
||||
func load_to_path(path: String) -> void:
|
||||
func load_to_path(path: String, initial_level: String = "") -> void:
|
||||
if is_loading:
|
||||
return
|
||||
|
||||
is_loading = true
|
||||
|
||||
await fade_in()
|
||||
await get_tree().create_timer(1.0).timeout
|
||||
#await get_tree().create_timer(1.0).timeout
|
||||
|
||||
# Load the initial level into memory first, so it can be retrived by other things later.
|
||||
if not initial_level.is_empty():
|
||||
LevelLoader.initial_level_reference = await interactive_loader.load_threaded(initial_level)
|
||||
|
||||
print("Initial Level Reference Loaded: ", LevelLoader.initial_level_reference)
|
||||
|
||||
var scene: PackedScene = await interactive_loader.load_threaded(path)
|
||||
|
||||
print("Scene Loaded: ", scene)
|
||||
assert(is_instance_valid(scene), "Scene is invalid.")
|
||||
|
||||
get_tree().change_scene_to_packed(scene)
|
||||
@ -49,13 +58,11 @@ func fade_in() -> void:
|
||||
|
||||
is_fading = false
|
||||
|
||||
loading_hint_animations.play(_ANIM_LOADING)
|
||||
loading_hint.show()
|
||||
set_loading_hints_visible(true)
|
||||
|
||||
|
||||
func fade_out() -> void:
|
||||
loading_hint_animations.stop()
|
||||
loading_hint.hide()
|
||||
set_loading_hints_visible(false)
|
||||
|
||||
is_fading = true
|
||||
|
||||
@ -65,3 +72,14 @@ func fade_out() -> void:
|
||||
|
||||
color_rect.hide()
|
||||
is_fading = false
|
||||
|
||||
|
||||
func set_loading_hints_visible(value: bool) -> void:
|
||||
loading_hint.visible = value
|
||||
loading_label.visible = value
|
||||
|
||||
if value:
|
||||
loading_label.set_text(loading_label.text) # Restart the effect.
|
||||
loading_hint_animations.play(_ANIM_LOADING)
|
||||
else:
|
||||
loading_hint_animations.stop()
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://dis4efdm5s2fc"]
|
||||
[gd_scene load_steps=9 format=3 uid="uid://dis4efdm5s2fc"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cynllcoh2smgv" path="res://src/globals/autoloads/scene_fader/scene_fader.gd" id="1_7tt87"]
|
||||
[ext_resource type="Script" uid="uid://d0k03wk1s7cw0" path="res://src/core/interactive_loader.gd" id="2_dwqb8"]
|
||||
[ext_resource type="Texture2D" uid="uid://dhw8y2oqxvgwu" path="res://godot_icon.svg" id="3_dwqb8"]
|
||||
[ext_resource type="Script" uid="uid://41co2svrlbkc" path="res://src/ui/rich_effects/loading_text_effect.gd" id="3_s8mqo"]
|
||||
|
||||
[sub_resource type="RichTextEffect" id="RichTextEffect_tvon4"]
|
||||
resource_name = "RichTextLoading"
|
||||
script = ExtResource("3_s8mqo")
|
||||
metadata/_custom_type_script = "uid://41co2svrlbkc"
|
||||
|
||||
[sub_resource type="Animation" id="Animation_t3447"]
|
||||
length = 0.001
|
||||
@ -85,6 +91,20 @@ grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="LoadingLabel" type="RichTextLabel" parent="."]
|
||||
anchors_preset = -1
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
bbcode_enabled = true
|
||||
text = "[loading]Loading...[/loading]"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
custom_effects = [SubResource("RichTextEffect_tvon4")]
|
||||
|
||||
[node name="HintMargin" type="MarginContainer" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
[gd_scene load_steps=8 format=3 uid="uid://dspysc2bld6eu"]
|
||||
[gd_scene load_steps=10 format=3 uid="uid://dspysc2bld6eu"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dfnb036hysorj" path="res://src/core/level/level_loader.gd" id="1_kntr3"]
|
||||
[ext_resource type="PackedScene" uid="uid://drr80goa61wrx" path="res://src/core/level/level_area.tscn" id="2_5mqkb"]
|
||||
[ext_resource type="Script" uid="uid://3hlvt5k34xva" path="res://src/core/player_spawn_point.gd" id="3_aoi14"]
|
||||
[ext_resource type="Script" uid="uid://dhrqjudaignuc" path="res://src/core/level/load_threshold_area.gd" id="3_mcc85"]
|
||||
[ext_resource type="Script" uid="uid://dgsfc4i6bovwa" path="res://src/core/chapter/chapter_area.gd" id="4_sujqt"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_aoi14"]
|
||||
@ -11,6 +12,9 @@ size = Vector3(17, 9, 36)
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_5mqkb"]
|
||||
size = Vector3(31, 19, 37)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_mcc85"]
|
||||
size = Vector3(4, 3, 0.5)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_sujqt"]
|
||||
size = Vector3(4, 3, 1)
|
||||
|
||||
@ -21,12 +25,14 @@ size = Vector3(4, 3, 1)
|
||||
[node name="OutsideArea" type="Marker3D" parent="LevelLoaders"]
|
||||
script = ExtResource("1_kntr3")
|
||||
scene_path = "uid://lraild3yetsh"
|
||||
level_id = &"OutsideArea"
|
||||
metadata/_custom_type_script = "uid://dfnb036hysorj"
|
||||
|
||||
[node name="EntranceHall" type="Marker3D" parent="LevelLoaders"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.3, 3.5, 33)
|
||||
script = ExtResource("1_kntr3")
|
||||
scene_path = "uid://cmdy6f6kesmbj"
|
||||
level_id = &"EntranceHall"
|
||||
metadata/_custom_type_script = "uid://dfnb036hysorj"
|
||||
|
||||
[node name="LevelAreas" type="Node" parent="."]
|
||||
@ -49,6 +55,25 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 9, 53)
|
||||
shape = SubResource("BoxShape3D_5mqkb")
|
||||
debug_color = Color(1, 1, 0, 0.41960785)
|
||||
|
||||
[node name="LevelLoadThresholds" type="Node" parent="."]
|
||||
|
||||
[node name="LevelThresholdArea" type="Area3D" parent="LevelLoadThresholds" node_paths=PackedStringArray("level_loaders")]
|
||||
collision_layer = 0
|
||||
collision_mask = 2
|
||||
script = ExtResource("3_mcc85")
|
||||
level_loaders = [NodePath("../../LevelLoaders/OutsideArea"), NodePath("../../LevelLoaders/EntranceHall")]
|
||||
metadata/_custom_type_script = "uid://dhrqjudaignuc"
|
||||
|
||||
[node name="CollisionShape" type="CollisionShape3D" parent="LevelLoadThresholds/LevelThresholdArea"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.8, 5, 36.2)
|
||||
shape = SubResource("BoxShape3D_mcc85")
|
||||
debug_color = Color(1, 0.5176471, 0, 0.41960785)
|
||||
|
||||
[node name="CollisionShape2" type="CollisionShape3D" parent="LevelLoadThresholds/LevelThresholdArea"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.8, 5, 33)
|
||||
shape = SubResource("BoxShape3D_mcc85")
|
||||
debug_color = Color(1, 0.5176471, 0, 0.41960785)
|
||||
|
||||
[node name="Spawnpoints" type="Node" parent="."]
|
||||
|
||||
[node name="OutsideSpawnPoint" type="Marker3D" parent="Spawnpoints"]
|
||||
|
||||
@ -12,6 +12,7 @@ const AMBIENCE_STREAM: AudioStream = preload("uid://cyxvsy5wjxhl7")
|
||||
|
||||
func _ready() -> void:
|
||||
continue_button.disabled = not SaveManager.save_exists()
|
||||
(continue_button if not continue_button.disabled else new_game_button).grab_focus()
|
||||
|
||||
AudioManager.play_audio(AMBIENCE_STREAM, AudioManager.AMBIENCE)
|
||||
|
||||
@ -24,7 +25,7 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||
|
||||
func load_game() -> void:
|
||||
AudioManager.fade_audio(AMBIENCE_STREAM, -80.0, SceneFader.fade_in_duration, AudioManager.AMBIENCE, true)
|
||||
SceneFader.load_to_path(GameGlobals.GAME_PATH)
|
||||
SceneFader.load_to_path(GameGlobals.GAME_PATH, GameGlobals.LEVELS.get(GameGlobals.level, &""))
|
||||
|
||||
|
||||
func _on_new_game_button_pressed() -> void:
|
||||
|
||||
@ -10,6 +10,9 @@ var can_pause: bool = true
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if LevelThresholdArea.is_level_loading:
|
||||
return
|
||||
|
||||
if event.is_action_pressed(ACTION_PAUSE):
|
||||
if options_menu.is_visible_in_tree():
|
||||
options_menu.close_menu()
|
||||
|
||||
48
source/src/ui/rich_effects/loading_text_effect.gd
Normal file
48
source/src/ui/rich_effects/loading_text_effect.gd
Normal file
@ -0,0 +1,48 @@
|
||||
@tool
|
||||
class_name RichTextLoading
|
||||
extends RichTextEffect
|
||||
|
||||
|
||||
var bbcode: String = "loading"
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
resource_name = "RichTextLoading"
|
||||
|
||||
|
||||
func _process_custom_fx(char_fx: CharFXTransform) -> bool:
|
||||
_process_big_wave(char_fx)
|
||||
_process_small_wave(char_fx)
|
||||
_process_fade(char_fx)
|
||||
return true
|
||||
|
||||
|
||||
func _process_big_wave(char_fx: CharFXTransform) -> void:
|
||||
var freq: float = char_fx.env.get("freq", 1.0)
|
||||
var height: float = char_fx.env.get("height", 25.0)
|
||||
var char_range: float = char_fx.env.get("range", 0.15)
|
||||
var curve: float = char_fx.env.get("curve", -13.0)
|
||||
|
||||
var time_offset := float(-char_fx.relative_index) * char_range
|
||||
var sined_time: float = (sin((char_fx.elapsed_time + PI) * freq + time_offset) + 1.0) / 2.0
|
||||
sined_time = ease(sined_time, curve)
|
||||
var y_offset: float = sined_time * height
|
||||
char_fx.offset += Vector2.DOWN * y_offset
|
||||
|
||||
|
||||
func _process_small_wave(char_fx: CharFXTransform) -> void:
|
||||
var freq: float = char_fx.env.get("freq", 4.0)
|
||||
var height: float = char_fx.env.get("height", 12.5)
|
||||
var char_range: float = char_fx.env.get("range", 0.5)
|
||||
var curve: float = char_fx.env.get("curve", 6.5)
|
||||
|
||||
var time_offset := float(-char_fx.relative_index) * char_range
|
||||
var sined_time: float = (sin((char_fx.elapsed_time + PI) * freq + time_offset) + 1.0) / 2.0
|
||||
sined_time = ease(sined_time, curve)
|
||||
var y_offset: float = sined_time * height * (1.0 - char_fx.offset.y / 25.0)
|
||||
char_fx.offset += Vector2.UP * y_offset
|
||||
|
||||
|
||||
func _process_fade(char_fx: CharFXTransform) -> void:
|
||||
var alpha: float = 1.0 - char_fx.offset.y / 25.0
|
||||
char_fx.color.a = alpha
|
||||
1
source/src/ui/rich_effects/loading_text_effect.gd.uid
Normal file
1
source/src/ui/rich_effects/loading_text_effect.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://41co2svrlbkc
|
||||
Loading…
Reference in New Issue
Block a user