diff --git a/addons/destruction/destruction.gd b/addons/destruction/destruction.gd new file mode 100644 index 0000000..d99380b --- /dev/null +++ b/addons/destruction/destruction.gd @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: 2023 Jummit +# +# SPDX-License-Identifier: MIT + +@tool +@icon("destruction_icon.svg") +class_name Destruction +extends Node + +## Handles destruction of the parent node. +## +## When [method destroy] is called, the parent node is freed and shards +## are added to the [member shard_container]. + +## A scene of the fragmented mesh containing multiple [MeshInstance3D]s. +@export var fragmented: PackedScene: set = set_fragmented +## The node where created shards are added to. +@onready @export var shard_container := get_node("../../") + +@export_group("Animation") +## How many seconds until the shards fade away. Set to -1 to disable fading. +@export var fade_delay := 2.0 +## How many seconds until the shards shrink. Set to -1 to disable shrinking. +@export var shrink_delay := 2.0 +## How long the animation lasts before the shard is removed. +@export var animation_length := 2.0 + +@export_group("Collision") +## The [member RigidBody3D.collision_layer] set on the created shards. +@export_flags_3d_physics var collision_layer = 1 +## The [member RigidBody3D.collision_mask] set on the created shards. +@export_flags_3d_physics var collision_mask = 1 + +## Cached shard meshes (instantiated from [member fragmented]). +static var cached_meshes := {} +## Cached collision shapes. +static var cached_shapes := {} + +## Remove the parent node and add shards to the shard container. +func destroy(explosion_power := 1.0) -> void: + if not fragmented in cached_meshes: + cached_meshes[fragmented] = fragmented.instantiate() + for shard_mesh in cached_meshes[fragmented].get_children(): + cached_shapes[shard_mesh] = shard_mesh.mesh.create_convex_shape() + var original_meshes = cached_meshes[fragmented] + for original in original_meshes.get_children(): + if original is MeshInstance3D: + _add_shard(original, explosion_power) + get_parent().queue_free() + + +func _add_shard(original: MeshInstance3D, explosion_power: float) -> void: + var body := RigidBody3D.new() + var mesh := MeshInstance3D.new() + var shape := CollisionShape3D.new() + body.add_child(mesh) + body.add_child(shape) + shard_container.add_child(body, true) + body.global_position = get_parent().global_transform.origin + original.position + body.collision_layer = collision_layer + body.collision_mask = collision_mask + shape.shape = cached_shapes[original] + mesh.mesh = original.mesh + if fade_delay >= 0: + var material = original.mesh.surface_get_material(0) + if material is StandardMaterial3D: + material = material.duplicate() + material.flags_transparent = true + get_tree().create_tween().tween_property(material, "albedo_color", + Color(1, 1, 1, 0), animation_length)\ + .set_delay(fade_delay)\ + .set_trans(Tween.TRANS_EXPO)\ + .set_ease(Tween.EASE_OUT) + mesh.material_override = material + else: + push_warning("Shard doesn't use a StandardMaterial3D, can't add transparency.") + body.apply_impulse(_random_direction() * explosion_power, + -original.position.normalized()) + if shrink_delay < 0 and fade_delay < 0: + get_tree().create_timer(animation_length)\ + .timeout.connect(func(): body.queue_free()) + elif shrink_delay >= 0: + var tween := get_tree().create_tween() + tween.tween_property(mesh, "scale", Vector3.ZERO, animation_length)\ + .set_delay(shrink_delay) + tween.finished.connect(func(): body.queue_free()) + + +func set_fragmented(to: PackedScene) -> void: + fragmented = to + if is_inside_tree(): + get_tree().node_configuration_warning_changed.emit(self) + + +func _get_configuration_warnings() -> PackedStringArray: + return ["No fragmented version set"] if not fragmented else [] + + +static func _random_direction() -> Vector3: + return (Vector3(randf(), randf(), randf()) - Vector3.ONE / 2.0).normalized() * 2.0 diff --git a/addons/destruction/destruction_icon.svg b/addons/destruction/destruction_icon.svg new file mode 100644 index 0000000..b0584d9 --- /dev/null +++ b/addons/destruction/destruction_icon.svg @@ -0,0 +1,94 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/addons/destruction/destruction_icon.svg.import b/addons/destruction/destruction_icon.svg.import new file mode 100644 index 0000000..1b267c1 --- /dev/null +++ b/addons/destruction/destruction_icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://co3om28rgeos3" +path="res://.godot/imported/destruction_icon.svg-716fc5b182e74f5a75cf299975d03542.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/destruction/destruction_icon.svg" +dest_files=["res://.godot/imported/destruction_icon.svg-716fc5b182e74f5a75cf299975d03542.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/destruction/destruction_icon.svg.import.license b/addons/destruction/destruction_icon.svg.import.license new file mode 100644 index 0000000..26e9709 --- /dev/null +++ b/addons/destruction/destruction_icon.svg.import.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Jummit +SPDX-FileContributor: Jummit + +SPDX-License-Identifier: CC0-1.0 diff --git a/addons/destruction/destruction_icon.svg.license b/addons/destruction/destruction_icon.svg.license new file mode 100644 index 0000000..26e9709 --- /dev/null +++ b/addons/destruction/destruction_icon.svg.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Jummit +SPDX-FileContributor: Jummit + +SPDX-License-Identifier: CC0-1.0 diff --git a/addons/destruction/plugin.cfg b/addons/destruction/plugin.cfg new file mode 100644 index 0000000..783667d --- /dev/null +++ b/addons/destruction/plugin.cfg @@ -0,0 +1,11 @@ +; SPDX-FileCopyrightText: 2023 Jummit +; +; SPDX-License-Identifier: MIT + +[plugin] + +name="Destruction" +description="Destroy 3D objects." +author="Jummit" +version="7.0" +script="plugin.gd" diff --git a/addons/destruction/plugin.gd b/addons/destruction/plugin.gd new file mode 100644 index 0000000..d7925f3 --- /dev/null +++ b/addons/destruction/plugin.gd @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: 2023 Jummit +# +# SPDX-License-Identifier: MIT + +@tool +extends EditorPlugin diff --git a/addons/destruction/shard.tscn.license b/addons/destruction/shard.tscn.license new file mode 100644 index 0000000..74ad372 --- /dev/null +++ b/addons/destruction/shard.tscn.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2023 Jummit +# +# SPDX-License-Identifier: MIT diff --git a/cube/cube_fragments.glb b/cube/cube_fragments.glb new file mode 100644 index 0000000..40b3a9e Binary files /dev/null and b/cube/cube_fragments.glb differ diff --git a/cube/cube_fragments.glb.import b/cube/cube_fragments.glb.import new file mode 100644 index 0000000..abfa959 --- /dev/null +++ b/cube/cube_fragments.glb.import @@ -0,0 +1,41 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://celvn43a7xgcb" +path="res://.godot/imported/cube_fragments.glb-b90c58c2cf782b8838d36706b8edb863.scn" + +[deps] + +source_file="res://cube/cube_fragments.glb" +dest_files=["res://.godot/imported/cube_fragments.glb-b90c58c2cf782b8838d36706b8edb863.scn"] + +[params] + +nodes/root_type="Node3D" +nodes/root_name="Scene Root" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +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 +import_script/path="" +_subresources={ +"materials": { +"Material": { +"use_external/enabled": true, +"use_external/path": "res://cube/marble.tres" +} +} +} +gltf/naming_version=0 +gltf/embedded_image_handling=1 diff --git a/cube/cube_fragments.tscn b/cube/cube_fragments.tscn new file mode 100644 index 0000000..f360441 --- /dev/null +++ b/cube/cube_fragments.tscn @@ -0,0 +1,5 @@ +[gd_scene load_steps=2 format=3 uid="uid://c61tpgoll0pap"] + +[ext_resource type="PackedScene" uid="uid://celvn43a7xgcb" path="res://cube/cube_fragments.glb" id="1_1v5wa"] + +[node name="cube_fragments" instance=ExtResource("1_1v5wa")] diff --git a/cube/destructible_cube.tscn b/cube/destructible_cube.tscn new file mode 100644 index 0000000..446d027 --- /dev/null +++ b/cube/destructible_cube.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=6 format=3 uid="uid://cexof5tlc7l1i"] + +[ext_resource type="Material" uid="uid://b4ygu62iepx6e" path="res://cube/marble.tres" id="1_j03bl"] +[ext_resource type="Script" path="res://addons/destruction/destruction.gd" id="2_gffgg"] +[ext_resource type="PackedScene" uid="uid://c61tpgoll0pap" path="res://cube/cube_fragments.tscn" id="3_prg0r"] + +[sub_resource type="BoxMesh" id="BoxMesh_h5eed"] +size = Vector3(5, 5, 1) + +[sub_resource type="BoxShape3D" id="BoxShape3D_uo2w7"] +size = Vector3(5, 5, 1) + +[node name="DestructibleCube" type="StaticBody3D"] + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +material_override = ExtResource("1_j03bl") +mesh = SubResource("BoxMesh_h5eed") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("BoxShape3D_uo2w7") + +[node name="Destruction" type="Node" parent="." node_paths=PackedStringArray("shard_container")] +script = ExtResource("2_gffgg") +fragmented = ExtResource("3_prg0r") +shard_container = NodePath("") diff --git a/cube/destructible_cube.tscn.license b/cube/destructible_cube.tscn.license new file mode 100644 index 0000000..26e9709 --- /dev/null +++ b/cube/destructible_cube.tscn.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Jummit +SPDX-FileContributor: Jummit + +SPDX-License-Identifier: CC0-1.0 diff --git a/cube/fractured_cube.glb.import.license b/cube/fractured_cube.glb.import.license new file mode 100644 index 0000000..26e9709 --- /dev/null +++ b/cube/fractured_cube.glb.import.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Jummit +SPDX-FileContributor: Jummit + +SPDX-License-Identifier: CC0-1.0 diff --git a/cube/fractured_cube.glb.license b/cube/fractured_cube.glb.license new file mode 100644 index 0000000..26e9709 --- /dev/null +++ b/cube/fractured_cube.glb.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Jummit +SPDX-FileContributor: Jummit + +SPDX-License-Identifier: CC0-1.0 diff --git a/cube/marble.tres b/cube/marble.tres new file mode 100644 index 0000000..65cfc9c --- /dev/null +++ b/cube/marble.tres @@ -0,0 +1,6 @@ +[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b4ygu62iepx6e"] + +[ext_resource type="Texture2D" uid="uid://bgo453hjk7h3b" path="res://cube/marble_albedo.jpg" id="1_eikhe"] + +[resource] +albedo_texture = ExtResource("1_eikhe") diff --git a/cube/marble.tres.license b/cube/marble.tres.license new file mode 100644 index 0000000..26e9709 --- /dev/null +++ b/cube/marble.tres.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Jummit +SPDX-FileContributor: Jummit + +SPDX-License-Identifier: CC0-1.0 diff --git a/cube/marble_albedo.jpg b/cube/marble_albedo.jpg new file mode 100644 index 0000000..54a279a Binary files /dev/null and b/cube/marble_albedo.jpg differ diff --git a/cube/marble_albedo.jpg.import b/cube/marble_albedo.jpg.import new file mode 100644 index 0000000..9cc3941 --- /dev/null +++ b/cube/marble_albedo.jpg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bgo453hjk7h3b" +path.s3tc="res://.godot/imported/marble_albedo.jpg-c54912b566eaf994372481bc1ead757e.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://cube/marble_albedo.jpg" +dest_files=["res://.godot/imported/marble_albedo.jpg-c54912b566eaf994372481bc1ead757e.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/cube/marble_albedo.jpg.import.license b/cube/marble_albedo.jpg.import.license new file mode 100644 index 0000000..26e9709 --- /dev/null +++ b/cube/marble_albedo.jpg.import.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Jummit +SPDX-FileContributor: Jummit + +SPDX-License-Identifier: CC0-1.0 diff --git a/cube/marble_albedo.jpg.license b/cube/marble_albedo.jpg.license new file mode 100644 index 0000000..5384855 --- /dev/null +++ b/cube/marble_albedo.jpg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 3DTextures + +SPDX-License-Identifier: CC0-1.0 diff --git a/demo.gd b/demo.gd new file mode 100644 index 0000000..4a0a730 --- /dev/null +++ b/demo.gd @@ -0,0 +1,23 @@ +# SPDX-FileCopyrightText: 2023 Jummit +# +# SPDX-License-Identifier: MIT + +extends Node3D + +## Demo of the Destruction plugin. +## +## Shows a [RigidBody3D] cube which can be destroyed by clicking a button. + +@onready var _destruction: Destruction = $DestructibleCube/Destruction +@onready var _destroy_button: Button = $DestroyButton + +var _destructible_cube_scene := preload("res://cube/destructible_cube.tscn") + +func _on_destroy_button_pressed() -> void: + _destruction.destroy(5) + _destroy_button.disabled = true + await get_tree().create_timer(1).timeout + var new := _destructible_cube_scene.instantiate() + add_child(new) + _destruction = new.get_node("Destruction") + _destroy_button.disabled = false diff --git a/demo.tscn b/demo.tscn new file mode 100644 index 0000000..a89adea --- /dev/null +++ b/demo.tscn @@ -0,0 +1,63 @@ +[gd_scene load_steps=8 format=3 uid="uid://dkgkgrq6507kj"] + +[ext_resource type="Script" path="res://demo.gd" id="1_xvv5r"] +[ext_resource type="PackedScene" uid="uid://cexof5tlc7l1i" path="res://cube/destructible_cube.tscn" id="2_1ot51"] + +[sub_resource type="BoxMesh" id="BoxMesh_yig7p"] +size = Vector3(20, 0.5, 20) + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_dirmc"] +data = PackedVector3Array(-10, 0.25, 10, 10, 0.25, 10, -10, -0.25, 10, 10, 0.25, 10, 10, -0.25, 10, -10, -0.25, 10, 10, 0.25, -10, -10, 0.25, -10, 10, -0.25, -10, -10, 0.25, -10, -10, -0.25, -10, 10, -0.25, -10, 10, 0.25, 10, 10, 0.25, -10, 10, -0.25, 10, 10, 0.25, -10, 10, -0.25, -10, 10, -0.25, 10, -10, 0.25, -10, -10, 0.25, 10, -10, -0.25, -10, -10, 0.25, 10, -10, -0.25, 10, -10, -0.25, -10, 10, 0.25, 10, -10, 0.25, 10, 10, 0.25, -10, -10, 0.25, 10, -10, 0.25, -10, 10, 0.25, -10, -10, -0.25, 10, 10, -0.25, 10, -10, -0.25, -10, 10, -0.25, 10, 10, -0.25, -10, -10, -0.25, -10) + +[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_d8soj"] +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_mukl1"] +sky_material = SubResource("ProceduralSkyMaterial_d8soj") + +[sub_resource type="Environment" id="Environment_hh15e"] +background_mode = 2 +sky = SubResource("Sky_mukl1") +tonemap_mode = 2 + +[node name="Demo" type="Node3D"] +script = ExtResource("1_xvv5r") + +[node name="DestructibleCube" parent="." instance=ExtResource("2_1ot51")] +editor_description = "The cube is replaced with a new instance once destroyed." +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.49026, -2) + +[node name="Floor" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.759737, 0) +mesh = SubResource("BoxMesh_yig7p") + +[node name="StaticBody3D" type="StaticBody3D" parent="Floor"] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor/StaticBody3D"] +shape = SubResource("ConcavePolygonShape3D_dirmc") + +[node name="Camera3D" type="Camera3D" parent="."] +transform = Transform3D(0.680694, 0.293844, -0.671052, 0, 0.916027, 0.401115, 0.732567, -0.273037, 0.623535, -5.55537, 3.32067, 5.16199) + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] +transform = Transform3D(-0.866023, -0.433016, 0.250001, 0, 0.499998, 0.866027, -0.500003, 0.749999, -0.43301, 0, 0, 0) + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_hh15e") + +[node name="DestroyButton" type="Button" parent="."] +anchors_preset = 7 +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +offset_left = -84.5 +offset_top = -97.0 +offset_right = 84.5 +offset_bottom = -21.0 +grow_horizontal = 2 +grow_vertical = 0 +text = "Destroy" + +[connection signal="pressed" from="DestroyButton" to="." method="_on_destroy_button_pressed"] diff --git a/project.godot b/project.godot index 7afc06d..a44a45c 100644 --- a/project.godot +++ b/project.godot @@ -23,6 +23,10 @@ boot_splash/show_image.editor=true window/stretch/mode="canvas_items" +[editor_plugins] + +enabled=PackedStringArray("res://addons/destruction/plugin.cfg") + [input] move_left={ @@ -65,8 +69,23 @@ interact={ "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,"echo":false,"script":null) ] } +gravity_activate={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":16,"position":Vector2(142, 11),"global_position":Vector2(146, 52),"factor":1.0,"button_index":5,"canceled":false,"pressed":true,"double_click":false,"script":null) +, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(337, 22),"global_position":Vector2(341, 63),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null) +] +} +gravity_change={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":2,"position":Vector2(338, 10),"global_position":Vector2(342, 51),"factor":1.0,"button_index":2,"canceled":false,"pressed":true,"double_click":false,"script":null) +] +} [rendering] +anti_aliasing/quality/msaa_3d=1 +anti_aliasing/quality/screen_space_aa=1 +anti_aliasing/quality/use_taa=true +anti_aliasing/quality/use_debanding=true environment/defaults/default_environment="res://resources/environment.tres" environment/defaults/default_clear_color.release=Color(0, 0, 0, 1) diff --git a/scenes/completion_counter.tscn b/scenes/completion_counter.tscn index 3ce34a3..4c99006 100644 --- a/scenes/completion_counter.tscn +++ b/scenes/completion_counter.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=3 format=3 uid="uid://6njtmij7sikl"] +[gd_scene load_steps=3 format=3 uid="uid://22blfybi6n4q"] [ext_resource type="Script" path="res://scripts/completion_counter.gd" id="1_40xge"] diff --git a/scenes/gravity_gun.tscn b/scenes/gravity_gun.tscn index 6a90ed6..0bc0c67 100644 --- a/scenes/gravity_gun.tscn +++ b/scenes/gravity_gun.tscn @@ -1,5 +1,6 @@ -[gd_scene load_steps=15 format=3 uid="uid://cl6gw3huejnrl"] +[gd_scene load_steps=21 format=3 uid="uid://cl6gw3huejnrl"] +[ext_resource type="Script" path="res://scripts/gravity_gun.gd" id="1_0upyy"] [ext_resource type="ArrayMesh" uid="uid://cxw30fmp15jsd" path="res://models/gun.obj" id="1_803cf"] [ext_resource type="Environment" uid="uid://drn5fwa4uhv4m" path="res://resources/environment.tres" id="1_vtn44"] [ext_resource type="Material" uid="uid://b6r8e4302xg1d" path="res://assets/materials/dark_metal.material" id="2_qrl87"] @@ -10,9 +11,16 @@ [ext_resource type="Material" uid="uid://c8bic1or51fbf" path="res://assets/materials/old_plastic.material" id="7_c1s4a"] [ext_resource type="Texture2D" uid="uid://b4en3dw3q324p" path="res://assets/textures/circle.png" id="8_al3c7"] -[sub_resource type="World3D" id="World3D_6qira"] +[sub_resource type="World3D" id="World3D_wp4pn"] environment = ExtResource("1_vtn44") +[sub_resource type="GDScript" id="GDScript_sr7lp"] +script/source = "extends SubViewport + +func _ready() -> void: + msaa_3d = ProjectSettings.get_setting(\"rendering/anti_aliasing/quality/msaa_3d\",0) +" + [sub_resource type="ShaderMaterial" id="ShaderMaterial_twwch"] render_priority = 0 shader = ExtResource("3_aeppb") @@ -33,7 +41,7 @@ scale_max = 0.07 collision_mode = 2 collision_use_scale = true -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_y24ld"] +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_rnipw"] transparency = 2 alpha_scissor_threshold = 0.9 alpha_antialiasing_mode = 0 @@ -45,30 +53,58 @@ billboard_mode = 1 billboard_keep_scale = true [sub_resource type="QuadMesh" id="QuadMesh_wtlns"] -material = SubResource("StandardMaterial3D_y24ld") +material = SubResource("StandardMaterial3D_rnipw") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_5ccgj"] +direction = Vector3(3, 0, 1) +initial_velocity_min = 10.0 +initial_velocity_max = 10.0 + +[sub_resource type="Curve" id="Curve_xucvk"] +_data = [Vector2(0.0245902, 0), 0.0, 1.4, 0, 0, Vector2(0.172131, 0), 1.65004, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_endjk"] +emission_enabled = true +emission = Color(0, 1, 1, 1) +emission_energy_multiplier = 16.0 +backlight = Color(1, 1, 1, 1) +billboard_keep_scale = true +point_size = 12.7 +use_particle_trails = true + +[sub_resource type="RibbonTrailMesh" id="RibbonTrailMesh_fwaab"] +material = SubResource("StandardMaterial3D_endjk") +size = 12.0 +section_length = 0.3 +section_segments = 2 +curve = SubResource("Curve_xucvk") [node name="GravityGun" type="CanvasLayer"] follow_viewport_enabled = true +script = ExtResource("1_0upyy") [node name="SubViewportContainer" type="SubViewportContainer" parent="."] -anchors_preset = 12 -anchor_top = 1.0 +anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 -offset_top = -324.0 grow_horizontal = 2 -grow_vertical = 0 -stretch_shrink = 2 -metadata/_edit_use_anchors_ = true +grow_vertical = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +stretch = true [node name="SubViewport" type="SubViewport" parent="SubViewportContainer"] -world_3d = SubResource("World3D_6qira") +own_world_3d = true +world_3d = SubResource("World3D_wp4pn") transparent_bg = true handle_input_locally = false -gui_embed_subwindows = true +scaling_3d_scale = 2.0 +sdf_scale = 0 size = Vector2i(1152, 648) size_2d_override_stretch = true render_target_update_mode = 4 +script = SubResource("GDScript_sr7lp") [node name="Node3D" type="Node3D" parent="SubViewportContainer/SubViewport"] @@ -119,3 +155,14 @@ draw_pass_1 = SubResource("QuadMesh_wtlns") [node name="GPUParticlesCollisionBox3D" type="GPUParticlesCollisionBox3D" parent="SubViewportContainer/SubViewport/Node3D/Camera3D/MeshInstance3D"] transform = Transform3D(0.999923, -0.012392, 0.000616441, 0.0123854, 0.999875, 0.00980631, -0.000737865, -0.00979792, 0.999952, 0.358337, 0.108517, -0.0012207) size = Vector3(1.17664, 0.301201, 0.299805) + +[node name="GravityParticles" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/Node3D/Camera3D/MeshInstance3D"] +transform = Transform3D(1, -2.79397e-08, 8.70349e-09, 1.9744e-07, 1, 5.83791e-08, -7.93013e-09, -5.67382e-07, 1, 1, 0.1, 0) +visible = false +amount = 20 +lifetime = 0.1 +visibility_aabb = AABB(0.0726342, 0.335538, 0.399176, 0.593013, 0.887273, 1.34056) +trail_enabled = true +trail_lifetime = 0.8 +process_material = SubResource("ParticleProcessMaterial_5ccgj") +draw_pass_1 = SubResource("RibbonTrailMesh_fwaab") diff --git a/scenes/levels/debug.tscn b/scenes/levels/debug.tscn index 007be02..074e284 100644 --- a/scenes/levels/debug.tscn +++ b/scenes/levels/debug.tscn @@ -4,7 +4,7 @@ [ext_resource type="PackedScene" uid="uid://ddwkhfly2xyyt" path="res://models/interior.obj" id="1_lphcl"] [ext_resource type="PackedScene" uid="uid://b8bvidqu7tmfs" path="res://scenes/objects/interactables/task_terminal.tscn" id="3_30m3x"] [ext_resource type="PackedScene" uid="uid://dqy8bqf1chm8c" path="res://scenes/objects/interactables/button_stand.tscn" id="4_cruoa"] -[ext_resource type="PackedScene" uid="uid://6njtmij7sikl" path="res://scenes/completion_counter.tscn" id="5_lo1l3"] +[ext_resource type="PackedScene" uid="uid://22blfybi6n4q" path="res://scenes/completion_counter.tscn" id="5_lo1l3"] [ext_resource type="PackedScene" uid="uid://cy0x2nliyw8gw" path="res://scenes/door.tscn" id="6_853p2"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_780x3"] @@ -39,6 +39,7 @@ transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0.5, 0 [node name="ButtonStand" parent="." instance=ExtResource("4_cruoa")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.7, 0) +one_shot = true [node name="CompletionCounter" parent="." node_paths=PackedStringArray("nodes_needed") instance=ExtResource("5_lo1l3")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0617981, 3.05379, 6.24098) @@ -50,6 +51,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.1, 1.425, 6.64) [node name="ButtonStand2" parent="." instance=ExtResource("4_cruoa")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0.7, 4) +[connection signal="lock" from="CompletionCounter" to="Door" method="close"] [connection signal="unlock" from="CompletionCounter" to="Door" method="open"] [editable path="interior"] diff --git a/scenes/player.tscn b/scenes/player.tscn index cd30638..bc8dea2 100644 --- a/scenes/player.tscn +++ b/scenes/player.tscn @@ -39,5 +39,3 @@ mesh = SubResource("QuadMesh_dicpk") script = ExtResource("2_jg7te") [node name="GravityGun" parent="." instance=ExtResource("2_ahuce")] - -[editable path="GravityGun"] diff --git a/scripts/completion_counter.gd b/scripts/completion_counter.gd index 4a54da0..9b96553 100644 --- a/scripts/completion_counter.gd +++ b/scripts/completion_counter.gd @@ -1,19 +1,28 @@ extends Node signal unlock +signal lock @export var nodes_needed: Array[Completer] -var uncompleted: int + +var unlocked: bool func _ready(): - uncompleted = nodes_needed.size() for node in nodes_needed: - node.completed.connect(complete) + node.triggered.connect(complete) func complete(): - uncompleted -= 1 - if uncompleted == 0: - unlock.emit() + if areAllNodesUnlocked(): + if !unlocked: + unlock.emit() + unlocked = true + else: + if unlocked: + lock.emit() + unlocked = false -func uncomplete(): - pass #TODO +func areAllNodesUnlocked(): + for node in nodes_needed: + if !node.completed: + return false + return true diff --git a/scripts/gravity_gun.gd b/scripts/gravity_gun.gd new file mode 100644 index 0000000..10c19a3 --- /dev/null +++ b/scripts/gravity_gun.gd @@ -0,0 +1,6 @@ +extends CanvasLayer + +@onready var gravity_particles: GPUParticles3D = $SubViewportContainer/SubViewport/Node3D/Camera3D/MeshInstance3D/GravityParticles + +func _process(_delta: float) -> void: + gravity_particles.visible = Input.is_action_pressed("gravity_activate") diff --git a/scripts/interactables/completer/button_stand.gd b/scripts/interactables/completer/button_stand.gd index 94f27f4..e529396 100644 --- a/scripts/interactables/completer/button_stand.gd +++ b/scripts/interactables/completer/button_stand.gd @@ -4,4 +4,7 @@ extends Completer func _on_interaction_area_interacted(): animation_player.play("press") - super.toggle_complete() + toggle_complete() + if one_shot: + await animation_player.animation_finished + $Button.hide() diff --git a/scripts/interactables/completer/completer_base.gd b/scripts/interactables/completer/completer_base.gd index a708079..3a8168c 100644 --- a/scripts/interactables/completer/completer_base.gd +++ b/scripts/interactables/completer/completer_base.gd @@ -1,16 +1,16 @@ +@tool extends Node class_name Completer @export var one_shot: bool -signal completed -signal uncompleted +signal triggered -var toggle: bool = true +var completed: bool func toggle_complete(): - toggle = !toggle - if one_shot || toggle: - completed.emit() + if one_shot: + completed = true else: - uncompleted.emit() + completed = !completed + triggered.emit()