Compare commits

..

2 Commits

Author SHA1 Message Date
YourWishes 7c9daf91a1 More camera tweaking 2026-06-12 07:44:32 -05:00
YourWishes c7b0d79d06 Entity movement improvements 2026-06-11 23:03:11 -05:00
7 changed files with 125 additions and 68 deletions
+20 -7
View File
@@ -1,6 +1,6 @@
class_name OverworldCamera extends Camera3D class_name OverworldCamera extends Camera3D
enum CameraMode { FREE, CENTERED } enum CameraMode { FREE, CENTERED, MANUAL_CENTER }
# const COLLISION_MARGIN:float = 0.1 # const COLLISION_MARGIN:float = 0.1
const COLLISION_MARGIN:float = 0 const COLLISION_MARGIN:float = 0
@@ -28,6 +28,7 @@ const COLLISION_MARGIN:float = 0
@export var centeredAcceleration:float = 180.0 @export var centeredAcceleration:float = 180.0
@export var centeredMaxYawDiff:float = 120.0 @export var centeredMaxYawDiff:float = 120.0
@export var centeredPitch:float = 30.0 @export var centeredPitch:float = 30.0
@export var manualCenterMultiplier:float = 10.0
@export_category("Collision") @export_category("Collision")
@export_flags_3d_physics var collisionMask:int = 1 @export_flags_3d_physics var collisionMask:int = 1
@@ -84,9 +85,9 @@ func _process(delta:float) -> void:
_pitch += _mouseDelta.y * mouseSensitivity * SETTINGS.cameraSpeedMouse * yMult _pitch += _mouseDelta.y * mouseSensitivity * SETTINGS.cameraSpeedMouse * yMult
_mouseDelta = Vector2.ZERO _mouseDelta = Vector2.ZERO
# center_camera input → switch to CENTERED immediately # center_camera input → switch to MANUAL_CENTER immediately
if Input.is_action_just_pressed("center_camera"): if Input.is_action_just_pressed("center_camera"):
_mode = CameraMode.CENTERED _mode = CameraMode.MANUAL_CENTER
# In FREE mode, accumulate time toward auto-centering while the player is moving # In FREE mode, accumulate time toward auto-centering while the player is moving
if _mode == CameraMode.FREE: if _mode == CameraMode.FREE:
@@ -102,16 +103,28 @@ func _process(delta:float) -> void:
# In CENTERED mode, accelerate a yaw velocity toward behind the player (using # In CENTERED mode, accelerate a yaw velocity toward behind the player (using
# actual movement velocity for direction) then friction-decay when idle — # actual movement velocity for direction) then friction-decay when idle —
# mirrors how controller input works so there's no sudden stop. # mirrors how controller input works so there's no sudden stop.
if _mode == CameraMode.CENTERED: if _mode == CameraMode.CENTERED or _mode == CameraMode.MANUAL_CENTER:
var centerBody := targetNode as CharacterBody3D var centerBody := targetNode as CharacterBody3D
var vel3d:Vector3 = Vector3.ZERO if centerBody == null else centerBody.velocity var vel3d:Vector3 = Vector3.ZERO if centerBody == null else centerBody.velocity
var behindYaw:float = 0.0
var hasTarget:bool = false
if vel3d.length_squared() > 0.1: if vel3d.length_squared() > 0.1:
var behindYaw:float = rad_to_deg(atan2(-vel3d.x, -vel3d.z)) behindYaw = rad_to_deg(atan2(-vel3d.x, -vel3d.z))
hasTarget = true
elif _mode == CameraMode.MANUAL_CENTER and targetNode != null:
behindYaw = rad_to_deg(targetNode.rotation.y)
hasTarget = true
if hasTarget:
var centerYawDiff:float = fposmod(behindYaw - _yaw + 180.0, 360.0) - 180.0 var centerYawDiff:float = fposmod(behindYaw - _yaw + 180.0, 360.0) - 180.0
if _mode == CameraMode.MANUAL_CENTER and abs(centerYawDiff) < centeredMaxYawDiff * 0.05:
_mode = CameraMode.FREE
var totalAngle:float = abs(centerYawDiff) + abs(centeredPitch - _pitch) var totalAngle:float = abs(centerYawDiff) + abs(centeredPitch - _pitch)
var dynamicRate:float = minf(centeredFollowRate * (1.0 + totalAngle / 90.0), centeredMaxFollowRate) var speedMult:float = manualCenterMultiplier if _mode == CameraMode.MANUAL_CENTER else 1.0
var dynamicRate:float = minf(centeredFollowRate * (1.0 + totalAngle / 90.0), centeredMaxFollowRate) * speedMult
if abs(centerYawDiff) <= centeredMaxYawDiff: if abs(centerYawDiff) <= centeredMaxYawDiff:
_centerVelocity = move_toward(_centerVelocity, centerYawDiff * dynamicRate, centeredAcceleration * delta) _centerVelocity = move_toward(_centerVelocity, centerYawDiff * dynamicRate, centeredAcceleration * speedMult * delta)
var tPitch:float = minf(dynamicRate * 3.0 * delta, 1.0) var tPitch:float = minf(dynamicRate * 3.0 * delta, 1.0)
_pitch = lerpf(_pitch, centeredPitch, tPitch) _pitch = lerpf(_pitch, centeredPitch, tPitch)
else: else:
+1
View File
@@ -27,6 +27,7 @@ size = Vector3(1.3, 1.3, 1.3)
[node name="Entity" type="CharacterBody3D"] [node name="Entity" type="CharacterBody3D"]
collision_layer = 2 collision_layer = 2
collision_mask = 3
script = ExtResource("1_8e8ef") script = ExtResource("1_8e8ef")
entityId = "35ce980f-3df9-4e09-b365-1a228948cf78" entityId = "35ce980f-3df9-4e09-b365-1a228948cf78"
metadata/_custom_type_script = "uid://c8146flooxeue" metadata/_custom_type_script = "uid://c8146flooxeue"
+7 -11
View File
@@ -2,17 +2,13 @@ class_name EntityMovement extends Node
const GRAVITY = Vector3.DOWN * 100 const GRAVITY = Vector3.DOWN * 100
const FRICTION = 0.01 const FRICTION = 0.01
const WALK_SPEED_DEFAULT = 8 const SPEED_DEFAULT = 8
const RUN_SPEED_DEFAULT = 12 const ROTATION_SPEED_DEFAULT = 15.0
# var _inputDir:Vector2 = Vector2.ZERO
# var _running:bool = false
@export var entity:Entity @export var entity:Entity
@export var interactingArea:EntityInteractingArea @export var interactingArea:EntityInteractingArea
# @export var rotate:Node3D @export var speed:float = SPEED_DEFAULT
@export var walkSpeed:float = WALK_SPEED_DEFAULT @export var rotationSpeed:float = ROTATION_SPEED_DEFAULT
# @export var runSpeed:float = RUN_SPEED_DEFAULT
# #
# Private Methods # Private Methods
@@ -21,7 +17,7 @@ func _applyGravity() -> void:
if !entity.is_on_floor(): if !entity.is_on_floor():
entity.velocity += GRAVITY * get_process_delta_time() entity.velocity += GRAVITY * get_process_delta_time()
func _applyPlayerMovement(_delta:float): func _applyPlayerMovement(delta:float):
# Interactions, may move # Interactions, may move
if Input.is_action_just_pressed("interact") && interactingArea && interactingArea.hasInteraction(): if Input.is_action_just_pressed("interact") && interactingArea && interactingArea.hasInteraction():
interactingArea.interact() interactingArea.interact()
@@ -48,9 +44,9 @@ func _applyPlayerMovement(_delta:float):
if directionAdjusted.length() <= 0.01: if directionAdjusted.length() <= 0.01:
return return
entity.look_at(entity.global_position + directionAdjusted, Vector3.UP) var targetYaw:float = atan2(-directionAdjusted.x, -directionAdjusted.z)
entity.rotation.y = lerp_angle(entity.rotation.y, targetYaw, rotationSpeed * delta)
var speed = walkSpeed
entity.velocity.x = directionAdjusted.x * speed entity.velocity.x = directionAdjusted.x * speed
entity.velocity.z = directionAdjusted.z * speed entity.velocity.z = directionAdjusted.z * speed
+41 -41
View File
@@ -65,6 +65,47 @@ theme/custom_font="uid://ck4rsg0nvvxtq"
[input] [input]
ui_accept={
"deadzone": 0.5,
"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":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":-1,"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":false,"script":null)
]
}
ui_cancel={
"deadzone": 0.5,
"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":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":false,"script":null)
]
}
ui_left={
"deadzone": 0.5,
"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":4194319,"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":13,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
]
}
ui_right={
"deadzone": 0.5,
"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":4194321,"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":14,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
]
}
ui_up={
"deadzone": 0.5,
"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":4194320,"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":11,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
]
}
ui_down={
"deadzone": 0.5,
"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":4194322,"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":12,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
]
}
move_left={ move_left={
"deadzone": 0.5, "deadzone": 0.5,
"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":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) "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":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
@@ -164,47 +205,6 @@ center_camera={
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":false,"script":null) , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":false,"script":null)
] ]
} }
ui_accept={
"deadzone": 0.5,
"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":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":-1,"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":false,"script":null)
]
}
ui_cancel={
"deadzone": 0.5,
"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":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":false,"script":null)
]
}
ui_up={
"deadzone": 0.5,
"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":4194320,"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":11,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
]
}
ui_down={
"deadzone": 0.5,
"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":4194322,"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":12,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
]
}
ui_left={
"deadzone": 0.5,
"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":4194319,"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":13,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
]
}
ui_right={
"deadzone": 0.5,
"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":4194321,"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":14,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
]
}
[internationalization] [internationalization]
+22 -1
View File
@@ -7,15 +7,36 @@ signal quitRequested
@export var btnResume:Button @export var btnResume:Button
@export var btnSettings:Button @export var btnSettings:Button
@export var btnQuit:Button @export var btnQuit:Button
@export var mainButtons:VBoxContainer
@export var confirmQuit:VBoxContainer
@export var btnQuitConfirm:Button
@export var btnQuitCancel:Button
func _ready() -> void: func _ready() -> void:
visible = false visible = false
btnResume.pressed.connect(resumeRequested.emit) btnResume.pressed.connect(resumeRequested.emit)
btnSettings.pressed.connect(settingsRequested.emit) btnSettings.pressed.connect(settingsRequested.emit)
btnQuit.pressed.connect(quitRequested.emit) btnQuit.pressed.connect(_showConfirm)
btnQuitConfirm.pressed.connect(quitRequested.emit)
btnQuitCancel.pressed.connect(cancelConfirm)
func _showConfirm() -> void:
mainButtons.visible = false
confirmQuit.visible = true
btnQuitCancel.grab_focus()
func cancelConfirm() -> void:
mainButtons.visible = true
confirmQuit.visible = false
btnQuit.grab_focus()
func isConfirming() -> bool:
return confirmQuit.visible
func open() -> void: func open() -> void:
visible = true visible = true
if isConfirming():
cancelConfirm()
btnResume.grab_focus() btnResume.grab_focus()
func close() -> void: func close() -> void:
+31 -7
View File
@@ -2,7 +2,7 @@
[ext_resource type="Script" uid="uid://c7kvg0jw6w340" path="res://ui/pause/PauseMain.gd" id="1_b5xfl"] [ext_resource type="Script" uid="uid://c7kvg0jw6w340" path="res://ui/pause/PauseMain.gd" id="1_b5xfl"]
[node name="PauseMain" type="VBoxContainer" node_paths=PackedStringArray("btnResume", "btnSettings", "btnQuit")] [node name="PauseMain" type="VBoxContainer" node_paths=PackedStringArray("btnResume", "btnSettings", "btnQuit", "mainButtons", "confirmQuit", "btnQuitConfirm", "btnQuitCancel")]
anchors_preset = 8 anchors_preset = 8
anchor_left = 0.5 anchor_left = 0.5
anchor_top = 0.5 anchor_top = 0.5
@@ -12,23 +12,47 @@ grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
script = ExtResource("1_b5xfl") script = ExtResource("1_b5xfl")
metadata/_custom_type_script = "uid://c7kvg0jw6w340" metadata/_custom_type_script = "uid://c7kvg0jw6w340"
btnResume = NodePath("Resume") btnResume = NodePath("MainButtons/Resume")
btnSettings = NodePath("Settings") btnSettings = NodePath("MainButtons/Settings")
btnQuit = NodePath("Quit") btnQuit = NodePath("MainButtons/Quit")
mainButtons = NodePath("MainButtons")
confirmQuit = NodePath("ConfirmQuit")
btnQuitConfirm = NodePath("ConfirmQuit/Yes")
btnQuitCancel = NodePath("ConfirmQuit/No")
[node name="Title" type="Label" parent="."] [node name="Title" type="Label" parent="."]
layout_mode = 2 layout_mode = 2
text = "Paused" text = "Paused"
horizontal_alignment = 1 horizontal_alignment = 1
[node name="Resume" type="Button" parent="."] [node name="MainButtons" type="VBoxContainer" parent="."]
layout_mode = 2
[node name="Resume" type="Button" parent="MainButtons"]
layout_mode = 2 layout_mode = 2
text = "Resume" text = "Resume"
[node name="Settings" type="Button" parent="."] [node name="Settings" type="Button" parent="MainButtons"]
layout_mode = 2 layout_mode = 2
text = "Settings" text = "Settings"
[node name="Quit" type="Button" parent="."] [node name="Quit" type="Button" parent="MainButtons"]
layout_mode = 2 layout_mode = 2
text = "Quit Game" text = "Quit Game"
[node name="ConfirmQuit" type="VBoxContainer" parent="."]
layout_mode = 2
visible = false
[node name="Label" type="Label" parent="ConfirmQuit"]
layout_mode = 2
text = "Quit to desktop?"
horizontal_alignment = 1
[node name="Yes" type="Button" parent="ConfirmQuit"]
layout_mode = 2
text = "Yes"
[node name="No" type="Button" parent="ConfirmQuit"]
layout_mode = 2
text = "No"
+3 -1
View File
@@ -31,7 +31,9 @@ func _unhandled_input(event:InputEvent) -> void:
if !visible: if !visible:
return return
if event.is_action_pressed("ui_cancel"): if event.is_action_pressed("ui_cancel"):
if settingsPanel.isOpen(): if MAIN.isConfirming():
MAIN.cancelConfirm()
elif settingsPanel.isOpen():
settingsPanel.close() settingsPanel.close()
MAIN.open() MAIN.open()
else: else: