enhancing car behavior

This commit is contained in:
hz 2026-01-21 18:16:04 -06:00
parent 582b2c43cb
commit aef117bcf9
6 changed files with 232 additions and 176 deletions

View File

@ -12,3 +12,11 @@
- `test1/test1` - Super User
- `test3/test3` - User
## Controls
- Move: WASD
- Jump: Space
- Interact (enter/exit car): E
- Flashlight: F
- Phone: Tab
- Pause menu: Esc

View File

@ -5,6 +5,7 @@ extends Node3D
@export var camera_path: NodePath
@export var look_origin_path: NodePath = NodePath("Body/HeadPivot")
@export var look_reference_path: NodePath = NodePath("Body")
@export var look_target_path: NodePath = NodePath("")
@export var lock_vertical: bool = true
@export var vertical_unlock_height: float = 0.6
@export var vertical_lock_smooth_speed: float = 6.0
@ -29,6 +30,7 @@ var _head_base_rot: Vector3
var _vertical_lock_factor: float = 1.0
var _vertical_hold_timer: float = 0.0
var _look_reference: Node3D
var _look_target: Node3D
func _ready() -> void:
@ -41,6 +43,7 @@ func _ready() -> void:
_camera = _resolve_camera()
_look_origin = get_node_or_null(look_origin_path) as Node3D
_look_reference = get_node_or_null(look_reference_path) as Node3D
_look_target = get_node_or_null(look_target_path) as Node3D
_head = get_node_or_null(head_path) as Node3D
if _head:
_head_base_rot = _head.rotation
@ -55,14 +58,20 @@ func _process(_delta: float) -> void:
func _update_pupils() -> void:
if _camera == null or not _camera.is_inside_tree():
if _look_target == null and look_target_path != NodePath(""):
_look_target = get_node_or_null(look_target_path) as Node3D
if _look_target == null:
var viewport_cam := get_viewport().get_camera_3d()
if viewport_cam != null and viewport_cam != _camera:
_camera = viewport_cam
elif _camera == null or not _camera.is_inside_tree():
_camera = _resolve_camera()
if _camera == null:
if _look_target == null and _camera == null:
return
var origin := _look_origin
if origin == null:
origin = self
var target := _camera.global_position
var target := _look_target.global_position if _look_target != null else _camera.global_position
var dir_world := target - origin.global_position
if dir_world.length_squared() <= 0.0001:
return

View File

@ -57,7 +57,12 @@ height = 1.1
[node name="RepoBot" type="Node3D"]
script = ExtResource("1_repo_bot")
[node name="Body" type="StaticBody3D" parent="."]
[node name="Body" type="RigidBody3D" parent="."]
mass = 1.5
axis_lock_angular_x = true
axis_lock_angular_z = true
angular_damp = 8.0
linear_damp = 0.5
[node name="CollisionShape3D" type="CollisionShape3D" parent="Body"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.55, 0)

View File

@ -43,6 +43,7 @@ script = ExtResource("1_a4mo8")
[node name="RepoBot" parent="." instance=ExtResource("4_repo")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.9426608, 0, -4.4451966)
look_target_path = NodePath("../Player")
[node name="Thing" type="RigidBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -3.7986288)
@ -84,6 +85,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
shape = SubResource("BoxShape3D_2q6dc")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00053596497, 0.0075991154, -0.0019865036)
mesh = SubResource("BoxMesh_w7c3h")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
@ -103,33 +105,6 @@ process_mode = 3
visible = false
script = ExtResource("3_tc7dm")
[node name="PhoneUI" type="CanvasLayer" parent="."]
layer = 5
visible = false
[node name="Control" type="Control" parent="PhoneUI"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="PhoneFrame" type="ColorRect" parent="PhoneUI/Control"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -180.0
offset_top = -320.0
offset_right = 180.0
offset_bottom = 320.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.08, 0.08, 0.1, 1)
[node name="Control" type="Control" parent="Menu"]
layout_mode = 3
anchors_preset = 15
@ -166,6 +141,33 @@ text = "Main Menu"
layout_mode = 2
text = "Quit"
[node name="PhoneUI" type="CanvasLayer" parent="."]
layer = 5
visible = false
[node name="Control" type="Control" parent="PhoneUI"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="PhoneFrame" type="ColorRect" parent="PhoneUI/Control"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -180.0
offset_top = -320.0
offset_right = 180.0
offset_bottom = 320.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.08, 0.08, 0.1, 1)
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_a4mo8")

View File

@ -6,6 +6,8 @@ extends RigidBody3D
@export var turn_speed := 2.0
@export var turn_accel := 8.0
@export var lateral_damp := 10.0
@export var launch_impulse := 28.0
@export var launch_up_impulse := 6.0
@export var seat_path: NodePath
@export var exit_path: NodePath
@export var camera_path: NodePath
@ -27,6 +29,8 @@ func _ready() -> void:
interact_area.body_exited.connect(_on_interact_body_exited)
if car_camera:
car_camera.current = false
contact_monitor = true
max_contacts_reported = 8
func _process(_delta: float) -> void:
if _driver == null and _nearby_driver != null and Input.is_action_just_pressed("interact"):
@ -56,6 +60,23 @@ func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
var target_turn: float = -input2v.x * turn_speed * speed_factor
angular_velocity.y = move_toward(angular_velocity.y, target_turn, turn_accel * state.step)
if speed_factor > 0.2:
var hit_ids := {}
for i in state.get_contact_count():
var collider := state.get_contact_collider_object(i)
if collider is RigidBody3D and collider != self:
var collider_id := (collider as Node).get_instance_id()
if hit_ids.has(collider_id):
continue
hit_ids[collider_id] = true
var contact_pos := state.get_contact_collider_position(i)
var launch_dir := (contact_pos - global_position).normalized()
if launch_dir.length() <= 0.001:
var normal_world := (global_transform.basis * state.get_contact_local_normal(i)).normalized()
launch_dir = normal_world if normal_world.length() > 0.001 else forward.normalized()
var impulse := launch_dir * (launch_impulse * speed_factor) + Vector3.UP * launch_up_impulse
(collider as RigidBody3D).apply_central_impulse(impulse)
func _enter_vehicle(player: Node) -> void:
if seat == null:
return

View File

@ -26,6 +26,9 @@ var _camera_pitch := 0.0
var _in_vehicle := false
var _vehicle_collision_layer := 0
var _vehicle_collision_mask := 0
var _vehicle_original_parent: Node = null
var _light_was_on := false
@onready var _flashlight: SpotLight3D = $SpotLight3D
@export var camera_follow_speed := 10.0
@ -156,7 +159,7 @@ func _input(event):
zoom_camera(ZOOM_FACTOR) # Zoom out
if event.is_action_pressed("player_light"):
$SpotLight3D.visible = !$SpotLight3D.visible
_flashlight.visible = !_flashlight.visible
func zoom_camera(factor):
var new_fov = cam.fov * factor
@ -168,7 +171,11 @@ func enter_vehicle(_vehicle: Node, seat: Node3D, vehicle_camera: Camera3D) -> vo
sleeping = true
collision_layer = 0
collision_mask = 0
_vehicle_original_parent = get_parent()
_light_was_on = _flashlight.visible
_flashlight.visible = false
if seat:
reparent(seat, true)
global_transform = seat.global_transform
if cam:
cam.current = false
@ -181,6 +188,10 @@ func exit_vehicle(exit_point: Node3D, vehicle_camera: Camera3D) -> void:
sleeping = false
collision_layer = _vehicle_collision_layer
collision_mask = _vehicle_collision_mask
if _vehicle_original_parent:
reparent(_vehicle_original_parent, true)
_vehicle_original_parent = null
_flashlight.visible = _light_was_on
if exit_point:
global_transform = exit_point.global_transform
if vehicle_camera: