mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 08:55:35 +00:00
3D Cameras with sweep and animation
This commit is contained in:
parent
4cc7a0c004
commit
7e76edc153
48 changed files with 3211 additions and 1511 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
BIN
3D/MapModels/actor_securitycamera.glb
Normal file
BIN
3D/MapModels/actor_securitycamera.glb
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
1137
3D/Maps/Level1.map
1137
3D/Maps/Level1.map
File diff suppressed because it is too large
Load diff
|
|
@ -1,8 +1,9 @@
|
|||
[gd_scene load_steps=8 format=3 uid="uid://cpx5yjfg3a2hw"]
|
||||
[gd_scene load_steps=9 format=3 uid="uid://cpx5yjfg3a2hw"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dxhf1twoxf4j0" path="res://Scripts/Interactables/AlarmBox3D.cs" id="1_4ysgp"]
|
||||
[ext_resource type="AudioStream" uid="uid://bjvklk7qmlivd" path="res://SFX/288963__littlerobotsoundfactory__click_electronic_14.wav" id="3_5t8l3"]
|
||||
[ext_resource type="PackedScene" uid="uid://s4yb3i3td11j" path="res://3D/BlockbenchModels/AlarmBox/Alarm_Box.gltf" id="4_4ysgp"]
|
||||
[ext_resource type="Script" uid="uid://0g2sdu48c2x8" path="res://Scripts/Actors/3D/AlarmSoundPlayer3D.cs" id="4_t4kxh"]
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_itd0i"]
|
||||
radius = 0.419927
|
||||
|
|
@ -55,7 +56,7 @@ metadata/_edit_group_ = true
|
|||
shape = SubResource("SphereShape3D_itd0i")
|
||||
|
||||
[node name="ActivationSound" type="AudioStreamPlayer3D" parent="."]
|
||||
visible = false
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.197789)
|
||||
stream = ExtResource("3_5t8l3")
|
||||
bus = &"Effects"
|
||||
|
||||
|
|
@ -66,4 +67,13 @@ libraries = {
|
|||
&"": SubResource("AnimationLibrary_t4kxh")
|
||||
}
|
||||
|
||||
[node name="AlarmSound" type="AudioStreamPlayer3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.198581)
|
||||
volume_db = -5.551
|
||||
max_distance = 25.08
|
||||
bus = &"Effects"
|
||||
script = ExtResource("4_t4kxh")
|
||||
|
||||
[connection signal="PlayActivationSound" from="." to="ActivationSound" method="play"]
|
||||
|
||||
[editable path="blockbench_export"]
|
||||
|
|
|
|||
|
|
@ -1,20 +1,48 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://b0rhxqjs52fsv"]
|
||||
[gd_scene load_steps=6 format=3 uid="uid://b0rhxqjs52fsv"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://ccxnvbthsvka3" path="res://Scripts/Actors/Destructible3D.cs" id="1_ix4p0"]
|
||||
[ext_resource type="Script" uid="uid://dg3aho2ulfngs" path="res://Scripts/Actors/3D/SecurityCamera3D.cs" id="1_tkk1t"]
|
||||
[ext_resource type="Resource" uid="uid://bes254wblt1lm" path="res://Resources/Bullets/Explosion_Harmless_Small_3D.tres" id="2_1t1m8"]
|
||||
[ext_resource type="PackedScene" uid="uid://bt5weyaiyhtrl" path="res://3D/BlockbenchModels/Camera/Camera.gltf" id="2_ix4p0"]
|
||||
[ext_resource type="Script" uid="uid://cmgcelj1qxg8o" path="res://addons/tattomoosa.vision_cone_3d/src/VisionCone3D.gd" id="4_f1teg"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_hsg1w"]
|
||||
size = Vector3(0.763428, 0.469452, 0.77832)
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_f1teg"]
|
||||
|
||||
[node name="Camera" type="StaticBody3D" groups=["Destroyable"]]
|
||||
collision_layer = 16
|
||||
collision_layer = 64
|
||||
collision_mask = 0
|
||||
script = ExtResource("1_ix4p0")
|
||||
script = ExtResource("1_tkk1t")
|
||||
Health = 6.0
|
||||
ExplosionData = ExtResource("2_1t1m8")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00549316, 0.0253752, -0.000488281)
|
||||
shape = SubResource("BoxShape3D_hsg1w")
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00549316, -0.419623, -0.000488281)
|
||||
shape = SubResource("CylinderShape3D_f1teg")
|
||||
|
||||
[node name="blockbench_export" parent="." instance=ExtResource("2_ix4p0")]
|
||||
|
||||
[node name="Camera" parent="blockbench_export/Node/Model" index="0"]
|
||||
transform = Transform3D(0.819152, 0.148453, -0.554032, 0, 0.965926, 0.258819, 0.573576, -0.212012, 0.79124, 0, 0.25, -0.0625)
|
||||
|
||||
[node name="RemoteTransform3D" type="RemoteTransform3D" parent="blockbench_export/Node/Model/Camera" index="2"]
|
||||
transform = Transform3D(1, -1.86265e-09, 0, 1.86265e-09, 1, 1.49012e-08, 0, -4.47035e-08, 1, -0.0399265, 0.00923264, -0.611748)
|
||||
remote_path = NodePath("../../../../../VisionCone3D")
|
||||
update_scale = false
|
||||
|
||||
[node name="VisionCone3D" type="Area3D" parent="."]
|
||||
transform = Transform3D(0.819145, 0.148452, -0.554027, 1.79916e-09, 0.965925, 0.258817, 0.573572, -0.212012, 0.791233, 0.307593, 0.100586, -0.571398)
|
||||
collision_layer = 32
|
||||
collision_mask = 2
|
||||
script = ExtResource("4_f1teg")
|
||||
range = 5.62515
|
||||
angle = 63.7926
|
||||
debug_draw = true
|
||||
vision_test_mode = 0
|
||||
collision_layer_ = 32
|
||||
collision_mask_ = 2
|
||||
collision_environment_mask = 17
|
||||
metadata/_custom_type_script = "uid://cmgcelj1qxg8o"
|
||||
|
||||
[connection signal="AnimationStart" from="." to="blockbench_export/AnimationPlayer" method="play"]
|
||||
[connection signal="body_sighted" from="VisionCone3D" to="." method="OnBodySighted"]
|
||||
|
||||
[editable path="blockbench_export"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
[gd_resource type="Resource" script_class="FuncGodotFGDModelPointClass" load_steps=4 format=3 uid="uid://m0xahs14etiy"]
|
||||
|
||||
[ext_resource type="Resource" uid="uid://5bc1qysixhmh" path="res://3D/TrenchBroom/EntityDefinitions/base/actor_base.tres" id="1_yxg7b"]
|
||||
[ext_resource type="PackedScene" uid="uid://b0rhxqjs52fsv" path="res://3D/Scenes/Props/Camera_3D.tscn" id="2_yxg7b"]
|
||||
[ext_resource type="Script" uid="uid://dkmyelig23ub5" path="res://addons/func_godot/src/fgd/func_godot_fgd_model_point_class.gd" id="3_mqd4f"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("3_mqd4f")
|
||||
target_map_editor = 1
|
||||
models_sub_folder = ""
|
||||
scale_expression = ""
|
||||
generate_size_property = false
|
||||
rotation_offset = Vector3(0, 180, 0)
|
||||
generate_gd_ignore_file = false
|
||||
scene_file = ExtResource("2_yxg7b")
|
||||
apply_rotation_on_map_build = true
|
||||
apply_scale_on_map_build = false
|
||||
classname = "actor_securitycamera"
|
||||
description = "Security Camera"
|
||||
func_godot_internal = false
|
||||
base_classes = Array[Resource]([ExtResource("1_yxg7b")])
|
||||
class_properties = {}
|
||||
class_property_descriptions = {}
|
||||
auto_apply_to_matching_node_properties = false
|
||||
meta_properties = {
|
||||
"model": "\"3D/MapModels/actor_securitycamera.glb\"",
|
||||
"size": AABB(-4, -4, -4, 4, 4, 4)
|
||||
}
|
||||
node_class = ""
|
||||
name_property = ""
|
||||
metadata/_custom_type_script = "uid://c83r7t467hm4m"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
[gd_resource type="Resource" script_class="FuncGodotFGDFile" load_steps=36 format=3 uid="uid://b700sa4be6dfa"]
|
||||
[gd_resource type="Resource" script_class="FuncGodotFGDFile" load_steps=37 format=3 uid="uid://b700sa4be6dfa"]
|
||||
|
||||
[ext_resource type="Resource" uid="uid://ia1t5p4mhom3" path="res://3D/TrenchBroom/EntityDefinitions/point/lights/light_omni.tres" id="1_7vcj1"]
|
||||
[ext_resource type="Script" uid="uid://cknmd0lgmorx2" path="res://addons/func_godot/src/fgd/func_godot_fgd_file.gd" id="1_lykim"]
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
[ext_resource type="Resource" uid="uid://bjqfsr0ws3kbi" path="res://3D/TrenchBroom/EntityDefinitions/point/actors/Actor_Teleporter.tres" id="32_elv2e"]
|
||||
[ext_resource type="Resource" uid="uid://yw4443572o6u" path="res://3D/TrenchBroom/EntityDefinitions/point/actors/Actor_Furniture_Triangle.tres" id="33_aawmv"]
|
||||
[ext_resource type="Resource" uid="uid://cr3xqfglolihb" path="res://3D/TrenchBroom/EntityDefinitions/point/actors/Actor_Furniture_ComputerTower.tres" id="34_wy0ht"]
|
||||
[ext_resource type="Resource" uid="uid://m0xahs14etiy" path="res://3D/TrenchBroom/EntityDefinitions/point/actors/Actor_SecurityCamera.tres" id="35_3jqmy"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_lykim")
|
||||
|
|
@ -42,5 +43,5 @@ export_file = false
|
|||
target_map_editor = 1
|
||||
fgd_name = "FuncGodot"
|
||||
base_fgd_files = Array[Resource]([])
|
||||
entity_definitions = Array[Resource]([ExtResource("1_7vcj1"), ExtResource("2_u7uvb"), ExtResource("3_u7uvb"), ExtResource("4_1nmxk"), ExtResource("5_ljb2x"), ExtResource("6_seuvu"), ExtResource("7_fmwex"), ExtResource("8_c8m8m"), ExtResource("9_14sjf"), ExtResource("10_xik3w"), ExtResource("11_dgiqm"), ExtResource("12_1teik"), ExtResource("13_f0hti"), ExtResource("14_6ld6e"), ExtResource("15_g8j5j"), ExtResource("16_7h4of"), ExtResource("17_m3sbm"), ExtResource("18_m3sbm"), ExtResource("19_hvhb8"), ExtResource("20_3v5us"), ExtResource("21_g67cj"), ExtResource("22_iy67w"), ExtResource("23_b5lmu"), ExtResource("24_ndas4"), ExtResource("25_n7wsi"), ExtResource("26_v48k5"), ExtResource("27_ombvk"), ExtResource("28_31lma"), ExtResource("29_louv0"), ExtResource("30_wfgfu"), ExtResource("31_elv2e"), ExtResource("32_elv2e"), ExtResource("33_aawmv"), ExtResource("34_wy0ht")])
|
||||
entity_definitions = Array[Resource]([ExtResource("1_7vcj1"), ExtResource("2_u7uvb"), ExtResource("3_u7uvb"), ExtResource("4_1nmxk"), ExtResource("5_ljb2x"), ExtResource("6_seuvu"), ExtResource("7_fmwex"), ExtResource("8_c8m8m"), ExtResource("9_14sjf"), ExtResource("10_xik3w"), ExtResource("11_dgiqm"), ExtResource("12_1teik"), ExtResource("13_f0hti"), ExtResource("14_6ld6e"), ExtResource("15_g8j5j"), ExtResource("16_7h4of"), ExtResource("17_m3sbm"), ExtResource("18_m3sbm"), ExtResource("19_hvhb8"), ExtResource("20_3v5us"), ExtResource("21_g67cj"), ExtResource("22_iy67w"), ExtResource("23_b5lmu"), ExtResource("24_ndas4"), ExtResource("25_n7wsi"), ExtResource("26_v48k5"), ExtResource("27_ombvk"), ExtResource("28_31lma"), ExtResource("29_louv0"), ExtResource("30_wfgfu"), ExtResource("31_elv2e"), ExtResource("32_elv2e"), ExtResource("33_aawmv"), ExtResource("34_wy0ht"), ExtResource("35_3jqmy")])
|
||||
metadata/_custom_type_script = "uid://cknmd0lgmorx2"
|
||||
|
|
|
|||
|
|
@ -1,19 +1,12 @@
|
|||
[gd_scene load_steps=60 format=3 uid="uid://ec4m3geediis"]
|
||||
[gd_scene load_steps=14 format=3 uid="uid://ec4m3geediis"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cvisn0b641od4" path="res://addons/cyclops_level_builder/nodes/cyclops_block.gd" id="1_18fbr"]
|
||||
[ext_resource type="Script" uid="uid://ba0tf7ihw4hpp" path="res://Scripts/Misc/CameraController3D.cs" id="1_g4gcm"]
|
||||
[ext_resource type="Script" uid="uid://b8g8mflgsr5dc" path="res://Scripts/GameController.cs" id="1_joeuf"]
|
||||
[ext_resource type="PackedScene" uid="uid://dkwi1hu1bixoe" path="res://Scenes/HUD/HUD.tscn" id="2_itd0i"]
|
||||
[ext_resource type="Script" uid="uid://djeq3sxhsep3c" path="res://addons/cyclops_level_builder/resources/data_vector_byte.gd" id="2_kler0"]
|
||||
[ext_resource type="Resource" uid="uid://bq2o78engsuyt" path="res://Resources/Maps/IsoMapTest2.tres" id="2_l7bgk"]
|
||||
[ext_resource type="Script" uid="uid://c5nxsq3tyxcx6" path="res://Scripts/InventoryManager.cs" id="3_itd0i"]
|
||||
[ext_resource type="Script" uid="uid://civ3w78ahacnu" path="res://addons/cyclops_level_builder/resources/data_vector_int.gd" id="3_k6bah"]
|
||||
[ext_resource type="Script" uid="uid://db41w3h28c2la" path="res://addons/cyclops_level_builder/resources/data_vector_float.gd" id="4_01bfr"]
|
||||
[ext_resource type="Script" uid="uid://c43o57os2lmc3" path="res://addons/cyclops_level_builder/resources/mesh_vector_data.gd" id="5_hmj6t"]
|
||||
[ext_resource type="Material" uid="uid://dc88uealq5q85" path="res://textures/Walls/Wall0.tres" id="6_k6bah"]
|
||||
[ext_resource type="Material" uid="uid://y1ovvv727tky" path="res://textures/Floors/Floor0.tres" id="7_01bfr"]
|
||||
[ext_resource type="PackedScene" uid="uid://bh0ye0m85cyb1" path="res://3D/box.tscn" id="9_hmj6t"]
|
||||
[ext_resource type="PackedScene" uid="uid://b5qj2iaprortr" path="res://3D/Mainframe3D.tscn" id="10_lkbo1"]
|
||||
[ext_resource type="Script" uid="uid://cnkipcolyj61w" path="res://Scripts/AlarmManager.cs" id="6_w4wji"]
|
||||
[ext_resource type="AudioStream" uid="uid://blohh20jktoyo" path="res://SFX/270641__phantastonia__alarm2.wav" id="7_5vm3d"]
|
||||
[ext_resource type="Texture2D" uid="uid://du8xcvbnf30o2" path="res://ExternalMaterial/Barrel/Barrels.png" id="11_id3mo"]
|
||||
[ext_resource type="PackedScene" uid="uid://rimplblbptcd" path="res://Scenes/Actors/IsoPlayer_FSM.tscn" id="12_g4gcm"]
|
||||
[ext_resource type="PackedScene" uid="uid://c8gtrjf2xeue7" path="res://3D/MapScenes/TestLevel.tscn" id="12_g83w3"]
|
||||
|
|
@ -21,399 +14,6 @@
|
|||
[ext_resource type="PackedScene" uid="uid://cupulrjeeivxm" path="res://3D/MapScenes/TestLevel2.tscn" id="18_e2nai"]
|
||||
[ext_resource type="PackedScene" uid="uid://diveeuoyyp7n" path="res://3D/MapScenes/RebelBase3D.tscn" id="20_1dvih"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_id3mo"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
name = &"selected"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_mgr2t"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
|
||||
name = &"color"
|
||||
category = ""
|
||||
data_type = 4
|
||||
stride = 4
|
||||
|
||||
[sub_resource type="Resource" id="Resource_g83w3"]
|
||||
script = ExtResource("3_k6bah")
|
||||
data = PackedInt32Array(0, 0, 0, 0, 0, 0)
|
||||
name = &"material_index"
|
||||
category = ""
|
||||
data_type = 1
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_joeuf"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(1, 1, 1, 1, 1, 1)
|
||||
name = &"selected"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_lhprj"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0)
|
||||
name = &"uv_transform"
|
||||
category = ""
|
||||
data_type = 8
|
||||
stride = 6
|
||||
|
||||
[sub_resource type="Resource" id="Resource_g4gcm"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(1, 1, 1, 1, 1, 1)
|
||||
name = &"visible"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_l7bgk"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
|
||||
name = &"color"
|
||||
category = ""
|
||||
data_type = 4
|
||||
stride = 4
|
||||
|
||||
[sub_resource type="Resource" id="Resource_itd0i"]
|
||||
script = ExtResource("3_k6bah")
|
||||
data = PackedInt32Array(0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5)
|
||||
name = &"face_index"
|
||||
category = ""
|
||||
data_type = 1
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_1dvih"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1)
|
||||
name = &"normal"
|
||||
category = ""
|
||||
data_type = 6
|
||||
stride = 3
|
||||
|
||||
[sub_resource type="Resource" id="Resource_e2nai"]
|
||||
script = ExtResource("3_k6bah")
|
||||
data = PackedInt32Array(0, 1, 2, 3, 7, 6, 5, 4, 1, 0, 4, 5, 2, 1, 5, 6, 3, 2, 6, 7, 0, 3, 7, 4)
|
||||
name = &"vertex_index"
|
||||
category = ""
|
||||
data_type = 1
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_ogy4l"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(0, 3, -3, 0, 3, 4, 0, 0, 4, 0, 0, -3, 1, 3, -3, 1, 3, 4, 1, 0, 4, 1, 0, -3)
|
||||
name = &"position"
|
||||
category = ""
|
||||
data_type = 6
|
||||
stride = 3
|
||||
|
||||
[sub_resource type="Resource" id="Resource_uusmx"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
name = &"selected"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_xevt1"]
|
||||
script = ExtResource("5_hmj6t")
|
||||
num_vertices = 8
|
||||
num_edges = 12
|
||||
num_faces = 6
|
||||
num_face_vertices = 24
|
||||
active_vertex = -1
|
||||
active_edge = -1
|
||||
active_face = 0
|
||||
active_face_vertex = -1
|
||||
edge_vertex_indices = PackedInt32Array(0, 1, 1, 2, 2, 3, 3, 0, 7, 6, 6, 5, 5, 4, 4, 7, 0, 4, 5, 1, 6, 2, 7, 3)
|
||||
edge_face_indices = PackedInt32Array(0, 2, 0, 3, 0, 4, 0, 5, 1, 4, 1, 3, 1, 2, 1, 5, 2, 5, 2, 3, 3, 4, 4, 5)
|
||||
face_vertex_count = PackedInt32Array(4, 4, 4, 4, 4, 4)
|
||||
face_vertex_indices = PackedInt32Array(0, 1, 2, 3, 7, 6, 5, 4, 1, 0, 4, 5, 2, 1, 5, 6, 3, 2, 6, 7, 0, 3, 7, 4)
|
||||
vertex_data = {
|
||||
&"position": SubResource("Resource_ogy4l"),
|
||||
&"selected": SubResource("Resource_uusmx")
|
||||
}
|
||||
edge_data = {
|
||||
&"selected": SubResource("Resource_id3mo")
|
||||
}
|
||||
face_data = {
|
||||
&"color": SubResource("Resource_mgr2t"),
|
||||
&"material_index": SubResource("Resource_g83w3"),
|
||||
&"selected": SubResource("Resource_joeuf"),
|
||||
&"uv_transform": SubResource("Resource_lhprj"),
|
||||
&"visible": SubResource("Resource_g4gcm")
|
||||
}
|
||||
face_vertex_data = {
|
||||
&"color": SubResource("Resource_l7bgk"),
|
||||
&"face_index": SubResource("Resource_itd0i"),
|
||||
&"normal": SubResource("Resource_1dvih"),
|
||||
&"vertex_index": SubResource("Resource_e2nai")
|
||||
}
|
||||
|
||||
[sub_resource type="Resource" id="Resource_ye808"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
name = &"selected"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_8okcc"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
|
||||
name = &"color"
|
||||
category = ""
|
||||
data_type = 4
|
||||
stride = 4
|
||||
|
||||
[sub_resource type="Resource" id="Resource_w4wji"]
|
||||
script = ExtResource("3_k6bah")
|
||||
data = PackedInt32Array(0, 0, 0, 0, 0, 0)
|
||||
name = &"material_index"
|
||||
category = ""
|
||||
data_type = 1
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_ed6ow"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(0, 0, 0, 0, 0, 0)
|
||||
name = &"selected"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_eoyv0"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0)
|
||||
name = &"uv_transform"
|
||||
category = ""
|
||||
data_type = 8
|
||||
stride = 6
|
||||
|
||||
[sub_resource type="Resource" id="Resource_5vm3d"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(1, 1, 1, 1, 1, 1)
|
||||
name = &"visible"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_x1so1"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
|
||||
name = &"color"
|
||||
category = ""
|
||||
data_type = 4
|
||||
stride = 4
|
||||
|
||||
[sub_resource type="Resource" id="Resource_jj2wv"]
|
||||
script = ExtResource("3_k6bah")
|
||||
data = PackedInt32Array(0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5)
|
||||
name = &"face_index"
|
||||
category = ""
|
||||
data_type = 1
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_kdjrl"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1)
|
||||
name = &"normal"
|
||||
category = ""
|
||||
data_type = 6
|
||||
stride = 3
|
||||
|
||||
[sub_resource type="Resource" id="Resource_nxryr"]
|
||||
script = ExtResource("3_k6bah")
|
||||
data = PackedInt32Array(0, 1, 2, 3, 7, 6, 5, 4, 1, 0, 4, 5, 2, 1, 5, 6, 3, 2, 6, 7, 0, 3, 7, 4)
|
||||
name = &"vertex_index"
|
||||
category = ""
|
||||
data_type = 1
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_bsjmx"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(0, 1, 0, 0, 1, 7, 0, 0, 7, 0, 0, 0, 8, 1, 0, 8, 1, 7, 8, 0, 7, 8, 0, 0)
|
||||
name = &"position"
|
||||
category = ""
|
||||
data_type = 6
|
||||
stride = 3
|
||||
|
||||
[sub_resource type="Resource" id="Resource_0dw8u"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
name = &"selected"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_5p6ad"]
|
||||
script = ExtResource("5_hmj6t")
|
||||
num_vertices = 8
|
||||
num_edges = 12
|
||||
num_faces = 6
|
||||
num_face_vertices = 24
|
||||
active_vertex = -1
|
||||
active_edge = -1
|
||||
active_face = -1
|
||||
active_face_vertex = -1
|
||||
edge_vertex_indices = PackedInt32Array(0, 1, 1, 2, 2, 3, 3, 0, 7, 6, 6, 5, 5, 4, 4, 7, 0, 4, 5, 1, 6, 2, 7, 3)
|
||||
edge_face_indices = PackedInt32Array(0, 2, 0, 3, 0, 4, 0, 5, 1, 4, 1, 3, 1, 2, 1, 5, 2, 5, 2, 3, 3, 4, 4, 5)
|
||||
face_vertex_count = PackedInt32Array(4, 4, 4, 4, 4, 4)
|
||||
face_vertex_indices = PackedInt32Array(0, 1, 2, 3, 7, 6, 5, 4, 1, 0, 4, 5, 2, 1, 5, 6, 3, 2, 6, 7, 0, 3, 7, 4)
|
||||
vertex_data = {
|
||||
&"position": SubResource("Resource_bsjmx"),
|
||||
&"selected": SubResource("Resource_0dw8u")
|
||||
}
|
||||
edge_data = {
|
||||
&"selected": SubResource("Resource_ye808")
|
||||
}
|
||||
face_data = {
|
||||
&"color": SubResource("Resource_8okcc"),
|
||||
&"material_index": SubResource("Resource_w4wji"),
|
||||
&"selected": SubResource("Resource_ed6ow"),
|
||||
&"uv_transform": SubResource("Resource_eoyv0"),
|
||||
&"visible": SubResource("Resource_5vm3d")
|
||||
}
|
||||
face_vertex_data = {
|
||||
&"color": SubResource("Resource_x1so1"),
|
||||
&"face_index": SubResource("Resource_jj2wv"),
|
||||
&"normal": SubResource("Resource_kdjrl"),
|
||||
&"vertex_index": SubResource("Resource_nxryr")
|
||||
}
|
||||
|
||||
[sub_resource type="Resource" id="Resource_37r6a"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
name = &"selected"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_064cf"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
|
||||
name = &"color"
|
||||
category = ""
|
||||
data_type = 4
|
||||
stride = 4
|
||||
|
||||
[sub_resource type="Resource" id="Resource_4r06m"]
|
||||
script = ExtResource("3_k6bah")
|
||||
data = PackedInt32Array(0, 0, 0, 0, 0, 0)
|
||||
name = &"material_index"
|
||||
category = ""
|
||||
data_type = 1
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_lxss8"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(0, 0, 0, 0, 0, 0)
|
||||
name = &"selected"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_f0u18"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0)
|
||||
name = &"uv_transform"
|
||||
category = ""
|
||||
data_type = 8
|
||||
stride = 6
|
||||
|
||||
[sub_resource type="Resource" id="Resource_8r0yo"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(1, 1, 1, 1, 1, 1)
|
||||
name = &"visible"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_2b1tp"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
|
||||
name = &"color"
|
||||
category = ""
|
||||
data_type = 4
|
||||
stride = 4
|
||||
|
||||
[sub_resource type="Resource" id="Resource_43spg"]
|
||||
script = ExtResource("3_k6bah")
|
||||
data = PackedInt32Array(0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5)
|
||||
name = &"face_index"
|
||||
category = ""
|
||||
data_type = 1
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_yc3ep"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1)
|
||||
name = &"normal"
|
||||
category = ""
|
||||
data_type = 6
|
||||
stride = 3
|
||||
|
||||
[sub_resource type="Resource" id="Resource_7onea"]
|
||||
script = ExtResource("3_k6bah")
|
||||
data = PackedInt32Array(0, 1, 2, 3, 7, 6, 5, 4, 1, 0, 4, 5, 2, 1, 5, 6, 3, 2, 6, 7, 0, 3, 7, 4)
|
||||
name = &"vertex_index"
|
||||
category = ""
|
||||
data_type = 1
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_631xa"]
|
||||
script = ExtResource("4_01bfr")
|
||||
data = PackedFloat32Array(-3, 3, 0, -3, 3, 1, -3, 0, 1, -3, 0, 0, 6, 3, 0, 6, 3, 1, 6, 0, 1, 6, 0, 0)
|
||||
name = &"position"
|
||||
category = ""
|
||||
data_type = 6
|
||||
stride = 3
|
||||
|
||||
[sub_resource type="Resource" id="Resource_fqk4s"]
|
||||
script = ExtResource("2_kler0")
|
||||
data = PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
name = &"selected"
|
||||
category = ""
|
||||
data_type = 0
|
||||
stride = 1
|
||||
|
||||
[sub_resource type="Resource" id="Resource_xk7ib"]
|
||||
script = ExtResource("5_hmj6t")
|
||||
num_vertices = 8
|
||||
num_edges = 12
|
||||
num_faces = 6
|
||||
num_face_vertices = 24
|
||||
active_vertex = -1
|
||||
active_edge = -1
|
||||
active_face = -1
|
||||
active_face_vertex = -1
|
||||
edge_vertex_indices = PackedInt32Array(0, 1, 1, 2, 2, 3, 3, 0, 7, 6, 6, 5, 5, 4, 4, 7, 0, 4, 5, 1, 6, 2, 7, 3)
|
||||
edge_face_indices = PackedInt32Array(0, 2, 0, 3, 0, 4, 0, 5, 1, 4, 1, 3, 1, 2, 1, 5, 2, 5, 2, 3, 3, 4, 4, 5)
|
||||
face_vertex_count = PackedInt32Array(4, 4, 4, 4, 4, 4)
|
||||
face_vertex_indices = PackedInt32Array(0, 1, 2, 3, 7, 6, 5, 4, 1, 0, 4, 5, 2, 1, 5, 6, 3, 2, 6, 7, 0, 3, 7, 4)
|
||||
vertex_data = {
|
||||
&"position": SubResource("Resource_631xa"),
|
||||
&"selected": SubResource("Resource_fqk4s")
|
||||
}
|
||||
edge_data = {
|
||||
&"selected": SubResource("Resource_37r6a")
|
||||
}
|
||||
face_data = {
|
||||
&"color": SubResource("Resource_064cf"),
|
||||
&"material_index": SubResource("Resource_4r06m"),
|
||||
&"selected": SubResource("Resource_lxss8"),
|
||||
&"uv_transform": SubResource("Resource_f0u18"),
|
||||
&"visible": SubResource("Resource_8r0yo")
|
||||
}
|
||||
face_vertex_data = {
|
||||
&"color": SubResource("Resource_2b1tp"),
|
||||
&"face_index": SubResource("Resource_43spg"),
|
||||
&"normal": SubResource("Resource_yc3ep"),
|
||||
&"vertex_index": SubResource("Resource_7onea")
|
||||
}
|
||||
|
||||
[node name="IsoMapTest2" type="Node3D"]
|
||||
|
||||
[node name="GameController" type="Node" parent="." node_paths=PackedStringArray("_cameraTarget", "PlayerParentNode")]
|
||||
|
|
@ -431,17 +31,9 @@ PlayerParentNode = NodePath("..")
|
|||
[node name="InventoryManager" type="Node" parent="GameController"]
|
||||
script = ExtResource("3_itd0i")
|
||||
|
||||
[node name="block0" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0)
|
||||
script = ExtResource("1_18fbr")
|
||||
mesh_vector_data = SubResource("Resource_xevt1")
|
||||
materials = Array[Material]([ExtResource("6_k6bah")])
|
||||
|
||||
[node name="Block_0" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0, -3)
|
||||
script = ExtResource("1_18fbr")
|
||||
mesh_vector_data = SubResource("Resource_5p6ad")
|
||||
materials = Array[Material]([ExtResource("7_01bfr")])
|
||||
[node name="AlarmManager" type="Node" parent="GameController"]
|
||||
script = ExtResource("6_w4wji")
|
||||
AlarmSound = ExtResource("7_5vm3d")
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(0.442606, -0.744379, 0.5, 0.287606, 0.645974, 0.707107, -0.849343, -0.169166, 0.5, 30.2584, 5.82742, 20.7297)
|
||||
|
|
@ -456,24 +48,12 @@ light_energy = 0.75
|
|||
light_bake_mode = 1
|
||||
shadow_enabled = true
|
||||
|
||||
[node name="block1" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -4)
|
||||
script = ExtResource("1_18fbr")
|
||||
mesh_vector_data = SubResource("Resource_xk7ib")
|
||||
materials = Array[Material]([ExtResource("6_k6bah")])
|
||||
|
||||
[node name="Box" parent="." instance=ExtResource("9_hmj6t")]
|
||||
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, -0.762422, 1.5, -1.73161)
|
||||
|
||||
[node name="OmniLight3D" type="OmniLight3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.24217, 2.81518, 1.21091)
|
||||
light_energy = 1.796
|
||||
omni_range = 6.367
|
||||
omni_attenuation = 0.86
|
||||
|
||||
[node name="Mainframe3d" parent="." instance=ExtResource("10_lkbo1")]
|
||||
transform = Transform3D(0.25, 0, 0, 0, 0.25, 0, 0, 0, 0.25, -1.33755, 1.30461, 0.470264)
|
||||
|
||||
[node name="Barrel" type="Sprite3D" parent="."]
|
||||
transform = Transform3D(0.707107, -0.5, 0.5, 0, 0.707107, 0.707107, -0.707107, -0.5, 0.5, 1.8865, 1.30887, -1.63081)
|
||||
pixel_size = 0.05
|
||||
|
|
@ -485,7 +65,7 @@ hframes = 4
|
|||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.84862, 0, -4.8932)
|
||||
|
||||
[node name="StartPosition" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 21.2092, 1.57535, 4.23742)
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 20.9212, 1.57535, 4.20806)
|
||||
|
||||
[node name="CameraTarget" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 21.0389, 2.33215, 3.16925)
|
||||
|
|
|
|||
27
Scripts/Actors/3D/AlarmSoundPlayer3D.cs
Normal file
27
Scripts/Actors/3D/AlarmSoundPlayer3D.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Actors._3D;
|
||||
|
||||
public partial class AlarmSoundPlayer3D : AudioStreamPlayer3D
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
if (AlarmManager.Instance is not null)
|
||||
{
|
||||
this.Stream = AlarmManager.Instance.AlarmSound;
|
||||
|
||||
AlarmManager.Instance.AlarmEnabled3D += InstanceOnAlarmEnabled3D;
|
||||
AlarmManager.Instance.AlarmDisabled += InstanceOnAlarmDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
private void InstanceOnAlarmDisabled()
|
||||
{
|
||||
this.Stop();
|
||||
}
|
||||
|
||||
private void InstanceOnAlarmEnabled3D(Vector3 location)
|
||||
{
|
||||
this.Play();
|
||||
}
|
||||
}
|
||||
1
Scripts/Actors/3D/AlarmSoundPlayer3D.cs.uid
Normal file
1
Scripts/Actors/3D/AlarmSoundPlayer3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://0g2sdu48c2x8
|
||||
24
Scripts/Actors/3D/SecurityCamera3D.cs
Normal file
24
Scripts/Actors/3D/SecurityCamera3D.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Actors._3D;
|
||||
|
||||
public partial class SecurityCamera3D : Destructible3D
|
||||
{
|
||||
[Export] public StringName SweepAnimation { get; private set; } = "SweepLoop";
|
||||
|
||||
[Signal]
|
||||
public delegate void AnimationStartEventHandler(string animationName);
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
if (Engine.IsEditorHint()) return;
|
||||
EmitSignalAnimationStart(SweepAnimation);
|
||||
}
|
||||
|
||||
public void OnBodySighted(Node3D body)
|
||||
{
|
||||
if (Engine.IsEditorHint()) return;
|
||||
GD.Print($"{body.Name} Sighted!");
|
||||
AlarmManager.Instance?.SoundAlarm(this.GlobalPosition);
|
||||
}
|
||||
}
|
||||
1
Scripts/Actors/3D/SecurityCamera3D.cs.uid
Normal file
1
Scripts/Actors/3D/SecurityCamera3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dg3aho2ulfngs
|
||||
|
|
@ -74,42 +74,6 @@ public partial class Destructible3D : StaticBody3D, IDestructible
|
|||
explosion.Initialize(ExplosionData.MakeBullet(new Vector2(this.GlobalPosition.X, this.GlobalPosition.Y)));
|
||||
}
|
||||
|
||||
// private void ApplyExplosionDamage()
|
||||
// {
|
||||
// var spaceState = GetWorld2D().DirectSpaceState;
|
||||
// var query = new PhysicsShapeQueryParameters2D();
|
||||
// var shape = new CircleShape2D { Radius = ExplosionRadius };
|
||||
//
|
||||
// query.SetShape(shape);
|
||||
// query.Transform = new Transform2D(0, GlobalPosition);
|
||||
// query.CollideWithBodies = false;
|
||||
// query.CollideWithAreas = true;
|
||||
// //query.CollisionMask = ;
|
||||
//
|
||||
// var results = spaceState.IntersectShape(query);
|
||||
//
|
||||
// GD.Print($"Shapes in range: {results.Count}");
|
||||
//
|
||||
// foreach (var result in results)
|
||||
// {
|
||||
// if (result.TryGetValue("collider", out var colliderObj))
|
||||
// {
|
||||
//
|
||||
// var collider = colliderObj.As<Node2D>();
|
||||
//
|
||||
//
|
||||
// if (collider.GetParent<Area2D>() is IDestructible destructible)
|
||||
// {
|
||||
// GD.Print($"HITTING {collider.Name}");
|
||||
// destructible.Hit(ExplosionDamage);
|
||||
// }
|
||||
// else {
|
||||
// GD.Print($"Collider {collider.Name} was not idestructible");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private void CreateDebris()
|
||||
{
|
||||
if (DebrisScene == null) return;
|
||||
|
|
|
|||
|
|
@ -23,20 +23,25 @@ public partial class AlarmManager : Node
|
|||
[Signal]
|
||||
public delegate void AlarmDisabledEventHandler();
|
||||
|
||||
private AudioStreamPlayer2D _player;
|
||||
//private AudioStreamPlayer _player;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
if (AlarmSound is not null)
|
||||
{
|
||||
var player = new AudioStreamPlayer2D();
|
||||
player.Stream = AlarmSound;
|
||||
this.CallDeferred("add_child", player);
|
||||
|
||||
_player = player;
|
||||
}
|
||||
// if (AlarmSound is not null)
|
||||
// {
|
||||
// var player = GetNodeOrNull<AudioStreamPlayer>("AlarmSoundPlayer");
|
||||
// if (player is not null)
|
||||
// {
|
||||
// player.Stream = AlarmSound;
|
||||
// _player = player;
|
||||
// }
|
||||
//
|
||||
// //this.CallDeferred("add_child", player);
|
||||
//
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
||||
public void SoundAlarm(Vector2 location)
|
||||
|
|
@ -47,7 +52,7 @@ public partial class AlarmManager : Node
|
|||
EmitSignalAlarmEnabled(location);
|
||||
|
||||
GD.Print($"Alarm sounded at {location}");
|
||||
_player?.Play();
|
||||
//_player?.Play();
|
||||
}
|
||||
|
||||
public void SoundAlarm(Vector3 location)
|
||||
|
|
@ -58,7 +63,7 @@ public partial class AlarmManager : Node
|
|||
EmitSignalAlarmEnabled3D(location);
|
||||
|
||||
GD.Print($"Alarm sounded at {location}");
|
||||
_player?.Play();
|
||||
//_player?.Play();
|
||||
}
|
||||
|
||||
public void SoundSilentAlarm(Vector2 location)
|
||||
|
|
@ -71,6 +76,6 @@ public partial class AlarmManager : Node
|
|||
{
|
||||
IsAlarmOn = false;
|
||||
EmitSignal(nameof(AlarmDisabled));
|
||||
_player?.Stop();
|
||||
//_player?.Stop();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,35 +5,53 @@ namespace Cirno.Scripts.Interactables;
|
|||
[Tool]
|
||||
public partial class AlarmBox3D : Interactable3D
|
||||
{
|
||||
private AudioStreamPlayer _activationSound;
|
||||
private readonly string _activationSoundName = "ActivationSound";
|
||||
private AnimationPlayer _animationPlayer;
|
||||
public StringName FlashAnimationName { get; private set; } = "Flash";
|
||||
|
||||
[Signal] public delegate void OnActivatedEventHandler(ActivationType activationType);
|
||||
|
||||
[Signal]
|
||||
public delegate void PlayActivationSoundEventHandler();
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
if (Engine.IsEditorHint()) return;
|
||||
|
||||
_activationSound = GetNodeOrNull<AudioStreamPlayer>(_activationSoundName);
|
||||
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
|
||||
//CallDeferred(MethodName.InitDeferred);
|
||||
InitDeferred();
|
||||
}
|
||||
|
||||
private void InitDeferred()
|
||||
{
|
||||
if (AlarmManager.Instance is not null)
|
||||
{
|
||||
AlarmManager.Instance.AlarmEnabled3D += OnAlarmEnabled3D;
|
||||
AlarmManager.Instance.AlarmDisabled += InstanceOnAlarmDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
private void InstanceOnAlarmDisabled()
|
||||
{
|
||||
_animationPlayer.Stop();
|
||||
}
|
||||
|
||||
private void OnAlarmEnabled3D(Vector3 location)
|
||||
{
|
||||
// TODO: set animation, make blinky
|
||||
GD.Print($"Enabled alarm in box {this.Name}");
|
||||
_animationPlayer.Play(FlashAnimationName);
|
||||
}
|
||||
|
||||
public override bool Activate(ActivationType activationType = ActivationType.Toggle)
|
||||
{
|
||||
EmitSignal(SignalName.OnActivated, (int)activationType);
|
||||
|
||||
EmitSignalPlayActivationSound();
|
||||
if (AlarmManager.Instance is not null)
|
||||
{
|
||||
_activationSound.Play();
|
||||
//_activationSound?.Play();
|
||||
|
||||
AlarmManager.Instance.DisableAlarm();
|
||||
}
|
||||
|
||||
|
|
|
|||
19
addons/tattomoosa.vision_cone_3d/LICENSE.txt
Normal file
19
addons/tattomoosa.vision_cone_3d/LICENSE.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2024 Matt O'Tousa
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
126
addons/tattomoosa.vision_cone_3d/README.md
Normal file
126
addons/tattomoosa.vision_cone_3d/README.md
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<div align="center">
|
||||
<br/>
|
||||
<br/>
|
||||
<img src="addons/tattomoosa.vision_cone_3d/icons/VisionCone3D.svg" width="100"/>
|
||||
<br/>
|
||||
<h1>
|
||||
VisionCone3D
|
||||
<br/>
|
||||
<sub>
|
||||
<sub>
|
||||
<sub>
|
||||
Simple but configurable 3D vision cone node for <a href="https://godotengine.org/">Godot</a>
|
||||
</sub>
|
||||
</sub>
|
||||
</sub>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
</h1>
|
||||
<br/>
|
||||
<br/>
|
||||
<img src="./readme_images/demo.png" height="140">
|
||||
<img src="./readme_images/stress_test.png" height="140">
|
||||
<img src="./readme_images/editor_view.png" height="140">
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
> Compatible with Godot 4.4 - see 4.3 branch for Godot 4.3 compatible version
|
||||
|
||||
Adds VisionCone3D, which tracks whether or not objects within its cone shape can be "seen".
|
||||
This can be used to let objects in your game "see" multiple objects efficiently.
|
||||
Default configuration should work for most use-cases out of the box.
|
||||
|
||||
## Features
|
||||
|
||||
* Edit range/angle of cone via 3D viewport editor gizmo
|
||||
* Debug visualization to easily diagnose any issues
|
||||
* Works with complex objects that have many collision shapes
|
||||
* Configurable vision probe settings allow tuning effectiveness and performance to your use-case
|
||||
* Ignore some physics bodies (eg the parent body)
|
||||
* Separate masks for bodies that can be seen and bodies that can only occlude other objects
|
||||
* Includes general-purpose ConeShape3D
|
||||
|
||||
## Installation
|
||||
|
||||
Install via the AssetLib tab within Godot by searching for VisionCone3D
|
||||
|
||||
## Usage
|
||||
|
||||
Add the VisionCone3D node to your scene. Turn on debug draw to see it working. Then you can...
|
||||
|
||||
### Connect to the body visible signals
|
||||
|
||||
These signals fire when a body is newly visible or newly hidden.
|
||||
|
||||
```python
|
||||
func _ready():
|
||||
vision_cone.body_sighted.connect(_on_body_sighted)
|
||||
vision_cone.body_hidden.connect(_on_body_hidden)
|
||||
|
||||
func _on_body_sighted(body: Node3D):
|
||||
print("body sighted: ", body.name)
|
||||
|
||||
func _on_body_hidden(body: Node3D):
|
||||
print("body hidden: ", body.name)
|
||||
```
|
||||
|
||||
### Poll the currently visible bodies
|
||||
|
||||
```python
|
||||
func _process(): # doesn't need to be during a physics frame
|
||||
print("bodies visible: ", vision_cone.get_visible_bodies())
|
||||
```
|
||||
|
||||
## Performance Tuning
|
||||
|
||||
### Vision Test Mode
|
||||
|
||||
#### Center
|
||||
|
||||
Samples only the center point (position) of the CollisionShape. Most efficient, but least effective
|
||||
as if the center of a shape is obscured it won't be seen.
|
||||
|
||||
```python
|
||||
vision_cone.vision_test_mode = VisionCone3D.VisionTestMode.SAMPLE_CENTER
|
||||
```
|
||||
|
||||
#### Sample Random Vertices
|
||||
|
||||
Uses CollisionShape's `get_debug_mesh` to get a mesh representation of the CollisionShape,
|
||||
then samples random vertex points from that mesh.
|
||||
Effectiveness determined by the max body count and max probe per shape count
|
||||
|
||||
```python
|
||||
vision_cone.vision_test_mode = VisionCone3D.VisionTestMode.SAMPLE_RANDOM_VERTICES
|
||||
vision_cone.vision_test_max_body_count = 50 # Bodies probed, per-frame
|
||||
vision_cone.vision_test_shape_max_probe_count = 5 # Probes per hidden shape
|
||||
```
|
||||
|
||||
### Collision Masks
|
||||
|
||||
VisionCone3D has 2 collision masks, one used for bodies that can be seen by the cone and one for an environment,
|
||||
which can occlude seen bodies but is not itself probed for visibility.
|
||||
|
||||
For example, add the level collision layer to `collision_environment_mask` and the player/enemy/object collision layer to the `collision_mask`.
|
||||
The player/enemy/object can then hide behind the level, but no processing/probing will occur on the level collision geometry itself.
|
||||
|
||||
## The Future
|
||||
|
||||
This asset is still in development. I have some ideas for further performance tuning options, and I'm open to feedback on the usability and how to improve documentation or workflows.
|
||||
|
||||
### 2D Support?
|
||||
|
||||
I am open to adding a 2D version of this addon if there is sufficient interest.
|
||||
|
||||
See if [VisionCone2D](https://github.com/d-bucur/godot-vision-cone) meets your needs in the meantime. No relation.
|
||||
|
||||
## Upgrading
|
||||
|
||||
### 0.1.0 -> 0.2.0
|
||||
|
||||
v0.2.0 has significant performance improvements. Probably should have waited a few days before publishing. It probably doesn't have any users yet, but just in case...
|
||||
|
||||
* Use "Change Type..." on your VisionCone3Ds and select Area3D.
|
||||
* Use new ConeShape3D for all your cone-y collision needs
|
||||
246
addons/tattomoosa.vision_cone_3d/examples/demo.tscn
Normal file
246
addons/tattomoosa.vision_cone_3d/examples/demo.tscn
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,71 @@
|
|||
extends PanelContainer
|
||||
|
||||
@export var vision_cone : VisionCone3D
|
||||
@export var cameras : Array[Camera3D] = []
|
||||
|
||||
@onready var vision_test_center_checkbox : CheckBox = %VisionTestCenterCheckBox
|
||||
@onready var vision_test_scatter_checkbox : CheckBox = %VisionTestScatterCheckBox
|
||||
@onready var raycast_count_slider : Slider = %RaycastsPerFrameSlider
|
||||
@onready var angle_slider : Slider = %AngleSlider
|
||||
@onready var range_slider : Slider = %RangeSlider
|
||||
@onready var rotation_slider : Slider = %ObserverRotationSlider
|
||||
@onready var position_slider : Slider = %ObserverPositionSlider
|
||||
@onready var max_bodies_slider : Slider = %MaxBodiesSlider
|
||||
@onready var switch_camera_button : Button = %SwitchCameraButton
|
||||
|
||||
func _ready():
|
||||
vision_test_center_checkbox.toggled.connect(_set_center)
|
||||
vision_test_scatter_checkbox.toggled.connect(_set_scatter)
|
||||
raycast_count_slider.value_changed.connect(func(value: float): vision_cone.vision_test_shape_max_probe_count = value)
|
||||
angle_slider.value_changed.connect(func(value: float): vision_cone.angle = value)
|
||||
range_slider.value_changed.connect(func(value: float): vision_cone.range = value)
|
||||
rotation_slider.value_changed.connect(func(value: float): vision_cone.get_parent().rotation_degrees.y = -value)
|
||||
position_slider.value_changed.connect(func(value: float): vision_cone.get_parent().position.x = value)
|
||||
max_bodies_slider.value_changed.connect(func(value: float): vision_cone.vision_test_max_body_count = value)
|
||||
if cameras.is_empty():
|
||||
switch_camera_button.hide()
|
||||
else:
|
||||
cameras[0].current = true
|
||||
switch_camera_button.text = "Current Camera: " + cameras[0].name
|
||||
switch_camera_button.pressed.connect(
|
||||
func():
|
||||
for i in cameras.size():
|
||||
var cam := cameras[i]
|
||||
if cam.current:
|
||||
cam.current = false
|
||||
var next_cam : Camera3D
|
||||
if (i + 1) < cameras.size():
|
||||
next_cam = cameras[i + 1]
|
||||
else:
|
||||
next_cam = cameras[0]
|
||||
next_cam.current = true
|
||||
switch_camera_button.text = "Current Camera: " + next_cam.name
|
||||
return
|
||||
)
|
||||
|
||||
angle_slider.value = vision_cone.angle
|
||||
range_slider.value = vision_cone.range
|
||||
max_bodies_slider.value = vision_cone.vision_test_max_body_count
|
||||
raycast_count_slider.value = vision_cone.vision_test_shape_max_probe_count
|
||||
|
||||
if vision_cone.get_parent() is CharacterBody3D:
|
||||
vision_cone.get_parent().rotation_degrees.y = -rotation_slider.value
|
||||
vision_cone.get_parent().position.x = position_slider.value
|
||||
else:
|
||||
rotation_slider.get_parent().hide()
|
||||
position_slider.get_parent().hide()
|
||||
|
||||
_set_center(vision_test_center_checkbox.button_pressed)
|
||||
_set_scatter(vision_test_scatter_checkbox.button_pressed)
|
||||
|
||||
size.y = 0
|
||||
|
||||
func _set_center(value: bool):
|
||||
if !value:
|
||||
return
|
||||
vision_cone.vision_test_mode = VisionCone3D.VisionTestMode.SAMPLE_CENTER
|
||||
|
||||
func _set_scatter(value: bool):
|
||||
if !value:
|
||||
return
|
||||
vision_cone.vision_test_mode = VisionCone3D.VisionTestMode.SAMPLE_RANDOM_VERTICES
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dof1xi7gcbq7s
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://mqvpirrmppob"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_da376"]
|
||||
size = Vector3(1, 3, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_mb6rt"]
|
||||
size = Vector3(1, 3, 1)
|
||||
|
||||
[node name="Blocker" type="StaticBody3D"]
|
||||
collision_layer = 2
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("BoxShape3D_da376")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("BoxMesh_mb6rt")
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://batptfh4cwpfb"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cmgl8607thxgg" path="res://addons/tattomoosa.vision_cone_3d/examples/example_src/observable.tscn" id="1_p0bro"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_c3q4w"]
|
||||
length = 0.001
|
||||
tracks/0/type = "position_3d"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = PackedFloat32Array(0, 1, -0.195181, 0, -1.77211)
|
||||
|
||||
[sub_resource type="Animation" id="Animation_jctf1"]
|
||||
resource_name = "back_and_forth"
|
||||
length = 8.0
|
||||
loop_mode = 1
|
||||
tracks/0/type = "position_3d"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath(".")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = PackedFloat32Array(0, 1, 0, 0, 0, 2.03333, 1, 4, 0, 0, 6.03333, 1, -4, 0, 0, 8, 1, 0, 0, 0)
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_al81f"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_c3q4w"),
|
||||
&"back_and_forth": SubResource("Animation_jctf1")
|
||||
}
|
||||
|
||||
[node name="MovingObservable" instance=ExtResource("1_p0bro")]
|
||||
transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, -0.195181, 0, -1.77211)
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="." index="2"]
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_al81f")
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://cmgl8607thxgg"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dnr2f"]
|
||||
albedo_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_nj3xo"]
|
||||
material = SubResource("StandardMaterial3D_dnr2f")
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ecabg"]
|
||||
albedo_color = Color(1, 0.635294, 1, 1)
|
||||
|
||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_5i4ah"]
|
||||
material = SubResource("StandardMaterial3D_ecabg")
|
||||
radius = 0.25
|
||||
height = 0.75
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cf0b5"]
|
||||
|
||||
[node name="Observable" type="CharacterBody3D"]
|
||||
transform = Transform3D(-1, 0, 8.74228e-08, 0, 1, 0, -8.74228e-08, 0, -1, 0, 0, 0)
|
||||
metadata/_edit_group_ = true
|
||||
|
||||
[node name="Body" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("CapsuleMesh_nj3xo")
|
||||
|
||||
[node name="Face" type="MeshInstance3D" parent="Body"]
|
||||
transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 0, 0.386695, -0.364832)
|
||||
mesh = SubResource("CapsuleMesh_5i4ah")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("CapsuleShape3D_cf0b5")
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://brqivkckug8uc"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cmgcelj1qxg8o" path="res://addons/tattomoosa.vision_cone_3d/src/VisionCone3D.gd" id="1_t4wly"]
|
||||
|
||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_td2ym"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ecabg"]
|
||||
albedo_color = Color(1, 0.635294, 1, 1)
|
||||
|
||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_5i4ah"]
|
||||
material = SubResource("StandardMaterial3D_ecabg")
|
||||
radius = 0.25
|
||||
height = 0.75
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cf0b5"]
|
||||
|
||||
[node name="Observer" type="CharacterBody3D"]
|
||||
metadata/_edit_group_ = true
|
||||
|
||||
[node name="VisionCone3D" type="Area3D" parent="." node_paths=PackedStringArray("vision_test_ignore_bodies")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.41062, -0.023833)
|
||||
script = ExtResource("1_t4wly")
|
||||
debug_draw = true
|
||||
vision_test_ignore_bodies = [NodePath("..")]
|
||||
|
||||
[node name="Body" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("CapsuleMesh_td2ym")
|
||||
|
||||
[node name="Face" type="MeshInstance3D" parent="Body"]
|
||||
transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 0, 0.386695, -0.364832)
|
||||
mesh = SubResource("CapsuleMesh_5i4ah")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("CapsuleShape3D_cf0b5")
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
extends Label
|
||||
|
||||
@export var range_control : Range
|
||||
|
||||
func _ready():
|
||||
range_control.value_changed.connect(_set_displayed_value)
|
||||
_set_displayed_value(range_control.value)
|
||||
|
||||
func _set_displayed_value(_value: float):
|
||||
text = str(_value)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://be67a8jv24c5o
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://cdbsstpvtrvhd"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dof1xi7gcbq7s" path="res://addons/tattomoosa.vision_cone_3d/examples/example_src/VisionConeDemoControls.gd" id="1_vf8s6"]
|
||||
[ext_resource type="Script" uid="uid://be67a8jv24c5o" path="res://addons/tattomoosa.vision_cone_3d/examples/example_src/ui/ValueLabel.gd" id="2_8lgvy"]
|
||||
|
||||
[sub_resource type="ButtonGroup" id="ButtonGroup_dqtte"]
|
||||
|
||||
[node name="VisionConeControls" type="PanelContainer"]
|
||||
offset_left = 13.0
|
||||
offset_top = 14.0
|
||||
offset_right = 308.0
|
||||
offset_bottom = 24.0
|
||||
script = ExtResource("1_vf8s6")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 20
|
||||
|
||||
[node name="Range" type="VBoxContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/Range"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/Range/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
text = "Range:"
|
||||
|
||||
[node name="RangeValueLabel" type="Label" parent="VBoxContainer/Range/HBoxContainer2" node_paths=PackedStringArray("range_control")]
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_8lgvy")
|
||||
range_control = NodePath("../../RangeSlider")
|
||||
|
||||
[node name="RangeSlider" type="HSlider" parent="VBoxContainer/Range"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = 1.0
|
||||
max_value = 40.0
|
||||
step = 0.5
|
||||
value = 20.0
|
||||
|
||||
[node name="Angle" type="VBoxContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/Angle"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/Angle/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
text = "Angle:"
|
||||
|
||||
[node name="AngleValueLabel" type="Label" parent="VBoxContainer/Angle/HBoxContainer2" node_paths=PackedStringArray("range_control")]
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_8lgvy")
|
||||
range_control = NodePath("../../AngleSlider")
|
||||
|
||||
[node name="AngleSlider" type="HSlider" parent="VBoxContainer/Angle"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = 0.1
|
||||
max_value = 90.0
|
||||
step = 0.1
|
||||
value = 45.0
|
||||
|
||||
[node name="VisionTestModeControls" type="VBoxContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label2" type="Label" parent="VBoxContainer/VisionTestModeControls"]
|
||||
layout_mode = 2
|
||||
text = "Vision Test Mode"
|
||||
|
||||
[node name="VisionTestMode" type="HBoxContainer" parent="VBoxContainer/VisionTestModeControls"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="VisionTestCenterCheckBox" type="CheckBox" parent="VBoxContainer/VisionTestModeControls/VisionTestMode"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
button_group = SubResource("ButtonGroup_dqtte")
|
||||
text = "Center"
|
||||
|
||||
[node name="VisionTestScatterCheckBox" type="CheckBox" parent="VBoxContainer/VisionTestModeControls/VisionTestMode"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
button_pressed = true
|
||||
button_group = SubResource("ButtonGroup_dqtte")
|
||||
text = "Scatter"
|
||||
|
||||
[node name="ProbesPerFrame" type="VBoxContainer" parent="VBoxContainer/VisionTestModeControls"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/VisionTestModeControls/ProbesPerFrame"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/VisionTestModeControls/ProbesPerFrame/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
text = "Max Probes Per Shape:"
|
||||
|
||||
[node name="RaycastPerFrameValueLabel" type="Label" parent="VBoxContainer/VisionTestModeControls/ProbesPerFrame/HBoxContainer2" node_paths=PackedStringArray("range_control")]
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_8lgvy")
|
||||
range_control = NodePath("../../RaycastsPerFrameSlider")
|
||||
|
||||
[node name="RaycastsPerFrameSlider" type="HSlider" parent="VBoxContainer/VisionTestModeControls/ProbesPerFrame"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = 1.0
|
||||
value = 10.0
|
||||
|
||||
[node name="MaxBodies" type="VBoxContainer" parent="VBoxContainer/VisionTestModeControls"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/VisionTestModeControls/MaxBodies"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/VisionTestModeControls/MaxBodies/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
text = "Max Bodies Per Frame:"
|
||||
|
||||
[node name="MaxBodiesFrameValueLabel" type="Label" parent="VBoxContainer/VisionTestModeControls/MaxBodies/HBoxContainer2" node_paths=PackedStringArray("range_control")]
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_8lgvy")
|
||||
range_control = NodePath("../../MaxBodiesSlider")
|
||||
|
||||
[node name="MaxBodiesSlider" type="HSlider" parent="VBoxContainer/VisionTestModeControls/MaxBodies"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = 1.0
|
||||
max_value = 500.0
|
||||
value = 11.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="SwitchCameraButton" type="Button" parent="VBoxContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Switch Camera"
|
||||
|
||||
[node name="ObserverRotation" type="VBoxContainer" parent="VBoxContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/VBoxContainer/ObserverRotation"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/VBoxContainer/ObserverRotation/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
text = "Observer Rotation:"
|
||||
|
||||
[node name="ObserverRotationValueLabel" type="Label" parent="VBoxContainer/VBoxContainer/ObserverRotation/HBoxContainer2" node_paths=PackedStringArray("range_control")]
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_8lgvy")
|
||||
range_control = NodePath("../../ObserverRotationSlider")
|
||||
|
||||
[node name="ObserverRotationSlider" type="HSlider" parent="VBoxContainer/VBoxContainer/ObserverRotation"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = -90.0
|
||||
max_value = 90.0
|
||||
|
||||
[node name="ObserverPosition" type="VBoxContainer" parent="VBoxContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/VBoxContainer/ObserverPosition"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/VBoxContainer/ObserverPosition/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
text = "Observer Position:"
|
||||
|
||||
[node name="ObserverPositionValueLabel" type="Label" parent="VBoxContainer/VBoxContainer/ObserverPosition/HBoxContainer2" node_paths=PackedStringArray("range_control")]
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_8lgvy")
|
||||
range_control = NodePath("../../ObserverPositionSlider")
|
||||
|
||||
[node name="ObserverPositionSlider" type="HSlider" parent="VBoxContainer/VBoxContainer/ObserverPosition"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = -8.0
|
||||
max_value = 8.0
|
||||
step = 0.1
|
||||
26
addons/tattomoosa.vision_cone_3d/examples/minimal.tscn
Normal file
26
addons/tattomoosa.vision_cone_3d/examples/minimal.tscn
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://doqrupj5l86sr"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cmgcelj1qxg8o" path="res://addons/tattomoosa.vision_cone_3d/src/VisionCone3D.gd" id="1_78jke"]
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_si8ep"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_bebrf"]
|
||||
|
||||
[node name="Node3D" type="Node3D"]
|
||||
|
||||
[node name="VisionCone3D" type="Area3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 3.00271)
|
||||
script = ExtResource("1_78jke")
|
||||
debug_draw = true
|
||||
|
||||
[node name="StaticBody3D" type="StaticBody3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -2.66644)
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="StaticBody3D"]
|
||||
mesh = SubResource("BoxMesh_si8ep")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
|
||||
shape = SubResource("BoxShape3D_bebrf")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 8.38814, 0)
|
||||
33
addons/tattomoosa.vision_cone_3d/icons/GizmoVisionCone.svg
Normal file
33
addons/tattomoosa.vision_cone_3d/icons/GizmoVisionCone.svg
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 28.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 128 128" style="enable-background:new 0 0 128 128;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{display:none;}
|
||||
.st1{display:inline;fill-opacity:0.294;}
|
||||
.st2{display:inline;fill:#FFFFFF;}
|
||||
.st3{fill:#FFFFFF;}
|
||||
.st4{fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
|
||||
.st5{fill:none;stroke:#000000;stroke-width:3;stroke-miterlimit:10;}
|
||||
.st6{fill:#231F20;}
|
||||
.st7{fill:none;stroke:#000000;stroke-width:4;stroke-miterlimit:10;}
|
||||
</style>
|
||||
<g id="Layer_1_00000012455106065017520430000009640333213232038794_" class="st0">
|
||||
<path class="st1" d="M52,4c-6.6,0-12,5.4-12,12v26.6C27.7,49.2,20,62,20,76v4h28.6c2.3,8.5,11.1,13.5,19.7,11.2
|
||||
c5.4-1.5,9.7-5.7,11.2-11.2H108v-4c0-14-7.7-26.8-20-33.4V16c0-6.6-5.4-12-12-12H52z M40.3,82c-1.6-0.1-3.2,0.3-4.6,1.1l-10.4,6
|
||||
c-3.8,2.2-5.1,7.1-2.9,10.9s7.1,5.1,10.9,2.9l10.4-6c3.8-2.2,5.1-7.1,2.9-10.9C45.4,83.7,43,82.2,40.3,82z M87.7,82
|
||||
c-4.4,0.3-7.7,4.1-7.5,8.5c0.2,2.7,1.7,5.1,4,6.4l10.4,6c3.8,2.2,8.7,0.9,10.9-2.9s0.9-8.7-2.9-10.9l-10.4-6
|
||||
C90.9,82.3,89.3,81.9,87.7,82L87.7,82z M64,96c-4.4,0-8,3.6-8,8v12c0,4.4,3.6,8,8,8s8-3.6,8-8v-12C72,99.6,68.4,96,64,96z"/>
|
||||
<path class="st2" d="M52,8c-4.4,0-8,3.6-8,8v28.9C31.6,51.3,24,63.2,24,76h28c0,6.6,5.4,12,12,12s12-5.4,12-12h28
|
||||
c0-12.8-7.6-24.7-20-31.1V16c0-4.4-3.6-8-8-8H52z M40,86c-0.8-0.1-1.6,0.1-2.3,0.5l-10.4,6c-1.9,1.1-2.6,3.6-1.5,5.5
|
||||
s3.6,2.6,5.5,1.5l10.4-6c1.9-1.1,2.6-3.6,1.5-5.5C42.5,86.8,41.4,86.1,40,86L40,86z M88,86c-2.2,0.1-3.9,2-3.7,4.3
|
||||
c0.1,1.3,0.8,2.5,2,3.2l10.4,6c1.9,1.1,4.4,0.4,5.5-1.5s0.4-4.4-1.5-5.5l-10.4-6C89.6,86.1,88.8,86,88,86L88,86z M64,100
|
||||
c-2.2,0-4,1.8-4,4v12c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4v-12C68,101.8,66.2,100,64,100z"/>
|
||||
</g>
|
||||
<path class="st3" d="M6.2,66.2l85.1,57.5L88,112.5c-8.8-30.2-8.8-62.4,0-92.6l3.3-11.2L6.2,66.2z"/>
|
||||
<path class="st4" d="M6.2,66.2l85.1,57.5L88,112.5c-8.8-30.2-8.8-62.4,0-92.6l3.3-11.2L6.2,66.2z"/>
|
||||
<ellipse class="st3" cx="107" cy="66.2" rx="15.7" ry="57.5"/>
|
||||
<ellipse class="st5" cx="107" cy="66.2" rx="15.7" ry="57.5"/>
|
||||
<ellipse class="st6" cx="98.3" cy="66.2" rx="3.6" ry="19.3"/>
|
||||
<ellipse class="st7" cx="99.3" cy="66.2" rx="3.6" ry="19.3"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
|
|
@ -0,0 +1,38 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://o1pkx5p4gmem"
|
||||
path.s3tc="res://.godot/imported/GizmoVisionCone.svg-ea8f76460bf35030690548bcee239273.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/tattomoosa.vision_cone_3d/icons/GizmoVisionCone.svg"
|
||||
dest_files=["res://.godot/imported/GizmoVisionCone.svg-ea8f76460bf35030690548bcee239273.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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
11
addons/tattomoosa.vision_cone_3d/icons/VisionCone3D.svg
Normal file
11
addons/tattomoosa.vision_cone_3d/icons/VisionCone3D.svg
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 28.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:none;stroke:#FC7F7F;stroke-width:2;stroke-linecap:round;}
|
||||
.st1{fill:none;stroke:#FC7F7F;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;}
|
||||
</style>
|
||||
<polyline class="st0" points="10.6,1.7 2.7,8 10.6,14.3 "/>
|
||||
<ellipse class="st1" cx="11.6" cy="8" rx="1.4" ry="3.7"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 662 B |
|
|
@ -0,0 +1,38 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://pgp4cqq8ov3o"
|
||||
path="res://.godot/imported/VisionCone3D.svg-2598d1ee3dd911c502082c26b2e835ec.ctex"
|
||||
metadata={
|
||||
"has_editor_variant": true,
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/tattomoosa.vision_cone_3d/icons/VisionCone3D.svg"
|
||||
dest_files=["res://.godot/imported/VisionCone3D.svg-2598d1ee3dd911c502082c26b2e835ec.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=true
|
||||
editor/convert_colors_with_editor_theme=true
|
||||
7
addons/tattomoosa.vision_cone_3d/plugin.cfg
Normal file
7
addons/tattomoosa.vision_cone_3d/plugin.cfg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[plugin]
|
||||
|
||||
name="VisionCone3D"
|
||||
description=""
|
||||
author="Tattomoosa"
|
||||
version="0.2.0"
|
||||
script="plugin.gd"
|
||||
21
addons/tattomoosa.vision_cone_3d/plugin.gd
Normal file
21
addons/tattomoosa.vision_cone_3d/plugin.gd
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
const DEBUG_DRAW_TOOL := "Set Vision Cone Debug Draw Visibility"
|
||||
const VisionCone3DGizmoPlugin := preload ("./src/editor/VisionCone3DGizmoPlugin.gd")
|
||||
var gizmo : VisionCone3DGizmoPlugin = VisionCone3DGizmoPlugin.new()
|
||||
|
||||
func _enter_tree() -> void:
|
||||
gizmo.undo_redo = get_undo_redo()
|
||||
add_node_3d_gizmo_plugin(gizmo)
|
||||
|
||||
# add_tool_menu_item(
|
||||
# DEBUG_DRAW_TOOL,
|
||||
# func():
|
||||
# VisionCone3D.debug_draw_all = !VisionCone3D.debug_draw_all
|
||||
# )
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_node_3d_gizmo_plugin(gizmo)
|
||||
# remove_tool_menu_item(DEBUG_DRAW_TOOL)
|
||||
1
addons/tattomoosa.vision_cone_3d/plugin.gd.uid
Normal file
1
addons/tattomoosa.vision_cone_3d/plugin.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://yxw0yuks1mme
|
||||
50
addons/tattomoosa.vision_cone_3d/src/ConeShape3D.gd
Normal file
50
addons/tattomoosa.vision_cone_3d/src/ConeShape3D.gd
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
@tool
|
||||
class_name ConeShape3D
|
||||
extends ConvexPolygonShape3D
|
||||
|
||||
## The height of the cone
|
||||
@export var height : float = 2.0:
|
||||
set(value):
|
||||
height = value
|
||||
_request_resize()
|
||||
## The radius of the bottom of the cone
|
||||
@export var radius : float = 0.5:
|
||||
set(value):
|
||||
radius = value
|
||||
_request_resize()
|
||||
## The number of radial segments of the cone
|
||||
@export var resolution : int = 8:
|
||||
set(value):
|
||||
resolution = value
|
||||
_request_resize()
|
||||
|
||||
# Resize requested
|
||||
var pending_resize := false
|
||||
|
||||
# Update size to initial state
|
||||
func _init() -> void:
|
||||
_request_resize()
|
||||
|
||||
# Will only resize once per frame, during idle time
|
||||
func _request_resize() -> void:
|
||||
if !pending_resize:
|
||||
_update_size.call_deferred()
|
||||
pending_resize = true
|
||||
|
||||
# Updates shape size
|
||||
func _update_size() -> void:
|
||||
points = _make_cone_polygon_points()
|
||||
pending_resize = false
|
||||
|
||||
# Makes a cone polygon
|
||||
@warning_ignore("return_value_discarded")
|
||||
func _make_cone_polygon_points() -> PackedVector3Array:
|
||||
var pts : PackedVector3Array = []
|
||||
var top : Vector3 = Vector3(0, height / 2, 0)
|
||||
for i in resolution:
|
||||
var angle := float(i) * TAU / resolution
|
||||
var x := cos(angle) * radius
|
||||
var y := sin(angle) * radius
|
||||
pts.push_back(Vector3(x, -height/2, y))
|
||||
pts.push_back(top)
|
||||
return pts
|
||||
1
addons/tattomoosa.vision_cone_3d/src/ConeShape3D.gd.uid
Normal file
1
addons/tattomoosa.vision_cone_3d/src/ConeShape3D.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bc32kei4pauw1
|
||||
421
addons/tattomoosa.vision_cone_3d/src/VisionCone3D.gd
Normal file
421
addons/tattomoosa.vision_cone_3d/src/VisionCone3D.gd
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
@tool
|
||||
@icon("../icons/VisionCone3D.svg")
|
||||
class_name VisionCone3D
|
||||
extends Area3D
|
||||
## Provides a "Vision Cone", a cone-shaped area where objects are then
|
||||
## probed for visibility via ray casts
|
||||
|
||||
## Emitted when a body is newly visible
|
||||
signal body_sighted(body: Node3D)
|
||||
|
||||
## Emitted when a body is newly not visible
|
||||
signal body_hidden(body: Node3D)
|
||||
|
||||
## Emitted when the cone shape changes
|
||||
signal shape_changed
|
||||
|
||||
#region VisionCone3D
|
||||
|
||||
#region members
|
||||
## Determines how visibility is probed for bodies within the cone area
|
||||
##
|
||||
enum VisionTestMode{
|
||||
## Samples the center of each CollisionShape. Maximum performance, least reliability
|
||||
SAMPLE_CENTER,
|
||||
## Samples random vertices of each CollisionShape, up to `vision_test_shape_max_probe_count`
|
||||
## for hidden objects
|
||||
## If shape was visible at last frame, tests last successful probe position first
|
||||
SAMPLE_RANDOM_VERTICES,
|
||||
## Gets a list of points where shapes collide from the physics engine
|
||||
# SAMPLE_COLLIDE_SHAPE,
|
||||
}
|
||||
|
||||
const VisionConeDebugVisualizer3D := preload("./debug/VisionConeDebugVisualizer3D.gd")
|
||||
|
||||
|
||||
## Distance that can be seen (the height of the vision cone)
|
||||
@warning_ignore("shadowed_global_identifier")
|
||||
@export var range := 20.0:
|
||||
set(v): range = v; _update_shape()
|
||||
|
||||
## Angle of the vision cone
|
||||
@export_range(0, 150) var angle := 45.0:
|
||||
set(v): angle = v; _update_shape()
|
||||
|
||||
## Whether or not to draw debug information
|
||||
@export var debug_draw := false:
|
||||
set(v):
|
||||
debug_draw = v
|
||||
if debug_draw and !_debug_visualizer:
|
||||
_debug_visualizer = VisionConeDebugVisualizer3D.new()
|
||||
add_child(_debug_visualizer)
|
||||
elif !debug_draw and _debug_visualizer:
|
||||
_debug_visualizer.queue_free()
|
||||
|
||||
@export_group("Vision Test", "vision_test_")
|
||||
|
||||
## Which VisionTestMode to use to determine if a shape is visible
|
||||
@export var vision_test_mode : VisionTestMode = VisionTestMode.SAMPLE_RANDOM_VERTICES
|
||||
## List of bodies to ignore in vision probing
|
||||
##
|
||||
## Useful for eg the VisionCone3D's parent body
|
||||
@export var vision_test_ignore_bodies : Array[PhysicsBody3D]
|
||||
|
||||
@export_subgroup("Per-frame probe settings")
|
||||
## Maximum amount of shape probes (per shape, per frame)
|
||||
@export var vision_test_shape_max_probe_count : int = 5
|
||||
## Maximum number of bodies to check, per-frame
|
||||
##
|
||||
## All bodies will still be evaluated as it will cycle through them
|
||||
## frame by frame, but `body_sighted` or `body_hidden` may lag behind
|
||||
## by some frames.
|
||||
@export var vision_test_max_body_count : int = 10
|
||||
|
||||
@export_group("Collision", "collision_")
|
||||
## Collision layer "hoisted" up from Area3D for convenience
|
||||
@export_flags_3d_physics var collision_layer_ : int = 1:
|
||||
get:
|
||||
return collision_layer
|
||||
set(value):
|
||||
collision_layer = value
|
||||
|
||||
## Collision mask "hoisted" up from Area3D for convenience
|
||||
##
|
||||
## This represents what can be "seen" and notified against. Generally useful for characters
|
||||
@export_flags_3d_physics var collision_mask_ : int = 1:
|
||||
get:
|
||||
return collision_mask
|
||||
set(value):
|
||||
collision_mask = value
|
||||
|
||||
## Collision mask of what objects can obscure visible objects (but don't need to
|
||||
## be tracked and probed to determine visibility)
|
||||
##
|
||||
## Generally useful for the environment but any node where you don't care
|
||||
## if its seen or not can be on this layer.
|
||||
## This layer only affects raycasts, which can collide with any layer
|
||||
## in either `collision_mask` or `collision_environment_mask`
|
||||
@export_flags_3d_physics var collision_environment_mask : int = 1
|
||||
|
||||
## Radius at the wide end of the vision cone
|
||||
var end_radius: float:
|
||||
get: return _get_end_radius()
|
||||
|
||||
# { Node3D "body" : Node3D "shape" }
|
||||
var _body_probe_data : Dictionary = {
|
||||
# Node3D "body" : [
|
||||
# "prober": VisionTestProber
|
||||
# ]
|
||||
}
|
||||
|
||||
var _last_probed_index : int = -1
|
||||
var _debug_visualizer : VisionConeDebugVisualizer3D
|
||||
var _collision_shape := CollisionShape3D.new()
|
||||
var _cone_shape := ConeShape3D.new()
|
||||
|
||||
#endregion members
|
||||
|
||||
## Returns a list of intersecting PhysicsBody3Ds. The overlapping body's
|
||||
## CollisionObject3D.collision_layer must be part of this area's CollisionObject3D.collision_mask
|
||||
## in order to be detected.
|
||||
func get_visible_bodies() -> Array[PhysicsBody3D]:
|
||||
var bodies : Array[PhysicsBody3D] = []
|
||||
for prober: VisionTestProber in _body_probe_data.values():
|
||||
bodies.push_back(prober.body)
|
||||
return bodies
|
||||
|
||||
## Whether or not a given point in global space is within the cone's
|
||||
## angle.
|
||||
func point_within_angle(global_point: Vector3) -> bool:
|
||||
var body_pos := -global_basis.z
|
||||
var pos := global_point - global_position
|
||||
var angle_to := pos.angle_to(body_pos)
|
||||
var angle_deg := rad_to_deg(angle_to)
|
||||
return angle_deg <= (angle / 2)
|
||||
|
||||
## Whether or not a given point in global space is within the cone
|
||||
func point_within_cone(global_point: Vector3) -> bool:
|
||||
var local_point := to_local(global_point)
|
||||
var z_distance : float = abs(local_point.z)
|
||||
if z_distance < 0 or z_distance > range:
|
||||
return false
|
||||
return point_within_angle(global_point)
|
||||
|
||||
func _init() -> void:
|
||||
add_child(_collision_shape)
|
||||
_collision_shape.shape = _cone_shape
|
||||
_collision_shape.rotation_degrees.x = 90
|
||||
_update_shape()
|
||||
# only true when copied
|
||||
if _debug_visualizer:
|
||||
_debug_visualizer.vision_cone = self
|
||||
|
||||
var err := body_shape_entered.connect(_on_body_shape_entered)
|
||||
if err != OK:
|
||||
push_warning("VisionCone3D body_shape_entered: ", error_string(err))
|
||||
err = body_shape_exited.connect(_on_body_shape_exited)
|
||||
if err != OK:
|
||||
push_warning("VisionCone3D body_shape_exited: ", error_string(err))
|
||||
|
||||
@warning_ignore("return_value_discarded")
|
||||
func _physics_process(_delta: float) -> void:
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
if !monitoring:
|
||||
return
|
||||
|
||||
var bodies_to_probe := _get_bodies_to_probe_this_frame()
|
||||
for body: CollisionObject3D in bodies_to_probe:
|
||||
if !is_instance_valid(body):
|
||||
push_warning("erasing invalid body")
|
||||
_body_probe_data.erase(body)
|
||||
continue
|
||||
_probe_body(body)
|
||||
|
||||
func _get_bodies_to_probe_this_frame() -> Array: # Array[CollisionObject3D]:
|
||||
var all_bodies := _body_probe_data.keys()
|
||||
if all_bodies.is_empty():
|
||||
return []
|
||||
if all_bodies.size() < vision_test_max_body_count:
|
||||
_last_probed_index = -1
|
||||
return all_bodies
|
||||
|
||||
var start_index := _last_probed_index + 1
|
||||
var to_end := all_bodies.slice(start_index, start_index + vision_test_max_body_count)
|
||||
var counted := to_end.size()
|
||||
var end_index : int = min(vision_test_max_body_count - counted, start_index)
|
||||
var from_start := all_bodies.slice(0, end_index)
|
||||
_last_probed_index = from_start.size() - 1 if from_start.size() > 0 else start_index + counted - 1
|
||||
return (to_end + from_start)
|
||||
|
||||
func _probe_body(body: CollisionObject3D) -> void:
|
||||
var body_was_visible_last_frame := false
|
||||
var body_is_visible := false
|
||||
var body_probes : Array[VisionTestProber]
|
||||
body_probes.assign(_body_probe_data[body])
|
||||
|
||||
for prober in body_probes:
|
||||
if prober.visible:
|
||||
body_was_visible_last_frame = true
|
||||
prober.probe()
|
||||
if prober.visible:
|
||||
body_is_visible = true
|
||||
|
||||
var body_visibility_changed := body_is_visible != body_was_visible_last_frame
|
||||
|
||||
if body_visibility_changed:
|
||||
if body_is_visible:
|
||||
body_sighted.emit(body)
|
||||
else:
|
||||
body_hidden.emit(body)
|
||||
|
||||
func _update_shape() -> void:
|
||||
_cone_shape.height = range
|
||||
_cone_shape.radius = end_radius
|
||||
_collision_shape.position.z = -range / 2
|
||||
update_gizmos()
|
||||
shape_changed.emit()
|
||||
|
||||
func _get_collision_shape_node_in_body(body: PhysicsBody3D, body_shape_index: int) -> Node3D:
|
||||
if !body:
|
||||
return null
|
||||
var body_shape_owner : int = body.shape_find_owner(body_shape_index)
|
||||
return body.shape_owner_get_owner(body_shape_owner)
|
||||
|
||||
func _get_end_radius() -> float:
|
||||
var angle_rad := deg_to_rad(angle / 2)
|
||||
return range * tan(angle_rad)
|
||||
|
||||
func _get_prober_for_shape(shape: CollisionShape3D, body: CollisionObject3D) -> VisionTestProber:
|
||||
for prober: VisionTestProber in _body_probe_data[body]:
|
||||
if prober.collision_shape == shape:
|
||||
return prober
|
||||
return null
|
||||
|
||||
@warning_ignore("return_value_discarded")
|
||||
func _on_body_shape_entered(
|
||||
_body_rid: RID,
|
||||
body: Node3D,
|
||||
body_shape_index: int,
|
||||
_local_shape_index: int,
|
||||
) -> void:
|
||||
# # weird!
|
||||
if !is_instance_valid(body):
|
||||
if _body_probe_data.has(body):
|
||||
_body_probe_data.erase(body)
|
||||
return
|
||||
var shape := _get_collision_shape_node_in_body(body, body_shape_index)
|
||||
var body_probes : Array[VisionTestProber] = _body_probe_data.get_or_add(
|
||||
body, [] as Array[VisionTestProber]
|
||||
)
|
||||
|
||||
var has_prober := _get_prober_for_shape(shape, body)
|
||||
if !has_prober:
|
||||
body_probes.push_back(VisionTestProber.new(self, shape, body))
|
||||
else:
|
||||
push_warning("Already has prober")
|
||||
|
||||
@warning_ignore("return_value_discarded")
|
||||
func _on_body_shape_exited(
|
||||
_body_rid: RID,
|
||||
body: Node3D,
|
||||
body_shape_index: int,
|
||||
_local_shape_index: int,
|
||||
) -> void:
|
||||
if !body:
|
||||
return
|
||||
var shape := _get_collision_shape_node_in_body(body, body_shape_index)
|
||||
var prober := _get_prober_for_shape(shape, body)
|
||||
var body_probers : Array[VisionTestProber]= _body_probe_data[body]
|
||||
body_probers.erase(prober)
|
||||
if body_probers.is_empty():
|
||||
_body_probe_data.erase(body)
|
||||
|
||||
|
||||
#endregion VisionCone3D
|
||||
|
||||
class VisionTestProber:
|
||||
## Useful for debugging probes
|
||||
const CONTINUE_PROBING_ON_SUCCESS := false
|
||||
|
||||
## Vision cone to probe for
|
||||
var vision_cone : VisionCone3D
|
||||
## Collision shape to probe
|
||||
var collision_shape: CollisionShape3D
|
||||
## Collision shape mesh representation
|
||||
var shape_probe_mesh: ArrayMesh
|
||||
## Collision shape's owning body
|
||||
var body : PhysicsBody3D
|
||||
|
||||
## Whether the probe found the shape to be visible
|
||||
var visible: bool = false
|
||||
## All probe results, for debugging
|
||||
var probe_results: Array[ProbeResult]
|
||||
|
||||
static var _rng := RandomNumberGenerator.new()
|
||||
|
||||
func _init(
|
||||
p_vision_cone: VisionCone3D,
|
||||
p_collision_shape: CollisionShape3D,
|
||||
p_body: PhysicsBody3D
|
||||
) -> void:
|
||||
vision_cone = p_vision_cone
|
||||
collision_shape = p_collision_shape
|
||||
body = p_body
|
||||
|
||||
func _probe_position(to: Vector3, shape_local_target: Vector3) -> ProbeResult:
|
||||
# Collide with bodies OR the environment
|
||||
var raycast_collision_mask := vision_cone.collision_mask | vision_cone.collision_environment_mask
|
||||
# can store reference to this?
|
||||
var space_state := vision_cone.get_world_3d().direct_space_state
|
||||
var from := vision_cone.global_position
|
||||
var exclude_bodies := vision_cone.vision_test_ignore_bodies\
|
||||
.filter(func(x: PhysicsBody3D) -> bool: return is_instance_valid(x))\
|
||||
.map(func(x: PhysicsBody3D) -> RID: return x.get_rid())
|
||||
var query := PhysicsRayQueryParameters3D.create(
|
||||
from,
|
||||
to,
|
||||
raycast_collision_mask,
|
||||
exclude_bodies
|
||||
)
|
||||
var result := space_state.intersect_ray(query)
|
||||
return ProbeResult.new(
|
||||
from,
|
||||
to,
|
||||
shape_local_target,
|
||||
result.collider if result.has("collider") else null
|
||||
)
|
||||
|
||||
func _get_last_visible_point_on_shape() -> Vector3:
|
||||
if probe_results.is_empty():
|
||||
push_warning("Shape was not determined to be visible during last _probe_position")
|
||||
|
||||
return Vector3.ZERO
|
||||
return probe_results[-1].shape_local_target
|
||||
|
||||
func _random_points_on_probe_mesh(count: int) -> PackedVector3Array:
|
||||
if !shape_probe_mesh:
|
||||
shape_probe_mesh = collision_shape.shape.get_debug_mesh()
|
||||
var vertices : PackedVector3Array = shape_probe_mesh.surface_get_arrays(0)[Mesh.ARRAY_VERTEX]
|
||||
var points : PackedVector3Array = []
|
||||
for point in count:
|
||||
points.push_back(vertices[_rng.randi_range(0, vertices.size() - 1)])
|
||||
return points
|
||||
|
||||
func _get_scatter_points(count: int) -> PackedVector3Array:
|
||||
var sample_points : PackedVector3Array = []
|
||||
# var random_point_count := vision_cone.vision_test_shape_max_probe_count
|
||||
sample_points.append_array(_random_points_on_probe_mesh(count))
|
||||
return sample_points
|
||||
|
||||
func _get_collide_points(count: int) -> PackedVector3Array:
|
||||
var sample_points : PackedVector3Array = []
|
||||
# var cone_shape := vision_cone._collision_shape.shape
|
||||
var observable_shape := collision_shape.shape
|
||||
var query := PhysicsShapeQueryParameters3D.new()
|
||||
query.collide_with_areas = true
|
||||
query.collide_with_bodies = false
|
||||
query.collision_mask = vision_cone.collision_layer
|
||||
query.shape_rid = observable_shape.get_rid()
|
||||
|
||||
var world_space := vision_cone.get_world_3d().direct_space_state
|
||||
var result := world_space.collide_shape(query)
|
||||
for i in result.size():
|
||||
if i % 2 == 1:
|
||||
continue
|
||||
sample_points.push_back(result[i])
|
||||
if sample_points.size() >= count:
|
||||
break
|
||||
return sample_points
|
||||
|
||||
func probe() -> void:
|
||||
var sample_points : PackedVector3Array = []
|
||||
var max_count := vision_cone.vision_test_shape_max_probe_count
|
||||
if visible:
|
||||
sample_points.append(_get_last_visible_point_on_shape())
|
||||
max_count -= 1
|
||||
match vision_cone.vision_test_mode:
|
||||
VisionTestMode.SAMPLE_CENTER:
|
||||
if !visible:
|
||||
sample_points.push_back(Vector3.ZERO)
|
||||
VisionTestMode.SAMPLE_RANDOM_VERTICES:
|
||||
sample_points.append_array(_get_scatter_points(max_count))
|
||||
|
||||
probe_results = []
|
||||
visible = false
|
||||
for shape_local_point in sample_points:
|
||||
var global_point := collision_shape.global_position +\
|
||||
(collision_shape.global_basis * shape_local_point)
|
||||
|
||||
if !vision_cone.point_within_cone(global_point):
|
||||
continue
|
||||
|
||||
var probe_result := _probe_position(global_point, shape_local_point)
|
||||
probe_results.push_back(probe_result)
|
||||
|
||||
# found body we were looking for
|
||||
if probe_result.collider == body:
|
||||
probe_result.visible = true
|
||||
visible = true
|
||||
if CONTINUE_PROBING_ON_SUCCESS:
|
||||
print_debug("visible - continuing to _probe_position")
|
||||
continue
|
||||
return
|
||||
|
||||
class ProbeResult:
|
||||
var start : Vector3
|
||||
var end : Vector3
|
||||
var shape_local_target : Vector3
|
||||
var collider : Node3D
|
||||
var visible : bool = false
|
||||
|
||||
func _init(
|
||||
p_start: Vector3,
|
||||
p_end: Vector3,
|
||||
p_shape_local_target: Vector3,
|
||||
p_collider: Node3D
|
||||
) -> void:
|
||||
start = p_start
|
||||
end = p_end
|
||||
shape_local_target = p_shape_local_target
|
||||
collider = p_collider
|
||||
1
addons/tattomoosa.vision_cone_3d/src/VisionCone3D.gd.uid
Normal file
1
addons/tattomoosa.vision_cone_3d/src/VisionCone3D.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cmgcelj1qxg8o
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
extends Node3D
|
||||
|
||||
const ProbeResult := VisionCone3D.VisionTestProber.ProbeResult
|
||||
|
||||
# TODO should be modifiable via EditorSettings
|
||||
const DEBUG_VISION_CONE_COLOR := Color(1, 1, 0, 0.02)
|
||||
# TODO should be modifiable via EditorSettings
|
||||
const DEBUG_RAY_COLOR_IS_VISIBLE := Color(Color.GREEN, 0.8)
|
||||
# TODO should be modifiable via EditorSettings
|
||||
const DEBUG_RAY_COLOR_IS_OBSTRUCTED := Color(Color.RED, 0.4)
|
||||
|
||||
@export var vision_cone : VisionCone3D
|
||||
|
||||
var debug_vision_cone_color := DEBUG_VISION_CONE_COLOR
|
||||
var debug_ray_color_is_visible := DEBUG_RAY_COLOR_IS_VISIBLE
|
||||
var debug_ray_color_in_cone := DEBUG_RAY_COLOR_IS_OBSTRUCTED
|
||||
|
||||
|
||||
var _bounds_renderer : MeshInstance3D
|
||||
var _probe_renderer : DebugProbeLineRenderer
|
||||
|
||||
func _init() -> void:
|
||||
# create cone renderer
|
||||
_bounds_renderer = MeshInstance3D.new()
|
||||
var mesh := CylinderMesh.new()
|
||||
mesh.material = make_visualizer_material()
|
||||
_bounds_renderer.mesh = mesh
|
||||
add_child(_bounds_renderer, false, INTERNAL_MODE_BACK)
|
||||
|
||||
_probe_renderer = DebugProbeLineRenderer.new()
|
||||
_probe_renderer.probe_success_material = make_visualizer_material(debug_ray_color_is_visible)
|
||||
_probe_renderer.probe_failure_material = make_visualizer_material(debug_ray_color_in_cone)
|
||||
add_child(_probe_renderer)
|
||||
|
||||
@warning_ignore("return_value_discarded")
|
||||
func _ready() -> void:
|
||||
vision_cone = get_parent()
|
||||
_probe_renderer.body_probe_data = vision_cone._body_probe_data
|
||||
vision_cone.shape_changed.connect(update_cone_shape)
|
||||
update_cone_shape()
|
||||
|
||||
func make_visualizer_material(albedo_color: Color = debug_vision_cone_color) -> StandardMaterial3D:
|
||||
var mat := StandardMaterial3D.new()
|
||||
mat.albedo_color = albedo_color
|
||||
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||
return mat
|
||||
|
||||
func update_cone_shape() -> void:
|
||||
var m : CylinderMesh = _bounds_renderer.mesh
|
||||
m.top_radius = 0
|
||||
m.bottom_radius = vision_cone.end_radius
|
||||
m.height = vision_cone.range
|
||||
_bounds_renderer.rotation_degrees = Vector3(90, 0, 0)
|
||||
_bounds_renderer.position.z = -vision_cone.range / 2
|
||||
|
||||
class DebugProbeLineRenderer extends MeshInstance3D:
|
||||
var body_probe_data: Dictionary
|
||||
var probe_success_material : StandardMaterial3D
|
||||
var probe_failure_material : StandardMaterial3D
|
||||
|
||||
func _init() -> void:
|
||||
mesh = ImmediateMesh.new()
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
(mesh as ImmediateMesh).clear_surfaces()
|
||||
if body_probe_data.is_empty():
|
||||
return
|
||||
var successful : Array[ProbeResult] = []
|
||||
var failed : Array[ProbeResult] = []
|
||||
|
||||
for prober_list : Array[VisionCone3D.VisionTestProber] in body_probe_data.values():
|
||||
for prober in prober_list:
|
||||
for probe in prober.probe_results:
|
||||
if probe.visible:
|
||||
successful.push_back(probe)
|
||||
else:
|
||||
failed.push_back(probe)
|
||||
|
||||
var material_index := 0
|
||||
if !successful.is_empty():
|
||||
_add_probe_lines_surface(successful)
|
||||
mesh.surface_set_material(material_index, probe_success_material)
|
||||
material_index += 1
|
||||
if !failed.is_empty():
|
||||
_add_probe_lines_surface(failed)
|
||||
mesh.surface_set_material(material_index, probe_failure_material)
|
||||
material_index += 1
|
||||
|
||||
func _add_probe_lines_surface(probes: Array[ProbeResult]) -> void:
|
||||
var imesh := mesh as ImmediateMesh
|
||||
imesh.surface_begin(Mesh.PRIMITIVE_LINES)
|
||||
for probe in probes:
|
||||
imesh.surface_add_vertex(to_local(probe.start))
|
||||
imesh.surface_add_vertex(to_local(probe.end))
|
||||
imesh.surface_end()
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://8mi2so0m8lyx
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
extends EditorNode3DGizmoPlugin
|
||||
|
||||
var texture : Texture2D = preload("../../icons/GizmoVisionCone.svg")
|
||||
var undo_redo: EditorUndoRedoManager
|
||||
|
||||
var _start_drag_mouse_world_position : Vector3
|
||||
var _start_drag_range: float
|
||||
var _start_drag_angle : float
|
||||
|
||||
func _init() -> void:
|
||||
create_material("cone_preview", Color(1, 1, 0), false)
|
||||
create_handle_material("handles")
|
||||
create_icon_material(
|
||||
"icon",
|
||||
texture,
|
||||
)
|
||||
|
||||
func _get_gizmo_name() -> String:
|
||||
return "VisionCone3D"
|
||||
|
||||
func _get_handle_name(
|
||||
_gizmo: EditorNode3DGizmo,
|
||||
handle_id: int,
|
||||
_secondary: bool
|
||||
) -> String:
|
||||
match handle_id:
|
||||
0: return "Range"
|
||||
1: return "Angle"
|
||||
_: return ""
|
||||
|
||||
func _get_handle_value(
|
||||
gizmo: EditorNode3DGizmo,
|
||||
handle_id: int,
|
||||
_secondary: bool
|
||||
) -> Variant:
|
||||
var vc : VisionCone3D = gizmo.get_node_3d()
|
||||
match handle_id:
|
||||
0: return vc.range
|
||||
1: return vc.angle
|
||||
_: return null
|
||||
|
||||
func _begin_handle_action(
|
||||
gizmo: EditorNode3DGizmo,
|
||||
handle_id: int,
|
||||
_secondary: bool
|
||||
) -> void:
|
||||
var vc : VisionCone3D = gizmo.get_node_3d()
|
||||
_start_drag_mouse_world_position = vc.global_position + (-vc.global_basis.z * vc.range)
|
||||
match handle_id:
|
||||
0: # range
|
||||
_start_drag_range = vc.range
|
||||
1: # angle
|
||||
_start_drag_angle = vc.angle
|
||||
|
||||
func _commit_handle(
|
||||
gizmo: EditorNode3DGizmo,
|
||||
handle_id: int,
|
||||
_secondary: bool,
|
||||
_restore: Variant,
|
||||
# TODO use cancel
|
||||
_cancel: bool
|
||||
) -> void:
|
||||
var vc : VisionCone3D = gizmo.get_node_3d()
|
||||
match handle_id:
|
||||
0: # range
|
||||
undo_redo.create_action("Set range")
|
||||
undo_redo.add_do_property(vc, "range", vc.range)
|
||||
undo_redo.add_undo_property(vc, "range", _start_drag_range)
|
||||
1: # angle
|
||||
undo_redo.create_action("Set angle")
|
||||
undo_redo.add_do_property(vc, "angle", vc.angle)
|
||||
undo_redo.add_undo_property(vc, "angle", _start_drag_angle)
|
||||
undo_redo.commit_action()
|
||||
|
||||
func _set_handle(
|
||||
gizmo: EditorNode3DGizmo,
|
||||
handle_id: int,
|
||||
_secondary: bool,
|
||||
camera: Camera3D,
|
||||
_screen_pos: Vector2,
|
||||
) -> void:
|
||||
var vc : VisionCone3D = gizmo.get_node_3d()
|
||||
match handle_id:
|
||||
0: # range
|
||||
# TODO this mostly works but not if camera.y is near vc.y
|
||||
var world_pos := _calculate_mouse_world_position(
|
||||
camera,
|
||||
vc.global_position.y,
|
||||
Vector3.UP
|
||||
)
|
||||
var local_pos := vc.to_local(world_pos)
|
||||
var new_range := -local_pos.z
|
||||
if new_range > 0:
|
||||
vc.range = new_range
|
||||
|
||||
1: # angle
|
||||
# var local_end_range_pos := Vector3(0, 0, -vc.range)
|
||||
|
||||
# TODO this mostly works but not if camera.y is near vc.y
|
||||
var world_pos := _calculate_mouse_world_position(
|
||||
camera,
|
||||
vc.global_position.y,
|
||||
Vector3.UP
|
||||
)
|
||||
var local_pos := vc.to_local(world_pos)
|
||||
var radius := local_pos.x
|
||||
vc.angle = abs(rad_to_deg(atan(radius / vc.range))) * 2
|
||||
gizmo.get_node_3d().update_gizmos()
|
||||
|
||||
func _has_gizmo(node: Node3D) -> bool:
|
||||
return node is VisionCone3D
|
||||
|
||||
func _redraw(gizmo: EditorNode3DGizmo) -> void:
|
||||
gizmo.clear()
|
||||
var vc : VisionCone3D = gizmo.get_node_3d()
|
||||
|
||||
gizmo.add_unscaled_billboard(get_material("icon", gizmo), 0.04)
|
||||
|
||||
var lines := _make_cone_lines(360, 6, vc.end_radius, vc.range)
|
||||
# var cylinder_mesh := CylinderMesh.new()
|
||||
|
||||
var handles := PackedVector3Array([
|
||||
Vector3(0, 0, -vc.range),
|
||||
Vector3(vc.end_radius, 0, -vc.range)
|
||||
])
|
||||
|
||||
var cone_alpha := 1.0
|
||||
|
||||
if EditorInterface.get_selection().get_selected_nodes().has(vc):
|
||||
gizmo.add_lines(lines, get_material("cone_preview", gizmo), false, Color(1, 1, 1, cone_alpha))
|
||||
gizmo.add_handles(handles, get_material("handles", gizmo), [])
|
||||
|
||||
@warning_ignore("shadowed_global_identifier")
|
||||
@warning_ignore("return_value_discarded")
|
||||
@warning_ignore("integer_division")
|
||||
func _make_cone_lines(
|
||||
resolution: int,
|
||||
support_resolution: int,
|
||||
end_radius: float,
|
||||
range: float
|
||||
) -> PackedVector3Array:
|
||||
var points: PackedVector3Array = []
|
||||
var support_every := resolution / support_resolution
|
||||
var start : Vector3
|
||||
for i in resolution:
|
||||
# circle logic
|
||||
var angle := float(i) * TAU / resolution
|
||||
var x := cos(angle) * end_radius
|
||||
var y := sin(angle) * end_radius
|
||||
var point := Vector3(x, y, -range)
|
||||
points.append(point)
|
||||
|
||||
if i % support_every == 0:
|
||||
points.append(Vector3.ZERO)
|
||||
points.append(point)
|
||||
|
||||
if i == 0:
|
||||
start = point
|
||||
else:
|
||||
points.append(point)
|
||||
points.append(start)
|
||||
points.append(Vector3.ZERO)
|
||||
points.append(Vector3(0, 0, -range))
|
||||
return points
|
||||
|
||||
static func _calculate_mouse_world_position(
|
||||
camera: Camera3D,
|
||||
# world position along plane normal, could use a better name
|
||||
intersection_point: float,
|
||||
plane_normal: Vector3 = Vector3.UP
|
||||
) -> Vector3:
|
||||
var position := camera.get_viewport().get_mouse_position()
|
||||
var camera_from := camera.project_ray_origin(position)
|
||||
var camera_to := camera.project_ray_normal(position)
|
||||
|
||||
var n := plane_normal # plane normal
|
||||
var p := camera_from # ray origin
|
||||
var v := camera_to # ray direction
|
||||
var d := intersection_point # distance of the plane from origin
|
||||
var t := -(n.dot(p) - d) / n.dot(v) # solving for plain/ray intersection
|
||||
|
||||
return p + t * v
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://b3snj0jopsyp1
|
||||
|
|
@ -164,7 +164,7 @@ movie_writer/movie_file="D:/Maddo/Recordings/Capture.avi"
|
|||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/cyclops_level_builder/plugin.cfg", "res://addons/dialogic/plugin.cfg", "res://addons/func_godot/plugin.cfg", "res://addons/godot_test_scene/plugin.cfg", "res://addons/resources_spreadsheet_view/plugin.cfg", "res://addons/scene_palette/plugin.cfg", "res://addons/smoothing/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/cyclops_level_builder/plugin.cfg", "res://addons/dialogic/plugin.cfg", "res://addons/func_godot/plugin.cfg", "res://addons/godot_test_scene/plugin.cfg", "res://addons/resources_spreadsheet_view/plugin.cfg", "res://addons/scene_palette/plugin.cfg", "res://addons/smoothing/plugin.cfg", "res://addons/tattomoosa.vision_cone_3d/plugin.cfg")
|
||||
|
||||
[global_group]
|
||||
|
||||
|
|
|
|||
BIN
textures/special/trigger.png
(Stored with Git LFS)
BIN
textures/special/trigger.png
(Stored with Git LFS)
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue