diff --git a/README.md b/README.md index 7da274e..43c7c04 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,12 @@ - `SUPER/SUPER` - Super User - `test1/test1` - Super User - `test3/test3` - User + +## Controls +- Move: WASD +- Jump: Space +- Interact (enter/exit car): E +- Flashlight: F +- Phone: Tab +- Pause menu: Esc diff --git a/game/scenes/Characters/repo_bot.gd b/game/scenes/Characters/repo_bot.gd index 7d0dd39..e789b09 100644 --- a/game/scenes/Characters/repo_bot.gd +++ b/game/scenes/Characters/repo_bot.gd @@ -3,8 +3,9 @@ extends Node3D @export var left_pupil_path: NodePath = NodePath("Body/HeadPivot/EyeLeft/Pupil") @export var right_pupil_path: NodePath = NodePath("Body/HeadPivot/EyeRight/Pupil") @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_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 @@ -28,10 +29,11 @@ var _head: Node3D 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_reference: Node3D +var _look_target: Node3D -func _ready() -> void: +func _ready() -> void: _left_pupil = get_node_or_null(left_pupil_path) as Node3D _right_pupil = get_node_or_null(right_pupil_path) as Node3D if _left_pupil: @@ -39,9 +41,10 @@ func _ready() -> void: if _right_pupil: _right_base = _right_pupil.position _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 - _head = get_node_or_null(head_path) as Node3D + _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 @@ -54,15 +57,21 @@ func _process(_delta: float) -> void: _update_pupils() -func _update_pupils() -> void: - if _camera == null or not _camera.is_inside_tree(): - _camera = _resolve_camera() - if _camera == null: - return - var origin := _look_origin - if origin == null: - origin = self - var target := _camera.global_position +func _update_pupils() -> void: + 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 _look_target == null and _camera == null: + return + var origin := _look_origin + if origin == null: + origin = self + 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 diff --git a/game/scenes/Characters/repo_bot.tscn b/game/scenes/Characters/repo_bot.tscn index a0e09a1..af9475a 100644 --- a/game/scenes/Characters/repo_bot.tscn +++ b/game/scenes/Characters/repo_bot.tscn @@ -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) diff --git a/game/scenes/Levels/level.tscn b/game/scenes/Levels/level.tscn index 777f49a..73cf7bc 100644 --- a/game/scenes/Levels/level.tscn +++ b/game/scenes/Levels/level.tscn @@ -1,77 +1,78 @@ [gd_scene load_steps=18 format=3 uid="uid://dchj6g2i8ebph"] - -[ext_resource type="Script" uid="uid://brgmxhhhtakja" path="res://scenes/Levels/level.gd" id="1_a4mo8"] -[ext_resource type="PackedScene" uid="uid://bb6hj6l23043x" path="res://assets/models/human.blend" id="1_eg4yq"] -[ext_resource type="Script" uid="uid://bpxggc8nr6tf6" path="res://scenes/player.gd" id="1_muv8p"] + +[ext_resource type="Script" uid="uid://brgmxhhhtakja" path="res://scenes/Levels/level.gd" id="1_a4mo8"] +[ext_resource type="PackedScene" uid="uid://bb6hj6l23043x" path="res://assets/models/human.blend" id="1_eg4yq"] +[ext_resource type="Script" uid="uid://bpxggc8nr6tf6" path="res://scenes/player.gd" id="1_muv8p"] [ext_resource type="PackedScene" uid="uid://c5of6aaxop1hl" path="res://scenes/block.tscn" id="2_tc7dm"] [ext_resource type="Script" uid="uid://b7fopt7sx74g8" path="res://scenes/Levels/menu.gd" id="3_tc7dm"] [ext_resource type="PackedScene" path="res://scenes/Characters/repo_bot.tscn" id="4_repo"] [ext_resource type="PackedScene" path="res://scenes/Vehicles/car.tscn" id="5_car"] - -[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_2q6dc"] -bounce = 0.5 - -[sub_resource type="SphereShape3D" id="SphereShape3D_2q6dc"] - -[sub_resource type="SphereMesh" id="SphereMesh_w7c3h"] - -[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_w8frs"] -bounce = 0.5 - -[sub_resource type="SphereShape3D" id="SphereShape3D_mx8sn"] - -[sub_resource type="BoxShape3D" id="BoxShape3D_2q6dc"] -size = Vector3(1080, 2, 1080) - -[sub_resource type="BoxMesh" id="BoxMesh_w7c3h"] -size = Vector3(1080, 2, 1080) - -[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_fi66n"] - -[sub_resource type="Sky" id="Sky_a4mo8"] -sky_material = SubResource("ProceduralSkyMaterial_fi66n") - -[sub_resource type="Environment" id="Environment_a4mo8"] -background_mode = 2 -sky = SubResource("Sky_a4mo8") -ambient_light_source = 3 - -[node name="Node3D" type="Node3D"] -script = ExtResource("1_a4mo8") - -[node name="human" parent="." instance=ExtResource("1_eg4yq")] - -[node name="RepoBot" parent="." instance=ExtResource("4_repo")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.9426608, 0, -4.4451966) - -[node name="Thing" type="RigidBody3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -3.7986288) -physics_material_override = SubResource("PhysicsMaterial_2q6dc") -gravity_scale = 0.0 -contact_monitor = true -max_contacts_reported = 5 - -[node name="CollisionShape3D" type="CollisionShape3D" parent="Thing"] -shape = SubResource("SphereShape3D_2q6dc") -debug_color = Color(0.29772994, 0.6216631, 0.28140613, 0.41960785) - -[node name="MeshInstance3D" type="MeshInstance3D" parent="Thing"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) -mesh = SubResource("SphereMesh_w7c3h") - + +[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_2q6dc"] +bounce = 0.5 + +[sub_resource type="SphereShape3D" id="SphereShape3D_2q6dc"] + +[sub_resource type="SphereMesh" id="SphereMesh_w7c3h"] + +[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_w8frs"] +bounce = 0.5 + +[sub_resource type="SphereShape3D" id="SphereShape3D_mx8sn"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_2q6dc"] +size = Vector3(1080, 2, 1080) + +[sub_resource type="BoxMesh" id="BoxMesh_w7c3h"] +size = Vector3(1080, 2, 1080) + +[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_fi66n"] + +[sub_resource type="Sky" id="Sky_a4mo8"] +sky_material = SubResource("ProceduralSkyMaterial_fi66n") + +[sub_resource type="Environment" id="Environment_a4mo8"] +background_mode = 2 +sky = SubResource("Sky_a4mo8") +ambient_light_source = 3 + +[node name="Node3D" type="Node3D"] +script = ExtResource("1_a4mo8") + +[node name="human" parent="." instance=ExtResource("1_eg4yq")] + +[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) +physics_material_override = SubResource("PhysicsMaterial_2q6dc") +gravity_scale = 0.0 +contact_monitor = true +max_contacts_reported = 5 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Thing"] +shape = SubResource("SphereShape3D_2q6dc") +debug_color = Color(0.29772994, 0.6216631, 0.28140613, 0.41960785) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Thing"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +mesh = SubResource("SphereMesh_w7c3h") + [node name="Player" type="RigidBody3D" parent="."] physics_material_override = SubResource("PhysicsMaterial_w8frs") script = ExtResource("1_muv8p") camera_path = NodePath("Camera3D") phone_path = NodePath("../PhoneUI") - -[node name="CollisionShape3D" type="CollisionShape3D" parent="Player"] -shape = SubResource("SphereShape3D_mx8sn") - -[node name="Camera3D" type="Camera3D" parent="Player"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.31670225, 0) -current = true - + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Player"] +shape = SubResource("SphereShape3D_mx8sn") + +[node name="Camera3D" type="Camera3D" parent="Player"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.31670225, 0) +current = true + [node name="SpotLight3D" type="SpotLight3D" parent="Player"] [node name="Car" parent="." instance=ExtResource("5_car")] @@ -79,96 +80,97 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 0, -3) [node name="Ground" type="StaticBody3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0) - -[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"] -shape = SubResource("BoxShape3D_2q6dc") - -[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"] -mesh = SubResource("BoxMesh_w7c3h") - -[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 0.5, 0.8660253, 0, -0.8660253, 0.5, 0, 34, 0) -shadow_enabled = true - -[node name="Starter Blocks" type="Node3D" parent="."] - -[node name="Block" parent="Starter Blocks" instance=ExtResource("2_tc7dm")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.298158, -7.0724635) - -[node name="Block2" parent="Starter Blocks" instance=ExtResource("2_tc7dm")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.63255787, 2.596316, -6.980046) - -[node name="Menu" type="CanvasLayer" parent="."] -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 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 - -[node name="VBoxContainer" type="VBoxContainer" parent="Menu/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 = -39.5 -offset_top = -33.0 -offset_right = 39.5 -offset_bottom = 33.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="ContinueButton" type="Button" parent="Menu/Control/VBoxContainer"] -layout_mode = 2 -text = "Continue" - -[node name="MainMenuButton" type="Button" parent="Menu/Control/VBoxContainer"] -layout_mode = 2 -text = "Main Menu" - -[node name="QuitButton" type="Button" parent="Menu/Control/VBoxContainer"] -layout_mode = 2 -text = "Quit" - -[node name="WorldEnvironment" type="WorldEnvironment" parent="."] -environment = SubResource("Environment_a4mo8") - -[connection signal="pressed" from="Menu/Control/VBoxContainer/ContinueButton" to="Menu" method="_on_continue_button_pressed"] -[connection signal="pressed" from="Menu/Control/VBoxContainer/MainMenuButton" to="Menu" method="_on_main_menu_button_pressed"] -[connection signal="pressed" from="Menu/Control/VBoxContainer/QuitButton" to="Menu" method="_on_quit_button_pressed"] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"] +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="."] +transform = Transform3D(1, 0, 0, 0, 0.5, 0.8660253, 0, -0.8660253, 0.5, 0, 34, 0) +shadow_enabled = true + +[node name="Starter Blocks" type="Node3D" parent="."] + +[node name="Block" parent="Starter Blocks" instance=ExtResource("2_tc7dm")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.298158, -7.0724635) + +[node name="Block2" parent="Starter Blocks" instance=ExtResource("2_tc7dm")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.63255787, 2.596316, -6.980046) + +[node name="Menu" type="CanvasLayer" parent="."] +process_mode = 3 +visible = false +script = ExtResource("3_tc7dm") + +[node name="Control" type="Control" parent="Menu"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 + +[node name="VBoxContainer" type="VBoxContainer" parent="Menu/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 = -39.5 +offset_top = -33.0 +offset_right = 39.5 +offset_bottom = 33.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="ContinueButton" type="Button" parent="Menu/Control/VBoxContainer"] +layout_mode = 2 +text = "Continue" + +[node name="MainMenuButton" type="Button" parent="Menu/Control/VBoxContainer"] +layout_mode = 2 +text = "Main Menu" + +[node name="QuitButton" type="Button" parent="Menu/Control/VBoxContainer"] +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") + +[connection signal="pressed" from="Menu/Control/VBoxContainer/ContinueButton" to="Menu" method="_on_continue_button_pressed"] +[connection signal="pressed" from="Menu/Control/VBoxContainer/MainMenuButton" to="Menu" method="_on_main_menu_button_pressed"] +[connection signal="pressed" from="Menu/Control/VBoxContainer/QuitButton" to="Menu" method="_on_quit_button_pressed"] diff --git a/game/scenes/Vehicles/car.gd b/game/scenes/Vehicles/car.gd index 9d92881..6a8c0eb 100644 --- a/game/scenes/Vehicles/car.gd +++ b/game/scenes/Vehicles/car.gd @@ -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 diff --git a/game/scenes/player.gd b/game/scenes/player.gd index cc6e206..7daecf0 100644 --- a/game/scenes/player.gd +++ b/game/scenes/player.gd @@ -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 @@ -155,8 +158,8 @@ func _input(event): elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN: zoom_camera(ZOOM_FACTOR) # Zoom out - if event.is_action_pressed("player_light"): - $SpotLight3D.visible = !$SpotLight3D.visible + if event.is_action_pressed("player_light"): + _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: