diff --git a/asset_dev/beast/beast.blend b/asset_dev/beast/beast.blend new file mode 100644 index 0000000..916b69c Binary files /dev/null and b/asset_dev/beast/beast.blend differ diff --git a/asset_dev/beast/beast.blend1 b/asset_dev/beast/beast.blend1 new file mode 100644 index 0000000..570d222 Binary files /dev/null and b/asset_dev/beast/beast.blend1 differ diff --git a/assets/npc/grunk_beast/grunk_beast.bin b/assets/npc/grunk_beast/grunk_beast.bin new file mode 100644 index 0000000..0d7292c Binary files /dev/null and b/assets/npc/grunk_beast/grunk_beast.bin differ diff --git a/assets/npc/grunk_beast/grunk_beast.gltf b/assets/npc/grunk_beast/grunk_beast.gltf new file mode 100644 index 0000000..1d0440c --- /dev/null +++ b/assets/npc/grunk_beast/grunk_beast.gltf @@ -0,0 +1,731 @@ +{ + "asset":{ + "generator":"Khronos glTF Blender I/O v4.3.47", + "version":"2.0" + }, + "scene":0, + "scenes":[ + { + "name":"Scene", + "nodes":[ + 24 + ] + } + ], + "nodes":[ + { + "name":"IK_Knee.F.L", + "rotation":[ + 0.1497122347354889, + -0.8684139847755432, + 0.3859991431236267, + 0.2728516459465027 + ], + "scale":[ + 0.9999998807907104, + 1.000000238418579, + 1 + ], + "translation":[ + -0.6344399452209473, + -0.8762551546096802, + -0.982624888420105 + ] + }, + { + "children":[ + 0 + ], + "name":"IK_Leg.F.L", + "rotation":[ + 2.56550283239676e-08, + 2.841698005795479e-07, + -3.3527612686157227e-08, + 1 + ], + "scale":[ + 1.0000001192092896, + 1, + 0.9999999403953552 + ], + "translation":[ + -8.568167686462402e-08, + 0.5844804644584656, + -1.7462298274040222e-08 + ] + }, + { + "children":[ + 1 + ], + "name":"Leg3.F.L", + "rotation":[ + -0.2818467915058136, + 0.06332080811262131, + 0.21096482872962952, + 0.933834433555603 + ], + "scale":[ + 1.0000001192092896, + 1, + 1 + ], + "translation":[ + -6.301623756144181e-08, + 1.4211536645889282, + -6.055779522284865e-08 + ] + }, + { + "children":[ + 2 + ], + "name":"Leg2.F.L", + "rotation":[ + -1.1081444739602375e-07, + -5.585075157910069e-08, + 0.0015022342558950186, + 0.999998927116394 + ], + "scale":[ + 0.9999999403953552, + 0.9999999403953552, + 1 + ], + "translation":[ + 2.1605956135317683e-08, + 1.5049428939819336, + -3.592887765080377e-08 + ] + }, + { + "children":[ + 3 + ], + "name":"Leg1.F.L", + "rotation":[ + -0.5007143020629883, + 0.4992845952510834, + -0.5007867813110352, + 0.4992120862007141 + ], + "scale":[ + 1, + 0.9999998211860657, + 0.9999999403953552 + ], + "translation":[ + -0.4196379482746124, + 1.06613290309906, + -0.6239852905273438 + ] + }, + { + "name":"IK_Knee.B.L", + "rotation":[ + 0.14971226453781128, + 0.868414044380188, + -0.3859991133213043, + 0.2728515863418579 + ], + "scale":[ + 1, + 1.0000001192092896, + 0.9999999403953552 + ], + "translation":[ + 0.6344399452209473, + -0.876255214214325, + -0.9826248288154602 + ] + }, + { + "children":[ + 5 + ], + "name":"IK_Leg.B.L", + "rotation":[ + 3.978493978706865e-08, + -4.42785704990456e-07, + 1.3038516932795119e-08, + 1 + ], + "scale":[ + 1, + 0.9999999403953552, + 0.9999999403953552 + ], + "translation":[ + -2.561137080192566e-09, + 0.5844804644584656, + -1.1641532182693481e-10 + ] + }, + { + "children":[ + 6 + ], + "name":"Leg3.B.L", + "rotation":[ + -0.2818467617034912, + -0.06332068145275116, + -0.2109648585319519, + 0.933834433555603 + ], + "scale":[ + 1, + 1, + 1.0000001192092896 + ], + "translation":[ + 3.4115803515533116e-09, + 1.4211534261703491, + -6.063782365117731e-08 + ] + }, + { + "children":[ + 7 + ], + "name":"Leg2.B.L", + "rotation":[ + -1.1077454331598346e-07, + 3.10951406845561e-08, + -0.0015022143488749862, + 0.999998927116394 + ], + "scale":[ + 0.9999999403953552, + 0.9999999403953552, + 1 + ], + "translation":[ + 1.4497345546260476e-08, + 1.5049431324005127, + -6.810057584516471e-08 + ] + }, + { + "children":[ + 8 + ], + "name":"Leg1.B.L", + "rotation":[ + -0.4992845356464386, + 0.5007143020629883, + -0.4992120862007141, + 0.5007867813110352 + ], + "scale":[ + 1, + 0.9999998807907104, + 0.9999999403953552 + ], + "translation":[ + -0.4196379482746124, + -0.06613290309906006, + -0.6239852905273438 + ] + }, + { + "name":"IK_Knee.F.R", + "rotation":[ + 0.14971230924129486, + 0.8684141039848328, + -0.38599905371665955, + 0.2728515863418579 + ], + "scale":[ + 1, + 0.9999997615814209, + 1 + ], + "translation":[ + 0.6344401836395264, + -0.8762552738189697, + -0.9826245307922363 + ] + }, + { + "children":[ + 10 + ], + "name":"IK_Leg.F.R", + "rotation":[ + -1.8553691916167736e-10, + -2.9994407668709755e-07, + -7.450580596923828e-09, + 1 + ], + "translation":[ + 2.584420144557953e-08, + 0.5844805240631104, + -1.6298145055770874e-09 + ] + }, + { + "children":[ + 11 + ], + "name":"Leg3.F.R", + "rotation":[ + -0.2818467915058136, + -0.06332076340913773, + -0.21096479892730713, + 0.933834433555603 + ], + "scale":[ + 1, + 1, + 1.0000001192092896 + ], + "translation":[ + 6.662163798409892e-08, + 1.4211536645889282, + -6.519984907527032e-08 + ] + }, + { + "children":[ + 12 + ], + "name":"Leg2.F.R", + "rotation":[ + -1.0645147341392658e-07, + 5.170326744519116e-08, + -0.001502234023064375, + 0.999998927116394 + ], + "scale":[ + 0.9999999403953552, + 0.9999999403953552, + 1 + ], + "translation":[ + -1.3940734788775444e-08, + 1.5049428939819336, + -2.2469436089522787e-08 + ] + }, + { + "children":[ + 13 + ], + "name":"Leg1.F.R", + "rotation":[ + -0.5007143020629883, + -0.4992845356464386, + 0.5007867813110352, + 0.4992121160030365 + ], + "scale":[ + 1, + 0.9999998211860657, + 0.9999999403953552 + ], + "translation":[ + 0.4196379482746124, + 1.06613290309906, + -0.6239852905273438 + ] + }, + { + "name":"IK_Knee.B.R", + "rotation":[ + 0.14971211552619934, + -0.868414044380188, + 0.3859991133213043, + 0.2728516757488251 + ], + "translation":[ + -0.6344397664070129, + -0.8762551546096802, + -0.9826247692108154 + ] + }, + { + "children":[ + 15 + ], + "name":"IK_Leg.B.R", + "rotation":[ + 2.153683809069662e-08, + 5.460678949020803e-07, + -5.587935802964239e-08, + 1 + ], + "scale":[ + 1, + 0.9999999403953552, + 0.9999999403953552 + ], + "translation":[ + 1.5832483768463135e-08, + 0.5844804644584656, + -1.1699739843606949e-08 + ] + }, + { + "children":[ + 16 + ], + "name":"Leg3.B.R", + "rotation":[ + -0.2818467617034912, + 0.06332061439752579, + 0.21096491813659668, + 0.933834433555603 + ], + "scale":[ + 1, + 1, + 1.0000001192092896 + ], + "translation":[ + 2.3854802577716328e-08, + 1.4211534261703491, + -5.756010779123244e-08 + ] + }, + { + "children":[ + 17 + ], + "name":"Leg2.B.R", + "rotation":[ + -1.070358877086619e-07, + -7.306381721861044e-09, + 0.0015022143488749862, + 0.999998927116394 + ], + "scale":[ + 0.9999999403953552, + 0.9999999403953552, + 1 + ], + "translation":[ + -6.83940015733242e-09, + 1.5049428939819336, + -5.24299252901983e-08 + ] + }, + { + "children":[ + 18 + ], + "name":"Leg1.B.R", + "rotation":[ + -0.4992845952510834, + -0.5007142424583435, + 0.4992120563983917, + 0.5007868409156799 + ], + "scale":[ + 1, + 0.9999998807907104, + 0.9999999403953552 + ], + "translation":[ + 0.4196378290653229, + -0.06613290309906006, + -0.6239852905273438 + ] + }, + { + "children":[ + 4, + 9, + 14, + 19 + ], + "name":"Body", + "rotation":[ + -0.5, + -0.5, + -0.5, + 0.5 + ], + "scale":[ + 1, + 0.9999999403953552, + 1 + ], + "translation":[ + -0.5, + 4, + 0 + ] + }, + { + "children":[ + 20 + ], + "name":"Root" + }, + { + "mesh":0, + "name":"Body", + "skin":0 + }, + { + "mesh":1, + "name":"Leg", + "skin":0 + }, + { + "children":[ + 22, + 23, + 21 + ], + "name":"Armature" + } + ], + "meshes":[ + { + "name":"Icosphere", + "primitives":[ + { + "attributes":{ + "POSITION":0, + "NORMAL":1, + "TEXCOORD_0":2, + "JOINTS_0":3, + "WEIGHTS_0":4 + }, + "indices":5 + } + ] + }, + { + "name":"Cone", + "primitives":[ + { + "attributes":{ + "POSITION":7, + "NORMAL":8, + "TEXCOORD_0":9, + "JOINTS_0":10, + "WEIGHTS_0":11 + }, + "indices":12 + } + ] + } + ], + "skins":[ + { + "inverseBindMatrices":6, + "joints":[ + 21, + 20, + 4, + 3, + 2, + 1, + 0, + 9, + 8, + 7, + 6, + 5, + 14, + 13, + 12, + 11, + 10, + 19, + 18, + 17, + 16, + 15 + ], + "name":"Armature" + } + ], + "accessors":[ + { + "bufferView":0, + "componentType":5126, + "count":1024, + "max":[ + 1.2054719924926758, + 4.738262176513672, + 0.7221531867980957 + ], + "min":[ + -1.1375094652175903, + 3.0816688537597656, + -0.7221531867980957 + ], + "type":"VEC3" + }, + { + "bufferView":1, + "componentType":5126, + "count":1024, + "type":"VEC3" + }, + { + "bufferView":2, + "componentType":5126, + "count":1024, + "type":"VEC2" + }, + { + "bufferView":3, + "componentType":5121, + "count":1024, + "type":"VEC4" + }, + { + "bufferView":4, + "componentType":5126, + "count":1024, + "type":"VEC4" + }, + { + "bufferView":5, + "componentType":5123, + "count":1416, + "type":"SCALAR" + }, + { + "bufferView":6, + "componentType":5126, + "count":22, + "type":"MAT4" + }, + { + "bufferView":7, + "componentType":5126, + "count":480, + "max":[ + 0.8181655406951904, + 3.48964786529541, + 0.7158815860748291 + ], + "min":[ + -0.8181655406951904, + 0, + -0.7158815860748291 + ], + "type":"VEC3" + }, + { + "bufferView":8, + "componentType":5126, + "count":480, + "type":"VEC3" + }, + { + "bufferView":9, + "componentType":5126, + "count":480, + "type":"VEC2" + }, + { + "bufferView":10, + "componentType":5121, + "count":480, + "type":"VEC4" + }, + { + "bufferView":11, + "componentType":5126, + "count":480, + "type":"VEC4" + }, + { + "bufferView":12, + "componentType":5123, + "count":672, + "type":"SCALAR" + } + ], + "bufferViews":[ + { + "buffer":0, + "byteLength":12288, + "byteOffset":0, + "target":34962 + }, + { + "buffer":0, + "byteLength":12288, + "byteOffset":12288, + "target":34962 + }, + { + "buffer":0, + "byteLength":8192, + "byteOffset":24576, + "target":34962 + }, + { + "buffer":0, + "byteLength":4096, + "byteOffset":32768, + "target":34962 + }, + { + "buffer":0, + "byteLength":16384, + "byteOffset":36864, + "target":34962 + }, + { + "buffer":0, + "byteLength":2832, + "byteOffset":53248, + "target":34963 + }, + { + "buffer":0, + "byteLength":1408, + "byteOffset":56080 + }, + { + "buffer":0, + "byteLength":5760, + "byteOffset":57488, + "target":34962 + }, + { + "buffer":0, + "byteLength":5760, + "byteOffset":63248, + "target":34962 + }, + { + "buffer":0, + "byteLength":3840, + "byteOffset":69008, + "target":34962 + }, + { + "buffer":0, + "byteLength":1920, + "byteOffset":72848, + "target":34962 + }, + { + "buffer":0, + "byteLength":7680, + "byteOffset":74768, + "target":34962 + }, + { + "buffer":0, + "byteLength":1344, + "byteOffset":82448, + "target":34963 + } + ], + "buffers":[ + { + "byteLength":83792, + "uri":"grunk_beast.bin" + } + ] +} diff --git a/assets/npc/grunk_beast/grunk_beast.gltf.import b/assets/npc/grunk_beast/grunk_beast.gltf.import new file mode 100644 index 0000000..79ec97a --- /dev/null +++ b/assets/npc/grunk_beast/grunk_beast.gltf.import @@ -0,0 +1,37 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://bi5mxt5s4aq1a" +path="res://.godot/imported/grunk_beast.gltf-120de489875ed9abbf222f99c2d4d2ab.scn" + +[deps] + +source_file="res://assets/npc/grunk_beast/grunk_beast.gltf" +dest_files=["res://.godot/imported/grunk_beast.gltf-120de489875ed9abbf222f99c2d4d2ab.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +_subresources={} +gltf/naming_version=1 +gltf/embedded_image_handling=1 diff --git a/levels/grunkbeast_test/fixed_camera.gd b/levels/grunkbeast_test/fixed_camera.gd new file mode 100644 index 0000000..99bcba6 --- /dev/null +++ b/levels/grunkbeast_test/fixed_camera.gd @@ -0,0 +1,11 @@ +extends Camera3D +## Tracks a target + +const SMOOTHING := 10.0 + +@export var target: Node3D + + +func _process(delta: float) -> void: + var target_basis := Basis.looking_at(target.global_position - global_position, Vector3.UP) + global_basis = global_basis.slerp(target_basis, SMOOTHING * delta).orthonormalized() diff --git a/levels/grunkbeast_test/fixed_camera.gd.uid b/levels/grunkbeast_test/fixed_camera.gd.uid new file mode 100644 index 0000000..0993bb3 --- /dev/null +++ b/levels/grunkbeast_test/fixed_camera.gd.uid @@ -0,0 +1 @@ +uid://cpt8dy0csa3eu diff --git a/levels/grunkbeast_test/frame_skipper.gd b/levels/grunkbeast_test/frame_skipper.gd new file mode 100644 index 0000000..fc36162 --- /dev/null +++ b/levels/grunkbeast_test/frame_skipper.gd @@ -0,0 +1,20 @@ +class_name FrameSkipper extends Node +## Disables child processing every N frames for some N + +@export var frame_skip := 1 + +@onready var frame_counter := frame_skip + + +func _set_child_process_mode(mode: ProcessMode) -> void: + for c: Node in get_children(): + c.process_mode = mode + + +func _process(_delta: float) -> void: + if frame_counter == 0: + _set_child_process_mode(Node.PROCESS_MODE_INHERIT) + frame_counter = frame_skip + else: + _set_child_process_mode(Node.PROCESS_MODE_DISABLED) + frame_counter -= 1 diff --git a/levels/grunkbeast_test/frame_skipper.gd.uid b/levels/grunkbeast_test/frame_skipper.gd.uid new file mode 100644 index 0000000..b9e2a40 --- /dev/null +++ b/levels/grunkbeast_test/frame_skipper.gd.uid @@ -0,0 +1 @@ +uid://bukihqt1lybnx diff --git a/levels/grunkbeast_test/grunkbeast_test.tscn b/levels/grunkbeast_test/grunkbeast_test.tscn new file mode 100644 index 0000000..da6473e --- /dev/null +++ b/levels/grunkbeast_test/grunkbeast_test.tscn @@ -0,0 +1,67 @@ +[gd_scene load_steps=11 format=3 uid="uid://cbxlfnlmgdvsq"] + +[ext_resource type="PackedScene" uid="uid://d2664rpg4losx" path="res://src/world/grunk_beast/grunk_beast.tscn" id="1_6yv42"] +[ext_resource type="Script" uid="uid://bukihqt1lybnx" path="res://levels/grunkbeast_test/frame_skipper.gd" id="1_eco5q"] +[ext_resource type="Script" uid="uid://cpt8dy0csa3eu" path="res://levels/grunkbeast_test/fixed_camera.gd" id="2_77sam"] + +[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_goufh"] + +[sub_resource type="Sky" id="Sky_pka60"] +sky_material = SubResource("ProceduralSkyMaterial_goufh") + +[sub_resource type="Environment" id="Environment_bg05n"] +background_mode = 2 +sky = SubResource("Sky_pka60") + +[sub_resource type="PlaneMesh" id="PlaneMesh_mn2wa"] +size = Vector2(50, 50) + +[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_mn2wa"] + +[sub_resource type="CylinderMesh" id="CylinderMesh_4n07c"] +top_radius = 2.0 +bottom_radius = 2.0 +height = 1.0 + +[sub_resource type="CylinderShape3D" id="CylinderShape3D_6yv42"] +height = 1.0 +radius = 2.0 + +[node name="GrunkbeastTest" type="Node3D"] + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] +transform = Transform3D(0.866025, -0.156955, -0.474726, 0.5, 0.271854, 0.82225, 0, -0.949453, 0.31391, 0, 0, 0) + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_bg05n") + +[node name="WorldFloor" type="StaticBody3D" parent="."] + +[node name="MeshInstance3D" type="MeshInstance3D" parent="WorldFloor"] +mesh = SubResource("PlaneMesh_mn2wa") +skeleton = NodePath("../..") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="WorldFloor"] +shape = SubResource("WorldBoundaryShape3D_mn2wa") + +[node name="Cylinder" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.5, 1, -4.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Cylinder"] +mesh = SubResource("CylinderMesh_4n07c") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Cylinder"] +shape = SubResource("CylinderShape3D_6yv42") + +[node name="FrameSkipper" type="Node" parent="."] +script = ExtResource("1_eco5q") +frame_skip = 3 + +[node name="GrunkBeast" parent="FrameSkipper" instance=ExtResource("1_6yv42")] +move_speed = 8.0 +step_time = 0.06 + +[node name="Camera3D" type="Camera3D" parent="." node_paths=PackedStringArray("target")] +transform = Transform3D(0.252101, -0.522855, 0.81429, 0, 0.841469, 0.540306, -0.967701, -0.136212, 0.212135, 6.63551, 7.43415, 1.1904) +script = ExtResource("2_77sam") +target = NodePath("../FrameSkipper/GrunkBeast") diff --git a/src/ui/hud/player_hud.tscn b/src/ui/hud/player_hud.tscn index e16e776..c572507 100644 --- a/src/ui/hud/player_hud.tscn +++ b/src/ui/hud/player_hud.tscn @@ -4,6 +4,33 @@ [ext_resource type="Script" uid="uid://lrsv0185bfu" path="res://src/ui/hud/player_hud.gd" id="2_j6lpx"] [ext_resource type="PackedScene" uid="uid://cq8qcp5xg41e0" path="res://src/ui/hud/grunk_counter/grunk_counter.tscn" id="3_5be8f"] +[sub_resource type="Animation" id="Animation_n6jee"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("GrunkAlert:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("GrunkAlert2:modulate") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} + [sub_resource type="Animation" id="Animation_5be8f"] resource_name = "grunk_alert" length = 4.0 @@ -33,33 +60,6 @@ tracks/1/keys = { "values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 0)] } -[sub_resource type="Animation" id="Animation_n6jee"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("GrunkAlert:modulate") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(1, 1, 1, 0)] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath("GrunkAlert2:modulate") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(1, 1, 1, 0)] -} - [sub_resource type="AnimationLibrary" id="AnimationLibrary_ud8na"] _data = { &"RESET": SubResource("Animation_n6jee"), diff --git a/src/world/grunk_beast/grunk_beast.gd b/src/world/grunk_beast/grunk_beast.gd new file mode 100644 index 0000000..f73bff8 --- /dev/null +++ b/src/world/grunk_beast/grunk_beast.gd @@ -0,0 +1,45 @@ +class_name GrunkBeast extends Node3D +## The nefarious grunkbeest! +## +## Procedural animation adapted from https://github.com/CBerry22/Godot-4.0-Procedural-Animation + +@export var move_speed := 6.0 +@export var turn_speed := 6.0 +@export var ground_offset := -1.5 + +@export_category("Step Parameters") +@export var step_height := 1.2 +@export var step_time := 0.1 +@export var step_distance := 1.0 +@export var step_target_offset := 10.0 + +@onready var target_fl: BeastIKTarget = $Armature/TargetFL +@onready var target_fr: BeastIKTarget = $Armature/TargetFR +@onready var target_bl: BeastIKTarget = $Armature/TargetBL +@onready var target_br: BeastIKTarget = $Armature/TargetBR + + +func _process(delta: float) -> void: + # Reorient based on relative leg position + var p1 := Plane(target_bl.global_position, target_fl.global_position, target_fr.global_position) + var p2 := Plane(target_fr.global_position, target_br.global_position, target_bl.global_position) + var normal := (p1.normal + p2.normal).normalized() + var reoriented_basis := ( + Basis(normal.cross(basis.z), normal, basis.x.cross(normal)).orthonormalized() + ) + basis = basis.slerp(reoriented_basis, move_speed * delta).orthonormalized() + + # Reposition body to hang between legs + var centroid := ( + (target_fl.position + target_fr.position + target_bl.position + target_br.position) / 4.0 + ) + var target_pos := centroid + basis.y * ground_offset + var distance := basis.tdoty(target_pos - position) + position = position.lerp(position + basis.y * distance, move_speed * delta) + + # Movement + var direction := Input.get_axis("ui_down", "ui_up") + translate(Vector3(0, 0, direction) * move_speed * delta) + + var a_direction := Input.get_axis("ui_right", "ui_left") + rotate_object_local(Vector3.UP, a_direction * turn_speed * delta) diff --git a/src/world/grunk_beast/grunk_beast.gd.uid b/src/world/grunk_beast/grunk_beast.gd.uid new file mode 100644 index 0000000..14dc415 --- /dev/null +++ b/src/world/grunk_beast/grunk_beast.gd.uid @@ -0,0 +1 @@ +uid://dgy2ubsj1fotp diff --git a/src/world/grunk_beast/grunk_beast.tscn b/src/world/grunk_beast/grunk_beast.tscn new file mode 100644 index 0000000..2eab42e --- /dev/null +++ b/src/world/grunk_beast/grunk_beast.tscn @@ -0,0 +1,198 @@ +[gd_scene load_steps=16 format=3 uid="uid://d2664rpg4losx"] + +[ext_resource type="PackedScene" uid="uid://bi5mxt5s4aq1a" path="res://assets/npc/grunk_beast/grunk_beast.gltf" id="1_hoss2"] +[ext_resource type="Script" uid="uid://dkll8s6kwb41r" path="res://src/world/grunk_beast/start_ik.gd" id="2_qic24"] +[ext_resource type="Script" uid="uid://dgy2ubsj1fotp" path="res://src/world/grunk_beast/grunk_beast.gd" id="2_qqnhb"] +[ext_resource type="Shader" uid="uid://ckxc0ngd37rtk" path="res://src/shaders/gunk.gdshader" id="4_0gxpq"] +[ext_resource type="Script" uid="uid://7is3sa00qejh" path="res://src/world/grunk_beast/ik_target.gd" id="4_3gbao"] +[ext_resource type="Script" uid="uid://bpyovjodpxjpb" path="res://src/world/grunk_beast/step_ray.gd" id="4_faau1"] +[ext_resource type="Script" uid="uid://c1gitpy7s78ev" path="res://src/world/grunk_beast/target_container.gd" id="5_wffas"] +[ext_resource type="Texture2D" uid="uid://cm1jrvx7ftx4c" path="res://assets/black.png" id="5_xuag8"] +[ext_resource type="FastNoiseLite" uid="uid://cnlvdtx68giv6" path="res://assets/materials/gunk_noise.tres" id="6_mbqcc"] + +[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_2roq2"] +width = 256 +height = 256 +depth = 32 +seamless = true +seamless_blend_skirt = 0.5 +noise = ExtResource("6_mbqcc") + +[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_fk1xc"] +width = 256 +height = 256 +depth = 32 +seamless = true +seamless_blend_skirt = 0.5 +noise = ExtResource("6_mbqcc") + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_7fplw"] +frequency = 0.0703 + +[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_omayi"] +width = 32 +height = 32 +depth = 128 +noise = SubResource("FastNoiseLite_7fplw") + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_vvw1q"] +resource_local_to_scene = true +render_priority = 0 +shader = ExtResource("4_0gxpq") +shader_parameter/color_1 = Color(0, 0.03, 0.1, 1) +shader_parameter/color_2 = Color(0, 0.1, 0.3, 1) +shader_parameter/emission_color = Color(0.25, 0.88, 1, 1) +shader_parameter/pixellation = 128.0 +shader_parameter/time_pixellation = 30.0 +shader_parameter/roughness = 0.15 +shader_parameter/specular_contribution = 0.8 +shader_parameter/emission_strength = 0.02 +shader_parameter/uv_scale = Vector2(2, 2) +shader_parameter/time_scale = 0.2 +shader_parameter/edge_bleed = 0.25 +shader_parameter/gunk_mask = ExtResource("5_xuag8") +shader_parameter/gunk_noise = SubResource("NoiseTexture3D_2roq2") +shader_parameter/gunk_normal_map = SubResource("NoiseTexture3D_fk1xc") +shader_parameter/jitter_magnitude = 0.3 +shader_parameter/jitter_time_scale = 0.6 +shader_parameter/jitter_noise = SubResource("NoiseTexture3D_omayi") +shader_parameter/vertex_inflation = 0.0 +shader_parameter/inflation_pixellation = 10.0 + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_ml8dd"] +resource_local_to_scene = true +render_priority = 0 +shader = ExtResource("4_0gxpq") +shader_parameter/color_1 = Color(0, 0.03, 0.1, 1) +shader_parameter/color_2 = Color(0, 0.1, 0.3, 1) +shader_parameter/emission_color = Color(0.25, 0.88, 1, 1) +shader_parameter/pixellation = 128.0 +shader_parameter/time_pixellation = 30.0 +shader_parameter/roughness = 0.15 +shader_parameter/specular_contribution = 0.8 +shader_parameter/emission_strength = 0.02 +shader_parameter/uv_scale = Vector2(2, 2) +shader_parameter/time_scale = 0.2 +shader_parameter/edge_bleed = 0.25 +shader_parameter/gunk_mask = ExtResource("5_xuag8") +shader_parameter/gunk_noise = SubResource("NoiseTexture3D_2roq2") +shader_parameter/gunk_normal_map = SubResource("NoiseTexture3D_fk1xc") +shader_parameter/jitter_magnitude = 0.1 +shader_parameter/jitter_time_scale = 0.6 +shader_parameter/jitter_noise = SubResource("NoiseTexture3D_omayi") +shader_parameter/vertex_inflation = 0.0 +shader_parameter/inflation_pixellation = 10.0 + +[node name="GrunkBeast" instance=ExtResource("1_hoss2")] +script = ExtResource("2_qqnhb") + +[node name="Armature" parent="." index="0"] +transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0, 0, 0) + +[node name="Skeleton3D" parent="Armature" index="0"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0) + +[node name="Body" parent="Armature/Skeleton3D" index="0"] +surface_material_override/0 = SubResource("ShaderMaterial_vvw1q") + +[node name="Leg" parent="Armature/Skeleton3D" index="1"] +surface_material_override/0 = SubResource("ShaderMaterial_ml8dd") + +[node name="FrontLeftLeg" type="SkeletonIK3D" parent="Armature/Skeleton3D" index="2"] +root_bone = &"Leg1.F.L" +tip_bone = &"IK_Leg.F.L" +use_magnet = true +magnet = Vector3(0, 10, 0) +target_node = NodePath("../../TargetFL") +script = ExtResource("2_qic24") + +[node name="FrontRightLeg" type="SkeletonIK3D" parent="Armature/Skeleton3D" index="3"] +root_bone = &"Leg1.F.R" +tip_bone = &"IK_Leg.F.R" +use_magnet = true +magnet = Vector3(0, 10, 0) +target_node = NodePath("../../TargetFR") +script = ExtResource("2_qic24") + +[node name="BackLeftLeg" type="SkeletonIK3D" parent="Armature/Skeleton3D" index="4"] +root_bone = &"Leg1.B.L" +tip_bone = &"IK_Leg.B.L" +use_magnet = true +magnet = Vector3(0, 10, 0) +target_node = NodePath("../../TargetBL") +script = ExtResource("2_qic24") + +[node name="BackRightLeg" type="SkeletonIK3D" parent="Armature/Skeleton3D" index="5"] +root_bone = &"Leg1.B.R" +tip_bone = &"IK_Leg.B.R" +use_magnet = true +magnet = Vector3(0, 10, 0) +target_node = NodePath("../../TargetBR") +script = ExtResource("2_qic24") + +[node name="TargetFL" type="Marker3D" parent="Armature" index="1" node_paths=PackedStringArray("step_target", "neighbor", "diagonal")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.5, 0, 1.5) +top_level = true +script = ExtResource("4_3gbao") +step_target = NodePath("../../StepTargets/RayFL/StepFL") +neighbor = NodePath("../TargetFR") +diagonal = NodePath("../TargetBR") + +[node name="TargetFR" type="Marker3D" parent="Armature" index="2" node_paths=PackedStringArray("step_target", "neighbor", "diagonal")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.5, 0, 1.5) +top_level = true +script = ExtResource("4_3gbao") +step_target = NodePath("../../StepTargets/RayFR/StepFR") +neighbor = NodePath("../TargetFL") +diagonal = NodePath("../TargetBL") + +[node name="TargetBL" type="Marker3D" parent="Armature" index="3" node_paths=PackedStringArray("step_target", "neighbor", "diagonal")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, -2) +top_level = true +script = ExtResource("4_3gbao") +step_target = NodePath("../../StepTargets/RayBL/StepBL") +neighbor = NodePath("../TargetBR") +diagonal = NodePath("../TargetFR") + +[node name="TargetBR" type="Marker3D" parent="Armature" index="4" node_paths=PackedStringArray("step_target", "neighbor", "diagonal")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0, -2) +top_level = true +script = ExtResource("4_3gbao") +step_target = NodePath("../../StepTargets/RayBR/StepBR") +neighbor = NodePath("../TargetBL") +diagonal = NodePath("../TargetFL") + +[node name="StepTargets" type="Node3D" parent="." index="1"] +script = ExtResource("5_wffas") + +[node name="RayFL" type="RayCast3D" parent="StepTargets" index="0"] +transform = Transform3D(0.996195, -0.0871557, 0, 0.0868241, 0.992404, 0.0871557, -0.00759612, -0.0868241, 0.996195, 1.5, 3.5, 1.5) +target_position = Vector3(0, -10, 0) +script = ExtResource("4_faau1") + +[node name="StepFL" type="Marker3D" parent="StepTargets/RayFL" index="0"] +transform = Transform3D(0.996195, 0.0868241, -0.00759612, -0.0871557, 0.992404, -0.0868241, 9.31323e-10, 0.0871557, 0.996195, -0.303884, -3.47341, -0.305045) + +[node name="RayFR" type="RayCast3D" parent="StepTargets" index="1"] +transform = Transform3D(0.996195, 0.0871557, 0, -0.0868241, 0.992404, 0.0871557, 0.00759612, -0.0868241, 0.996195, -1.5, 3.5, 1.5) +target_position = Vector3(0, -10, 0) +script = ExtResource("4_faau1") + +[node name="StepFR" type="Marker3D" parent="StepTargets/RayFR" index="0"] +transform = Transform3D(0.996195, -0.0868241, 0.00759612, 0.0871557, 0.992404, -0.0868241, -9.31323e-10, 0.0871557, 0.996195, 0.303884, -3.47341, -0.305045) + +[node name="RayBL" type="RayCast3D" parent="StepTargets" index="2"] +transform = Transform3D(0.996195, -0.0871557, 0, 0.0868241, 0.992404, -0.0871557, 0.00759612, 0.0868241, 0.996195, 2, 3.5, -2) +target_position = Vector3(0, -10, 0) +script = ExtResource("4_faau1") + +[node name="StepBL" type="Marker3D" parent="StepTargets/RayBL" index="0"] +transform = Transform3D(0.996195, 0.0868241, 0.00759612, -0.0871557, 0.992404, 0.0868241, -9.31323e-10, -0.0871557, 0.996195, -0.303884, -3.47341, 0.305045) + +[node name="RayBR" type="RayCast3D" parent="StepTargets" index="3"] +transform = Transform3D(0.996195, 0.0871557, 0, -0.0868241, 0.992404, -0.0871557, -0.00759612, 0.0868241, 0.996195, -2, 3.5, -2) +target_position = Vector3(0, -10, 0) +script = ExtResource("4_faau1") + +[node name="StepBR" type="Marker3D" parent="StepTargets/RayBR" index="0"] +transform = Transform3D(0.996195, -0.0868241, -0.00759612, 0.0871557, 0.992404, 0.0868241, 1.39698e-09, -0.0871557, 0.996195, 0.303884, -3.47341, 0.305045) diff --git a/src/world/grunk_beast/ik_target.gd b/src/world/grunk_beast/ik_target.gd new file mode 100644 index 0000000..b0d784d --- /dev/null +++ b/src/world/grunk_beast/ik_target.gd @@ -0,0 +1,49 @@ +class_name BeastIKTarget extends Marker3D + +const CRITICAL_ANGLE := 0.1 + +@export var step_target: Node3D + +@export var neighbor: BeastIKTarget +@export var diagonal: BeastIKTarget + +var stepping := false +var _resting := false + +@onready var parent := owner as GrunkBeast + + +func step() -> void: + # Tween a rough arc + var up := parent.basis.y + var midpoint := 0.5 * (global_position + step_target.global_position) + up * parent.step_height + var time := 0.5 * parent.step_time + + stepping = true + + # TODO: tween this? + global_basis = step_target.global_basis + + var tween := create_tween() + tween.tween_property(self, "global_position", midpoint, time) + tween.tween_property(self, "global_position", step_target.global_position, time) + tween.tween_callback(_end_step) + + +func _end_step() -> void: + stepping = false + _resting = true + + +func _process(_delta: float) -> void: + if _resting: + _resting = false + return + + if ( + !stepping + and !neighbor.stepping + and global_position.distance_to(step_target.global_position) >= parent.step_distance + ): + step() + diagonal.step() diff --git a/src/world/grunk_beast/ik_target.gd.uid b/src/world/grunk_beast/ik_target.gd.uid new file mode 100644 index 0000000..6a9ba1d --- /dev/null +++ b/src/world/grunk_beast/ik_target.gd.uid @@ -0,0 +1 @@ +uid://7is3sa00qejh diff --git a/src/world/grunk_beast/start_ik.gd b/src/world/grunk_beast/start_ik.gd new file mode 100644 index 0000000..bbadab2 --- /dev/null +++ b/src/world/grunk_beast/start_ik.gd @@ -0,0 +1,7 @@ +@tool +extends SkeletonIK3D +## Simply starts the IK simulation on ready. + + +func _ready() -> void: + start() diff --git a/src/world/grunk_beast/start_ik.gd.uid b/src/world/grunk_beast/start_ik.gd.uid new file mode 100644 index 0000000..6801d91 --- /dev/null +++ b/src/world/grunk_beast/start_ik.gd.uid @@ -0,0 +1 @@ +uid://dkll8s6kwb41r diff --git a/src/world/grunk_beast/step_ray.gd b/src/world/grunk_beast/step_ray.gd new file mode 100644 index 0000000..9499a90 --- /dev/null +++ b/src/world/grunk_beast/step_ray.gd @@ -0,0 +1,15 @@ +extends RayCast3D +## Snaps step targets to surfaces + +@export var step_target: Node3D + + +func _ready() -> void: + if not step_target: + step_target = get_child(0) as Node3D + + +func _physics_process(_delta: float) -> void: + var point := get_collision_point() + if point: + step_target.global_position = point diff --git a/src/world/grunk_beast/step_ray.gd.uid b/src/world/grunk_beast/step_ray.gd.uid new file mode 100644 index 0000000..b8153e8 --- /dev/null +++ b/src/world/grunk_beast/step_ray.gd.uid @@ -0,0 +1 @@ +uid://bpyovjodpxjpb diff --git a/src/world/grunk_beast/target_container.gd b/src/world/grunk_beast/target_container.gd new file mode 100644 index 0000000..b1467cf --- /dev/null +++ b/src/world/grunk_beast/target_container.gd @@ -0,0 +1,10 @@ +extends Node3D + +@onready var parent := owner as GrunkBeast +@onready var prev_position := parent.global_position + + +func _process(_delta: float) -> void: + var diff := parent.global_position - prev_position + global_position = parent.global_position + diff * parent.step_target_offset + prev_position = parent.global_position diff --git a/src/world/grunk_beast/target_container.gd.uid b/src/world/grunk_beast/target_container.gd.uid new file mode 100644 index 0000000..1cab8b4 --- /dev/null +++ b/src/world/grunk_beast/target_container.gd.uid @@ -0,0 +1 @@ +uid://c1gitpy7s78ev diff --git a/src/world/mechanics/relay/gunk_relay.tscn b/src/world/mechanics/relay/gunk_relay.tscn index 14f7065..12c6bf5 100644 --- a/src/world/mechanics/relay/gunk_relay.tscn +++ b/src/world/mechanics/relay/gunk_relay.tscn @@ -17,21 +17,6 @@ height = 0.2 [sub_resource type="SphereShape3D" id="SphereShape3D_gk1l0"] radius = 0.1 -[sub_resource type="Animation" id="Animation_rdv5j"] -resource_name = "trigger" -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("MeshInstance3D:mesh:material:emission_energy_multiplier") -tracks/0/interp = 2 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0, 0.166667, 1), -"transitions": PackedFloat32Array(1, 1, 1), -"update": 0, -"values": [0.0, 2.0, 0.0] -} - [sub_resource type="Animation" id="Animation_ipm58"] length = 0.001 tracks/0/type = "value" @@ -47,6 +32,21 @@ tracks/0/keys = { "values": [0.0] } +[sub_resource type="Animation" id="Animation_rdv5j"] +resource_name = "trigger" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("MeshInstance3D:mesh:material:emission_energy_multiplier") +tracks/0/interp = 2 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.166667, 1), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [0.0, 2.0, 0.0] +} + [sub_resource type="AnimationLibrary" id="AnimationLibrary_ipm58"] _data = { &"RESET": SubResource("Animation_ipm58"), diff --git a/vault/TODO.md b/vault/TODO.md index 0f07c43..6fe9532 100644 --- a/vault/TODO.md +++ b/vault/TODO.md @@ -5,18 +5,18 @@ - [x] [[nodules]] - [ ] #equipment - [ ] [[spray beam]] - - [ ] Spray nozzle asset + - [x] Spray nozzle asset - [x] Point spray - [x] Wide-angle spray - [x] Tall-angle spray? - [ ] Spray-can? - - [ ] [[chisel]] + - [x] [[toothbrush]] - [ ] [[radar]] - [ ] [[mp3 player]] - [ ] [[manual]] - [ ] #mechanics - - [ ] [[grunk alert]] - - [ ] [[alarm]] + - [x] [[grunk alert]] + - [x] [[alarm]] - [ ] [[hotwire]] - [ ] [[tripwire]] - [ ] [[looker]] diff --git a/vault/elements/alarm.md b/vault/elements/alarm.md index 4b54366..87d9181 100644 --- a/vault/elements/alarm.md +++ b/vault/elements/alarm.md @@ -1,6 +1,6 @@ Does nothing on its own, but increases the [[grunk alert]] when activated by a connected component like a [[tripwire]] or [[listener]]. -Will activate if the player tries to remove with the spray beam. Can be safely deactivated & harvested with the [[chisel]]. +Will activate if the player tries to remove with the spray beam. Can be safely deactivated & harvested with the [[toothbrush]]. For flavor, maybe screeches or something when activated? diff --git a/vault/elements/grunk.md b/vault/elements/grunk.md index c142e43..0656e90 100644 --- a/vault/elements/grunk.md +++ b/vault/elements/grunk.md @@ -6,4 +6,4 @@ The player is employed (sentenced) to harvest grunk, which is a somewhat valuabl ## #mechanics -Grunk can be cleared using the [[spray beam]] or [[chisel]]. #mechanics components must have a continuous [[grunk]] connection to an [[alarm]] to activate it. \ No newline at end of file +Grunk can be cleared using the [[spray beam]] or [[toothbrush]]. #mechanics components must have a continuous [[grunk]] connection to an [[alarm]] to activate it. \ No newline at end of file diff --git a/vault/elements/listener.md b/vault/elements/listener.md index 41af1d5..9b47e98 100644 --- a/vault/elements/listener.md +++ b/vault/elements/listener.md @@ -4,7 +4,7 @@ Triggers a connected [[alarm]] when the player makes noise nearby. Noises includ - #maybe moving without sneaking? - #maybe using the MP3 player, just for fun -Grunk can be cleared silently with the [[chisel]]. +Grunk can be cleared silently with the [[toothbrush]]. tags: #mechanics \ No newline at end of file diff --git a/vault/elements/chisel.md b/vault/elements/toothbrush.md similarity index 100% rename from vault/elements/chisel.md rename to vault/elements/toothbrush.md