diff --git a/addons/shaker/assets/Pause.svg b/addons/shaker/assets/Pause.svg new file mode 100644 index 00000000..5b720e01 --- /dev/null +++ b/addons/shaker/assets/Pause.svg @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/Pause.svg.import b/addons/shaker/assets/Pause.svg.import new file mode 100644 index 00000000..a563f3c2 --- /dev/null +++ b/addons/shaker/assets/Pause.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gdl502i1v8r0" +path="res://.godot/imported/Pause.svg-bf8a05fc34af72ad423e24582ebdfe77.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/Pause.svg" +dest_files=["res://.godot/imported/Pause.svg-bf8a05fc34af72ad423e24582ebdfe77.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/Play.svg b/addons/shaker/assets/Play.svg new file mode 100644 index 00000000..c0148f3c --- /dev/null +++ b/addons/shaker/assets/Play.svg @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/Play.svg.import b/addons/shaker/assets/Play.svg.import new file mode 100644 index 00000000..bc11ba59 --- /dev/null +++ b/addons/shaker/assets/Play.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bkiomqdsxl5am" +path="res://.godot/imported/Play.svg-7dc254fbb0920cfd077cd3ee6c205a32.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/Play.svg" +dest_files=["res://.godot/imported/Play.svg-7dc254fbb0920cfd077cd3ee6c205a32.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShaderPreset.svg.import b/addons/shaker/assets/ShaderPreset.svg.import new file mode 100644 index 00000000..af1974b2 --- /dev/null +++ b/addons/shaker/assets/ShaderPreset.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhcslgdhamqy2" +path="res://.godot/imported/ShaderPreset.svg-baad8a708c9f1500bbd83c441bef7504.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShaderPreset.svg" +dest_files=["res://.godot/imported/ShaderPreset.svg-baad8a708c9f1500bbd83c441bef7504.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakeTypeBase.svg.import b/addons/shaker/assets/ShakeTypeBase.svg.import new file mode 100644 index 00000000..e31e7072 --- /dev/null +++ b/addons/shaker/assets/ShakeTypeBase.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ds3kdjxwpmo1g" +path="res://.godot/imported/ShakeTypeBase.svg-a9a71023b460c004e6d4f7703e2899c5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakeTypeBase.svg" +dest_files=["res://.godot/imported/ShakeTypeBase.svg-a9a71023b460c004e6d4f7703e2899c5.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=0.12 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/Shaker.svg b/addons/shaker/assets/Shaker.svg new file mode 100644 index 00000000..6e5ba215 --- /dev/null +++ b/addons/shaker/assets/Shaker.svg @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/Shaker.svg.import b/addons/shaker/assets/Shaker.svg.import new file mode 100644 index 00000000..8a7a3d54 --- /dev/null +++ b/addons/shaker/assets/Shaker.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbffv1avjrgvs" +path="res://.godot/imported/Shaker.svg-c2d9686bdc2ea03ed737291e31637bc9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/Shaker.svg" +dest_files=["res://.godot/imported/Shaker.svg-c2d9686bdc2ea03ed737291e31637bc9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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=4.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/Shaker2D.svg b/addons/shaker/assets/Shaker2D.svg new file mode 100644 index 00000000..20ba9f9b --- /dev/null +++ b/addons/shaker/assets/Shaker2D.svg @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/Shaker2D.svg.import b/addons/shaker/assets/Shaker2D.svg.import new file mode 100644 index 00000000..7367279d --- /dev/null +++ b/addons/shaker/assets/Shaker2D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dn8xxp7r67as3" +path="res://.godot/imported/Shaker2D.svg-a5c6b73315dff06dec7bf743af8bf0a9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/Shaker2D.svg" +dest_files=["res://.godot/imported/Shaker2D.svg-a5c6b73315dff06dec7bf743af8bf0a9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/Shaker3D.svg b/addons/shaker/assets/Shaker3D.svg new file mode 100644 index 00000000..fcfa230d --- /dev/null +++ b/addons/shaker/assets/Shaker3D.svg @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/Shaker3D.svg.import b/addons/shaker/assets/Shaker3D.svg.import new file mode 100644 index 00000000..0b634a3b --- /dev/null +++ b/addons/shaker/assets/Shaker3D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dm4yc7w77q1u8" +path="res://.godot/imported/Shaker3D.svg-ed425183c69b0c043ce3ce5088c6ff49.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/Shaker3D.svg" +dest_files=["res://.godot/imported/Shaker3D.svg-ed425183c69b0c043ce3ce5088c6ff49.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerEmitter.svg b/addons/shaker/assets/ShakerEmitter.svg new file mode 100644 index 00000000..466356b4 --- /dev/null +++ b/addons/shaker/assets/ShakerEmitter.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerEmitter.svg.import b/addons/shaker/assets/ShakerEmitter.svg.import new file mode 100644 index 00000000..42b31289 --- /dev/null +++ b/addons/shaker/assets/ShakerEmitter.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://do6o8aob6hi6v" +path="res://.godot/imported/ShakerEmitter.svg-99409f1c9ef4b7c7de1c60cac5619af4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerEmitter.svg" +dest_files=["res://.godot/imported/ShakerEmitter.svg-99409f1c9ef4b7c7de1c60cac5619af4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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=4.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerEmitter2D.svg b/addons/shaker/assets/ShakerEmitter2D.svg new file mode 100644 index 00000000..62f7f5fd --- /dev/null +++ b/addons/shaker/assets/ShakerEmitter2D.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerEmitter2D.svg.import b/addons/shaker/assets/ShakerEmitter2D.svg.import new file mode 100644 index 00000000..bbade203 --- /dev/null +++ b/addons/shaker/assets/ShakerEmitter2D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://blvoltt74gide" +path="res://.godot/imported/ShakerEmitter2D.svg-8c956d5aa03f14ce38dd1438d858114a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerEmitter2D.svg" +dest_files=["res://.godot/imported/ShakerEmitter2D.svg-8c956d5aa03f14ce38dd1438d858114a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerEmitter3D.svg b/addons/shaker/assets/ShakerEmitter3D.svg new file mode 100644 index 00000000..73359d51 --- /dev/null +++ b/addons/shaker/assets/ShakerEmitter3D.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerEmitter3D.svg.import b/addons/shaker/assets/ShakerEmitter3D.svg.import new file mode 100644 index 00000000..bbbf5eda --- /dev/null +++ b/addons/shaker/assets/ShakerEmitter3D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbu31ogcp75bh" +path="res://.godot/imported/ShakerEmitter3D.svg-b7aef419023b93692d18599c57d2046e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerEmitter3D.svg" +dest_files=["res://.godot/imported/ShakerEmitter3D.svg-b7aef419023b93692d18599c57d2046e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerPreset.svg b/addons/shaker/assets/ShakerPreset.svg new file mode 100644 index 00000000..43c82936 --- /dev/null +++ b/addons/shaker/assets/ShakerPreset.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerPreset.svg.import b/addons/shaker/assets/ShakerPreset.svg.import new file mode 100644 index 00000000..23bda4ac --- /dev/null +++ b/addons/shaker/assets/ShakerPreset.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://24qdtwt14uiu" +path="res://.godot/imported/ShakerPreset.svg-e4c67cf03c32289efa8dece68a179055.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerPreset.svg" +dest_files=["res://.godot/imported/ShakerPreset.svg-e4c67cf03c32289efa8dece68a179055.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerPreset2D.svg b/addons/shaker/assets/ShakerPreset2D.svg new file mode 100644 index 00000000..090a93a9 --- /dev/null +++ b/addons/shaker/assets/ShakerPreset2D.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerPreset2D.svg.import b/addons/shaker/assets/ShakerPreset2D.svg.import new file mode 100644 index 00000000..403f3e29 --- /dev/null +++ b/addons/shaker/assets/ShakerPreset2D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dkyto2qkh0a2h" +path="res://.godot/imported/ShakerPreset2D.svg-dda8f976490b38216c486a3c325a6e1c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerPreset2D.svg" +dest_files=["res://.godot/imported/ShakerPreset2D.svg-dda8f976490b38216c486a3c325a6e1c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerPreset3D.svg b/addons/shaker/assets/ShakerPreset3D.svg new file mode 100644 index 00000000..39fbda6a --- /dev/null +++ b/addons/shaker/assets/ShakerPreset3D.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerPreset3D.svg.import b/addons/shaker/assets/ShakerPreset3D.svg.import new file mode 100644 index 00000000..22ca476b --- /dev/null +++ b/addons/shaker/assets/ShakerPreset3D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://3461bedpoktj" +path="res://.godot/imported/ShakerPreset3D.svg-ac15877b6c78545ef46f5ca5bf99cede.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerPreset3D.svg" +dest_files=["res://.godot/imported/ShakerPreset3D.svg-ac15877b6c78545ef46f5ca5bf99cede.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerReceiver.svg b/addons/shaker/assets/ShakerReceiver.svg new file mode 100644 index 00000000..b4029d4c --- /dev/null +++ b/addons/shaker/assets/ShakerReceiver.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerReceiver.svg.import b/addons/shaker/assets/ShakerReceiver.svg.import new file mode 100644 index 00000000..a25a0020 --- /dev/null +++ b/addons/shaker/assets/ShakerReceiver.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://5ubwmsna8qv3" +path="res://.godot/imported/ShakerReceiver.svg-8fa75e085c3c726d592ed5236376746f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerReceiver.svg" +dest_files=["res://.godot/imported/ShakerReceiver.svg-8fa75e085c3c726d592ed5236376746f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerReceiver2D.svg b/addons/shaker/assets/ShakerReceiver2D.svg new file mode 100644 index 00000000..e20c9b0b --- /dev/null +++ b/addons/shaker/assets/ShakerReceiver2D.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerReceiver2D.svg.import b/addons/shaker/assets/ShakerReceiver2D.svg.import new file mode 100644 index 00000000..9f51f6c0 --- /dev/null +++ b/addons/shaker/assets/ShakerReceiver2D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bu1om2nm428ec" +path="res://.godot/imported/ShakerReceiver2D.svg-99072f9033b4ac51b75a8e8f089f2f8c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerReceiver2D.svg" +dest_files=["res://.godot/imported/ShakerReceiver2D.svg-99072f9033b4ac51b75a8e8f089f2f8c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerReceiver3D.svg b/addons/shaker/assets/ShakerReceiver3D.svg new file mode 100644 index 00000000..82c325aa --- /dev/null +++ b/addons/shaker/assets/ShakerReceiver3D.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerReceiver3D.svg.import b/addons/shaker/assets/ShakerReceiver3D.svg.import new file mode 100644 index 00000000..1289fd32 --- /dev/null +++ b/addons/shaker/assets/ShakerReceiver3D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bfwyj7gf187kd" +path="res://.godot/imported/ShakerReceiver3D.svg-1cf90100ef9bf3dbbc6653627fdab7fc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerReceiver3D.svg" +dest_files=["res://.godot/imported/ShakerReceiver3D.svg-1cf90100ef9bf3dbbc6653627fdab7fc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerType.svg b/addons/shaker/assets/ShakerType.svg new file mode 100644 index 00000000..a172e84d --- /dev/null +++ b/addons/shaker/assets/ShakerType.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerType.svg.import b/addons/shaker/assets/ShakerType.svg.import new file mode 100644 index 00000000..e7342339 --- /dev/null +++ b/addons/shaker/assets/ShakerType.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ch5mp344tqj3w" +path="res://.godot/imported/ShakerType.svg-0e40c87944ca8f10dcb4da67f37ccfdf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerType.svg" +dest_files=["res://.godot/imported/ShakerType.svg-0e40c87944ca8f10dcb4da67f37ccfdf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerType2D.svg b/addons/shaker/assets/ShakerType2D.svg new file mode 100644 index 00000000..01b9deb5 --- /dev/null +++ b/addons/shaker/assets/ShakerType2D.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerType2D.svg.import b/addons/shaker/assets/ShakerType2D.svg.import new file mode 100644 index 00000000..ddcab397 --- /dev/null +++ b/addons/shaker/assets/ShakerType2D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://caqg2nfs1y64r" +path="res://.godot/imported/ShakerType2D.svg-a5c5aa77a1e3263e925140c95a5a30c3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerType2D.svg" +dest_files=["res://.godot/imported/ShakerType2D.svg-a5c5aa77a1e3263e925140c95a5a30c3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/ShakerType3D.svg b/addons/shaker/assets/ShakerType3D.svg new file mode 100644 index 00000000..99b7eb16 --- /dev/null +++ b/addons/shaker/assets/ShakerType3D.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/ShakerType3D.svg.import b/addons/shaker/assets/ShakerType3D.svg.import new file mode 100644 index 00000000..c605f013 --- /dev/null +++ b/addons/shaker/assets/ShakerType3D.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dd7q87w4eoudf" +path="res://.godot/imported/ShakerType3D.svg-1bc2b24943aa01bcdaa956f9b08b254c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/ShakerType3D.svg" +dest_files=["res://.godot/imported/ShakerType3D.svg-1bc2b24943aa01bcdaa956f9b08b254c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/Stop.svg b/addons/shaker/assets/Stop.svg new file mode 100644 index 00000000..82c898cf --- /dev/null +++ b/addons/shaker/assets/Stop.svg @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/addons/shaker/assets/Stop.svg.import b/addons/shaker/assets/Stop.svg.import new file mode 100644 index 00000000..f0f73795 --- /dev/null +++ b/addons/shaker/assets/Stop.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://m45uspfna0ol" +path="res://.godot/imported/Stop.svg-ae1c54e343f70b570e088fac0e2ac232.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/Stop.svg" +dest_files=["res://.godot/imported/Stop.svg-ae1c54e343f70b570e088fac0e2ac232.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/shaker/assets/icon.png b/addons/shaker/assets/icon.png new file mode 100644 index 00000000..7ae824c0 --- /dev/null +++ b/addons/shaker/assets/icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b2633a59c816940b80d69d61b07a5568e764e464e80e7d9b735e5cdb08bd37f3 +size 19416 diff --git a/addons/shaker/assets/icon.png.import b/addons/shaker/assets/icon.png.import new file mode 100644 index 00000000..b6c8d3f9 --- /dev/null +++ b/addons/shaker/assets/icon.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://8m3nobyk16wm" +path="res://.godot/imported/icon.png-0661645ebcd1f259541e43f0afd1f280.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/shaker/assets/icon.png" +dest_files=["res://.godot/imported/icon.png-0661645ebcd1f259541e43f0afd1f280.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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 diff --git a/addons/shaker/data/BaseShakerType.gd b/addons/shaker/data/BaseShakerType.gd new file mode 100644 index 00000000..336c9cfe --- /dev/null +++ b/addons/shaker/data/BaseShakerType.gd @@ -0,0 +1,112 @@ +@icon("res://addons/shaker/assets/ShakerType.svg") +@tool +class_name ShakerTypeBase +extends Resource + +# Enumerations for blending modes and graph axes +enum BlendingModes { + Add, + Override, + Multiply, + Subtract, + Average, + Max, + Min +} + +# Shake Properties +@export_group("Shake Properties") +@export var BlendingMode: BlendingModes = BlendingModes.Add: + set = set_blending_mode, + get = get_blending_mode + +@export_exp_easing var fade_in: float = 0.0: + set = set_fade_in, + get = get_fade_in + +@export_exp_easing("attenuation") var fade_out: float = 0.0: + set = set_fade_out, + get = get_fade_out + +@export_range(0.0, 1.0) var start_percent: float = 0.0: + set = set_start_percent, + get = get_start_percent + +@export_range(0.0, 1.0) var end_percent: float = 1.0: + set = set_end_percent, + get = get_end_percent + +# Live Shake Graph +@export_group("Live Shake Graph") +@export var _temp_graph: bool = false + +@export_range(16, 96) var bake_internal: int = 64: + set = set_bake_internal, + get = get_bake_internal + +var duration = 0.0: + set = set_duration, + get = get_duration + +func _init(blending_mode:BlendingModes=BlendingModes.Add, fade_in:float=self.fade_in, fade_out:float=self.fade_out, start_percent:float=self.start_percent, end_percent:float=self.end_percent) -> void: + self.BlendingMode = blending_mode + self.fade_in = fade_in + self.fade_out = fade_out + self.start_percent = start_percent + self.end_percent = end_percent + +# Signals +signal property_changed(name: StringName) + +# Custom setter and getter functions +func set_blending_mode(value: BlendingModes) -> void: + BlendingMode = value + _on_property_changed("BlendingMode") + +func get_blending_mode() -> BlendingModes: + return BlendingMode + +func set_fade_in(value: float) -> void: + fade_in = value + _on_property_changed("fade_in") + +func get_fade_in() -> float: + return fade_in + +func set_fade_out(value: float) -> void: + fade_out = value + _on_property_changed("fade_out") + +func get_fade_out() -> float: + return fade_out + +func set_start_percent(value: float) -> void: + start_percent = min(value, end_percent) + _on_property_changed("start_percent") + +func get_start_percent() -> float: + return start_percent + +func set_end_percent(value: float) -> void: + end_percent = max(value, start_percent) + _on_property_changed("end_percent") + +func get_end_percent() -> float: + return end_percent + +func set_bake_internal(value: int) -> void: + bake_internal = clamp(value, 16, 96) + _on_property_changed("bake_internal") + +func get_bake_internal() -> int: + return bake_internal + +func set_duration(value: float = 0.0) -> void: + duration = value + +func get_duration() -> float: + return duration + +# Handle property changes +func _on_property_changed(property_name: StringName) -> void: + property_changed.emit(property_name) diff --git a/addons/shaker/data/BaseShakerType.gd.uid b/addons/shaker/data/BaseShakerType.gd.uid new file mode 100644 index 00000000..cb993e13 --- /dev/null +++ b/addons/shaker/data/BaseShakerType.gd.uid @@ -0,0 +1 @@ +uid://d2i321te0ny64 diff --git a/addons/shaker/data/ShakerPresetBase.gd b/addons/shaker/data/ShakerPresetBase.gd new file mode 100644 index 00000000..3444beec --- /dev/null +++ b/addons/shaker/data/ShakerPresetBase.gd @@ -0,0 +1,53 @@ +@tool +@icon("res://addons/shaker/assets/ShakerPreset.svg") +class_name ShakerPresetBase +extends Resource + +# Enum for shake categories +enum Categories { + POSITION, + ROTATION, + SCALE +} + +# Graph panel reference +var Graph: Panel + +# Bake internal setting +@export_range(16, 96) var bake_internal: int = 64: + set = set_bake_internal, + get = get_bake_internal + +# Follow timeline flag +@export var __follow_timeline: bool = false: + set = set_follow_timeline, + get = get_follow_timeline + +# Component duration and parent node +var component_duration: float = 0.0 +var parent: Node + +# Signal for property changes +signal property_changed(name: StringName) + +func set_bake_internal(value: int) -> void: + bake_internal = clamp(value, 16, 96) + _on_property_changed("bake_internal") + +func get_bake_internal() -> int: + return bake_internal + +func set_follow_timeline(value: bool) -> void: + __follow_timeline = value + _on_property_changed("__follow_timeline") + +func get_follow_timeline() -> bool: + return __follow_timeline + +# Handle property changes +func _on_property_changed(property_name: StringName) -> void: + property_changed.emit(property_name) + +# Calculate the difference between two arrays +func _array_difference(a: Array, b: Array) -> Array: + return b.filter(func(item): return not a.has(item)) diff --git a/addons/shaker/data/ShakerPresetBase.gd.uid b/addons/shaker/data/ShakerPresetBase.gd.uid new file mode 100644 index 00000000..01390867 --- /dev/null +++ b/addons/shaker/data/ShakerPresetBase.gd.uid @@ -0,0 +1 @@ +uid://cveqkhn5t8vng diff --git a/addons/shaker/data/ShakerProperty.gd b/addons/shaker/data/ShakerProperty.gd new file mode 100644 index 00000000..221dabca --- /dev/null +++ b/addons/shaker/data/ShakerProperty.gd @@ -0,0 +1,24 @@ +@tool +@icon("res://addons/shaker/assets/ShakerPreset.svg") +class_name ShakerProperty +extends Resource + +@export var property_name:String +# Properties +@export var shake_type:ShakerTypeBase + +# Signal for property changes +signal property_changed(name: StringName) + +func _init(property_name:String="", shake_type:ShakerTypeBase=null) -> void: + self.property_name = property_name + self.shake_type = shake_type + +# Handle property changes +func _on_property_changed(property_name: StringName) -> void: + property_changed.emit(property_name) + +func get_value(_t:float) -> Variant: + if shake_type: + return shake_type.get_value(_t) + return 0.0 diff --git a/addons/shaker/data/ShakerProperty.gd.uid b/addons/shaker/data/ShakerProperty.gd.uid new file mode 100644 index 00000000..22ec96d8 --- /dev/null +++ b/addons/shaker/data/ShakerProperty.gd.uid @@ -0,0 +1 @@ +uid://bd8eceas8jvyl diff --git a/addons/shaker/data/Single/BaseShakerType1D.gd b/addons/shaker/data/Single/BaseShakerType1D.gd new file mode 100644 index 00000000..2d4be567 --- /dev/null +++ b/addons/shaker/data/Single/BaseShakerType1D.gd @@ -0,0 +1,46 @@ +@icon("res://addons/shaker/assets/ShakerType.svg") +@tool +class_name ShakerTypeBase1D +extends ShakerTypeBase + +enum GraphAxis { + X, +} + +@export var amplitude:float = 1.0: + set = set_amplitude, + get = get_amplitude + +@export var offset:float = 0.0: + set = set_offset, + get = get_offset + +func set_amplitude(value: float) -> void: + amplitude = value + _on_property_changed("amplitude") + +func get_amplitude() -> float: + return amplitude + +func set_offset(value: float) -> void: + offset = value + _on_property_changed("offset") + +func get_offset() -> float: + return offset + +# Get the shake value at a given time +func get_value(t: float) -> float: + var result:float = 0.0; + return _calc_value(fmod(t, 1.0), result) + +# Calculate the shake value +func _calc_value(t: float, result: float) -> float: + if duration > 0: + t /= duration + if (start_percent != 0 && start_percent > t) || (end_percent != 1 && end_percent < t): + result = 0.0; + else: + result = result * amplitude + offset + result *= (ease(t, fade_in) if fade_in > 0.0001 else 1.0) * (ease(1.0 - t, fade_out) if fade_out > 0.0001 else 1.0) + return result; diff --git a/addons/shaker/data/Single/BaseShakerType1D.gd.uid b/addons/shaker/data/Single/BaseShakerType1D.gd.uid new file mode 100644 index 00000000..8e6e5bcf --- /dev/null +++ b/addons/shaker/data/Single/BaseShakerType1D.gd.uid @@ -0,0 +1 @@ +uid://bhqlklbhcxfgf diff --git a/addons/shaker/data/Single/ShakerTypeAudioBus1D.gd b/addons/shaker/data/Single/ShakerTypeAudioBus1D.gd new file mode 100644 index 00000000..4620c993 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeAudioBus1D.gd @@ -0,0 +1,43 @@ +@tool +class_name ShakerTypeAudioBus1D +extends ShakerTypeBase1D + +@export var bus_name:String = "Master": + set = set_bus_name, + get = get_bus_name +@export_range(20, 20000) var min_frequence:float = 20 +@export_range(20, 20000) var max_frequence:float = 20000 + +var bus_index:int = 0 +var effect:AudioEffectSpectrumAnalyzerInstance + +## Calculates the value of the square wave at time t. +func get_value(t: float) -> float: + var result:float = 0.0 + if effect: + var mag:Vector2 = effect.get_magnitude_for_frequency_range(min_frequence, max_frequence, AudioEffectSpectrumAnalyzerInstance.MAGNITUDE_MAX) + result = mag.length() + return _calc_value(t, result) + +func set_bus_name(value: String) -> void: + bus_name = value + _update_bus_index() + _on_property_changed("bus_name") + +func get_bus_name() -> String: + return bus_name + +func _update_bus_index() -> void: + bus_index = AudioServer.get_bus_index(bus_name) + if bus_index > -1: + for e in AudioServer.get_bus_effect_count(bus_index): + var _effect:AudioEffect = AudioServer.get_bus_effect(bus_index, e) + if _effect is AudioEffectSpectrumAnalyzer: + effect = AudioServer.get_bus_effect_instance(bus_index, e, 0) + break; + if effect == null: + AudioServer.add_bus_effect(bus_index, AudioEffectSpectrumAnalyzer.new(), 0) + effect = AudioServer.get_bus_effect_instance(bus_index, 0) + else: + push_error("Error: Bus '" + bus_name + "' not found!") + effect = null diff --git a/addons/shaker/data/Single/ShakerTypeAudioBus1D.gd.uid b/addons/shaker/data/Single/ShakerTypeAudioBus1D.gd.uid new file mode 100644 index 00000000..200f8d62 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeAudioBus1D.gd.uid @@ -0,0 +1 @@ +uid://dshti5xd41w07 diff --git a/addons/shaker/data/Single/ShakerTypeBrownianShake1D.gd b/addons/shaker/data/Single/ShakerTypeBrownianShake1D.gd new file mode 100644 index 00000000..504dca3e --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeBrownianShake1D.gd @@ -0,0 +1,42 @@ +@tool +class_name ShakerTypeBrownianShake1D +extends ShakerTypeBase1D + +@export var roughness:float = 1.0: + set = set_roughness, + get = get_roughness + +@export var persistence:float = 0.5: + set = set_persistence, + get = get_persistence + +var _generator: RandomNumberGenerator = RandomNumberGenerator.new() +var _last_pos:float = 0.0 + +func _init() -> void: + property_changed.connect(_property_changed) + +func get_value(t: float) -> float: + var result:float = 0.0 + result = (_last_pos + _generator.randf_range(-roughness, roughness)) + result = _calc_value(t, result) + + _last_pos = lerpf(_last_pos, result, 1.0 - persistence) + return _last_pos + +func _property_changed(name: StringName) -> void: + _last_pos = 0.0 + +func set_roughness(value: float) -> void: + roughness = value + _on_property_changed("roughness") + +func get_roughness() -> float: + return roughness + +func set_persistence(value: float) -> void: + persistence = clamp(persistence,0, 1) + _on_property_changed("persistence") + +func get_persistence() -> float: + return persistence diff --git a/addons/shaker/data/Single/ShakerTypeBrownianShake1D.gd.uid b/addons/shaker/data/Single/ShakerTypeBrownianShake1D.gd.uid new file mode 100644 index 00000000..418ea2dd --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeBrownianShake1D.gd.uid @@ -0,0 +1 @@ +uid://62yumjskyeow diff --git a/addons/shaker/data/Single/ShakerTypeCurve1D.gd b/addons/shaker/data/Single/ShakerTypeCurve1D.gd new file mode 100644 index 00000000..ea914745 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeCurve1D.gd @@ -0,0 +1,41 @@ +@tool +class_name ShakerTypeCurve1D +extends ShakerTypeBase1D + +@export var curve: Curve: + set = set_curve, + get = get_curve + +@export var loop: bool = true: + set = set_loop, + get = get_loop + +func _curve_changed() -> void: + _on_property_changed("curve") + +func get_value(t: float) -> float: + var result: float = 0.0 + if loop && t > 1.0: + t = fmod(t, 1.0) + if curve: + result = curve.sample(t) + + return _calc_value(t, result) + +func set_curve(value: Curve) -> void: + if curve: + curve.changed.disconnect(_curve_changed) + curve = value + if curve: + curve.changed.connect(_curve_changed) + else: + _curve_changed() +func get_curve() -> Curve: + return curve + +func set_loop(value: bool) -> void: + loop = value + _on_property_changed("loop") + +func get_loop() -> bool: + return loop diff --git a/addons/shaker/data/Single/ShakerTypeCurve1D.gd.uid b/addons/shaker/data/Single/ShakerTypeCurve1D.gd.uid new file mode 100644 index 00000000..04399af2 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeCurve1D.gd.uid @@ -0,0 +1 @@ +uid://dadkdm3tvmuqq diff --git a/addons/shaker/data/Single/ShakerTypeNoiseShake1D.gd b/addons/shaker/data/Single/ShakerTypeNoiseShake1D.gd new file mode 100644 index 00000000..758f44aa --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeNoiseShake1D.gd @@ -0,0 +1,32 @@ +@tool +class_name ShakerTypeNoiseShake1D +extends ShakerTypeBase1D + +@export var noise_texture: NoiseTexture2D = NoiseTexture2D.new(): + set = set_noise_texture, + get = get_noise_texture + +func _init() -> void: + noise_texture.changed.connect(_on_noise_changed) + +func get_value(t: float) -> float: + var result:float = 0.0 + if noise_texture && noise_texture.noise: + var noise_size:Vector2 = Vector2(noise_texture.width, noise_texture.height) + var noise_offset:float = t * noise_size.x + result = noise_texture.noise.get_noise_1d(noise_offset) + result *= 2.0 + return _calc_value(t, result) + +func _on_noise_changed() -> void: + _on_property_changed("noise_texture") + +func set_noise_texture(value: NoiseTexture2D) -> void: + if noise_texture: + noise_texture.changed.disconnect(_on_noise_changed) + noise_texture = value + if noise_texture: + noise_texture.changed.connect(_on_noise_changed) + +func get_noise_texture() -> NoiseTexture2D: + return noise_texture diff --git a/addons/shaker/data/Single/ShakerTypeNoiseShake1D.gd.uid b/addons/shaker/data/Single/ShakerTypeNoiseShake1D.gd.uid new file mode 100644 index 00000000..9328b4a4 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeNoiseShake1D.gd.uid @@ -0,0 +1 @@ +uid://bdrk4rkut1y3l diff --git a/addons/shaker/data/Single/ShakerTypeRandom1D.gd b/addons/shaker/data/Single/ShakerTypeRandom1D.gd new file mode 100644 index 00000000..727965f2 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeRandom1D.gd @@ -0,0 +1,30 @@ +@tool +class_name ShakerTypeRandom1D +extends ShakerTypeBase1D + +## The seed for the random number generator. +@export var seed: int = 0: + set = set_seed + +## The random number generator instance. +var _generator: RandomNumberGenerator = RandomNumberGenerator.new() + +## Initializes the shake type with the given seed. +func _init() -> void: + set_seed(seed) + +## Calculates a random value for each axis at time t. +func get_value(t: float) -> float: + var result:float = 0.0 + result = _generator.randf_range(-1.0, 1.0) + return _calc_value(t, result) + +## Sets the seed for the random number generator. +func set_seed(value: int) -> void: + seed = value + _generator.seed = seed + _on_property_changed("seed") + +## Gets the current seed of the random number generator. +func get_seed() -> int: + return seed diff --git a/addons/shaker/data/Single/ShakerTypeRandom1D.gd.uid b/addons/shaker/data/Single/ShakerTypeRandom1D.gd.uid new file mode 100644 index 00000000..3112efa7 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeRandom1D.gd.uid @@ -0,0 +1 @@ +uid://buor2ix0dmwk2 diff --git a/addons/shaker/data/Single/ShakerTypeSawtoothWave1D.gd b/addons/shaker/data/Single/ShakerTypeSawtoothWave1D.gd new file mode 100644 index 00000000..abb0be9c --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeSawtoothWave1D.gd @@ -0,0 +1,41 @@ +@tool +class_name ShakerTypeSawtoothWave1D +extends ShakerTypeBase1D + +## The frequency of the sawtooth wave for each axis. +@export var frequency:float = 5.0: + set = set_frequency + +## The asymmetry of the sawtooth wave for each axis (0 to 1). +@export var asymmetry:float = 0.5: + set = set_asymmetry + +## Sets the frequency of the sawtooth wave. +func set_frequency(value: float) -> void: + frequency = value + _on_property_changed("frequency") + +## Gets the frequency of the sawtooth wave. +func get_frequency() -> float: + return frequency + +## Sets the asymmetry of the sawtooth wave. +func set_asymmetry(value: float) -> void: + asymmetry = clamp(value, 0.0, 0.0) + _on_property_changed("asymmetry") + +## Gets the asymmetry of the sawtooth wave. +func get_asymmetry() -> float: + return asymmetry + +## Calculates the value of the sawtooth wave at time t. +func get_value(t: float) -> float: + var result:float = 0.0 + var _real_time:float = fmod(t, 1.0) if t > 1.0 else t + var wave:float = fmod(_real_time * frequency, 1.0) + + wave = wave / asymmetry if wave < asymmetry else (1.0 - wave) / (1.0 - asymmetry) + result = wave + result = _calc_value(t, result) + result = (result - amplitude * 0.5) * 2.0 + return result diff --git a/addons/shaker/data/Single/ShakerTypeSawtoothWave1D.gd.uid b/addons/shaker/data/Single/ShakerTypeSawtoothWave1D.gd.uid new file mode 100644 index 00000000..c64e3385 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeSawtoothWave1D.gd.uid @@ -0,0 +1 @@ +uid://tftoajmajyfg diff --git a/addons/shaker/data/Single/ShakerTypeSineWave1D.gd b/addons/shaker/data/Single/ShakerTypeSineWave1D.gd new file mode 100644 index 00000000..ddc5f389 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeSineWave1D.gd @@ -0,0 +1,32 @@ +@tool +class_name ShakerTypeSineWave1D +extends ShakerTypeBase1D + +@export_group("Sinewave Properties") +@export var frequency:float = 1.0: + set = set_frequency, + get = get_frequency + +@export var phase:float = 0.0: + set = set_phase, + get = get_phase + +func get_value(t: float) -> float: + var result:float = 0.0 + var _real_time: float = fmod(t, 1.0) if t > 1.0 else t + result = sin(t * frequency * TAU + phase) + return _calc_value(_real_time, result) + +func set_frequency(value: float) -> void: + frequency = value + _on_property_changed("frequency") + +func get_frequency() -> float: + return frequency + +func set_phase(value: float) -> void: + phase = value + _on_property_changed("phase") + +func get_phase() -> float: + return phase diff --git a/addons/shaker/data/Single/ShakerTypeSineWave1D.gd.uid b/addons/shaker/data/Single/ShakerTypeSineWave1D.gd.uid new file mode 100644 index 00000000..ffa9e241 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeSineWave1D.gd.uid @@ -0,0 +1 @@ +uid://vvwsdrpmw7w4 diff --git a/addons/shaker/data/Single/ShakerTypeSquareWave1D.gd b/addons/shaker/data/Single/ShakerTypeSquareWave1D.gd new file mode 100644 index 00000000..9f2f440e --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeSquareWave1D.gd @@ -0,0 +1,35 @@ +@tool +class_name ShakerTypeSquareWave1D +extends ShakerTypeBase1D + +## The frequency of the square wave for each axis. +@export var frequency:float = 5.0: + set = set_frequency + +## The duty cycle of the square wave for each axis (0 to 1). +@export var duty_cycle:float = 0.5: + set = set_duty_cycle + +## Sets the frequency of the square wave. +func set_frequency(value:float) -> void: + frequency = value + _on_property_changed("frequency") + +## Gets the frequency of the square wave. +func get_frequency() -> float: + return frequency + +## Sets the duty cycle of the square wave. +func set_duty_cycle(value:float) -> void: + duty_cycle = clamp(value, 0.0, 0.0) + _on_property_changed("duty_cycle") + +## Gets the duty cycle of the square wave. +func get_duty_cycle() -> float: + return duty_cycle + +## Calculates the value of the square wave at time t. +func get_value(t: float) -> float: + var result:float = 0.0 + result = 1.0 if fmod(t * frequency, 1.0) < duty_cycle else -1.0 + return _calc_value(t, result) diff --git a/addons/shaker/data/Single/ShakerTypeSquareWave1D.gd.uid b/addons/shaker/data/Single/ShakerTypeSquareWave1D.gd.uid new file mode 100644 index 00000000..fe004800 --- /dev/null +++ b/addons/shaker/data/Single/ShakerTypeSquareWave1D.gd.uid @@ -0,0 +1 @@ +uid://bwuxn8yt7jiwy diff --git a/addons/shaker/data/Vector2/BaseShakerType2D.gd b/addons/shaker/data/Vector2/BaseShakerType2D.gd new file mode 100644 index 00000000..d27815b6 --- /dev/null +++ b/addons/shaker/data/Vector2/BaseShakerType2D.gd @@ -0,0 +1,47 @@ +@icon("res://addons/shaker/assets/ShakerType2D.svg") +@tool +class_name ShakerTypeBase2D +extends ShakerTypeBase + +enum GraphAxis { + X, + Y, +} + +@export var amplitude: Vector2 = Vector2.ONE: + set = set_amplitude, + get = get_amplitude + +@export var offset: Vector2 = Vector2.ZERO: + set = set_offset, + get = get_offset + +func set_amplitude(value: Vector2) -> void: + amplitude = value + _on_property_changed("amplitude") + +func get_amplitude() -> Vector2: + return amplitude + +func set_offset(value: Vector2) -> void: + offset = value + _on_property_changed("offset") + +func get_offset() -> Vector2: + return offset + +# Get the shake value at a given time +func get_value(t: float) -> Vector2: + var result: Vector2 = Vector2.ZERO + return _calc_value(fmod(t, 1.0), result) + +# Calculate the shake value +func _calc_value(t: float, result: Vector2) -> Vector2: + if duration > 0: + t /= duration + if (start_percent != 0 && start_percent > t) || (end_percent != 1 && end_percent < t): + result = Vector2.ZERO + else: + result = result * amplitude + offset + result *= (ease(t, fade_in) if fade_in > 0.0001 else 1.0) * (ease(1.0 - t, fade_out) if fade_out > 0.0001 else 1.0) + return result diff --git a/addons/shaker/data/Vector2/BaseShakerType2D.gd.uid b/addons/shaker/data/Vector2/BaseShakerType2D.gd.uid new file mode 100644 index 00000000..21135260 --- /dev/null +++ b/addons/shaker/data/Vector2/BaseShakerType2D.gd.uid @@ -0,0 +1 @@ +uid://chp1jfq2fdtbm diff --git a/addons/shaker/data/Vector2/ShakerPreset2D.gd b/addons/shaker/data/Vector2/ShakerPreset2D.gd new file mode 100644 index 00000000..4d23cd3a --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerPreset2D.gd @@ -0,0 +1,94 @@ +@tool +@icon("res://addons/shaker/assets/ShakerPreset2D.svg") +class_name ShakerPreset2D +extends ShakerPresetBase + + +# Shake type arrays for each category +@export var PositionShake: Array[ShakerTypeBase2D]: + set = set_position_shake, + get = get_position_shake + +@export var RotationShake: Array[ShakerTypeBase1D]: + set = set_rotation_shake, + get = get_rotation_shake + +@export var ScaleShake: Array[ShakerTypeBase2D]: + set = set_scale_shake, + get = get_scale_shake + +# Custom setter and getter functions +func set_position_shake(value: Array[ShakerTypeBase2D]) -> void: + for _shake_type in _array_difference(PositionShake, value): + if _shake_type != null: + _shake_type.property_changed.connect(_on_property_changed) + PositionShake = value + _on_property_changed("PositionShake") + if Graph != null: + Graph._on_fit_button_clicked() + +func get_position_shake() -> Array[ShakerTypeBase2D]: + return PositionShake + +func set_rotation_shake(value: Array[ShakerTypeBase1D]) -> void: + for _shake_type in _array_difference(RotationShake, value): + if _shake_type != null: + _shake_type.property_changed.connect(_on_property_changed) + RotationShake = value + _on_property_changed("RotationShake") + if Graph != null: + Graph._on_fit_button_clicked() + +func get_rotation_shake() -> Array[ShakerTypeBase1D]: + return RotationShake + +func get_shakes_by_category(category:Categories) -> Array: + if category == Categories.POSITION: + return PositionShake + elif category == Categories.ROTATION: + return RotationShake + elif category == Categories.SCALE: + return ScaleShake + return [null] + +func set_scale_shake(value: Array[ShakerTypeBase2D]) -> void: + for _shake_type in _array_difference(ScaleShake, value): + if _shake_type != null: + _shake_type.property_changed.connect(_on_property_changed) + ScaleShake = value + _on_property_changed("ScaleShake") + if Graph != null: + Graph._on_fit_button_clicked() + +func get_scale_shake() -> Array[ShakerTypeBase2D]: + return ScaleShake + +# Get the shake value for a given time and category +func get_value(t: float, _category: Categories = Categories.POSITION): + var result + if _category == Categories.ROTATION: + result = 0.0 + else: + result = Vector2.ZERO + for shake_type in [PositionShake, RotationShake, ScaleShake][_category]: + if shake_type != null: + shake_type.duration = component_duration + var _shake_result = shake_type.get_value(t) + match shake_type.BlendingMode: + shake_type.BlendingModes.Add: + result += _shake_result + shake_type.BlendingModes.Multiply: + result *= _shake_result + shake_type.BlendingModes.Subtract: + result -= _shake_result + shake_type.BlendingModes.Max: + result.x = max(result.x, _shake_result.x) + result.y = max(result.y, _shake_result.y) + shake_type.BlendingModes.Min: + result.x = min(result.x, _shake_result.x) + result.y = min(result.y, _shake_result.y) + shake_type.BlendingModes.Average: + result = (result + _shake_result) * 0.5 + shake_type.BlendingModes.Override: + result = _shake_result + return result diff --git a/addons/shaker/data/Vector2/ShakerPreset2D.gd.uid b/addons/shaker/data/Vector2/ShakerPreset2D.gd.uid new file mode 100644 index 00000000..2e41a547 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerPreset2D.gd.uid @@ -0,0 +1 @@ +uid://ieocwh32dyx1 diff --git a/addons/shaker/data/Vector2/ShakerTypeAudioBus2D.gd b/addons/shaker/data/Vector2/ShakerTypeAudioBus2D.gd new file mode 100644 index 00000000..5509fd18 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeAudioBus2D.gd @@ -0,0 +1,45 @@ +@tool +class_name ShakerTypeAudioBus2D +extends ShakerTypeBase2D + +@export var bus_name:String = "Master": + set = set_bus_name, + get = get_bus_name +@export var min_frequence:Vector2 = Vector2(20, 20) +@export var max_frequence:Vector2 = Vector2(20000, 20000) + +var bus_index:int = 0 +var effect:AudioEffectSpectrumAnalyzerInstance + +## Calculates the value of the square wave at time t. +func get_value(t: float) -> Vector2: + var result:Vector2 = Vector2.ZERO + if effect: + var mag_x:Vector2 = effect.get_magnitude_for_frequency_range(min_frequence.x, max_frequence.x, AudioEffectSpectrumAnalyzerInstance.MAGNITUDE_MAX) + var mag_y:Vector2 = effect.get_magnitude_for_frequency_range(min_frequence.y, max_frequence.y, AudioEffectSpectrumAnalyzerInstance.MAGNITUDE_MAX) + result.x = mag_x.length() + result.y = mag_y.length() + return _calc_value(t, result) + +func set_bus_name(value: String) -> void: + bus_name = value + _update_bus_index() + _on_property_changed("bus_name") + +func get_bus_name() -> String: + return bus_name + +func _update_bus_index() -> void: + bus_index = AudioServer.get_bus_index(bus_name) + if bus_index > -1: + for e in AudioServer.get_bus_effect_count(bus_index): + var _effect:AudioEffect = AudioServer.get_bus_effect(bus_index, e) + if _effect is AudioEffectSpectrumAnalyzer: + effect = AudioServer.get_bus_effect_instance(bus_index, e, 0) + break; + if effect == null: + AudioServer.add_bus_effect(bus_index, AudioEffectSpectrumAnalyzer.new(), 0) + effect = AudioServer.get_bus_effect_instance(bus_index, 0) + else: + push_error("Error: Bus '" + bus_name + "' not found!") + effect = null diff --git a/addons/shaker/data/Vector2/ShakerTypeAudioBus2D.gd.uid b/addons/shaker/data/Vector2/ShakerTypeAudioBus2D.gd.uid new file mode 100644 index 00000000..3833d851 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeAudioBus2D.gd.uid @@ -0,0 +1 @@ +uid://4msbbvpnv85g diff --git a/addons/shaker/data/Vector2/ShakerTypeBrownianShake2D.gd b/addons/shaker/data/Vector2/ShakerTypeBrownianShake2D.gd new file mode 100644 index 00000000..97a52a30 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeBrownianShake2D.gd @@ -0,0 +1,44 @@ +@tool +class_name ShakerTypeBrownianShake2D +extends ShakerTypeBase2D + +@export var roughness: Vector2 = Vector2.ONE * 1.0: + set = set_roughness, + get = get_roughness + +@export var persistence: Vector2 = Vector2.ONE * 0.5: + set = set_persistence, + get = get_persistence + +var _generator: RandomNumberGenerator = RandomNumberGenerator.new() +var _last_pos: Vector2 = Vector2.ZERO + +func _init() -> void: + property_changed.connect(_property_changed) + +func get_value(t: float) -> Vector2: + var result: Vector2 = Vector2.ZERO + result.x = (_last_pos.x + _generator.randf_range(-roughness.x, roughness.x)) + result.y = (_last_pos.y + _generator.randf_range(-roughness.y, roughness.y)) + result = _calc_value(t, result) + + _last_pos.x = lerpf(_last_pos.x, result.x, 1.0 - persistence.x) + _last_pos.y = lerpf(_last_pos.y, result.y, 1.0 - persistence.y) + return _last_pos + +func _property_changed(name: StringName) -> void: + _last_pos = Vector2.ZERO + +func set_roughness(value: Vector2) -> void: + roughness = value + _on_property_changed("roughness") + +func get_roughness() -> Vector2: + return roughness + +func set_persistence(value: Vector2) -> void: + persistence = value.clamp(Vector2(0,0),Vector2(1,1)) + _on_property_changed("persistence") + +func get_persistence() -> Vector2: + return persistence diff --git a/addons/shaker/data/Vector2/ShakerTypeBrownianShake2D.gd.uid b/addons/shaker/data/Vector2/ShakerTypeBrownianShake2D.gd.uid new file mode 100644 index 00000000..481696c9 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeBrownianShake2D.gd.uid @@ -0,0 +1 @@ +uid://c2p5nhqgceojd diff --git a/addons/shaker/data/Vector2/ShakerTypeCurve2D.gd b/addons/shaker/data/Vector2/ShakerTypeCurve2D.gd new file mode 100644 index 00000000..1baebd71 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeCurve2D.gd @@ -0,0 +1,60 @@ +@tool +class_name ShakerTypeCurve2D +extends ShakerTypeBase2D + +@export var curve_x: Curve: + set = set_curve_x, + get = get_curve_x + +@export var curve_y: Curve: + set = set_curve_y, + get = get_curve_y + +@export var loop: bool = true: + set = set_loop, + get = get_loop + +func _curve_changed() -> void: + _on_property_changed("curve_") + +func get_value(t: float) -> Vector2: + var result: Vector2 = Vector2.ZERO + if loop && t > 1.0: + t = fmod(t, 1.0) + if curve_x: + result.x = curve_x.sample(t) + if curve_y: + result.y = curve_y.sample(t) + + return _calc_value(t, result) + +func set_curve_x(value: Curve) -> void: + if curve_x: + curve_x.changed.disconnect(_curve_changed) + curve_x = value + if curve_x: + curve_x.changed.connect(_curve_changed) + else: + _curve_changed() + +func get_curve_x() -> Curve: + return curve_x + +func set_curve_y(value: Curve) -> void: + if curve_y: + curve_y.changed.disconnect(_curve_changed) + curve_y = value + if curve_y: + curve_y.changed.connect(_curve_changed) + else: + _curve_changed() + +func get_curve_y() -> Curve: + return curve_y + +func set_loop(value: bool) -> void: + loop = value + _on_property_changed("loop") + +func get_loop() -> bool: + return loop diff --git a/addons/shaker/data/Vector2/ShakerTypeCurve2D.gd.uid b/addons/shaker/data/Vector2/ShakerTypeCurve2D.gd.uid new file mode 100644 index 00000000..6de51741 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeCurve2D.gd.uid @@ -0,0 +1 @@ +uid://dd6hr5hjnra0i diff --git a/addons/shaker/data/Vector2/ShakerTypeNoiseShake2D.gd b/addons/shaker/data/Vector2/ShakerTypeNoiseShake2D.gd new file mode 100644 index 00000000..c1f0dc5d --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeNoiseShake2D.gd @@ -0,0 +1,33 @@ +@tool +class_name ShakerTypeNoiseShake2D +extends ShakerTypeBase2D + +@export var noise_texture: NoiseTexture2D = NoiseTexture2D.new(): + set = set_noise_texture, + get = get_noise_texture + +func _init() -> void: + noise_texture.changed.connect(_on_noise_changed) + +func get_value(t: float) -> Vector2: + var result: Vector2 = Vector2.ZERO + if noise_texture && noise_texture.noise: + var noise_size: Vector2 = Vector2(noise_texture.width, noise_texture.height) + var noise_offset: Vector2 = t * noise_size + result.x = noise_texture.noise.get_noise_2d(noise_offset.x, 0.0) + result.y = noise_texture.noise.get_noise_2d(0.0, noise_offset.y) + result *= 2.0 + return _calc_value(t, result) + +func _on_noise_changed() -> void: + _on_property_changed("noise_texture") + +func set_noise_texture(value: NoiseTexture2D) -> void: + if noise_texture: + noise_texture.changed.disconnect(_on_noise_changed) + noise_texture = value + if noise_texture: + noise_texture.changed.connect(_on_noise_changed) + +func get_noise_texture() -> NoiseTexture2D: + return noise_texture diff --git a/addons/shaker/data/Vector2/ShakerTypeNoiseShake2D.gd.uid b/addons/shaker/data/Vector2/ShakerTypeNoiseShake2D.gd.uid new file mode 100644 index 00000000..2abe4ef8 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeNoiseShake2D.gd.uid @@ -0,0 +1 @@ +uid://rytryaspugdk diff --git a/addons/shaker/data/Vector2/ShakerTypeRandom2D.gd b/addons/shaker/data/Vector2/ShakerTypeRandom2D.gd new file mode 100644 index 00000000..3a23abe5 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeRandom2D.gd @@ -0,0 +1,31 @@ +@tool +class_name ShakerTypeRandom2D +extends ShakerTypeBase2D + +## The seed for the random number generator. +@export var seed: int = 0: + set = set_seed + +## The random number generator instance. +var _generator: RandomNumberGenerator = RandomNumberGenerator.new() + +## Initializes the shake type with the given seed. +func _init() -> void: + set_seed(seed) + +## Calculates a random value for each axis at time t. +func get_value(t: float) -> Vector2: + var result: Vector2 = Vector2.ZERO + result.x = _generator.randf_range(-1.0, 1.0) + result.y = _generator.randf_range(-1.0, 1.0) + return _calc_value(t, result) + +## Sets the seed for the random number generator. +func set_seed(value: int) -> void: + seed = value + _generator.seed = seed + _on_property_changed("seed") + +## Gets the current seed of the random number generator. +func get_seed() -> int: + return seed diff --git a/addons/shaker/data/Vector2/ShakerTypeRandom2D.gd.uid b/addons/shaker/data/Vector2/ShakerTypeRandom2D.gd.uid new file mode 100644 index 00000000..659f7133 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeRandom2D.gd.uid @@ -0,0 +1 @@ +uid://c7jr8ltct1k17 diff --git a/addons/shaker/data/Vector2/ShakerTypeSawtoothWave2D.gd b/addons/shaker/data/Vector2/ShakerTypeSawtoothWave2D.gd new file mode 100644 index 00000000..54bc2f43 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeSawtoothWave2D.gd @@ -0,0 +1,42 @@ +@tool +class_name ShakerTypeSawtoothWave2D +extends ShakerTypeBase2D + +## The frequency of the sawtooth wave for each axis. +@export var frequency: Vector2 = Vector2.ONE * 5.0: + set = set_frequency + +## The asymmetry of the sawtooth wave for each axis (0 to 1). +@export var asymmetry: Vector2 = Vector2.ONE * 0.5: + set = set_asymmetry + +## Sets the frequency of the sawtooth wave. +func set_frequency(value: Vector2) -> void: + frequency = value + _on_property_changed("frequency") + +## Gets the frequency of the sawtooth wave. +func get_frequency() -> Vector2: + return frequency + +## Sets the asymmetry of the sawtooth wave. +func set_asymmetry(value: Vector2) -> void: + asymmetry = value.clamp(Vector2.ZERO, Vector2.ONE) + _on_property_changed("asymmetry") + +## Gets the asymmetry of the sawtooth wave. +func get_asymmetry() -> Vector2: + return asymmetry + +## Calculates the value of the sawtooth wave at time t. +func get_value(t: float) -> Vector2: + var result: Vector2 = Vector2.ZERO + var _real_time: float = fmod(t, 1.0) if t > 1.0 else t + var wave: Vector2 = (_real_time * frequency).posmod(1.0) + + wave.x = wave.x / asymmetry.x if wave.x < asymmetry.x else (1.0 - wave.x) / (1.0 - asymmetry.x) + wave.y = wave.y / asymmetry.y if wave.y < asymmetry.y else (1.0 - wave.y) / (1.0 - asymmetry.y) + result = wave + result = _calc_value(t, result) + result = (result - amplitude * 0.5) * 2.0 + return result diff --git a/addons/shaker/data/Vector2/ShakerTypeSawtoothWave2D.gd.uid b/addons/shaker/data/Vector2/ShakerTypeSawtoothWave2D.gd.uid new file mode 100644 index 00000000..331eb73f --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeSawtoothWave2D.gd.uid @@ -0,0 +1 @@ +uid://x16d6et41iut diff --git a/addons/shaker/data/Vector2/ShakerTypeSineWave2D.gd b/addons/shaker/data/Vector2/ShakerTypeSineWave2D.gd new file mode 100644 index 00000000..e3c4b822 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeSineWave2D.gd @@ -0,0 +1,33 @@ +@tool +class_name ShakerTypeSineWave2D +extends ShakerTypeBase2D + +@export_group("Sinewave Properties") +@export var frequency: Vector2 = Vector2.ONE: + set = set_frequency, + get = get_frequency + +@export var phase: Vector2 = Vector2.ONE: + set = set_phase, + get = get_phase + +func get_value(t: float) -> Vector2: + var result: Vector2 = Vector2.ZERO + var _real_time: float = fmod(t, 1.0) if t > 1.0 else t + result.x = sin(t * frequency.x * TAU + phase.x) + result.y = sin(t * frequency.y * TAU + phase.y + PI/2) + return _calc_value(_real_time, result) + +func set_frequency(value: Vector2) -> void: + frequency = value + _on_property_changed("frequency") + +func get_frequency() -> Vector2: + return frequency + +func set_phase(value: Vector2) -> void: + phase = value + _on_property_changed("phase") + +func get_phase() -> Vector2: + return phase diff --git a/addons/shaker/data/Vector2/ShakerTypeSineWave2D.gd.uid b/addons/shaker/data/Vector2/ShakerTypeSineWave2D.gd.uid new file mode 100644 index 00000000..563657d4 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeSineWave2D.gd.uid @@ -0,0 +1 @@ +uid://drm7drd6f4t4x diff --git a/addons/shaker/data/Vector2/ShakerTypeSquareWave2D.gd b/addons/shaker/data/Vector2/ShakerTypeSquareWave2D.gd new file mode 100644 index 00000000..788e55b4 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeSquareWave2D.gd @@ -0,0 +1,36 @@ +@tool +class_name ShakerTypeSquareWave2D +extends ShakerTypeBase2D + +## The frequency of the square wave for each axis. +@export var frequency: Vector2 = Vector2.ONE * 5.0: + set = set_frequency + +## The duty cycle of the square wave for each axis (0 to 1). +@export var duty_cycle: Vector2 = Vector2.ONE * 0.5: + set = set_duty_cycle + +## Sets the frequency of the square wave. +func set_frequency(value: Vector2) -> void: + frequency = value + _on_property_changed("frequency") + +## Gets the frequency of the square wave. +func get_frequency() -> Vector2: + return frequency + +## Sets the duty cycle of the square wave. +func set_duty_cycle(value: Vector2) -> void: + duty_cycle = value.clamp(Vector2.ZERO, Vector2.ONE) + _on_property_changed("duty_cycle") + +## Gets the duty cycle of the square wave. +func get_duty_cycle() -> Vector2: + return duty_cycle + +## Calculates the value of the square wave at time t. +func get_value(t: float) -> Vector2: + var result: Vector2 = Vector2.ZERO + result.x = 1.0 if fmod(t * frequency.x, 1.0) < duty_cycle.x else -1.0 + result.y = 1.0 if fmod(t * frequency.y, 1.0) < duty_cycle.y else -1.0 + return _calc_value(t, result) diff --git a/addons/shaker/data/Vector2/ShakerTypeSquareWave2D.gd.uid b/addons/shaker/data/Vector2/ShakerTypeSquareWave2D.gd.uid new file mode 100644 index 00000000..a8789f41 --- /dev/null +++ b/addons/shaker/data/Vector2/ShakerTypeSquareWave2D.gd.uid @@ -0,0 +1 @@ +uid://btxrpjbvdcl1f diff --git a/addons/shaker/data/Vector3/BaseShakerType3D.gd b/addons/shaker/data/Vector3/BaseShakerType3D.gd new file mode 100644 index 00000000..9255d376 --- /dev/null +++ b/addons/shaker/data/Vector3/BaseShakerType3D.gd @@ -0,0 +1,48 @@ +@icon("res://addons/shaker/assets/ShakerType3D.svg") +@tool +class_name ShakerTypeBase3D +extends ShakerTypeBase + +enum GraphAxis { + X, + Y, + Z +} + +@export var amplitude: Vector3 = Vector3.ONE: + set = set_amplitude, + get = get_amplitude + +@export var offset: Vector3 = Vector3.ZERO: + set = set_offset, + get = get_offset + +func set_amplitude(value: Vector3) -> void: + amplitude = value + _on_property_changed("amplitude") + +func get_amplitude() -> Vector3: + return amplitude + +func set_offset(value: Vector3) -> void: + offset = value + _on_property_changed("offset") + +func get_offset() -> Vector3: + return offset + +# Get the shake value at a given time +func get_value(t: float) -> Vector3: + var result: Vector3 = Vector3.ZERO + return _calc_value(fmod(t, 1.0), result) + +# Calculate the shake value +func _calc_value(t: float, result: Vector3) -> Vector3: + if duration > 0: + t /= duration + if (start_percent != 0 && start_percent > t) || (end_percent != 1 && end_percent < t): + result = Vector3.ZERO + else: + result = result * amplitude + offset + result *= (ease(t, fade_in) if abs(fade_in) > 0.0001 else 1.0) * (ease(1.0 - t, fade_out) if abs(fade_out) > 0.0001 else 1.0) + return result diff --git a/addons/shaker/data/Vector3/BaseShakerType3D.gd.uid b/addons/shaker/data/Vector3/BaseShakerType3D.gd.uid new file mode 100644 index 00000000..1950fb48 --- /dev/null +++ b/addons/shaker/data/Vector3/BaseShakerType3D.gd.uid @@ -0,0 +1 @@ +uid://0tu2q57qqu4s diff --git a/addons/shaker/data/Vector3/ShakerPreset3D.gd b/addons/shaker/data/Vector3/ShakerPreset3D.gd new file mode 100644 index 00000000..1059613c --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerPreset3D.gd @@ -0,0 +1,103 @@ +@tool +@icon("res://addons/shaker/assets/ShakerPreset3D.svg") +class_name ShakerPreset3D +extends ShakerPresetBase + +# Shake type arrays for each category +@export var PositionShake: Array[ShakerTypeBase3D]: + set = set_position_shake, + get = get_position_shake + +@export var RotationShake: Array[ShakerTypeBase3D]: + set = set_rotation_shake, + get = get_rotation_shake + +@export var ScaleShake: Array[ShakerTypeBase3D]: + set = set_scale_shake, + get = get_scale_shake + +# Custom setter and getter functions +func set_position_shake(value: Array[ShakerTypeBase3D]) -> void: + for _shake_type in _array_difference(PositionShake, value): + if _shake_type != null: + _shake_type.property_changed.connect(_on_property_changed) + _shake_type.property_changed.connect(_change_graph_category.bind(0)) + PositionShake = value + if Graph != null: + Graph.select_category(0) + Graph._on_fit_button_clicked() + _on_property_changed("PositionShake") + +func get_position_shake() -> Array[ShakerTypeBase3D]: + return PositionShake + +func set_rotation_shake(value: Array[ShakerTypeBase3D]) -> void: + for _shake_type in _array_difference(RotationShake, value): + if _shake_type != null: + _shake_type.property_changed.connect(_on_property_changed) + _shake_type.property_changed.connect(_change_graph_category.bind(1)) + RotationShake = value + if Graph != null: + Graph.select_category(1) + Graph._on_fit_button_clicked() + _on_property_changed("RotationShake") + +func get_rotation_shake() -> Array[ShakerTypeBase3D]: + return RotationShake + +func set_scale_shake(value: Array[ShakerTypeBase3D]) -> void: + for _shake_type in _array_difference(ScaleShake, value): + if _shake_type != null: + _shake_type.property_changed.connect(_on_property_changed) + _shake_type.property_changed.connect(_change_graph_category.bind(2)) + ScaleShake = value + if Graph != null: + Graph.select_category(2) + Graph._on_fit_button_clicked() + _on_property_changed("ScaleShake") + +func get_scale_shake() -> Array[ShakerTypeBase3D]: + return ScaleShake + +# Get the shake value for a given time and category +func get_value(t: float, _category: Categories = Categories.POSITION) -> Vector3: + var result: Vector3 = Vector3.ZERO + var selected_category: Array[ShakerTypeBase3D] = [PositionShake, RotationShake, ScaleShake][_category] + for shake_type in selected_category: + if shake_type != null: + shake_type.duration = component_duration + var _shake_result: Vector3 = shake_type.get_value(t) + match shake_type.BlendingMode: + shake_type.BlendingModes.Add: + result += _shake_result + shake_type.BlendingModes.Multiply: + result *= _shake_result + shake_type.BlendingModes.Subtract: + result -= _shake_result + shake_type.BlendingModes.Max: + result.x = max(result.x, _shake_result.x) + result.y = max(result.y, _shake_result.y) + result.z = max(result.z, _shake_result.z) + shake_type.BlendingModes.Min: + result.x = min(result.x, _shake_result.x) + result.y = min(result.y, _shake_result.y) + result.z = min(result.z, _shake_result.z) + shake_type.BlendingModes.Average: + result = (result + _shake_result) * 0.5 + shake_type.BlendingModes.Override: + result = _shake_result + return result + +func _change_graph_category(_name:String, _category_index:int) -> void: + if Graph: + Graph.category_button.select(_category_index) + Graph.category_button.item_selected.emit(_category_index) + +func get_shakes_by_category(category:Categories) -> Array: + if category == Categories.POSITION: + return PositionShake + elif category == Categories.ROTATION: + return RotationShake + elif category == Categories.SCALE: + return ScaleShake + return [null] diff --git a/addons/shaker/data/Vector3/ShakerPreset3D.gd.uid b/addons/shaker/data/Vector3/ShakerPreset3D.gd.uid new file mode 100644 index 00000000..f0edd1e9 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerPreset3D.gd.uid @@ -0,0 +1 @@ +uid://mlwdmecg12xd diff --git a/addons/shaker/data/Vector3/ShakerTypeAudioBus3D.gd b/addons/shaker/data/Vector3/ShakerTypeAudioBus3D.gd new file mode 100644 index 00000000..d8330368 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeAudioBus3D.gd @@ -0,0 +1,49 @@ +@tool +class_name ShakerTypeAudioBus3D +extends ShakerTypeBase3D + +@export var bus_name:String = "Master": + set = set_bus_name, + get = get_bus_name +@export var min_frequence:Vector3 = Vector3(20, 20, 20) +@export var max_frequence:Vector3 = Vector3(20000, 20000, 20000) + +var bus_index:int = 0 +var effect:AudioEffectSpectrumAnalyzerInstance + +func _init(): + _update_bus_index() +## Calculates the value of the square wave at time t. +func get_value(t: float) -> Vector3: + var result:Vector3 = Vector3.ZERO + if effect: + var mag_x:Vector2 = effect.get_magnitude_for_frequency_range(min_frequence.x, max_frequence.x, AudioEffectSpectrumAnalyzerInstance.MAGNITUDE_MAX) + var mag_y:Vector2 = effect.get_magnitude_for_frequency_range(min_frequence.y, max_frequence.y, AudioEffectSpectrumAnalyzerInstance.MAGNITUDE_MAX) + var mag_z:Vector2 = effect.get_magnitude_for_frequency_range(min_frequence.z, max_frequence.z, AudioEffectSpectrumAnalyzerInstance.MAGNITUDE_MAX) + result.x = mag_x.length() + result.y = mag_y.length() + result.z = mag_y.length() + return _calc_value(t, result) + +func set_bus_name(value: String) -> void: + bus_name = value + _update_bus_index() + _on_property_changed("bus_name") + +func get_bus_name() -> String: + return bus_name + +func _update_bus_index() -> void: + bus_index = AudioServer.get_bus_index(bus_name) + if bus_index > -1: + for e in AudioServer.get_bus_effect_count(bus_index): + var _effect:AudioEffect = AudioServer.get_bus_effect(bus_index, e) + if _effect is AudioEffectSpectrumAnalyzer: + effect = AudioServer.get_bus_effect_instance(bus_index, e, 0) + break; + if effect == null: + AudioServer.add_bus_effect(bus_index, AudioEffectSpectrumAnalyzer.new(), 0) + effect = AudioServer.get_bus_effect_instance(bus_index, 0) + else: + push_error("Error: Bus '" + bus_name + "' not found!") + effect = null diff --git a/addons/shaker/data/Vector3/ShakerTypeAudioBus3D.gd.uid b/addons/shaker/data/Vector3/ShakerTypeAudioBus3D.gd.uid new file mode 100644 index 00000000..a2aa063c --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeAudioBus3D.gd.uid @@ -0,0 +1 @@ +uid://cdne0sspxhssj diff --git a/addons/shaker/data/Vector3/ShakerTypeBrownianShake3D.gd b/addons/shaker/data/Vector3/ShakerTypeBrownianShake3D.gd new file mode 100644 index 00000000..f51b34f6 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeBrownianShake3D.gd @@ -0,0 +1,46 @@ +@tool +class_name ShakerTypeBrownianShake3D +extends ShakerTypeBase3D + +@export var roughness: Vector3 = Vector3.ONE * 1.0: + set = set_roughness, + get = get_roughness + +@export var persistence: Vector3 = Vector3.ONE * 0.5: + set = set_persistence, + get = get_persistence + +var _generator: RandomNumberGenerator = RandomNumberGenerator.new() +var _last_pos: Vector3 = Vector3.ZERO + +func _init() -> void: + property_changed.connect(_property_changed) + +func get_value(t: float) -> Vector3: + var result: Vector3 = Vector3.ZERO + result.x = (_last_pos.x + _generator.randf_range(-roughness.x, roughness.x)) + result.y = (_last_pos.y + _generator.randf_range(-roughness.y, roughness.y)) + result.z = (_last_pos.z + _generator.randf_range(-roughness.z, roughness.z)) + result = _calc_value(t, result) + + _last_pos.x = lerpf(_last_pos.x, result.x, 1.0 - persistence.x) + _last_pos.y = lerpf(_last_pos.y, result.y, 1.0 - persistence.y) + _last_pos.z = lerpf(_last_pos.z, result.z, 1.0 - persistence.z) + return _last_pos + +func _property_changed(name: StringName) -> void: + _last_pos = Vector3.ZERO + +func set_roughness(value: Vector3) -> void: + roughness = value + _on_property_changed("roughness") + +func get_roughness() -> Vector3: + return roughness + +func set_persistence(value: Vector3) -> void: + persistence = value.clamp(Vector3.ZERO, Vector3.ONE) + _on_property_changed("persistence") + +func get_persistence() -> Vector3: + return persistence diff --git a/addons/shaker/data/Vector3/ShakerTypeBrownianShake3D.gd.uid b/addons/shaker/data/Vector3/ShakerTypeBrownianShake3D.gd.uid new file mode 100644 index 00000000..8a0c185d --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeBrownianShake3D.gd.uid @@ -0,0 +1 @@ +uid://ddk408cg8156q diff --git a/addons/shaker/data/Vector3/ShakerTypeCurve3D.gd b/addons/shaker/data/Vector3/ShakerTypeCurve3D.gd new file mode 100644 index 00000000..5325b98d --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeCurve3D.gd @@ -0,0 +1,78 @@ +@tool +class_name ShakerTypeCurve3D +extends ShakerTypeBase3D + +@export var curve_x: Curve: + set = set_curve_x, + get = get_curve_x + +@export var curve_y: Curve: + set = set_curve_y, + get = get_curve_y + +@export var curve_z: Curve: + set = set_curve_z, + get = get_curve_z + +@export var loop: bool = true: + set = set_loop, + get = get_loop + +func _curve_changed() -> void: + _on_property_changed("curve_") + +func get_value(t: float) -> Vector3: + var result: Vector3 = Vector3.ZERO + if loop && t > 1.0: + t = fmod(t, 1.0) + if curve_x: + result.x = curve_x.sample(t) + if curve_y: + result.y = curve_y.sample(t) + if curve_z: + result.z = curve_z.sample(t) + + return _calc_value(t, result) + +func set_curve_x(value: Curve) -> void: + if curve_x: + curve_x.changed.disconnect(_curve_changed) + curve_x = value + if curve_x: + curve_x.changed.connect(_curve_changed) + else: + _curve_changed() + +func get_curve_x() -> Curve: + return curve_x + +func set_curve_y(value: Curve) -> void: + if curve_y: + curve_y.changed.disconnect(_curve_changed) + curve_y = value + if curve_y: + curve_y.changed.connect(_curve_changed) + else: + _curve_changed() + +func get_curve_y() -> Curve: + return curve_y + +func set_curve_z(value: Curve) -> void: + if curve_z: + curve_z.changed.disconnect(_curve_changed) + curve_z = value + if curve_z: + curve_z.changed.connect(_curve_changed) + else: + _curve_changed() + +func get_curve_z() -> Curve: + return curve_z + +func set_loop(value: bool) -> void: + loop = value + _on_property_changed("loop") + +func get_loop() -> bool: + return loop diff --git a/addons/shaker/data/Vector3/ShakerTypeCurve3D.gd.uid b/addons/shaker/data/Vector3/ShakerTypeCurve3D.gd.uid new file mode 100644 index 00000000..4e6f0ec1 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeCurve3D.gd.uid @@ -0,0 +1 @@ +uid://biqfuixncau4j diff --git a/addons/shaker/data/Vector3/ShakerTypeNoiseShake3D.gd b/addons/shaker/data/Vector3/ShakerTypeNoiseShake3D.gd new file mode 100644 index 00000000..e9fcb465 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeNoiseShake3D.gd @@ -0,0 +1,34 @@ +@tool +class_name ShakerTypeNoiseShake3D +extends ShakerTypeBase3D + +@export var noise_texture: NoiseTexture3D = NoiseTexture3D.new(): + set = set_noise_texture, + get = get_noise_texture + +func _init() -> void: + noise_texture.changed.connect(_on_noise_changed) + +func get_value(t: float) -> Vector3: + var result: Vector3 = Vector3.ZERO + if noise_texture && noise_texture.noise: + var noise_size: Vector3 = Vector3(noise_texture.width, noise_texture.height, noise_texture.depth) + var noise_offset: Vector3 = t * noise_size + result.x = noise_texture.noise.get_noise_3d(noise_offset.x, 0.0, 0.0) + result.y = noise_texture.noise.get_noise_3d(0.0, noise_offset.y, 0.0) + result.z = noise_texture.noise.get_noise_3d(0.0, 0.0, noise_offset.z) + result *= 2.0 + return _calc_value(t, result) + +func _on_noise_changed() -> void: + _on_property_changed("noise_texture") + +func set_noise_texture(value: NoiseTexture3D) -> void: + if noise_texture: + noise_texture.changed.disconnect(_on_noise_changed) + noise_texture = value + if noise_texture: + noise_texture.changed.connect(_on_noise_changed) + +func get_noise_texture() -> NoiseTexture3D: + return noise_texture diff --git a/addons/shaker/data/Vector3/ShakerTypeNoiseShake3D.gd.uid b/addons/shaker/data/Vector3/ShakerTypeNoiseShake3D.gd.uid new file mode 100644 index 00000000..a2d0e965 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeNoiseShake3D.gd.uid @@ -0,0 +1 @@ +uid://ptaespkh1sk2 diff --git a/addons/shaker/data/Vector3/ShakerTypeRandom3D.gd b/addons/shaker/data/Vector3/ShakerTypeRandom3D.gd new file mode 100644 index 00000000..b5ac3a79 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeRandom3D.gd @@ -0,0 +1,32 @@ +@tool +class_name ShakerTypeRandom3D +extends ShakerTypeBase3D + +## The seed for the random number generator. +@export var seed: int = 0: + set = set_seed + +## The random number generator instance. +var _generator: RandomNumberGenerator = RandomNumberGenerator.new() + +## Initializes the shake type with the given seed. +func _init() -> void: + set_seed(seed) + +## Calculates a random value for each axis at time t. +func get_value(t: float) -> Vector3: + var result: Vector3 = Vector3.ZERO + result.x = _generator.randf_range(-1.0, 1.0) + result.y = _generator.randf_range(-1.0, 1.0) + result.z = _generator.randf_range(-1.0, 1.0) + return _calc_value(t, result) + +## Sets the seed for the random number generator. +func set_seed(value: int) -> void: + seed = value + _generator.seed = seed + _on_property_changed("seed") + +## Gets the current seed of the random number generator. +func get_seed() -> int: + return seed diff --git a/addons/shaker/data/Vector3/ShakerTypeRandom3D.gd.uid b/addons/shaker/data/Vector3/ShakerTypeRandom3D.gd.uid new file mode 100644 index 00000000..77f9008b --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeRandom3D.gd.uid @@ -0,0 +1 @@ +uid://jyrxhux22cdm diff --git a/addons/shaker/data/Vector3/ShakerTypeSawtoothWave3D.gd b/addons/shaker/data/Vector3/ShakerTypeSawtoothWave3D.gd new file mode 100644 index 00000000..1a384223 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeSawtoothWave3D.gd @@ -0,0 +1,43 @@ +@tool +class_name ShakerTypeSawtoothWave3D +extends ShakerTypeBase3D + +## The frequency of the sawtooth wave for each axis. +@export var frequency: Vector3 = Vector3.ONE * 5.0: + set = set_frequency + +## The asymmetry of the sawtooth wave for each axis (0 to 1). +@export var asymmetry: Vector3 = Vector3.ONE * 0.5: + set = set_asymmetry + +## Sets the frequency of the sawtooth wave. +func set_frequency(value: Vector3) -> void: + frequency = value + _on_property_changed("frequency") + +## Gets the frequency of the sawtooth wave. +func get_frequency() -> Vector3: + return frequency + +## Sets the asymmetry of the sawtooth wave. +func set_asymmetry(value: Vector3) -> void: + asymmetry = value.clamp(Vector3.ZERO, Vector3.ONE) + _on_property_changed("asymmetry") + +## Gets the asymmetry of the sawtooth wave. +func get_asymmetry() -> Vector3: + return asymmetry + +## Calculates the value of the sawtooth wave at time t. +func get_value(t: float) -> Vector3: + var result: Vector3 = Vector3.ZERO + var _real_time: float = fmod(t, 1.0) if t > 1.0 else t + var wave: Vector3 = (_real_time * frequency).posmod(1.0) + + wave.x = wave.x / asymmetry.x if wave.x < asymmetry.x else (1.0 - wave.x) / (1.0 - asymmetry.x) + wave.y = wave.y / asymmetry.y if wave.y < asymmetry.y else (1.0 - wave.y) / (1.0 - asymmetry.y) + wave.z = wave.z / asymmetry.z if wave.z < asymmetry.z else (1.0 - wave.z) / (1.0 - asymmetry.z) + result = wave + result = _calc_value(t, result) + result = (result - amplitude * 0.5) * 2.0 + return result diff --git a/addons/shaker/data/Vector3/ShakerTypeSawtoothWave3D.gd.uid b/addons/shaker/data/Vector3/ShakerTypeSawtoothWave3D.gd.uid new file mode 100644 index 00000000..f8f8801c --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeSawtoothWave3D.gd.uid @@ -0,0 +1 @@ +uid://dpoggf3psdkci diff --git a/addons/shaker/data/Vector3/ShakerTypeSineWave3D.gd b/addons/shaker/data/Vector3/ShakerTypeSineWave3D.gd new file mode 100644 index 00000000..d3334c11 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeSineWave3D.gd @@ -0,0 +1,34 @@ +@tool +class_name ShakerTypeSineWave3D +extends ShakerTypeBase3D + +@export_group("Sinewave Properties") +@export var frequency: Vector3 = Vector3.ONE: + set = set_frequency, + get = get_frequency + +@export var phase: Vector3 = Vector3.ONE: + set = set_phase, + get = get_phase + +func get_value(t: float) -> Vector3: + var result: Vector3 = Vector3.ZERO + var _real_time: float = fmod(t, 1.0) if t > 1.0 else t + result.x = sin(t * frequency.x * TAU + phase.x) + result.y = sin(t * frequency.y * TAU + phase.y + PI/2) + result.z = sin(t * frequency.z * TAU + phase.z + PI/4) + return _calc_value(_real_time, result) + +func set_frequency(value: Vector3) -> void: + frequency = value + _on_property_changed("frequency") + +func get_frequency() -> Vector3: + return frequency + +func set_phase(value: Vector3) -> void: + phase = value + _on_property_changed("phase") + +func get_phase() -> Vector3: + return phase diff --git a/addons/shaker/data/Vector3/ShakerTypeSineWave3D.gd.uid b/addons/shaker/data/Vector3/ShakerTypeSineWave3D.gd.uid new file mode 100644 index 00000000..b280d1a1 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeSineWave3D.gd.uid @@ -0,0 +1 @@ +uid://sih7vd0uinav diff --git a/addons/shaker/data/Vector3/ShakerTypeSquareWave3D.gd b/addons/shaker/data/Vector3/ShakerTypeSquareWave3D.gd new file mode 100644 index 00000000..68699388 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeSquareWave3D.gd @@ -0,0 +1,37 @@ +@tool +class_name ShakerTypeSquareWave3D +extends ShakerTypeBase3D + +## The frequency of the square wave for each axis. +@export var frequency: Vector3 = Vector3.ONE * 5.0: + set = set_frequency + +## The duty cycle of the square wave for each axis (0 to 1). +@export var duty_cycle: Vector3 = Vector3.ONE * 0.5: + set = set_duty_cycle + +## Sets the frequency of the square wave. +func set_frequency(value: Vector3) -> void: + frequency = value + _on_property_changed("frequency") + +## Gets the frequency of the square wave. +func get_frequency() -> Vector3: + return frequency + +## Sets the duty cycle of the square wave. +func set_duty_cycle(value: Vector3) -> void: + duty_cycle = value.clamp(Vector3.ZERO, Vector3.ONE) + _on_property_changed("duty_cycle") + +## Gets the duty cycle of the square wave. +func get_duty_cycle() -> Vector3: + return duty_cycle + +## Calculates the value of the square wave at time t. +func get_value(t: float) -> Vector3: + var result: Vector3 = Vector3.ZERO + result.x = 1.0 if fmod(t * frequency.x, 1.0) < duty_cycle.x else -1.0 + result.y = 1.0 if fmod(t * frequency.y, 1.0) < duty_cycle.y else -1.0 + result.z = 1.0 if fmod(t * frequency.z, 1.0) < duty_cycle.z else -1.0 + return _calc_value(t, result) diff --git a/addons/shaker/data/Vector3/ShakerTypeSquareWave3D.gd.uid b/addons/shaker/data/Vector3/ShakerTypeSquareWave3D.gd.uid new file mode 100644 index 00000000..8ff70c81 --- /dev/null +++ b/addons/shaker/data/Vector3/ShakerTypeSquareWave3D.gd.uid @@ -0,0 +1 @@ +uid://drpiei33e2en diff --git a/addons/shaker/data/resources/box_opening3D.tres b/addons/shaker/data/resources/box_opening3D.tres new file mode 100644 index 00000000..a287537c --- /dev/null +++ b/addons/shaker/data/resources/box_opening3D.tres @@ -0,0 +1,90 @@ +[gd_resource type="Resource" script_class="ShakerPreset3D" load_steps=13 format=3 uid="uid://cqfe3012jylqs"] + +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerTypeCurve3D.gd" id="2_020y4"] +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerTypeRandom3D.gd" id="3_6s2h2"] +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerPreset3D.gd" id="4_ko4ur"] + +[sub_resource type="Curve" id="Curve_csfne"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.429245, 0), 0.0, 0.0, 0, 0, Vector2(0.457547, 1), 0.0, 0.0, 0, 0, Vector2(0.787736, 1), 0.0, 0.0, 0, 0, Vector2(0.985849, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 6 + +[sub_resource type="Resource" id="Resource_n7d86"] +script = ExtResource("2_020y4") +curve_y = SubResource("Curve_csfne") +loop = true +amplitude = Vector3(1, 1, 1) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 0.0 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[sub_resource type="Resource" id="Resource_c2tfw"] +script = ExtResource("3_6s2h2") +seed = 0 +amplitude = Vector3(0.25, 0.25, 0.25) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 5.42787 +start_percent = 0.0 +end_percent = 0.59 +_temp_graph = false +bake_internal = 64 + +[sub_resource type="Curve" id="Curve_ioyrx"] +_data = [Vector2(0.501572, 0), 0.0, 0.0, 0, 0, Vector2(1, 1), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="Resource" id="Resource_1e44d"] +script = ExtResource("2_020y4") +curve_y = SubResource("Curve_ioyrx") +loop = true +amplitude = Vector3(2, 2, 2) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 0.0 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[sub_resource type="Curve" id="Curve_01cbm"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.0613208, 0.20904), 0.0, 0.0, 0, 0, Vector2(0.143082, 0), 0.0, 0.0, 0, 0, Vector2(0.215409, 0.20904), 0.0, 0.0, 0, 0, Vector2(0.275157, 0), 0.0, 0.0, 0, 0, Vector2(0.429245, 0), 0.0, 0.0, 0, 0, Vector2(0.463836, 1), 0.0, 0.0, 0, 0, Vector2(0.905204, 1), 0.35252, 0.35252, 0, 0, Vector2(0.957249, 0.482796), 0.0, 0.0, 0, 0, Vector2(0.99999, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 11 + +[sub_resource type="Curve" id="Curve_uayq1"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.0613208, 0.20904), 0.0, 0.0, 0, 0, Vector2(0.143082, 0), 0.0, 0.0, 0, 0, Vector2(0.215409, 0.20904), 0.0, 0.0, 0, 0, Vector2(0.275157, 0), 0.0, 0.0, 0, 0, Vector2(0.429245, 0), 0.0, 0.0, 0, 0, Vector2(0.463836, 1), 0.0, 0.0, 0, 0, Vector2(0.905204, 1), 0.35252, 0.35252, 0, 0, Vector2(0.957249, 0.482796), 0.0, 0.0, 0, 0, Vector2(0.99999, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 11 + +[sub_resource type="Curve" id="Curve_b6gtf"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.0613208, 0.20904), 0.0, 0.0, 0, 0, Vector2(0.143082, 0), 0.0, 0.0, 0, 0, Vector2(0.215409, 0.20904), 0.0, 0.0, 0, 0, Vector2(0.275157, 0), 0.0, 0.0, 0, 0, Vector2(0.429245, 0), 0.0, 0.0, 0, 0, Vector2(0.463836, 1), 0.0, 0.0, 0, 0, Vector2(0.905204, 1), 0.35252, 0.35252, 0, 0, Vector2(0.957249, 0.482796), 0.0, 0.0, 0, 0, Vector2(0.99999, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 11 + +[sub_resource type="Resource" id="Resource_011mv"] +script = ExtResource("2_020y4") +curve_x = SubResource("Curve_01cbm") +curve_y = SubResource("Curve_uayq1") +curve_z = SubResource("Curve_b6gtf") +loop = true +amplitude = Vector3(0.5, 0.5, 0.5) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 0.0 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[resource] +script = ExtResource("4_ko4ur") +PositionShake = Array[Resource("res://addons/shaker/data/Vector3/BaseShakerType3D.gd")]([SubResource("Resource_n7d86")]) +RotationShake = Array[Resource("res://addons/shaker/data/Vector3/BaseShakerType3D.gd")]([SubResource("Resource_c2tfw"), SubResource("Resource_1e44d")]) +ScaleShake = Array[Resource("res://addons/shaker/data/Vector3/BaseShakerType3D.gd")]([SubResource("Resource_011mv")]) +bake_internal = 64 +__follow_timeline = true diff --git a/addons/shaker/data/resources/shaker_earthquake3D.tres b/addons/shaker/data/resources/shaker_earthquake3D.tres new file mode 100644 index 00000000..6ab68c8f --- /dev/null +++ b/addons/shaker/data/resources/shaker_earthquake3D.tres @@ -0,0 +1,55 @@ +[gd_resource type="Resource" script_class="ShakerPreset3D" load_steps=8 format=3 uid="uid://cvklw5ika1tao"] + +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/BaseShakerType3D.gd" id="1_d2tua"] +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerTypeSineWave3D.gd" id="2_pfinc"] +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerTypeRandom3D.gd" id="3_ghpi8"] +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerPreset3D.gd" id="4_trx4m"] + +[sub_resource type="Resource" id="Resource_pq027"] +script = ExtResource("2_pfinc") +frequency = Vector3(10, 10, 1) +phase = Vector3(1, 1, 1) +amplitude = Vector3(0.25, 0.2, 0) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 1e-05 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[sub_resource type="Resource" id="Resource_won02"] +script = ExtResource("3_ghpi8") +seed = 0 +amplitude = Vector3(0.25, 0.25, 0) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 0.633041 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[sub_resource type="Resource" id="Resource_twjh4"] +script = ExtResource("2_pfinc") +frequency = Vector3(1, 1, 1) +phase = Vector3(1, 1, 1) +amplitude = Vector3(0.025, 0, 0.025) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 0.0 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[resource] +script = ExtResource("4_trx4m") +PositionShake = Array[ExtResource("1_d2tua")]([SubResource("Resource_pq027"), SubResource("Resource_won02")]) +RotationShake = Array[ExtResource("1_d2tua")]([SubResource("Resource_twjh4")]) +ScaleShake = Array[ExtResource("1_d2tua")]([]) +bake_internal = 64 +__follow_timeline = false diff --git a/addons/shaker/data/resources/shaker_head_blob3D.tres b/addons/shaker/data/resources/shaker_head_blob3D.tres new file mode 100644 index 00000000..8c0d5a69 --- /dev/null +++ b/addons/shaker/data/resources/shaker_head_blob3D.tres @@ -0,0 +1,55 @@ +[gd_resource type="Resource" script_class="ShakerPreset3D" load_steps=7 format=3 uid="uid://bgwupdyecxqic"] + +[ext_resource type="Resource" uid="uid://cqhisip66ngbl" path="res://ShakerDemoScenes/HeadBobWalking.tres" id="2_abfix"] +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerTypeSineWave3D.gd" id="2_lj1xu"] +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerPreset3D.gd" id="3_1llgx"] + +[sub_resource type="Resource" id="Resource_hui0g"] +script = ExtResource("2_lj1xu") +frequency = Vector3(0.75, 1, 1) +phase = Vector3(1, 1, 1) +amplitude = Vector3(0.04, 0.08, 0) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 0.0 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[sub_resource type="Resource" id="Resource_usaqk"] +script = ExtResource("2_lj1xu") +frequency = Vector3(1, 1, 1) +phase = Vector3(1.5, 1, 1) +amplitude = Vector3(0.02, 0, 0) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 0.0 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[sub_resource type="Resource" id="Resource_sxvgt"] +script = ExtResource("2_lj1xu") +frequency = Vector3(0.5, 1, 0.25) +phase = Vector3(1, 1, 1) +amplitude = Vector3(0.02, 0, 0.008) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 0.0 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[resource] +script = ExtResource("3_1llgx") +PositionShake = Array[Resource("res://addons/shaker/data/Vector3/BaseShakerType3D.gd")]([SubResource("Resource_hui0g"), SubResource("Resource_usaqk")]) +RotationShake = Array[Resource("res://addons/shaker/data/Vector3/BaseShakerType3D.gd")]([SubResource("Resource_sxvgt"), ExtResource("2_abfix")]) +ScaleShake = Array[Resource("res://addons/shaker/data/Vector3/BaseShakerType3D.gd")]([]) +bake_internal = 64 +__follow_timeline = false diff --git a/addons/shaker/data/resources/strong_shake3D.tres b/addons/shaker/data/resources/strong_shake3D.tres new file mode 100644 index 00000000..bb500beb --- /dev/null +++ b/addons/shaker/data/resources/strong_shake3D.tres @@ -0,0 +1,40 @@ +[gd_resource type="Resource" script_class="ShakerPreset3D" load_steps=5 format=3 uid="uid://dakufr1eoowxf"] + +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerTypeSineWave3D.gd" id="2_dydew"] +[ext_resource type="Script" path="res://addons/shaker/data/Vector3/ShakerPreset3D.gd" id="3_1oh1n"] + +[sub_resource type="Resource" id="Resource_rqq58"] +script = ExtResource("2_dydew") +frequency = Vector3(7.065, 1, 1) +phase = Vector3(1, 1, 1) +amplitude = Vector3(0.5, 0.5, 0) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 2.36259 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[sub_resource type="Resource" id="Resource_4yuof"] +script = ExtResource("2_dydew") +frequency = Vector3(2.94, 1.125, 1) +phase = Vector3(1, 1, 1) +amplitude = Vector3(0.053, 0.05, 0.1) +offset = Vector3(0, 0, 0) +BlendingMode = 0 +fade_in = 0.0 +fade_out = 2.36259 +start_percent = 0.0 +end_percent = 1.0 +_temp_graph = false +bake_internal = 64 + +[resource] +script = ExtResource("3_1oh1n") +PositionShake = Array[Resource("res://addons/shaker/data/Vector3/BaseShakerType3D.gd")]([SubResource("Resource_rqq58")]) +RotationShake = Array[Resource("res://addons/shaker/data/Vector3/BaseShakerType3D.gd")]([SubResource("Resource_4yuof")]) +ScaleShake = Array[Resource("res://addons/shaker/data/Vector3/BaseShakerType3D.gd")]([]) +bake_internal = 64 +__follow_timeline = false diff --git a/addons/shaker/plugin.cfg b/addons/shaker/plugin.cfg new file mode 100644 index 00000000..bd9db9cd --- /dev/null +++ b/addons/shaker/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Shaker" +description="" +author="Eneskp" +version="1.0.7" +script="src/shaker_plugin.gd" diff --git a/addons/shaker/src/Shaker.gd b/addons/shaker/src/Shaker.gd new file mode 100644 index 00000000..a8e476af --- /dev/null +++ b/addons/shaker/src/Shaker.gd @@ -0,0 +1,92 @@ +extends Node + + +func shake_by_preset(preset:ShakerPresetBase, node:Node, duration:float, speed:float=1.0, intensity:float=1.0, fade_in:float=0.25, fade_out:float=2.0): + if (preset is ShakerPreset2D && not node is Node2D): assert(false, "ShakerPreset2D only works for Node2D type") + if (preset is ShakerPreset3D && not node is Node3D): assert(false, "ShakerPreset3D only works for Node3D type") + if preset is ShakerPreset3D: + var component:ShakerComponent3D = ShakerComponent3D.new() + add_child(component) + component.name = "TEMP_ShakerComponent3D" + component.custom_target = true + component.intensity = intensity + component.Targets.append(node) + component.duration = duration + component.shake_speed = speed + component.fade_in = fade_in + component.fade_out = fade_out + component.shakerPreset = preset + component.shake_finished.connect(_on_shake_finished.bind(component)) + component.play_shake() + + elif preset is ShakerPreset2D: + var component:ShakerComponent2D = ShakerComponent2D.new() + component.name = "ShakerComponent2D" + add_child(component) + component.custom_target = true + component.Targets.append(node) + component.duration = duration + component.intensity = intensity + component.shake_speed = speed + component.fade_in = fade_in + component.fade_out = fade_out + component.shakerPreset = preset + component.shake_finished.connect(_on_shake_finished.bind(component)) + + component.play_shake() + +func shake_property(property:ShakerProperty, node:Node, duration:float, speed:float=1.0, intensity:float=1.0, fade_in:float=0.25, fade_out:float=2.0) -> ShakerComponent: + var component:ShakerComponent = ShakerComponent.new() + component.name = "ShakerComponent" + add_child(component) + component.custom_target = true + component.Targets.append(node) + component.duration = duration + component.shake_speed = speed + component.intensity = intensity + component.fade_in = fade_in + component.fade_out = fade_out + component.shakerProperty.append(property) + component.shake_finished.connect(_on_shake_finished.bind(component)) + + component.play_shake() + return component + +func shake_emit_3d(position:Vector3,preset:ShakerPreset3D, max_distance:float, duration:float, distance_attenuation:float=0.5, speed:float=1.0, fade_in:float=0.25, fade_out:float=2.0) -> ShakerEmitter3D: + var component:ShakerEmitter3D = ShakerEmitter3D.new() + component.name = "ShakerEmitter3D" + add_child(component) + component.max_distance = max_distance + component.global_position = position + component.duration = duration + component.shake_speed = speed + component.fade_in = fade_in + component.fade_out = fade_out + component.shakerPreset = preset + component.collision.shape = SphereShape3D.new() + component.collision.shape.radius = max_distance + component.shake_finished.connect(_on_shake_finished.bind(component)) + + component.play_shake() + return component + +func shake_emit_2d(position:Vector2,preset:ShakerPreset2D, max_distance:float, duration:float, distance_attenuation:float=0.5, speed:float=1.0, fade_in:float=0.25, fade_out:float=2.0) -> ShakerEmitter2D: + var component:ShakerEmitter2D = ShakerEmitter2D.new() + component.name = "ShakerEmitter2D" + add_child(component) + component.max_distance = max_distance + component.global_position = position + component.duration = duration + component.shake_speed = speed + component.fade_in = fade_in + component.fade_out = fade_out + component.shakerPreset = preset + component.collision.shape = CircleShape2D.new() + component.collision.shape.radius = max_distance + component.shake_finished.connect(_on_shake_finished.bind(component)) + + component.play_shake() + return component + +func _on_shake_finished(shaker_component) -> void: + shaker_component.queue_free() diff --git a/addons/shaker/src/Shaker.gd.uid b/addons/shaker/src/Shaker.gd.uid new file mode 100644 index 00000000..373ef131 --- /dev/null +++ b/addons/shaker/src/Shaker.gd.uid @@ -0,0 +1 @@ +uid://c7flmumgr5w3u diff --git a/addons/shaker/src/Vector2/ShakerBase2D.gd b/addons/shaker/src/Vector2/ShakerBase2D.gd new file mode 100644 index 00000000..d4a9fc73 --- /dev/null +++ b/addons/shaker/src/Vector2/ShakerBase2D.gd @@ -0,0 +1,90 @@ +@tool +extends Node2D + +# Shake intensity +@export_range(0.0, 1.0, 0.001, "or_greater") var intensity: float = 1.0: + set = set_intensity, + get = get_intensity + +# Shake duration +@export var duration: float = 0.00: + set = set_duration, + get = get_duration + +# Shake speed +@export_range(0.0, 1.0, 0.001, "or_greater") var shake_speed: float = 1.0: + set = set_shake_speed, + get = get_shake_speed + +# Fade-in easing +@export_exp_easing var fade_in: float = 0.25: + set = set_fade_in, + get = get_fade_in + +# Fade-out easing +@export_exp_easing("attenuation") var fade_out: float = 0.25: + set = set_fade_out, + get = get_fade_out + +# Shaker preset +@export var shakerPreset:ShakerPreset2D: + set = set_shaker_preset, + get = get_shaker_preset + +# Timer for shake progress +var timer: float = 0.0: + set = _on_timeline_progress + +# SIGNALS +signal timeline_progress(progress: float) +signal shake_started +signal shake_finished +signal shake_fading_out + +func set_intensity(value: float) -> void: + intensity = max(value, 0.0) + +func get_intensity() -> float: + return intensity + +func set_duration(value: float) -> void: + duration = max(value, 0.0) + if shakerPreset != null: + shakerPreset.component_duration = duration + notify_property_list_changed() + +func get_duration() -> float: + return duration + +func set_shake_speed(value: float) -> void: + shake_speed = max(value, 0.001) + notify_property_list_changed() + +func get_shake_speed() -> float: + return shake_speed + +func set_fade_in(value: float) -> void: + fade_in = value + +func get_fade_in() -> float: + return fade_in + +func set_fade_out(value: float) -> void: + fade_out = value + +func get_fade_out() -> float: + return fade_out + +func set_shaker_preset(value: ShakerPreset2D) -> void: + shakerPreset = value + if shakerPreset != null: + shakerPreset.parent = self + shakerPreset.component_duration = duration + +func get_shaker_preset() -> ShakerPreset2D: + return shakerPreset + +# Handles timeline progress +func _on_timeline_progress(value: float) -> void: + timer = value + timeline_progress.emit(timer) diff --git a/addons/shaker/src/Vector2/ShakerBase2D.gd.uid b/addons/shaker/src/Vector2/ShakerBase2D.gd.uid new file mode 100644 index 00000000..d31ecbbe --- /dev/null +++ b/addons/shaker/src/Vector2/ShakerBase2D.gd.uid @@ -0,0 +1 @@ +uid://c0tuadw5ygn6m diff --git a/addons/shaker/src/Vector2/ShakerEmitter2D.gd b/addons/shaker/src/Vector2/ShakerEmitter2D.gd new file mode 100644 index 00000000..690fb0a2 --- /dev/null +++ b/addons/shaker/src/Vector2/ShakerEmitter2D.gd @@ -0,0 +1,172 @@ +@icon("res://addons/shaker/assets/ShakerEmitter2D.svg") +@tool +class_name ShakerEmitter2D +extends "res://addons/shaker/src/Vector2/ShakerBase2D.gd" + +## It emits shake values and is received by ShakeEmitter2D. + +# Exported variables +@export var emit: bool: + set = set_emit, + get = get_emit + +@export var max_distance: float = 0.0: + set = set_max_distance, + get = get_max_distance + +@export_exp_easing("attenuation") var distance_attenuation: float = 0.5: + set = set_distance_attenuation, + get = get_distance_attenuation + +# Private variables +var emitting: bool = false +var _timer_offset: float = 0.0 +var _fading_out: bool = false +var shake_offset_position: Vector2 = Vector2.ZERO +var shake_offset_rotation:float = 0.0 +var shake_offset_scale: Vector2 = Vector2.ZERO +var area2d: Area2D +var collision:CollisionShape2D + +# Called when the node enters the scene tree for the first time +func _ready() -> void: + add_to_group("ShakerEmitter") + + for child in get_children(): + if child is Area2D: + area2d = child + + if not area2d: + _create_Area2D() + + set_emit(emit) + +# Creates an Area2D child node if one doesn't exist +func _create_Area2D() -> void: + area2d = Area2D.new() + collision = CollisionShape2D.new() + add_child(area2d) + area2d.add_child(collision) + area2d.set_owner(get_tree().edited_scene_root) + collision.set_owner(get_tree().edited_scene_root) + area2d.name = "Area2D" + collision.name = "CollisionShape2D" + + area2d.collision_layer = 1 << 9 + area2d.collision_mask = 0 + +# Called every frame +func _process(delta: float) -> void: + if emitting: + if shakerPreset != null: + if timer <= duration or duration == 0.0: + _progress_shake() + timer += delta * shake_speed + else: + force_stop_shake() + else: + if timer > 0: + force_stop_shake() + +# Progresses the shake effect +func _progress_shake() -> void: + var _ease_in: float = 1.0 + var _ease_out: float = 1.0 + var _final_duration: float = duration if (duration > 0 and not _fading_out) else 1.0 + + _ease_in = ease(timer/_final_duration, fade_in) + _ease_out = ease(1.0 - (max((timer - _timer_offset), 0.0))/_final_duration, fade_out) + + if not (duration > 0) or _fading_out: + if _ease_out <= get_process_delta_time(): + force_stop_shake() + + var _shake_position: Vector2 = Vector2.ZERO + var _shake_rotation:float = 0.0 + var _shake_scale: Vector2 = Vector2.ZERO + + if shakerPreset != null: + var _value: float = timer + var _strength: float = intensity * _ease_in * _ease_out + + _shake_position += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.POSITION) * _strength) + _shake_rotation += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.ROTATION) * _strength * (PI/2.0)) + _shake_scale += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.SCALE) * _strength) + + shake_offset_position = _shake_position + shake_offset_rotation = _shake_rotation + shake_offset_scale = _shake_scale + +# Starts the shake effect +func play_shake() -> void: + if shakerPreset != null: + emitting = true + _fading_out = false + _initialize_timer_offset() + shake_started.emit() + +func _initialize_timer_offset() -> void: + if !(duration > 0): _timer_offset = 0x80000 + else: _timer_offset = 0.0 + +# Stops the shake effect with a fade-out +func stop_shake() -> void: + if not _fading_out: + _timer_offset = timer + _fading_out = true + shake_fading_out.emit() + +# Immediately stops the shake effect +func force_stop_shake() -> void: + if emitting: + if emit: emit = false + _fading_out = false + emitting = false + set_progress(0.0) + shake_finished.emit() + +# Returns configuration warnings +func _get_configuration_warnings() -> PackedStringArray: + if not get_children().any(func(child): return child is Area2D): + return ["First child must be Area2D"] + return [] + +# Sets the shake progress +func set_progress(value: float) -> void: + timer = value + _progress_shake() + +# Setter for emit property +func set_emit(value: bool) -> void: + emit = value + if value: + play_shake() + elif timer > 0: + force_stop_shake() + +# Getter for emit property +func get_emit() -> bool: + return emit + +# Setter for max_distance property +func set_max_distance(value: float) -> void: + max_distance = value + notify_property_list_changed() + +# Getter for max_distance property +func get_max_distance() -> float: + return max_distance + +# Setter for distance_attenuation property +func set_distance_attenuation(value: float) -> void: + distance_attenuation = value + +# Getter for distance_attenuation property +func get_distance_attenuation() -> float: + return distance_attenuation + +# Validates properties +func _validate_property(property: Dictionary) -> void: + if property.name == "distance_attenuation": + if not (max_distance > 0): + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/shaker/src/Vector2/ShakerEmitter2D.gd.uid b/addons/shaker/src/Vector2/ShakerEmitter2D.gd.uid new file mode 100644 index 00000000..3597b2d2 --- /dev/null +++ b/addons/shaker/src/Vector2/ShakerEmitter2D.gd.uid @@ -0,0 +1 @@ +uid://ddpgk78xe5y4g diff --git a/addons/shaker/src/Vector2/ShakerReceiver2D.gd b/addons/shaker/src/Vector2/ShakerReceiver2D.gd new file mode 100644 index 00000000..522bc881 --- /dev/null +++ b/addons/shaker/src/Vector2/ShakerReceiver2D.gd @@ -0,0 +1,148 @@ +@icon("res://addons/shaker/assets/ShakerReceiver2D.svg") +@tool +class_name ShakerReceiver2D +extends Node2D + +## Transmits values from ShakerEmitter2D to ShakerComponent2D + +# Fade-in easing +@export_exp_easing var enter_fade_in: float = 0.1: + set = set_fade_in, + get = get_fade_in + +# Fade-out easing +@export_exp_easing("attenuation") var exit_fade_out: float = 3.0: + set = set_fade_out, + get = get_fade_out + +# Private variables +var area2D: Area2D +var position_offset: Vector2 = Vector2.ZERO +var rotation_offset:float = 0.0 +var scale_offset: Vector2 = Vector2.ZERO +var emitter_list: Array[EmitterData] + +# Called when the node enters the scene tree for the first time +func _ready() -> void: + _setup_area2D() + if !Engine.is_editor_hint(): + add_to_group("ShakerReceiver") + _connect_signals() + +# Sets up the Area2D node +func _setup_area2D() -> void: + for child in get_children(): + if child is Area2D: + area2D = child + return + + area2D = Area2D.new() + var collision = CollisionShape2D.new() + add_child(area2D) + area2D.add_child(collision) + area2D.set_owner(get_tree().edited_scene_root) + collision.set_owner(get_tree().edited_scene_root) + area2D.name = "Area2D" + collision.name = "CollisionShape2D" + + area2D.collision_layer = 0 + area2D.collision_mask = 1 << 9 + +# Connects signals +func _connect_signals() -> void: + area2D.area_entered.connect(on_area_entered) + area2D.area_exited.connect(on_area_exited) + +# Called every frame +func _process(delta: float) -> void: + position_offset = Vector2.ZERO + rotation_offset = 0.0 + scale_offset = Vector2.ZERO + + if emitter_list.size() > 0: + for emitter_data in emitter_list: + _process_emitter(emitter_data, delta) + +# Processes each emitter +func _process_emitter(emitter_data: EmitterData, delta: float) -> void: + if emitter_data.emitter: + var ease_in: float = ease(emitter_data.timer, enter_fade_in) + var ease_out: float = ease(1.0 - (emitter_data.timer - emitter_data.fade_out_timer), exit_fade_out) if emitter_data.fade_out_timer != 0.0 else 1.0 + emitter_data.ease_out_intensity = move_toward(emitter_data.ease_out_intensity, ease_out, delta) + ease_out = emitter_data.ease_out_intensity + var max_distance: float = emitter_data.emitter.max_distance + var distance: float = min(emitter_data.emitter.global_position.distance_to(global_position), max_distance) / max(max_distance, 0.001) + var attenuation: float = ease(1.0 - distance, emitter_data.emitter.distance_attenuation) + position_offset += emitter_data.emitter.shake_offset_position * ease_in * ease_out * attenuation + rotation_offset += emitter_data.emitter.shake_offset_rotation * ease_in * ease_out * attenuation + scale_offset += emitter_data.emitter.shake_offset_scale * ease_in * ease_out * attenuation + + emitter_data.timer += delta + if ease_out <= delta: + emitter_list.erase(emitter_data) + else: + emitter_list.erase(emitter_data) +# Returns the current shake values +func get_value() -> Array[Vector2]: + return [position_offset, Vector2(rotation_offset, 0.0), scale_offset] + +# Returns configuration warnings +func _get_configuration_warnings() -> PackedStringArray: + if not get_parent() is ShakerComponent2D: + return ["Parent must be ShakerComponent2D"] + var _ex:bool = false + for i in get_children(): + if i is Area2D: + _ex = true + break + if !_ex: + return ["ShakerReceiver2D needs Area2D to work"] + return [] + +# Called when an area enters +func on_area_entered(area: Area2D) -> void: + var node = area.get_parent() + if node is ShakerEmitter2D: + var data = EmitterData.new(node) + emitter_list.append(data) + +# Called when an area exits +func on_area_exited(area: Area2D) -> void: + var node = area.get_parent() + if node is ShakerEmitter2D: + for index in emitter_list.size(): + var data = emitter_list[index] + if data.emitter == node: + data.fade_out_timer = data.timer + break + +# Setter for enter_fade_in +func set_fade_in(value: float) -> void: + enter_fade_in = value + +# Getter for enter_fade_in +func get_fade_in() -> float: + return enter_fade_in + +# Setter for exit_fade_out +func set_fade_out(value: float) -> void: + exit_fade_out = value + +# Getter for exit_fade_out +func get_fade_out() -> float: + return exit_fade_out + +# EmitterData inner class +class EmitterData: + var emitter: ShakerEmitter2D + var timer: float = 0.0 + var fade_out_timer: float = 0.0 + var ease_out_intensity:float = 1.0 + + func _init(_emitter: ShakerEmitter2D) -> void: + self.emitter = _emitter +func is_playing() -> bool: + for i:EmitterData in emitter_list: + return i.emitter.emitting + return false + diff --git a/addons/shaker/src/Vector2/ShakerReceiver2D.gd.uid b/addons/shaker/src/Vector2/ShakerReceiver2D.gd.uid new file mode 100644 index 00000000..5b2c9ae8 --- /dev/null +++ b/addons/shaker/src/Vector2/ShakerReceiver2D.gd.uid @@ -0,0 +1 @@ +uid://ca4ybjjck0t0a diff --git a/addons/shaker/src/Vector2/shaker_component2D.gd b/addons/shaker/src/Vector2/shaker_component2D.gd new file mode 100644 index 00000000..dca2fece --- /dev/null +++ b/addons/shaker/src/Vector2/shaker_component2D.gd @@ -0,0 +1,287 @@ +@tool +@icon("res://addons/shaker/assets/Shaker2D.svg") +class_name ShakerComponent2D +extends "res://addons/shaker/src/Vector2/ShakerBase2D.gd" + +## Allows you to apply shake effect to any 2D node according to position, rotation, scale + +enum ShakeAddMode { + add, + override +} + +# Custom target flag +@export var custom_target: bool = false: + set = set_custom_target, + get = get_custom_target + +# Array of target Node2D objects +@export var Targets: Array[Node2D] + +# Randomization flag +@export var randomize: bool = false: + set = set_randomize, + get = get_randomize + +# Playing state +@export var is_playing: bool = false + +@export var AutoPlay:bool = false + +# Private variables +var _last_position_shake: Array[Vector2] = [Vector2.ZERO] +var _last_scale_shake: Array[Vector2] = [Vector2.ZERO] +var _last_rotation_shake: Array[float] = [0] +var _timer_offset: float = 0.0 +var _fading_out: bool = false +var _seed: float = 203445 +var _external_shakes:Array[ExternalShake] + +# Called when the node enters the scene tree for the first time +func _ready() -> void: + set_process_input(false) + set_process_internal(false) + set_process_shortcut_input(false) + set_process_unhandled_input(false) + set_physics_process(false) + set_physics_process_internal(false) + add_to_group("ShakerComponent") + + if !Engine.is_editor_hint(): + if AutoPlay: + play_shake() + +# Resets the shaker to its initial state +func _reset() -> void: + _last_position_shake = [Vector2.ZERO] + _last_scale_shake = [Vector2.ZERO] + _last_rotation_shake = [0] + _external_shakes.clear() + _initalize_prev_positions() + is_playing = false + _initialize_timer_offset() + _fading_out = false + _initalize_target() + +# Initializes previous positions for randomized shaking +func _initalize_prev_positions() -> void: + _last_position_shake.resize(Targets.size()) + _last_position_shake.fill(Vector2.ZERO) + + _last_scale_shake.resize(Targets.size()) + _last_scale_shake.fill(Vector2.ZERO) + + _last_rotation_shake.resize(Targets.size()) + _last_rotation_shake.fill(0) + +# Called every frame +func _process(delta: float) -> void: + if is_playing: + if shakerPreset != null || _external_shakes.size() > 0 || is_receiving_from_emitters(): + if timer <= duration || duration == 0.0: + _progress_shake() + timer += delta * shake_speed + else: + force_stop_shake() + else: + if timer > 0: + force_stop_shake() + + +# Progresses the shake effect +func _progress_shake() -> void: + var _ease_in: float = 1.0 + var _ease_out: float = 1.0 + var _final_duration: float = duration if (duration > 0 && !_fading_out) else 1.0 + + _ease_in = ease((timer)/_final_duration, fade_in) + _ease_out = ease(1.0-(max((timer)-_timer_offset, 0.0))/_final_duration, fade_out) + + if (!(duration > 0) || _fading_out) && is_playing: + if _ease_out <= get_process_delta_time(): + force_stop_shake() + + var _shake_position: Array[Vector2] = [] + var _shake_rotation: Array[float] = [] + var _shake_scale: Array[Vector2] = [] + + var _count:int =(Targets.size() if randomize else 1) + + _shake_position.resize(_count) + _shake_position.fill(Vector2.ZERO) + _shake_rotation.resize(_count) + _shake_rotation.fill(0) + _shake_scale.resize(_count) + _shake_scale.fill(Vector2.ZERO) + + for _index in _count: + var _randomized: float = (_seed * (float(_index+1) / Targets.size())) if randomize else 0.0 + if _last_position_shake.size() != _count: _initalize_prev_positions() + + # Shaker Preset + if shakerPreset != null: + var _value:float = timer + _randomized + var _strength:float = intensity * _ease_in * _ease_out + + _shake_position[_index] += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.POSITION) * _strength) + _shake_rotation[_index] += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.ROTATION) * _strength * (PI/2.0)) + _shake_scale[_index] += (shakerPreset.get_value(_value, ShakerPreset2D.Categories.SCALE) * _strength) + + # External Shake Addition + for external_shake:ExternalShake in _external_shakes: + var _real_time:float = min(timer-external_shake.start_time, external_shake.duration) + _ease_in = ease(_real_time/external_shake.duration, external_shake.fade_in) + _ease_out = ease(1.0-(_real_time/external_shake.duration), external_shake.fade_out) + var _value:float = (_real_time*external_shake.speed) + _randomized + var _strength:float = external_shake.intensity * intensity * _ease_in * _ease_out + var _mode_value:Array[Vector2] = [Vector2.ZERO, Vector2.ZERO, Vector2.ZERO] + match external_shake.mode: + ShakeAddMode.add: + _mode_value = [_shake_position[_index], Vector2(_shake_rotation[_index], 0.0), _shake_scale[_index] ] + _shake_position[_index] = _mode_value[0] + (external_shake.preset.get_value(_value, ShakerPreset2D.Categories.POSITION) * _strength) + _shake_rotation[_index] = _mode_value[1].x +(external_shake.preset.get_value(_value, ShakerPreset2D.Categories.ROTATION).x * _strength * (PI/2.0)) + _shake_scale[_index] = _mode_value[2] + (external_shake.preset.get_value(_value, ShakerPreset2D.Categories.SCALE) * _strength) + + if _real_time >= external_shake.duration: + _external_shakes.erase(external_shake) + + # Shake Emitter + for _child in get_children(): + if _child is ShakerReceiver2D: + _shake_position[_index] += _child.position_offset + _shake_rotation[_index] += _child.rotation_offset + _shake_scale[_index] += _child.scale_offset + + for index: int in Targets.size(): + var target: Node2D = Targets[index] + if !is_instance_valid(target): + Targets.remove_at(index) + index-=1 + if Targets.size() <= 0: + shake_finished.emit() + break + var _i:int = fmod(index, _shake_position.size()) + target.position += -_last_position_shake[_i] + _shake_position[_i] + target.rotation += -_last_rotation_shake[_i] + _shake_rotation[_i] + target.scale += -_last_scale_shake[_i] + _shake_scale[_i] + + _last_position_shake = _shake_position + _last_rotation_shake = _shake_rotation + _last_scale_shake = _shake_scale + +# Stops the shake effect with a fade-out +func stop_shake() -> void: + if !_fading_out: + _timer_offset = timer + _fading_out = true + shake_fading_out.emit() + +# Immediately stops the shake effect +func force_stop_shake() -> void: + if is_playing || _fading_out: + set_progress(0.0) + _reset() + shake_finished.emit() + +# Starts the shake effect +func play_shake() -> void: + _initalize_target() + randomize_shake() + is_playing = !is_playing if Engine.is_editor_hint() else true + _fading_out = false + _initialize_timer_offset() + shake_started.emit() + +func randomize_shake() -> void: + _seed = randf_range(10000, 99999) + +func _initalize_target() -> void: + if !custom_target: + Targets.clear() + if get_parent() is Node2D: + Targets.append(get_parent()) + +# Placeholder for shake function +func shake(shaker_preset:ShakerPreset2D, _mode:ShakeAddMode=ShakeAddMode.add, duration:float=1.0, speed:float=1.0, intensity:float=1.0, fade_in:float=.25, fade_out:float=.25) -> void: + var external_shake:ExternalShake = ExternalShake.new() + external_shake.preset = shaker_preset + external_shake.duration = duration + external_shake.speed = speed + external_shake.intensity = intensity + external_shake.start_time = timer + external_shake.fade_in = fade_in + external_shake.fade_out = fade_out + external_shake.mode = _mode + _external_shakes.append(external_shake) + if Targets.is_empty(): + _initalize_target() + is_playing = true + +# Validates property visibility +func _validate_property(property: Dictionary) -> void: + if property.name == "Targets" || property.name == "randomize": + if !custom_target: + property.usage = PROPERTY_USAGE_NONE + if property.name == "fade_time": + if duration > 0: + property.usage = PROPERTY_USAGE_NONE + +# Get configuration warnings +func _get_configuration_warnings() -> PackedStringArray: + if !custom_target: + if not get_parent() is Node2D: + return ["Parent must be Node2D"] + + return [] + +# Sets the shake progress +func set_progress(value: float) -> void: + timer = value + _progress_shake() + + + +# Custom setter and getter functions for @export variables +func set_custom_target(value: bool) -> void: + custom_target = value + notify_property_list_changed() + +func get_custom_target() -> bool: + return custom_target + +func set_randomize(value: bool) -> void: + if custom_target && Targets.size() > 1: + for index: int in Targets.size(): + var target: Node2D = Targets[index] + var i = fmod(index, _last_position_shake.size()) + target.position += -_last_position_shake[i] + target.rotation += -_last_rotation_shake[i] + target.scale += -_last_scale_shake[i] + _last_position_shake.fill(_last_position_shake[0]) + _last_rotation_shake.fill(_last_rotation_shake[0]) + _last_scale_shake.fill(_last_scale_shake[0]) + randomize = value + randomize_shake() + +func get_randomize() -> bool: + return randomize + +class ExternalShake: + var preset:ShakerPreset2D + var duration:float = 1.0 + var speed:float = 1.0 + var intensity:float = 1.0 + var start_time:float = 0.0 + var fade_in:float = 0.25 + var fade_out:float = 0.25 + var mode:ShakeAddMode=ShakeAddMode.add + +func _initialize_timer_offset() -> void: + if !(duration > 0): _timer_offset = 0x80000 + else: _timer_offset = 0.0 + +func is_receiving_from_emitters() -> bool: + for _child in get_children(): + if _child is ShakerReceiver2D: + return _child.is_playing() + return false diff --git a/addons/shaker/src/Vector2/shaker_component2D.gd.uid b/addons/shaker/src/Vector2/shaker_component2D.gd.uid new file mode 100644 index 00000000..eb57ed90 --- /dev/null +++ b/addons/shaker/src/Vector2/shaker_component2D.gd.uid @@ -0,0 +1 @@ +uid://b78swtk5maey2 diff --git a/addons/shaker/src/Vector3/ShakerBase3D.gd b/addons/shaker/src/Vector3/ShakerBase3D.gd new file mode 100644 index 00000000..f8f01009 --- /dev/null +++ b/addons/shaker/src/Vector3/ShakerBase3D.gd @@ -0,0 +1,91 @@ +@tool +#class_name ShakerBase3D +extends Node3D + +# Shake intensity +@export_range(0.0, 1.0, 0.001, "or_greater") var intensity: float = 1.0: + set = set_intensity, + get = get_intensity + +# Shake duration +@export var duration: float = 0.00: + set = set_duration, + get = get_duration + +# Shake speed +@export_range(0.0, 1.0, 0.001, "or_greater") var shake_speed: float = 1.0: + set = set_shake_speed, + get = get_shake_speed + +# Fade-in easing +@export_exp_easing var fade_in: float = 0.25: + set = set_fade_in, + get = get_fade_in + +# Fade-out easing +@export_exp_easing("attenuation") var fade_out: float = 0.25: + set = set_fade_out, + get = get_fade_out + +# Shaker preset +@export var shakerPreset:ShakerPreset3D: + set = set_shaker_preset, + get = get_shaker_preset + +# Timer for shake progress +var timer: float = 0.0: + set = _on_timeline_progress + +# SIGNALS +signal timeline_progress(progress: float) +signal shake_started +signal shake_finished +signal shake_fading_out + +func set_intensity(value: float) -> void: + intensity = max(value, 0.0) + +func get_intensity() -> float: + return intensity + +func set_duration(value: float) -> void: + duration = max(value, 0.0) + if shakerPreset != null: + shakerPreset.component_duration = duration + notify_property_list_changed() + +func get_duration() -> float: + return duration + +func set_shake_speed(value: float) -> void: + shake_speed = max(value, 0.001) + notify_property_list_changed() + +func get_shake_speed() -> float: + return shake_speed + +func set_fade_in(value: float) -> void: + fade_in = value + +func get_fade_in() -> float: + return fade_in + +func set_fade_out(value: float) -> void: + fade_out = value + +func get_fade_out() -> float: + return fade_out + +func set_shaker_preset(value: ShakerPreset3D) -> void: + shakerPreset = value + if shakerPreset != null: + shakerPreset.parent = self + shakerPreset.component_duration = duration + +func get_shaker_preset() -> ShakerPreset3D: + return shakerPreset + +# Handles timeline progress +func _on_timeline_progress(value: float) -> void: + timer = value + timeline_progress.emit(timer) diff --git a/addons/shaker/src/Vector3/ShakerBase3D.gd.uid b/addons/shaker/src/Vector3/ShakerBase3D.gd.uid new file mode 100644 index 00000000..df835625 --- /dev/null +++ b/addons/shaker/src/Vector3/ShakerBase3D.gd.uid @@ -0,0 +1 @@ +uid://cna76yluotcdw diff --git a/addons/shaker/src/Vector3/ShakerEmitter3D.gd b/addons/shaker/src/Vector3/ShakerEmitter3D.gd new file mode 100644 index 00000000..4ee775df --- /dev/null +++ b/addons/shaker/src/Vector3/ShakerEmitter3D.gd @@ -0,0 +1,183 @@ +@icon("res://addons/shaker/assets/ShakerEmitter3D.svg") +@tool +class_name ShakerEmitter3D +extends "res://addons/shaker/src/Vector3/ShakerBase3D.gd" + +## It emits shake values and is received by ShakeEmitter3D. + +# Exported variables +@export var emit: bool: + set = set_emit, + get = get_emit + +@export var max_distance: float = 0.0: + set = set_max_distance, + get = get_max_distance + +@export_exp_easing("attenuation") var distance_attenuation: float = 0.5: + set = set_distance_attenuation, + get = get_distance_attenuation + +# Private variables +var emitting: bool = false +var _timer_offset: float = 0.0 +var _fading_out: bool = false +var shake_offset_position: Vector3 = Vector3.ZERO +var shake_offset_rotation: Vector3 = Vector3.ZERO +var shake_offset_scale: Vector3 = Vector3.ZERO +var area3d: Area3D +var collision:CollisionShape3D + +# Called when the node enters the scene tree for the first time +func _ready() -> void: + add_to_group("ShakerEmitter") + + for child in get_children(): + if child is Area3D: + area3d = child + + if not area3d: + _create_area3d() + + set_emit(emit) + +# Creates an Area3D child node if one doesn't exist +func _create_area3d() -> void: + area3d = Area3D.new() + collision = CollisionShape3D.new() + add_child(area3d) + area3d.add_child(collision) + area3d.set_owner(get_tree().edited_scene_root) + collision.set_owner(get_tree().edited_scene_root) + area3d.name = "Area3D" + collision.name = "CollisionShape3D" + + area3d.collision_layer = 1 << 9 + area3d.collision_mask = 0 + +# Called every frame +func _process(delta: float) -> void: + if !Engine.is_editor_hint(): + if emitting: + if shakerPreset != null: + if timer <= duration or duration == 0.0: + _progress_shake() + timer += delta * shake_speed + else: + force_stop_shake() + else: + if timer > 0: + force_stop_shake() + +# Progresses the shake effect +func _progress_shake() -> void: + if !Engine.is_editor_hint(): + var _ease_in: float = 1.0 + var _ease_out: float = 1.0 + var _final_duration: float = duration if (duration > 0 and not _fading_out) else 1.0 + + _ease_in = ease(timer/_final_duration, fade_in) + _ease_out = ease(1.0 - (max((timer - _timer_offset), 0.0))/_final_duration, fade_out) + + if not (duration > 0) or _fading_out: + if _ease_out <= get_process_delta_time(): + force_stop_shake() + + var _shake_position: Vector3 = Vector3.ZERO + var _shake_rotation: Vector3 = Vector3.ZERO + var _shake_scale: Vector3 = Vector3.ZERO + + if shakerPreset != null: + var _value: float = timer + var _strength: float = intensity * _ease_in * _ease_out + + _shake_position += (shakerPreset.get_value(_value, ShakerPreset3D.Categories.POSITION) * _strength) + _shake_rotation += (shakerPreset.get_value(_value, ShakerPreset3D.Categories.ROTATION) * _strength * (PI/2.0)) + _shake_scale += (shakerPreset.get_value(_value, ShakerPreset3D.Categories.SCALE) * _strength) + + shake_offset_position = _shake_position + shake_offset_rotation = _shake_rotation + shake_offset_scale = _shake_scale + +# Starts the shake effect +func play_shake() -> void: + if !Engine.is_editor_hint(): + if shakerPreset != null: + emitting = true + _fading_out = false + _initialize_timer_offset() + shake_started.emit() + +func _initialize_timer_offset() -> void: + if !(duration > 0): _timer_offset = 0x80000 + else: _timer_offset = 0.0 + +# Updates the gizmo +#func update_gizmo() -> void: + #if _gizmo: + #_gizmo._redraw() + +# Stops the shake effect with a fade-out +func stop_shake() -> void: + if !Engine.is_editor_hint(): + if not _fading_out: + _timer_offset = timer + _fading_out = true + shake_fading_out.emit() + +# Immediately stops the shake effect +func force_stop_shake() -> void: + if emitting: + if emit: emit = false + _fading_out = false + emitting = false + set_progress(0.0) + shake_finished.emit() + +# Returns configuration warnings +func _get_configuration_warnings() -> PackedStringArray: + if not get_children().any(func(child): return child is Area3D): + return ["First child must be Area3D"] + return [] + +# Sets the shake progress +func set_progress(value: float) -> void: + if !Engine.is_editor_hint(): + timer = value + _progress_shake() + +# Setter for emit property +func set_emit(value: bool) -> void: + emit = value + if !Engine.is_editor_hint(): + if value: + play_shake() + elif timer > 0: + force_stop_shake() + +# Getter for emit property +func get_emit() -> bool: + return emit + +# Setter for max_distance property +func set_max_distance(value: float) -> void: + max_distance = value + notify_property_list_changed() + +# Getter for max_distance property +func get_max_distance() -> float: + return max_distance + +# Setter for distance_attenuation property +func set_distance_attenuation(value: float) -> void: + distance_attenuation = value + +# Getter for distance_attenuation property +func get_distance_attenuation() -> float: + return distance_attenuation + +# Validates properties +func _validate_property(property: Dictionary) -> void: + if property.name == "distance_attenuation": + if not (max_distance > 0): + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/shaker/src/Vector3/ShakerEmitter3D.gd.uid b/addons/shaker/src/Vector3/ShakerEmitter3D.gd.uid new file mode 100644 index 00000000..22b35b48 --- /dev/null +++ b/addons/shaker/src/Vector3/ShakerEmitter3D.gd.uid @@ -0,0 +1 @@ +uid://vo46i2pfq0uf diff --git a/addons/shaker/src/Vector3/ShakerReceiver3D.gd b/addons/shaker/src/Vector3/ShakerReceiver3D.gd new file mode 100644 index 00000000..490b983a --- /dev/null +++ b/addons/shaker/src/Vector3/ShakerReceiver3D.gd @@ -0,0 +1,159 @@ +@icon("res://addons/shaker/assets/ShakerReceiver3D.svg") +@tool +class_name ShakerReceiver3D +extends Node3D + +## Transmits values from ShakerEmitter3D to ShakerComponent3D + +# Fade-in easing +@export_exp_easing var enter_fade_in: float = 0.1: + set = set_fade_in, + get = get_fade_in + +# Fade-out easing +@export_exp_easing("attenuation") var exit_fade_out: float = 3.0: + set = set_fade_out, + get = get_fade_out + +# Private variables +var area3d: Area3D +var position_offset: Vector3 = Vector3.ZERO +var rotation_offset: Vector3 = Vector3.ZERO +var scale_offset: Vector3 = Vector3.ZERO +var emitter_list: Array[EmitterData] + +# Called when the node enters the scene tree for the first time +func _ready() -> void: + _setup_area3d() + if !Engine.is_editor_hint(): + add_to_group("ShakerReceiver") + _connect_signals() + +# Sets up the Area3D node +func _setup_area3d() -> void: + for child in get_children(): + if child is Area3D: + area3d = child + return + + area3d = Area3D.new() + var collision = CollisionShape3D.new() + add_child(area3d) + area3d.add_child(collision) + area3d.set_owner(get_tree().edited_scene_root) + collision.set_owner(get_tree().edited_scene_root) + area3d.name = "Area3D" + collision.name = "CollisionShape3D" + + area3d.collision_layer = 0 + area3d.collision_mask = 1 << 9 + +# Connects signals +func _connect_signals() -> void: + area3d.area_entered.connect(on_area_entered) + area3d.area_exited.connect(on_area_exited) + +# Called every frame +func _process(delta: float) -> void: + if !Engine.is_editor_hint(): + position_offset = Vector3.ZERO + rotation_offset = Vector3.ZERO + scale_offset = Vector3.ZERO + + if emitter_list.size() > 0: + for emitter_data in emitter_list: + _process_emitter(emitter_data, delta) + +# Processes each emitter +func _process_emitter(emitter_data: EmitterData, delta: float) -> void: + if !Engine.is_editor_hint(): + if is_instance_valid(emitter_data.emitter): + var ease_in: float = ease(emitter_data.timer, enter_fade_in) + var ease_out: float = ease(1.0 - (emitter_data.timer - emitter_data.fade_out_timer), exit_fade_out) if emitter_data.fade_out_timer != 0.0 else 1.0 + emitter_data.ease_out_intensity = move_toward(emitter_data.ease_out_intensity, ease_out, delta) + ease_out = emitter_data.ease_out_intensity + var max_distance: float = emitter_data.emitter.max_distance + var distance: float = min(emitter_data.emitter.global_position.distance_to(global_position), max_distance) / max(max_distance, 0.001) + + var attenuation: float = ease(1.0 - distance, emitter_data.emitter.distance_attenuation) + position_offset += emitter_data.emitter.shake_offset_position * ease_in * ease_out * attenuation + rotation_offset += emitter_data.emitter.shake_offset_rotation * ease_in * ease_out * attenuation + scale_offset += emitter_data.emitter.shake_offset_scale * ease_in * ease_out * attenuation + emitter_data.timer += delta + if ease_out <= delta: + emitter_list.erase(emitter_data) + else: + emitter_list.erase(emitter_data) + + +# Returns the current shake values +func get_value() -> Array[Vector3]: + return [position_offset, rotation_offset, scale_offset] + +# Returns configuration warnings +func _get_configuration_warnings() -> PackedStringArray: + if not get_parent() is ShakerComponent3D: + return ["Parent must be ShakerComponent3D"] + var _ex:bool = false + for i in get_children(): + if i is Area3D: + _ex = true + break + if !_ex: + return ["ShakerReceiver3D needs Area3D to work"] + return [] + +# Called when an area enters +func on_area_entered(area: Area3D) -> void: + var node = area.get_parent() + if node is ShakerEmitter3D: + var _exists = null + for index in emitter_list.size(): + var data = emitter_list[index] + if data.emitter == node: _exists = data + if !_exists: + var data = EmitterData.new(node) + emitter_list.append(data) + else: + _exists.fade_out_timer = 0.0 + +# Called when an area exits +func on_area_exited(area: Area3D) -> void: + var node = area.get_parent() + if node is ShakerEmitter3D: + for index in emitter_list.size(): + var data = emitter_list[index] + if data.emitter == node: + data.fade_out_timer = data.timer + break + +# Setter for enter_fade_in +func set_fade_in(value: float) -> void: + enter_fade_in = value + +# Getter for enter_fade_in +func get_fade_in() -> float: + return enter_fade_in + +# Setter for exit_fade_out +func set_fade_out(value: float) -> void: + exit_fade_out = value + +# Getter for exit_fade_out +func get_fade_out() -> float: + return exit_fade_out + +# EmitterData inner class +class EmitterData: + var emitter: ShakerEmitter3D + var timer: float = 0.0 + var fade_out_timer: float = 0.0 + var ease_out_intensity:float = 1.0 + + func _init(_emitter: ShakerEmitter3D) -> void: + self.emitter = _emitter + +func is_playing() -> bool: + for i:EmitterData in emitter_list: + return i.emitter.emitting + return false diff --git a/addons/shaker/src/Vector3/ShakerReceiver3D.gd.uid b/addons/shaker/src/Vector3/ShakerReceiver3D.gd.uid new file mode 100644 index 00000000..409bf595 --- /dev/null +++ b/addons/shaker/src/Vector3/ShakerReceiver3D.gd.uid @@ -0,0 +1 @@ +uid://csr4nkcrmm0bq diff --git a/addons/shaker/src/Vector3/shaker_component3D.gd b/addons/shaker/src/Vector3/shaker_component3D.gd new file mode 100644 index 00000000..3d044b03 --- /dev/null +++ b/addons/shaker/src/Vector3/shaker_component3D.gd @@ -0,0 +1,284 @@ +@tool +@icon("res://addons/shaker/assets/Shaker3D.svg") +class_name ShakerComponent3D +extends "res://addons/shaker/src/Vector3/ShakerBase3D.gd" + +## Allows you to apply shake effect to any 3D node according to position, rotation, scale + +enum ShakeAddMode { + add, + override +} + +# Custom target flag +@export var custom_target: bool = false: + set = set_custom_target, + get = get_custom_target + +# Array of target Node3D objects +@export var Targets: Array[Node3D] + +# Randomization flag +@export var randomize: bool = false: + set = set_randomize, + get = get_randomize + +# Playing state +@export var is_playing: bool = false + +@export var AutoPlay:bool = false + +# Private variables +var _last_position_shake: Array[Vector3] = [Vector3.ZERO] +var _last_scale_shake: Array[Vector3] = [Vector3.ZERO] +var _last_rotation_shake: Array[Vector3] = [Vector3.ZERO] +var _timer_offset: float = 0.0 +var _fading_out: bool = false +var _seed: float = 203445 +var _external_shakes:Array[ExternalShake] + +# Called when the node enters the scene tree for the first time +func _ready() -> void: + set_process_input(false) + set_process_internal(false) + set_process_shortcut_input(false) + set_process_unhandled_input(false) + set_physics_process(false) + set_physics_process_internal(false) + add_to_group("ShakerComponent") + if !Engine.is_editor_hint(): + if AutoPlay: + play_shake() + +# Resets the shaker to its initial state +func _reset() -> void: + _last_position_shake = [Vector3.ZERO] + _last_scale_shake = [Vector3.ZERO] + _last_rotation_shake = [Vector3.ZERO] + _external_shakes.clear() + _initalize_prev_positions() + is_playing = false + _initialize_timer_offset() + _fading_out = false + _initalize_target() + +# Initializes previous positions for randomized shaking +func _initalize_prev_positions() -> void: + _last_position_shake.resize(Targets.size()) + _last_position_shake.fill(Vector3.ZERO) + + _last_scale_shake.resize(Targets.size()) + _last_scale_shake.fill(Vector3.ZERO) + + _last_rotation_shake.resize(Targets.size()) + _last_rotation_shake.fill(Vector3.ZERO) + +# Called every frame +func _process(delta: float) -> void: + if is_playing: + if shakerPreset != null || _external_shakes.size() > 0 || is_receiving_from_emitters(): + if timer <= duration || duration == 0.0: + _progress_shake() + timer += delta * shake_speed + else: + force_stop_shake() + else: + if timer > 0: + force_stop_shake() + + +# Progresses the shake effect +func _progress_shake() -> void: + var _ease_in: float = 1.0 + var _ease_out: float = 1.0 + var _final_duration: float = duration if (duration > 0 && !_fading_out) else 1.0 + + _ease_in = ease((timer) /_final_duration, fade_in) + _ease_out = ease(1.0-(max((timer-_timer_offset), 0.0))/_final_duration, fade_out) + + if (!(duration > 0) || _fading_out) && is_playing: + if _ease_out <= get_process_delta_time(): + force_stop_shake() + + var _shake_position: Array[Vector3] = [] + var _shake_rotation: Array[Vector3] = [] + var _shake_scale: Array[Vector3] = [] + + var _count:int =(Targets.size() if randomize else 1) + + _shake_position.resize(_count) + _shake_position.fill(Vector3.ZERO) + _shake_rotation.resize(_count) + _shake_rotation.fill(Vector3.ZERO) + _shake_scale.resize(_count) + _shake_scale.fill(Vector3.ZERO) + + for _index in _count: + var _randomized: float = (_seed * (float(_index+1) / Targets.size())) if randomize else 0.0 + if _last_position_shake.size() != _count: _initalize_prev_positions() + + # Shaker Preset + if shakerPreset != null: + var _value:float = timer + _randomized + var _strength:float = intensity * _ease_in * _ease_out + _shake_position[_index] += (shakerPreset.get_value(_value, ShakerPreset3D.Categories.POSITION) * _strength) + _shake_rotation[_index] += (shakerPreset.get_value(_value, ShakerPreset3D.Categories.ROTATION) * _strength * (PI/2.0)) + _shake_scale[_index] += (shakerPreset.get_value(_value, ShakerPreset3D.Categories.SCALE) * _strength) + + # External Shake Addition + for external_shake:ExternalShake in _external_shakes: + var _real_time:float = min(timer-external_shake.start_time, external_shake.duration) + _ease_in = ease(_real_time/external_shake.duration, external_shake.fade_in) + _ease_out = ease(1.0-(_real_time/external_shake.duration), external_shake.fade_out) + var _value:float = (_real_time*external_shake.speed) + _randomized + var _strength:float = external_shake.intensity * intensity * _ease_in * _ease_out + var _mode_value:Array[Vector3] = [Vector3.ZERO, Vector3.ZERO, Vector3.ZERO] + match external_shake.mode: + ShakeAddMode.add: + _mode_value = [_shake_position[_index], _shake_rotation[_index], _shake_scale[_index] ] + _shake_position[_index] = _mode_value[0] + (external_shake.preset.get_value(_value, ShakerPreset3D.Categories.POSITION) * _strength) + _shake_rotation[_index] = _mode_value[1] +(external_shake.preset.get_value(_value, ShakerPreset3D.Categories.ROTATION) * _strength * (PI/2.0)) + _shake_scale[_index] = _mode_value[2] + (external_shake.preset.get_value(_value, ShakerPreset3D.Categories.SCALE) * _strength) + + if _real_time >= external_shake.duration: + _external_shakes.erase(external_shake) + + # Shake Emitter + for _child in get_children(): + if _child is ShakerReceiver3D: + _shake_position[_index] += _child.position_offset + _shake_rotation[_index] += _child.rotation_offset + _shake_scale[_index] += _child.scale_offset + + for index: int in Targets.size(): + var target: Node3D = Targets[index] + if !is_instance_valid(target): + Targets.remove_at(index) + index-=1 + if Targets.size() <= 0: + shake_finished.emit() + break + + var _i: int = fmod(index, _shake_position.size()) + target.position += -_last_position_shake[_i] + _shake_position[_i] + target.rotation += -_last_rotation_shake[_i] + _shake_rotation[_i] + target.scale += -_last_scale_shake[_i] + _shake_scale[_i] + + _last_position_shake = _shake_position + _last_rotation_shake = _shake_rotation + _last_scale_shake = _shake_scale + +# Stops the shake effect with a fade-out +func stop_shake() -> void: + if !_fading_out: + _timer_offset = timer + _fading_out = true + shake_fading_out.emit() + +# Immediately stops the shake effect +func force_stop_shake() -> void: + if is_playing || _fading_out: + set_progress(0.0) + _reset() + shake_finished.emit() + +# Starts the shake effect +func play_shake() -> void: + _initalize_target() + randomize_shake() + is_playing = !is_playing if Engine.is_editor_hint() else true + _fading_out = false + _initialize_timer_offset() + shake_started.emit() + +func randomize_shake() -> void: + _seed = randf_range(10000, 99999) + +func _initialize_timer_offset() -> void: + if !(duration > 0): _timer_offset = 0x80000 + else: _timer_offset = 0.0 + +func _initalize_target() -> void: + if !custom_target: + Targets.clear() + if get_parent() is Node3D: + Targets.append(get_parent()) + +# Placeholder for shake function +func shake(shaker_preset:ShakerPreset3D, _mode:ShakeAddMode=ShakeAddMode.add, duration:float=1.0, speed:float=1.0, intensity:float=1.0, fade_in:float=.25, fade_out:float=.25) -> void: + var external_shake:ExternalShake = ExternalShake.new() + external_shake.preset = shaker_preset + external_shake.duration = duration + external_shake.speed = speed + external_shake.intensity = intensity + external_shake.start_time = timer + external_shake.fade_in = fade_in + external_shake.fade_out = fade_out + external_shake.mode = _mode + _external_shakes.append(external_shake) + if Targets.is_empty(): + _initalize_target() + is_playing = true + +# Validates property visibility +func _validate_property(property: Dictionary) -> void: + if property.name == "Targets" || property.name == "randomize": + if !custom_target: + property.usage = PROPERTY_USAGE_NONE + if property.name == "fade_time": + if duration > 0: + property.usage = PROPERTY_USAGE_NONE + +# Get configuration warnings +func _get_configuration_warnings() -> PackedStringArray: + if !custom_target: + if not get_parent() is Node3D: + return ["Parent must be Node3D"] + + return [] + +# Sets the shake progress +func set_progress(value: float) -> void: + timer = value + _progress_shake() + +# Custom setter and getter functions for @export variables +func set_custom_target(value: bool) -> void: + custom_target = value + notify_property_list_changed() + +func get_custom_target() -> bool: + return custom_target + +func set_randomize(value: bool) -> void: + if custom_target && Targets.size() > 1: + for index: int in Targets.size(): + var target: Node3D = Targets[index] + var i = fmod(index, _last_position_shake.size()) + target.position += -_last_position_shake[i] + target.rotation += -_last_rotation_shake[i] + target.scale += -_last_scale_shake[i] + _last_position_shake.fill(_last_position_shake[0]) + _last_rotation_shake.fill(_last_rotation_shake[0]) + _last_scale_shake.fill(_last_scale_shake[0]) + randomize = value + randomize_shake() + +func get_randomize() -> bool: + return randomize + +class ExternalShake: + var preset:ShakerPreset3D + var duration:float = 1.0 + var speed:float = 1.0 + var intensity:float = 1.0 + var start_time:float = 0.0 + var fade_in:float = 0.25 + var fade_out:float = 0.25 + var mode:ShakeAddMode=ShakeAddMode.add + +func is_receiving_from_emitters() -> bool: + for _child in get_children(): + if _child is ShakerReceiver3D: + return _child.is_playing() + return false diff --git a/addons/shaker/src/Vector3/shaker_component3D.gd.uid b/addons/shaker/src/Vector3/shaker_component3D.gd.uid new file mode 100644 index 00000000..fc418910 --- /dev/null +++ b/addons/shaker/src/Vector3/shaker_component3D.gd.uid @@ -0,0 +1 @@ +uid://dnlxsrumw6ygp diff --git a/addons/shaker/src/shaker_component.gd b/addons/shaker/src/shaker_component.gd new file mode 100644 index 00000000..72461baf --- /dev/null +++ b/addons/shaker/src/shaker_component.gd @@ -0,0 +1,347 @@ +@tool +@icon("res://addons/shaker/assets/Shaker.svg") +class_name ShakerComponent +extends Node + +# Allows you to apply a shake effect to any variable of a node of any type + +# Custom target flag +@export var custom_target: bool = false: + set = set_custom_target, + get = get_custom_target + +# Array of target Node objects +@export var Targets: Array[Node] + +# Randomization flag +@export var randomize: bool = false: + set = set_randomize, + get = get_randomize + +@export var AutoPlay:bool = false + +# Playing state +@export var play:bool = false: + set(value): + play = value + if value: + play_shake() + elif timer > 0: + force_stop_shake() + +var is_playing: bool = false + +# Shake intensity +@export_range(0.0, 1.0, 0.001, "or_greater") var intensity: float = 1.0: + set = set_intensity, + get = get_intensity + +# Shake duration +@export var duration: float = 0.00: + set = set_duration, + get = get_duration + +# Shake speed +@export_range(0.0, 1.0, 0.001, "or_greater") var shake_speed: float = 1.0: + set = set_shake_speed, + get = get_shake_speed + +# Fade-in easing +@export_exp_easing var fade_in: float = 0.25: + set = set_fade_in, + get = get_fade_in + +# Fade-out easing +@export_exp_easing("attenuation") var fade_out: float = 0.25: + set = set_fade_out, + get = get_fade_out + +# Shaker preset +@export var shakerProperty:Array[ShakerProperty]: + set = set_shaker_property, + get = get_shaker_property + +# Timer for shake progress +var timer: float = 0.0: + set = _on_timeline_progress + +# SIGNALS +signal timeline_progress(progress: float) +signal shake_started +signal shake_finished +signal shake_fading_out + +func set_intensity(value: float) -> void: + intensity = max(value, 0.0) + +func get_intensity() -> float: + return intensity + +func set_duration(value: float) -> void: + duration = max(value, 0.0) + notify_property_list_changed() + +func get_duration() -> float: + return duration + +func set_shake_speed(value: float) -> void: + shake_speed = max(value, 0.001) + notify_property_list_changed() + +func get_shake_speed() -> float: + return shake_speed + +func set_fade_in(value: float) -> void: + fade_in = value + +func get_fade_in() -> float: + return fade_in + +func set_fade_out(value: float) -> void: + fade_out = value + +func get_fade_out() -> float: + return fade_out + +# Handles timeline progress +func _on_timeline_progress(value: float) -> void: + timer = value + timeline_progress.emit(timer) + +# Private variables +var _timer_offset: float = 0.0 +var _fading_out: bool = false +var _seed: float = 203445 +var _last_values:Array[Dictionary] + +# Called when the node enters the scene tree for the first time +func _ready() -> void: + set_process_input(false) + set_process_internal(false) + set_process_shortcut_input(false) + set_process_unhandled_input(false) + set_physics_process(false) + set_physics_process_internal(false) + add_to_group("ShakerComponent") + + if !Engine.is_editor_hint(): + if AutoPlay: + play_shake() + +# Resets the shaker to its initial state +func _reset() -> void: + _last_values = [] + is_playing = false + _initialize_timer_offset() + _fading_out = false + _initalize_target() + +# Called every frame +func _process(delta: float) -> void: + if is_playing: + if shakerProperty != null: + if timer <= duration || duration == 0.0: + _progress_shake() + timer += delta * shake_speed + else: + force_stop_shake() + else: + if timer > 0: + force_stop_shake() + + +# Progresses the shake effect +func _progress_shake() -> void: + var _ease_in: float = 1.0 + var _ease_out: float = 1.0 + var _final_duration: float = duration if (duration > 0 && !_fading_out) else 1.0 + + _ease_in = ease(timer/_final_duration, fade_in) + _ease_out = ease(1.0-(max((timer-_timer_offset), 0.0))/_final_duration, fade_out) + + # Check all targets + for i:int in Targets.size(): + var target:Node = Targets[i] + if !is_instance_valid(target): + Targets.remove_at(i) + i -= 1 + if Targets.size() <= 0: + shake_finished.emit() + break + + if (!(duration > 0) || _fading_out) && is_playing: + if _ease_out <= get_process_delta_time(): + force_stop_shake() + var _count:int = Targets.size() # if randomize else 1) + var _value_temp:Array[Dictionary] = [] + for i in _count: + _value_temp.append({}) + + for _index:int in _count: + var _randomized:float = (_seed * (float(_index+1) / Targets.size())) if randomize else 0.0 + var target:Node = Targets[_index] + if _index > _last_values.size()-1: + _last_values.append({}) + + # Shaker Preset + for shake:ShakerProperty in shakerProperty: + if shake: + if !shake.property_name.is_empty() && shake.shake_type: + var _value:float = timer + _randomized + + var _add_value = (shake.get_value(_value)) + var current_value = target.get(shake.property_name) + if typeof(current_value) == typeof(current_value): + if !(_last_values[_index].has(shake.property_name)): + _last_values[_index][shake.property_name] = {} + _last_values[_index][shake.property_name]["value"] = _add_value * 0.0 + + var _prev_temp = (_add_value * 0.0) if !(_value_temp[_index].has(shake.property_name)) else _value_temp[_index][shake.property_name]["value"] + _value_temp[_index][shake.property_name] = {} + _value_temp[_index][shake.property_name]["value"] = _prev_temp + _add_value + _value_temp[_index][shake.property_name]["blend_mode"] = shake.shake_type.BlendingMode + else: + push_error("Variable value type is %s but Shake type is %s" % [type_string(current_value), type_string(_add_value)]) + var _strength:float = intensity * _ease_in * _ease_out + for index:int in Targets.size(): + var target:Node = Targets[index] + var i:int = fmod(index, _value_temp.size()) + var property = _value_temp[i] + for property_index:int in property.size(): + var property_name:StringName = property.keys()[property_index] + if !property_name.is_empty(): + var value = property[property_name]["value"] + var blend_mode = property[property_name]["blend_mode"] + var current_value = target.get(property_name)-_last_values[i][property_name]["value"] + var default_value = current_value + match blend_mode: + ShakerTypeBase.BlendingModes.Add: + current_value += value + ShakerTypeBase.BlendingModes.Multiply: + current_value *= value + ShakerTypeBase.BlendingModes.Subtract: + current_value -= value + ShakerTypeBase.BlendingModes.Max: + if typeof(current_value) == TYPE_VECTOR2 || typeof(current_value) == TYPE_VECTOR2I: + current_value.x = max(current_value.x, value.x) + current_value.y = max(current_value.y, value.y) + elif typeof(current_value) == TYPE_VECTOR3 || typeof(current_value) == TYPE_VECTOR3I: + current_value.x = max(current_value.x, value.x) + current_value.y = max(current_value.y, value.y) + current_value.z = max(current_value.z, value.z) + else: + current_value = max(current_value, value) + ShakerTypeBase.BlendingModes.Min: + if typeof(current_value) == TYPE_VECTOR2 || typeof(current_value) == TYPE_VECTOR2I: + current_value.x = min(current_value.x, value.x) + current_value.y = min(current_value.y, value.y) + elif typeof(current_value) == TYPE_VECTOR3 || typeof(current_value) == TYPE_VECTOR3I: + current_value.x = min(current_value.x, value.x) + current_value.y = min(current_value.y, value.y) + current_value.z = min(current_value.z, value.z) + else: + current_value = min(current_value, value) + ShakerTypeBase.BlendingModes.Average: + current_value = (current_value + value) * 0.5 + ShakerTypeBase.BlendingModes.Override: + current_value = value + + if current_value != null: + var _added_value = (current_value - default_value) * _strength + target.set(property_name, default_value + _added_value ) + _value_temp[i][property_name]["value"] = _added_value + else: + push_error(name," Variable Error: ",target," has no variable named \"",property_name,"\"") + _last_values = _value_temp + +# Stops the shake effect with a fade-out +func stop_shake() -> void: + if !_fading_out: + _timer_offset = timer + _fading_out = true + shake_fading_out.emit() + +# Immediately stops the shake effect +func force_stop_shake() -> void: + if is_playing || _fading_out: + set_progress(0.0) + is_playing = false + _fading_out = false + _last_values.clear() + shake_finished.emit() + +func set_shaker_property(value:Array[ShakerProperty]) -> void: + shakerProperty = value + +func get_shaker_property() -> Array[ShakerProperty]: + return shakerProperty + +# Starts the shake effect +func play_shake() -> void: + if shakerProperty != null: + _initalize_target() + randomize_shake() + is_playing = !is_playing if Engine.is_editor_hint() else true + _fading_out = false + _initialize_timer_offset() + shake_started.emit() + +func randomize_shake() -> void: + _seed = randf_range(10000, 99999) + +func _initalize_target() -> void: + if !custom_target: + Targets.clear() + if get_parent() is Node: + Targets.append(get_parent()) + + +# Validates property visibility +func _validate_property(property: Dictionary) -> void: + if property.name == "Targets" || property.name == "randomize": + if !custom_target: + property.usage = PROPERTY_USAGE_NONE + if property.name == "fade_time": + if duration > 0: + property.usage = PROPERTY_USAGE_NONE + +# Get configuration warnings +func _get_configuration_warnings() -> PackedStringArray: + if !custom_target: + if not get_parent() is Node: + return ["Parent must be Node"] + + return [] + +# Sets the shake progress +func set_progress(value: float) -> void: + timer = value + _progress_shake() + +# Custom setter and getter functions for @export variables +func set_custom_target(value: bool) -> void: + custom_target = value + notify_property_list_changed() + +func get_custom_target() -> bool: + return custom_target + +func set_randomize(value: bool) -> void: + if custom_target && Targets.size() > 1: + if _last_values.size() > 0: + for index: int in Targets.size(): + var target:Node = Targets[index] + var i:int = fmod(index, _last_values.size()) + for shake:ShakerProperty in shakerProperty: + var current_value = target.get(shake.property_name) + target.set(shake.property_name, current_value - _last_values[i][shake.property_name]["value"]) + _last_values.clear() + randomize = value + randomize_shake() + +func _initialize_timer_offset() -> void: + if !(duration > 0): _timer_offset = 0x80000 + else: _timer_offset = 0.0 + +func get_randomize() -> bool: + return randomize diff --git a/addons/shaker/src/shaker_component.gd.uid b/addons/shaker/src/shaker_component.gd.uid new file mode 100644 index 00000000..4e35c637 --- /dev/null +++ b/addons/shaker/src/shaker_component.gd.uid @@ -0,0 +1 @@ +uid://dqvqij8tcek5 diff --git a/addons/shaker/src/shaker_graph.gd b/addons/shaker/src/shaker_graph.gd new file mode 100644 index 00000000..cab2c3b9 --- /dev/null +++ b/addons/shaker/src/shaker_graph.gd @@ -0,0 +1,265 @@ +@tool +extends Panel + +const TIME_LINE_SCRIPT: GDScript = preload("res://addons/shaker/src/shaker_timeline.gd") +const ShakerBase3d = preload("res://addons/shaker/src/Vector3/ShakerBase3D.gd") +const ShakerBase2d = preload("res://addons/shaker/src/Vector2/ShakerBase2D.gd") + +# Graph properties +var graph_points:Array[PackedFloat32Array] +var y_scale: float = 32.0 +var width: float = 2.0 +var shake: Resource +var graph_offset: Vector2 = Vector2(15.0, 0.0) + +# Private variables +var _graph_min: float = -1.0 +var _graph_max: float = 1.0 +var _graph_max_total: float = 1.0 +var layout_box: HBoxContainer = HBoxContainer.new() +var axis_button: OptionButton = OptionButton.new() +var fit_button: Button = Button.new() +var category_button: OptionButton +var time_line: Control +var flip_y: bool = true +var selected_category: int = 0 +var graph_pressing: bool = false +var graph_middle_pressing: bool = false +var point_color_by_axis:Array[Color] = [Color.RED, Color.GREEN, Color.DEEP_SKY_BLUE] +var _unselected_opacity:float = .10 + +# Graph time offset property +var graph_time_offset: float = 0.0: + set = set_graph_time_offset, + get = get_graph_time_offset + +# Called when the node enters the scene tree for the first timeX +func _ready() -> void: + shake.property_changed.connect(on_property_changed) + + clip_contents = true + _setup_timeline() + _setup_layout_box() + _setup_fit_button() + _setup_category_button() + _setup_axis_button() + + _update_graph() + _on_fit_button_clicked() + +# Sets up the timeline +func _setup_timeline() -> void: + if shake is ShakerPresetBase: + time_line = TIME_LINE_SCRIPT.new() + time_line.GRAPH = self + add_child(time_line) + +# Sets up the layout box +func _setup_layout_box() -> void: + add_child(layout_box) + layout_box.set_anchors_preset(Control.PRESET_TOP_WIDE) + layout_box.custom_minimum_size.y = 16 + layout_box.alignment = BoxContainer.ALIGNMENT_END + +# Sets up the fit button +func _setup_fit_button() -> void: + layout_box.add_child(fit_button) + fit_button.text = "Fit" + fit_button.pressed.connect(_on_fit_button_clicked) + +# Sets up the category button +func _setup_category_button() -> void: + if shake is ShakerPresetBase: + category_button = OptionButton.new() + category_button.item_selected.connect(_on_category_selected) + layout_box.add_child(category_button) + category_button.custom_minimum_size = Vector2(16, 16) + for _category_index in shake.Categories.size(): + var _category_name: StringName = shake.Categories.keys()[_category_index] + var _category_value: int = shake.Categories.values()[_category_index] + category_button.add_item(_category_name, _category_value) + if shake.Categories.size() > 0: category_button.select(0) + +# Sets up the axis button +func _setup_axis_button() -> void: + if axis_button.get_parent() != layout_box: + layout_box.add_child(axis_button) + axis_button.position = Vector2(-32, 4) + axis_button.custom_minimum_size = Vector2(16, 16) + axis_button.item_selected.connect(_axis_selected) + axis_button.add_theme_color_override("background_color", Color.GREEN) + + var selected:int = max(axis_button.get_selected_id(), 0) + axis_button.clear() + var Axis:Array = [] + + if shake is ShakerTypeBase: + Axis = shake.GraphAxis.keys() + elif shake is ShakerPresetBase: + var shakes:Array = shake.get_shakes_by_category(category_button.selected) + if shakes.size() > 0 && shakes[0]: + Axis = shakes[0].get_script().GraphAxis.keys() + for axis in Axis: + axis_button.add_item(axis) + selected = min(selected, Axis.size()) + if Axis.size() > 0: + axis_button.select(selected) + +# Updates the graph +func _update_graph() -> void: + graph_points.clear() + if not axis_button.get_selected_id() < 0: + var _baked: float = round(shake.bake_internal) + _graph_min = 0.0 + _graph_max = 0.0 + graph_points.resize(axis_button.item_count) + for axis_index in axis_button.item_count: + for i in _baked + 1: + var _args: Array = [graph_time_offset + (i / _baked)] + if shake is ShakerPresetBase: + _args.append(selected_category) + var _val = shake.callv("get_value", _args) + if typeof(_val) != TYPE_FLOAT: _val = _val[axis_index] + var _result: float = _val * (-1 if flip_y else 1) + graph_points[axis_index].append(_result) + _graph_min = min(_graph_min, _result) + _graph_max = max(_graph_max, _result) + _graph_max_total = max(abs(_graph_max), abs(_graph_min)) + +# Draws the graph +func _draw() -> void: + _draw_zero_line() + _draw_min_max() + _draw_graph_points() + _draw_graph_info() + +# Draws the zero line +func _draw_zero_line() -> void: + var font_size: int = 8 + draw_line(Vector2(0, size.y * 0.5), Vector2(size.x, size.y * 0.5), Color.DIM_GRAY, 1, false) + draw_string(ThemeDB.fallback_font, Vector2(5.0, size.y * 0.5 + font_size * 0.5), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color.DIM_GRAY, TextServer.JUSTIFICATION_NONE, TextServer.DIRECTION_AUTO, TextServer.ORIENTATION_HORIZONTAL) + +# Draws the min/max values +func _draw_min_max() -> void: + var font_size: int = 8 + var _view_percent: float = (y_scale * _graph_max_total) / (size.y * 0.5) + if (_view_percent * _graph_max_total) > 0.25: + var _padding: int = 10 + var _up_offset: float = max((-size.y * 0.5) * min(_view_percent, 1.0), -size.y * 0.5 + _padding) + var _down_offset: float = min((size.y * 0.5) * min(_view_percent, 1.0), size.y * 0.5 - _padding) + var _min_max_percent: float = 1.0 / max(_view_percent, 1.0) + draw_string(ThemeDB.fallback_font, Vector2(5.0, size.y * 0.5 + font_size * 0.5 + _up_offset), "%.2f" % (1.0 * _graph_max_total * _min_max_percent), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color.DIM_GRAY, TextServer.JUSTIFICATION_NONE, TextServer.DIRECTION_AUTO, TextServer.ORIENTATION_HORIZONTAL) + draw_string(ThemeDB.fallback_font, Vector2(5.0, size.y * 0.5 + font_size * 0.5 + _down_offset), "%.2f" % (1.0 * _graph_min * _min_max_percent), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color.DIM_GRAY, TextServer.JUSTIFICATION_NONE, TextServer.DIRECTION_AUTO, TextServer.ORIENTATION_HORIZONTAL) + +# Draws the graph points +func _draw_graph_points() -> void: + for axis_index in graph_points.size(): + var _point_length:int = graph_points[axis_index].size() + var _point_color:Color = point_color_by_axis[fmod(axis_index, point_color_by_axis.size())] + var alpha:float = _unselected_opacity if axis_index != axis_button.get_selected_id() else 1.0 + var _final_size: Vector2 = size - graph_offset + var _offset: Vector2 = Vector2(1, y_scale) + for point_index in _point_length: + var _size_offset = Vector2((_final_size.x / (_point_length)) * point_index, _final_size.y * 0.5) + var point:float = graph_points[axis_index][point_index] + if point_index < _point_length - 1: + var _size_offset_next = Vector2((_final_size.x / (_point_length)) * (point_index + 1), _final_size.y * 0.5) + var point_next:float = graph_points[axis_index][point_index + 1] + var _final_point_1: Vector2 = graph_offset + _size_offset + Vector2(0.0, point) * _offset + var _final_point_2: Vector2 = graph_offset + _size_offset_next + Vector2(0.0, point_next) * _offset + draw_line(_final_point_1, _final_point_2, _point_color * Color(1,1,1, alpha), width, false) + +# Draws the graph info +func _draw_graph_info() -> void: + var font_size: int = 8 + var _text = "Zoom: %.2f | Zoom IN / OUT with mouse scroll" % (y_scale / (size.y * 0.5 / _graph_max_total)) + var _text_size: float = _text.length() * font_size * 0.5 + draw_string(ThemeDB.fallback_font, Vector2(size.x - _text_size, size.y - 8.0), _text, HORIZONTAL_ALIGNMENT_RIGHT, -1, font_size, Color.GRAY, TextServer.JUSTIFICATION_NONE, TextServer.DIRECTION_AUTO, TextServer.ORIENTATION_HORIZONTAL) + +# Handles GUI input +func _gui_input(event: InputEvent) -> void: + if event is InputEventMouseButton: + _handle_mouse_button(event) + if event is InputEventMouseMotion: + _handle_mouse_motion(event) + +# Handles mouse button input +func _handle_mouse_button(event: InputEventMouseButton) -> void: + if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + y_scale -= 1.0 / _graph_max_total + accept_event() + elif event.button_index == MOUSE_BUTTON_WHEEL_UP: + y_scale += 1.0 / _graph_max_total + accept_event() + elif event.button_index == MOUSE_BUTTON_LEFT: + if shake is ShakerPresetBase: + graph_pressing = event.pressed + update_timeline_position(event.position) + if event.button_index == MOUSE_BUTTON_MIDDLE: + if shake is ShakerPresetBase: + graph_middle_pressing = event.pressed + y_scale = max(y_scale, 1) + queue_redraw() + +# Handles mouse motion input +func _handle_mouse_motion(event: InputEventMouseMotion) -> void: + if graph_pressing: + update_timeline_position(event.position) + if graph_middle_pressing: + graph_time_offset += -(event.relative.x / size.x) + graph_time_offset = max(graph_time_offset, 0.0) + +# Updates the timeline position +func update_timeline_position(pos: Vector2) -> void: + if shake is ShakerPresetBase: + var _press_percent: float = max(((pos.x) - graph_offset.x) / (size.x - graph_offset.x), 0.0) + if shake.parent is ShakerBase3d || shake.parent is ShakerBase2d: + var _shaker_component = shake.parent + if _shaker_component != null: + _shaker_component.set_progress(_press_percent + graph_time_offset) + +# Called when a property changes +func on_property_changed(_name: StringName) -> void: + _setup_axis_button() + _update_graph() + queue_redraw() + if is_inf(y_scale) or is_nan(y_scale): + _on_fit_button_clicked() + +# Called when an axis is selected +func _axis_selected(item: int) -> void: + _update_graph() + _on_fit_button_clicked() + +# Called when the fit button is clicked +func _on_fit_button_clicked() -> void: + y_scale = (size.y * 0.5) / _graph_max_total + graph_time_offset = 0.0 + queue_redraw() + +# Called when a category is selected +func _on_category_selected(item: int) -> void: + selected_category = item + _setup_axis_button() + _update_graph() + _on_fit_button_clicked() + +# Setter for graph_time_offset +func set_graph_time_offset(value: float) -> void: + graph_time_offset = value + if time_line != null: + time_line.queue_redraw() + _update_graph() + queue_redraw() + +# Getter for graph_time_offset +func get_graph_time_offset() -> float: + return graph_time_offset + +func select_axis(index:int) -> void: + if axis_button.has_selectable_items(): + axis_button.select(index) + +func select_category(index:int) -> void: + if category_button.has_selectable_items(): + category_button.select(index) diff --git a/addons/shaker/src/shaker_graph.gd.uid b/addons/shaker/src/shaker_graph.gd.uid new file mode 100644 index 00000000..16e757f2 --- /dev/null +++ b/addons/shaker/src/shaker_graph.gd.uid @@ -0,0 +1 @@ +uid://bihgv1h2lc26e diff --git a/addons/shaker/src/shaker_inspector.gd b/addons/shaker/src/shaker_inspector.gd new file mode 100644 index 00000000..de767336 --- /dev/null +++ b/addons/shaker/src/shaker_inspector.gd @@ -0,0 +1,50 @@ +extends EditorInspectorPlugin + +const GRAPH_SCRIPT = preload("res://addons/shaker/src/shaker_graph.gd") +const SHAKER_PANEL = preload("res://addons/shaker/src/shaker_panel.gd") + +func _can_handle(object: Object) -> bool: + return (object is ShakerTypeBase || object is ShakerPresetBase || object is ShakerComponent3D || object is ShakerComponent2D ) + +func _parse_group(object: Object, group: String) -> void: + if object is ShakerTypeBase: + if group == "Live Shake Graph": + add_graph(object) + +func _parse_category(object: Object, category: String) -> void: + pass + +func _parse_begin(object: Object) -> void: + if object is ShakerComponent3D || object is ShakerComponent2D: + var _panel:MarginContainer = SHAKER_PANEL.new() + _panel.Target = object; + _panel.set_anchors_preset(Control.PRESET_FULL_RECT) + add_custom_control(_panel) + +func _parse_end(object: Object) -> void: + pass + +func add_graph(_object:Object) -> Panel: + var property_control:Panel = Panel.new() + property_control.set_script(GRAPH_SCRIPT) + property_control.shake = _object; + add_custom_control(property_control) + property_control.custom_minimum_size.y = 128; + property_control.set_anchors_preset(Control.PRESET_FULL_RECT) + return property_control; + +func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool: + if object is ShakerTypeBase: + if name == "_temp_graph": + return true; + if object is ShakerPresetBase: + if name == "bake_internal": + object.Graph = add_graph(object) + if object is ShakerComponent3D: + if name == "is_playing": + #var _panel:Panel = SHAKER_PANEL.new() + #_panel.Target = object; + #_panel.set_anchors_preset(Control.PRESET_FULL_RECT) + #add_custom_control(_panel) + return true; + return false; diff --git a/addons/shaker/src/shaker_inspector.gd.uid b/addons/shaker/src/shaker_inspector.gd.uid new file mode 100644 index 00000000..a016ea59 --- /dev/null +++ b/addons/shaker/src/shaker_inspector.gd.uid @@ -0,0 +1 @@ +uid://bj0ltv8atp1sn diff --git a/addons/shaker/src/shaker_panel.gd b/addons/shaker/src/shaker_panel.gd new file mode 100644 index 00000000..67c2b3ef --- /dev/null +++ b/addons/shaker/src/shaker_panel.gd @@ -0,0 +1,63 @@ +@tool +extends MarginContainer + +var _texture_button_play:Button = Button.new() +var _texture_button_stop:Button = Button.new() +var hbox:HBoxContainer = HBoxContainer.new() + +const play_texture:CompressedTexture2D = preload("res://addons/shaker/assets/Play.svg") +const pause_texture:CompressedTexture2D = preload("res://addons/shaker/assets/Pause.svg") +const stop_texture:CompressedTexture2D = preload("res://addons/shaker/assets/Stop.svg") + +var Target; +var button_width:float = 96; + +func _ready() -> void: + custom_minimum_size.y = 32; + add_theme_constant_override("margin_left",5) + add_theme_constant_override("margin_right",5) + add_theme_constant_override("margin_bottom",5) + add_theme_constant_override("margin_top",5) + add_child(hbox) + hbox.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT, Control.PRESET_MODE_KEEP_HEIGHT, 5) + hbox.alignment = BoxContainer.ALIGNMENT_CENTER; + + hbox.add_child(_texture_button_play) + _texture_button_play.custom_minimum_size.x = button_width; + _texture_button_play.expand_icon = true; + _update_buttons() + + hbox.add_child(_texture_button_stop) + _texture_button_stop.text = "Stop" + _texture_button_stop.icon = stop_texture; + _texture_button_stop.custom_minimum_size.x = button_width; + _texture_button_stop.expand_icon = true; + + _texture_button_play.pressed.connect(_on_play_pressed) + _texture_button_stop.pressed.connect(_on_stop_pressed) + + if Target != null: + Target.timeline_progress.connect(func(progress:float): + _update_buttons() + ) + + Target.shake_finished.connect(func(): + _update_buttons() + ) + +func _on_play_pressed() -> void: + Target.play_shake() + _update_buttons() + +func _update_buttons() -> void: + _texture_button_play.text = "Play" if (Target.timer == 0.0 || !Target.is_playing) else "Pause" + _texture_button_play.icon = play_texture if (Target.timer == 0.0 || !Target.is_playing) else pause_texture; + + _texture_button_stop.text = "Stop" if (!Target._fading_out) else "Force Stop" + _texture_button_stop.modulate = Color.WHITE if (!Target._fading_out) else Color.INDIAN_RED; +func _on_stop_pressed() -> void: + if !Target._fading_out: + Target.stop_shake() + else: + Target.force_stop_shake() + #_update_buttons() diff --git a/addons/shaker/src/shaker_panel.gd.uid b/addons/shaker/src/shaker_panel.gd.uid new file mode 100644 index 00000000..867ce05f --- /dev/null +++ b/addons/shaker/src/shaker_panel.gd.uid @@ -0,0 +1 @@ +uid://biww5l4smr7f0 diff --git a/addons/shaker/src/shaker_plugin.gd b/addons/shaker/src/shaker_plugin.gd new file mode 100644 index 00000000..aa44b32b --- /dev/null +++ b/addons/shaker/src/shaker_plugin.gd @@ -0,0 +1,14 @@ +@tool +extends EditorPlugin + +var SHAKER_INSPECTOR_PLUGIN:EditorInspectorPlugin = preload("res://addons/shaker/src/shaker_inspector.gd").new() + +func _enter_tree() -> void: + # Initialization of the plugin goes here. + add_inspector_plugin(SHAKER_INSPECTOR_PLUGIN) + add_autoload_singleton("Shaker", "res://addons/shaker/src/Shaker.gd") + +func _exit_tree() -> void: + # Clean-up of the plugin goes here. + remove_inspector_plugin(SHAKER_INSPECTOR_PLUGIN) + remove_autoload_singleton("Shaker") diff --git a/addons/shaker/src/shaker_plugin.gd.uid b/addons/shaker/src/shaker_plugin.gd.uid new file mode 100644 index 00000000..1b920aed --- /dev/null +++ b/addons/shaker/src/shaker_plugin.gd.uid @@ -0,0 +1 @@ +uid://xqg7s8xnwljh diff --git a/addons/shaker/src/shaker_timeline.gd b/addons/shaker/src/shaker_timeline.gd new file mode 100644 index 00000000..6d6f16ed --- /dev/null +++ b/addons/shaker/src/shaker_timeline.gd @@ -0,0 +1,41 @@ +@tool +extends Control + +const ShakerBase3d = preload("res://addons/shaker/src/Vector3/ShakerBase3D.gd") +const ShakerBase2d = preload("res://addons/shaker/src/Vector2/ShakerBase2D.gd") + +var GRAPH:Panel: + set=_initalize_graph + +var timer:float = 0.0; +var playing:bool = false; +var _shaker_component; + +func _ready() -> void: + mouse_filter = MOUSE_FILTER_IGNORE; + set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT, Control.PRESET_MODE_KEEP_SIZE) + + +func _initalize_graph(value:Panel) -> void: + GRAPH = value; + if GRAPH != null: + if GRAPH.shake is ShakerPresetBase: + _shaker_component = GRAPH.shake.parent; + if _shaker_component != null: + _shaker_component.timeline_progress.connect(update_timeline) + _shaker_component.shake_finished.connect(func(): + if GRAPH.shake is ShakerPresetBase: + GRAPH.graph_time_offset = 0.0; + ) +func update_timeline(value=1) -> void: + timer = value; + if GRAPH.shake is ShakerPresetBase && _shaker_component != null: + if GRAPH.shake.__follow_timeline && _shaker_component.is_playing: + GRAPH.graph_time_offset = max(timer - .5, 0.0) + queue_redraw() + +func _draw() -> void: + # Playing Timeline + var _final_size:Vector2 = size - GRAPH.graph_offset; + var _timeline_offset:Vector2 = Vector2(-GRAPH.graph_time_offset * _final_size.x, 0.0) + draw_line(GRAPH.graph_offset+_timeline_offset+Vector2(timer*_final_size.x, 0.0), GRAPH.graph_offset+_timeline_offset+Vector2(timer*_final_size.x, _final_size.y), Color.ORANGE, 1, false) diff --git a/addons/shaker/src/shaker_timeline.gd.uid b/addons/shaker/src/shaker_timeline.gd.uid new file mode 100644 index 00000000..3c04e87e --- /dev/null +++ b/addons/shaker/src/shaker_timeline.gd.uid @@ -0,0 +1 @@ +uid://dk3dikejci4sq diff --git a/player_controller/Scripts/PlayerController.cs b/player_controller/Scripts/PlayerController.cs index 30aa2c6c..51ed8a7b 100644 --- a/player_controller/Scripts/PlayerController.cs +++ b/player_controller/Scripts/PlayerController.cs @@ -1787,13 +1787,19 @@ public partial class PlayerController : CharacterBody3D, var finalDamage = CDamageable.TakeDamage(damageRecord); DamageTaken?.Invoke(this, finalDamage); + HeadSystem.OnGetHit(); TriggerHitstop(); - - _isInvincible = true; - _invincibilityTimer.Start(); + OnHitInvincibility(); return finalDamage; } + + public void OnHitInvincibility() + { + _isInvincible = true; + _invincibilityTimer.Start(); + } + public void OnInputHitPressed() { if (_aiming.Active && WeaponSystem.InHandState.Active) @@ -1842,6 +1848,8 @@ public partial class PlayerController : CharacterBody3D, foreach (var damageable in _hitEnemies) damageable.TakeDamage(new DamageRecord(this, RDamage)); _hitEnemies.Clear(); + + HeadSystem.OnHitTarget(); TriggerHitstop(); } diff --git a/project.godot b/project.godot index e592f32d..aebea61e 100644 --- a/project.godot +++ b/project.godot @@ -26,6 +26,7 @@ AppConfig="*res://addons/maaacks_game_template/base/scenes/autoloads/app_config. SceneLoader="*res://addons/maaacks_game_template/base/scenes/autoloads/scene_loader.tscn" ProjectMusicController="*res://addons/maaacks_game_template/base/scenes/autoloads/project_music_controller.tscn" ProjectUISoundController="*res://addons/maaacks_game_template/base/scenes/autoloads/project_ui_sound_controller.tscn" +Shaker="*res://addons/shaker/src/Shaker.gd" [display] @@ -38,7 +39,7 @@ project/assembly_name="Movement tests" [editor_plugins] -enabled=PackedStringArray("res://addons/godot_state_charts/plugin.cfg", "res://addons/guide/plugin.cfg", "res://addons/maaacks_game_template/plugin.cfg") +enabled=PackedStringArray("res://addons/godot_state_charts/plugin.cfg", "res://addons/guide/plugin.cfg", "res://addons/maaacks_game_template/plugin.cfg", "res://addons/shaker/plugin.cfg") [gui] diff --git a/systems/head/HeadSystem.cs b/systems/head/HeadSystem.cs index b8635c3e..c9833092 100644 --- a/systems/head/HeadSystem.cs +++ b/systems/head/HeadSystem.cs @@ -10,6 +10,11 @@ public partial class HeadSystem : Node3D public delegate void HitboxActivatedEventHandler(); [Signal] public delegate void HitboxDeactivatedEventHandler(); + + [Signal] + public delegate void HitTargetEventHandler(); + [Signal] + public delegate void GotHitEventHandler(); public record CameraParameters( double Delta, @@ -121,6 +126,15 @@ public partial class HeadSystem : Node3D _animationTree.Set("parameters/OnHit/request", (int) AnimationNodeOneShot.OneShotRequest.Fire); } + public void OnHitTarget() + { + EmitSignalHitTarget(); + } + public void OnGetHit() + { + EmitSignalGotHit(); + } + public void OnHitboxActivated() { EmitSignalHitboxActivated(); diff --git a/systems/head/head_system.tscn b/systems/head/head_system.tscn index 646112e1..6b907411 100644 --- a/systems/head/head_system.tscn +++ b/systems/head/head_system.tscn @@ -1,8 +1,75 @@ -[gd_scene load_steps=11 format=3 uid="uid://0ysqmqphq6mq"] +[gd_scene load_steps=29 format=3 uid="uid://0ysqmqphq6mq"] [ext_resource type="Script" uid="uid://dtkdrnsmlwm67" path="res://systems/head/HeadSystem.cs" id="1_8abgy"] [ext_resource type="ArrayMesh" uid="uid://ckr26s4e3fj1m" path="res://assets/swords/resources/fp_sword23.tres" id="2_c5qep"] [ext_resource type="AnimationNodeBlendTree" uid="uid://c26yvcyyyj811" path="res://systems/head/fp_blend_tree.tres" id="3_r0h40"] +[ext_resource type="Script" uid="uid://dnlxsrumw6ygp" path="res://addons/shaker/src/Vector3/shaker_component3D.gd" id="3_ubhf8"] +[ext_resource type="Script" uid="uid://0tu2q57qqu4s" path="res://addons/shaker/data/Vector3/BaseShakerType3D.gd" id="4_1ay6d"] +[ext_resource type="Script" uid="uid://ptaespkh1sk2" path="res://addons/shaker/data/Vector3/ShakerTypeNoiseShake3D.gd" id="5_sdjj3"] +[ext_resource type="Script" uid="uid://mlwdmecg12xd" path="res://addons/shaker/data/Vector3/ShakerPreset3D.gd" id="6_ll12k"] + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_ubhf8"] +frequency = 0.15 +fractal_octaves = 1 + +[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_1ay6d"] +noise = SubResource("FastNoiseLite_ubhf8") + +[sub_resource type="Resource" id="Resource_sdjj3"] +script = ExtResource("5_sdjj3") +noise_texture = SubResource("NoiseTexture3D_1ay6d") +amplitude = Vector3(0.1, 0.1, 0.1) +metadata/_custom_type_script = "uid://ptaespkh1sk2" + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_sdjj3"] +frequency = 0.1 + +[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_ll12k"] +noise = SubResource("FastNoiseLite_sdjj3") + +[sub_resource type="Resource" id="Resource_dvot2"] +script = ExtResource("5_sdjj3") +noise_texture = SubResource("NoiseTexture3D_ll12k") +amplitude = Vector3(0.02, 0.02, 0.02) +metadata/_custom_type_script = "uid://ptaespkh1sk2" + +[sub_resource type="Resource" id="Resource_60ouj"] +script = ExtResource("6_ll12k") +PositionShake = Array[ExtResource("4_1ay6d")]([SubResource("Resource_sdjj3")]) +RotationShake = Array[ExtResource("4_1ay6d")]([SubResource("Resource_dvot2")]) +metadata/_custom_type_script = "uid://mlwdmecg12xd" + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_1ay6d"] +frequency = 0.02 +fractal_octaves = 1 + +[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_sdjj3"] +noise = SubResource("FastNoiseLite_1ay6d") + +[sub_resource type="Resource" id="Resource_ll12k"] +script = ExtResource("5_sdjj3") +noise_texture = SubResource("NoiseTexture3D_sdjj3") +amplitude = Vector3(0.2, 0, 0) +metadata/_custom_type_script = "uid://ptaespkh1sk2" + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_ll12k"] +frequency = 0.02 +fractal_octaves = 1 + +[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_se3kf"] +noise = SubResource("FastNoiseLite_ll12k") + +[sub_resource type="Resource" id="Resource_0k6hv"] +script = ExtResource("5_sdjj3") +noise_texture = SubResource("NoiseTexture3D_se3kf") +amplitude = Vector3(0.1, 0.2, 0.1) +metadata/_custom_type_script = "uid://ptaespkh1sk2" + +[sub_resource type="Resource" id="Resource_se3kf"] +script = ExtResource("6_ll12k") +PositionShake = Array[ExtResource("4_1ay6d")]([SubResource("Resource_ll12k")]) +RotationShake = Array[ExtResource("4_1ay6d")]([SubResource("Resource_0k6hv")]) +metadata/_custom_type_script = "uid://mlwdmecg12xd" [sub_resource type="Animation" id="Animation_urko7"] length = 0.001 @@ -268,10 +335,29 @@ mesh = ExtResource("2_c5qep") transform = Transform3D(1, -0.00011616431, 0, 0.00011616433, 0.9999998, 0, 0, 0, 0.9999998, 0, 0, 0) [node name="Camera3D" type="Camera3D" parent="CameraSmooth"] -transform = Transform3D(1, 0, 0, 0, 0.99999994, 0, 0, 0, 0.99999994, 0, 0, 0) +transform = Transform3D(1, -7.508787e-09, -1.4551914e-08, 7.508788e-09, 0.99999994, -1.5046679e-08, 1.4551915e-08, 1.5046679e-08, 0.99999994, -0.04610423, -0.02960227, -0.053528003) current = true fov = 90.0 +[node name="OnGetHitShaker" type="Node3D" parent="CameraSmooth/Camera3D"] +transform = Transform3D(1, 0, 0, -7.275958e-12, 0.99999976, 0, 0, 0, 0.99999976, 0, 1.8626451e-09, 3.7252903e-09) +script = ExtResource("3_ubhf8") +intensity = 1.2 +duration = 0.5 +fade_in = 0.06470415 +fade_out = 0.46651623 +shakerPreset = SubResource("Resource_60ouj") +metadata/_custom_type_script = "uid://dnlxsrumw6ygp" + +[node name="OnHitShaker" type="Node3D" parent="CameraSmooth/Camera3D"] +transform = Transform3D(1, 0, 0, -7.275958e-12, 0.99999976, 0, 0, 0, 0.99999976, 0, 1.8626451e-09, 3.7252903e-09) +script = ExtResource("3_ubhf8") +duration = 0.3 +fade_in = 0.041234624 +fade_out = 0.5547845 +shakerPreset = SubResource("Resource_se3kf") +metadata/_custom_type_script = "uid://dnlxsrumw6ygp" + [node name="CameraAnchor" type="Marker3D" parent="."] [node name="AnimationPlayer" type="AnimationPlayer" parent="."] @@ -296,3 +382,6 @@ parameters/OnJumpEnd/request = 0 parameters/OnMantle/active = false parameters/OnMantle/internal_active = false parameters/OnMantle/request = 0 + +[connection signal="GotHit" from="." to="CameraSmooth/Camera3D/OnGetHitShaker" method="play_shake"] +[connection signal="HitTarget" from="." to="CameraSmooth/Camera3D/OnHitShaker" method="play_shake"]