diff --git a/project.godot b/project.godot index 85bfb67..447bee5 100644 --- a/project.godot +++ b/project.godot @@ -11,5 +11,59 @@ config_version=5 [application] config/name="fml-avs" +run/main_scene="res://scenes/devworld.tscn" config/features=PackedStringArray("4.3", "Forward Plus") config/icon="res://icon.svg" + +[input] + +move_forward={ +"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":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) +] +} +move_backward={ +"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":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null) +] +} +move_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":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) +] +} +move_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":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) +] +} +jump={ +"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":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) +] +} +interact={ +"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":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null) +] +} +run={ +"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":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +pause={ +"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":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +noclip={ +"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":86,"key_label":0,"unicode":118,"location":0,"echo":false,"script":null) +] +} +flashlight={ +"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":70,"key_label":0,"unicode":102,"location":0,"echo":false,"script":null) +] +} diff --git a/scenes/devworld.tscn b/scenes/devworld.tscn new file mode 100644 index 0000000..31c6e88 --- /dev/null +++ b/scenes/devworld.tscn @@ -0,0 +1,62 @@ +[gd_scene load_steps=8 format=3 uid="uid://vv1rwk4sfpch"] + +[ext_resource type="PackedScene" uid="uid://clvn53i6enmno" path="res://assets/maps/devworld.blend" id="1_pj3hd"] +[ext_resource type="PackedScene" uid="uid://cy86jyiy6skvk" path="res://scenes/player.tscn" id="2_b2roh"] +[ext_resource type="PackedScene" uid="uid://nnxd1djnxech" path="res://scenes/phys_cube.tscn" id="3_8byy4"] +[ext_resource type="PackedScene" uid="uid://c8untjpyh1rjm" path="res://assets/models/general/mirror.blend" id="4_8rfge"] + +[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_2mm68"] +sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1) +ground_horizon_color = Color(0.64625, 0.65575, 0.67075, 1) + +[sub_resource type="Sky" id="Sky_frs4c"] +sky_material = SubResource("ProceduralSkyMaterial_2mm68") + +[sub_resource type="Environment" id="Environment_x3vhq"] +background_mode = 2 +sky = SubResource("Sky_frs4c") +tonemap_mode = 2 +ssr_enabled = true +ssao_enabled = true +ssil_enabled = true +sdfgi_enabled = true +sdfgi_use_occlusion = true +glow_enabled = true + +[node name="Devworld" type="Node3D"] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_x3vhq") + +[node name="devworld" parent="." instance=ExtResource("1_pj3hd")] + +[node name="cameratri" parent="devworld/player" index="1"] +visible = false + +[node name="cameraframe" parent="devworld/player" index="2"] +visible = false + +[node name="Point" parent="devworld" index="2"] +visible = false + +[node name="Player" parent="." instance=ExtResource("2_b2roh")] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 5.803, 0, 7.171) + +[node name="PhysCube" parent="." instance=ExtResource("3_8byy4")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.51921, 5.04702, 11.6844) + +[node name="CSGBox3D" type="CSGBox3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.11, 0) +use_collision = true +size = Vector3(60, 0.2, 60) + +[node name="mirror" parent="." instance=ExtResource("4_8rfge")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.21713, 1.33524, 15.4176) + +[node name="OmniLight3D" type="OmniLight3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 6.60592, 0) +light_energy = 16.41 +omni_range = 4096.0 + +[editable path="devworld"] +[editable path="mirror"] diff --git a/scenes/phys_cube.tscn b/scenes/phys_cube.tscn new file mode 100644 index 0000000..5714260 --- /dev/null +++ b/scenes/phys_cube.tscn @@ -0,0 +1,17 @@ +[gd_scene load_steps=3 format=3 uid="uid://nnxd1djnxech"] + +[ext_resource type="Script" path="res://scripts/physics_object.gd" id="1_lx1c5"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_h6ouo"] +size = Vector3(9.24554, 1, 1) + +[node name="PhysCube" type="RigidBody3D"] +script = ExtResource("1_lx1c5") + +[node name="CSGBox3D" type="CSGBox3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) +size = Vector3(9.21936, 1, 1) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) +shape = SubResource("BoxShape3D_h6ouo") diff --git a/scenes/player.tscn b/scenes/player.tscn new file mode 100644 index 0000000..226f3be --- /dev/null +++ b/scenes/player.tscn @@ -0,0 +1,33 @@ +[gd_scene load_steps=4 format=3 uid="uid://cy86jyiy6skvk"] + +[ext_resource type="Script" path="res://scripts/player.gd" id="1_ocinr"] + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_ljkaw"] + +[sub_resource type="CapsuleMesh" id="CapsuleMesh_muavk"] + +[node name="Player" type="CharacterBody3D"] +script = ExtResource("1_ocinr") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +shape = SubResource("CapsuleShape3D_ljkaw") + +[node name="CSGMesh3D" type="CSGMesh3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +mesh = SubResource("CapsuleMesh_muavk") + +[node name="Camera3D" type="Camera3D" parent="CSGMesh3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +fov = 90.0 + +[node name="Ball" type="CSGSphere3D" parent="."] +radius = 0.1 + +[node name="Flashlight" type="SpotLight3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.990268, 0.139173, 0, -0.139173, 0.990268, 0, 1.5, -0.4) +light_color = Color(1, 1, 0.768627, 1) +shadow_enabled = true +distance_fade_enabled = true +spot_range = 23.178 +spot_angle = 40.14 diff --git a/scripts/physics_object.gd b/scripts/physics_object.gd new file mode 100644 index 0000000..dd981b7 --- /dev/null +++ b/scripts/physics_object.gd @@ -0,0 +1,25 @@ +extends RigidBody3D +# +#const QUAKE = 0.0625 / 2 +#const g = -800 * QUAKE +# +#@export +#var push_force = 400 +#@export +#var max_velocity: float = 1000.0 +# +# +##var is_held = false +##var target_velocity: Vector3 = Vector3(0, 0, 0) +## +## +##func _physics_process(delta): + ##if is_held: + ##linear_velocity = target_velocity * delta + ##else: + ##linear_velocity.y += g * delta +# +# +func can_hold(player): + return true + diff --git a/scripts/player.gd b/scripts/player.gd new file mode 100644 index 0000000..b28cdf2 --- /dev/null +++ b/scripts/player.gd @@ -0,0 +1,216 @@ +extends CharacterBody3D + +# Member variables +const QUAKE = 0.0625 / 2 +const g = -800 * QUAKE +const MAX_SPEED = 320 * QUAKE +const MAX_AIR_SPEED = 30 * QUAKE +const FRICTION = 4# * QUAKE +const STOP_SPEED = 100 * QUAKE +const ACCEL = 15# * QUAKE +const AIR_ACCEL = 2# * QUAKE +const FORWARD_SPEED = 200 * QUAKE +const SIDE_SPEED = 350 * QUAKE +const UP_SPEED = 270 * QUAKE +const JUMP_SPEED = 270 * QUAKE + +@export +var hold_force = 400 +@export +var max_hold_velocity: float = 1000.0 + +# const DEACCEL= 8 +# const MAX_SLOPE_ANGLE = 30https://www.youtube.com/watch?v=v3zT3Z5apaM + +@onready +var _camera = $CSGMesh3D/Camera3D +@onready +var _ball = $Ball +@onready +var _collider = $CollisionShape3D +@onready +var _flashlight: SpotLight3D = $Flashlight + +var _paused = false +var _noclip = false + +var _held_object = null + + +func _ready(): + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + + +func _process(_delta): + # Do this on the render tick so it doesnt jitter at higher FPS + _ball.global_position = _camera.global_position - _camera.global_transform.basis.z * 2.0 + + +func _physics_process(delta): + # Shamelessly stolen code from quake :) + + var fmove = 0.0 + var smove = 0.0 + var upmove = 0.0 + + if Input.is_action_pressed("move_forward"): + fmove += -FORWARD_SPEED + if Input.is_action_pressed("move_backward"): + fmove += FORWARD_SPEED + if Input.is_action_pressed("move_left"): + smove += -SIDE_SPEED + if Input.is_action_pressed("move_right"): + smove += SIDE_SPEED + #if Input.is_action_pressed("up"): + # upmove += UP_SPEED + if Input.is_action_pressed("run"): + fmove *= 2.0 + smove *= 2.0 + + var wishvel = Vector3() + var cam_xform: Transform3D = _camera.get_global_transform() + var cam_basis: Basis = cam_xform.basis + + wishvel = cam_basis.z * fmove + cam_basis.x * smove + + if _noclip: + wishvel.y += upmove + + var wishdir = wishvel.normalized() + var wishspeed = wishvel.length() + + if wishspeed > MAX_SPEED: + wishvel *= MAX_SPEED / wishspeed + wishspeed = MAX_SPEED + + if Input.is_action_just_pressed("jump") and is_on_floor(): + velocity.y += JUMP_SPEED + + var vel = velocity + if _noclip: + vel = wishvel * 2 + elif is_on_floor(): + vel = _apply_friction(vel, delta) + vel = _apply_accel(vel, wishdir, wishspeed, delta) + else: + vel = _apply_air_accel(vel, wishvel, wishspeed, delta) + + if not _noclip and not is_on_floor(): + vel.y += g * delta + + velocity = vel + move_and_slide() + + if _held_object: + _apply_holding_force(delta) + +func _apply_friction(vel: Vector3, delta: float): + var speed = sqrt(vel.x ** 2 + vel.z ** 2) + if(speed == 0.0): return vel + + # TODO: edge detect friction? + var friction = FRICTION + + var control = 0.0 + if speed < STOP_SPEED: + control = STOP_SPEED + else: + control = speed + + var newspeed = speed - delta * control * friction + + if newspeed < 0.0: + newspeed = 0.0 + else: + newspeed /= speed + + return vel * newspeed + +func _apply_accel(vel: Vector3, wishdir: Vector3, wishspeed: float, delta: float): + var currentspeed = vel.dot(wishdir) + var addspeed = wishspeed - currentspeed + if addspeed <= 0.0: + return vel + + var accelspeed = ACCEL * delta * wishspeed + if accelspeed > addspeed: + accelspeed = addspeed + + return vel + accelspeed * wishdir + +func _apply_air_accel(vel: Vector3, wishvel: Vector3, wishspeed: float, delta: float): + var wishveloc = wishvel.normalized() + var wishspd = wishvel.length() + + if wishspd > MAX_AIR_SPEED: + wishspd = MAX_AIR_SPEED + + var currentspeed = vel.dot(wishveloc) + var addspeed = wishspd - currentspeed + if addspeed <= 0: + return vel + + var accelspeed = AIR_ACCEL * wishspeed * delta + if accelspeed > addspeed: + accelspeed = addspeed + + return vel + accelspeed * wishveloc + +func _apply_holding_force(delta): + var delta_position = _ball.global_position - _held_object.global_position + var move_speed = min(delta_position.length() * hold_force, max_hold_velocity) + _held_object.linear_velocity = delta_position.normalized() * move_speed * delta + +func _input(event): + if event.is_action_pressed("pause"): + _paused = not _paused + if _paused: + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + else: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + + if _paused: return + + if event.is_action_pressed('noclip'): + _noclip = not _noclip + if _noclip: + _collider.disabled = true + else: + _collider.disabled = false + + if event.is_action_pressed('flashlight'): + _flashlight.visible = not _flashlight.visible + + # Camera + if event is InputEventMouseMotion: + rotation.y += -event.relative.x * 0.005 + _camera.rotation.x += -event.relative.y * 0.005 + _camera.rotation.x = clamp(_camera.rotation.x, deg_to_rad(-90), deg_to_rad(90)) + + # Rotate flashlight + _flashlight.rotation.x = _camera.rotation.x + + if event.is_action_pressed("interact"): + # Handle dropping things + if _held_object: + #_held_object.drop() + _held_object = null + return + + var space_state = get_world_3d().direct_space_state + # use global coordinates, not local to node + var query = PhysicsRayQueryParameters3D.create(_camera.global_position, _ball.global_position) + # Don't collide with ourselves + query.exclude = [self] + var result = space_state.intersect_ray(query) + if result.has('collider'): + print(result) + var other: Node3D = result.collider + if other.has_method('interact'): + other.interact(self) + if other.has_method('can_hold'): + print('Object') + if other.can_hold(self): + print('Can Hold') + _held_object = other + print(_held_object)