diff --git a/Models/Dart/Dart.blend b/Models/Dart/Dart.blend deleted file mode 100644 index 6fd06e1..0000000 Binary files a/Models/Dart/Dart.blend and /dev/null differ diff --git a/Models/Dart/Dart.blend1 b/Models/Dart/Dart.blend1 deleted file mode 100644 index f9649fe..0000000 Binary files a/Models/Dart/Dart.blend1 and /dev/null differ diff --git a/Models/Dart/Dart.glb b/Models/Dart/Dart.glb deleted file mode 100644 index 30d5418..0000000 Binary files a/Models/Dart/Dart.glb and /dev/null differ diff --git a/Models/Dart/Dart_Dart-Default.png b/Models/Dart/Dart_Dart-Default.png deleted file mode 100644 index bfbaad5..0000000 Binary files a/Models/Dart/Dart_Dart-Default.png and /dev/null differ diff --git a/Models/Dart/Dart_Wings-Default.png b/Models/Dart/Dart_Wings-Default.png deleted file mode 100644 index 6c07cdc..0000000 Binary files a/Models/Dart/Dart_Wings-Default.png and /dev/null differ diff --git a/Models/Dart/Textures/Dart-Default.png b/Models/Dart/Textures/Dart-Default.png deleted file mode 100644 index bfbaad5..0000000 Binary files a/Models/Dart/Textures/Dart-Default.png and /dev/null differ diff --git a/Models/Dart/Textures/Wings-Default.png b/Models/Dart/Textures/Wings-Default.png deleted file mode 100644 index 6c07cdc..0000000 Binary files a/Models/Dart/Textures/Wings-Default.png and /dev/null differ diff --git a/Models/Dart/Textures/Wings-Red-Blue.png b/Models/Dart/Textures/Wings-Red-Blue.png deleted file mode 100644 index f56e5cc..0000000 Binary files a/Models/Dart/Textures/Wings-Red-Blue.png and /dev/null differ diff --git a/Models/Dartboard/Dartboard-Proto.blend b/Models/Dartboard/Dartboard-Proto.blend deleted file mode 100644 index 20771e6..0000000 Binary files a/Models/Dartboard/Dartboard-Proto.blend and /dev/null differ diff --git a/Models/Dartboard/Dartboard-Proto.blend1 b/Models/Dartboard/Dartboard-Proto.blend1 deleted file mode 100644 index 2a08ad5..0000000 Binary files a/Models/Dartboard/Dartboard-Proto.blend1 and /dev/null differ diff --git a/Models/Dartboard/Dartboard-Proto.glb b/Models/Dartboard/Dartboard-Proto.glb deleted file mode 100644 index 8da6afd..0000000 Binary files a/Models/Dartboard/Dartboard-Proto.glb and /dev/null differ diff --git a/Models/Dartboard/Dartboard-Proto.glb.import b/Models/Dartboard/Dartboard-Proto.glb.import deleted file mode 100644 index 5731dd9..0000000 --- a/Models/Dartboard/Dartboard-Proto.glb.import +++ /dev/null @@ -1,45 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://c7ysojicqbx2v" -path="res://.godot/imported/Dartboard-Proto.glb-f1487085b0c09a3b97c6aa8be3864f01.scn" - -[deps] - -source_file="res://Models/Dartboard/Dartboard-Proto.glb" -dest_files=["res://.godot/imported/Dartboard-Proto.glb-f1487085b0c09a3b97c6aa8be3864f01.scn"] - -[params] - -nodes/root_type="" -nodes/root_name="" -nodes/root_script=null -mesh_library/use_node_names_as_mesh_names=false -array_mesh/deduplicate_surfaces=true -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=2 -gltf/embedded_image_handling=1 -gltf/texture_map_mode=1 diff --git a/Models/Dartboard/Dartboard-Proto_Cork.png b/Models/Dartboard/Dartboard-Proto_Cork.png deleted file mode 100644 index 090f376..0000000 Binary files a/Models/Dartboard/Dartboard-Proto_Cork.png and /dev/null differ diff --git a/Models/Dartboard/Dartboard-Proto_Green.png b/Models/Dartboard/Dartboard-Proto_Green.png deleted file mode 100644 index b63714c..0000000 Binary files a/Models/Dartboard/Dartboard-Proto_Green.png and /dev/null differ diff --git a/Models/Dartboard/Dartboard-Proto_Green.png.import b/Models/Dartboard/Dartboard-Proto_Green.png.import deleted file mode 100644 index 2e57368..0000000 --- a/Models/Dartboard/Dartboard-Proto_Green.png.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cs381hglod4k1" -path.s3tc="res://.godot/imported/Dartboard-Proto_Green.png-0f939f85106a12f4ae54352c096222a2.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} -generator_parameters={ -"md5": "c03f264d9d0115e28f662ed5ab27bbb2" -} - -[deps] - -source_file="res://Models/Dartboard/Dartboard-Proto_Green.png" -dest_files=["res://.godot/imported/Dartboard-Proto_Green.png-0f939f85106a12f4ae54352c096222a2.s3tc.ctex"] - -[params] - -compress/mode=2 -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=true -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=0 diff --git a/Models/Dartboard/Dartboard-Proto_Red.png b/Models/Dartboard/Dartboard-Proto_Red.png deleted file mode 100644 index d3ddab7..0000000 Binary files a/Models/Dartboard/Dartboard-Proto_Red.png and /dev/null differ diff --git a/Models/Dartboard/Dartboard-Sectors.blend b/Models/Dartboard/Dartboard-Sectors.blend deleted file mode 100644 index 480b85d..0000000 Binary files a/Models/Dartboard/Dartboard-Sectors.blend and /dev/null differ diff --git a/Models/Dartboard/Dartboard-Sectors.blend1 b/Models/Dartboard/Dartboard-Sectors.blend1 deleted file mode 100644 index 34f5604..0000000 Binary files a/Models/Dartboard/Dartboard-Sectors.blend1 and /dev/null differ diff --git a/Models/Dartboard/Dartboard.blend b/Models/Dartboard/Dartboard.blend deleted file mode 100644 index ce7bdce..0000000 Binary files a/Models/Dartboard/Dartboard.blend and /dev/null differ diff --git a/Models/Dartboard/Dartboard.blend1 b/Models/Dartboard/Dartboard.blend1 deleted file mode 100644 index ba66638..0000000 Binary files a/Models/Dartboard/Dartboard.blend1 and /dev/null differ diff --git a/Models/Dartboard/Dartboard.glb b/Models/Dartboard/Dartboard.glb deleted file mode 100644 index ce876ee..0000000 Binary files a/Models/Dartboard/Dartboard.glb and /dev/null differ diff --git a/Models/Dartboard/Dartboard.glb.import b/Models/Dartboard/Dartboard.glb.import deleted file mode 100644 index 4d8fd15..0000000 --- a/Models/Dartboard/Dartboard.glb.import +++ /dev/null @@ -1,45 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://6nml3641dpce" -path="res://.godot/imported/Dartboard.glb-35f0707e0e9b18915b2d48c5c14ac862.scn" - -[deps] - -source_file="res://Models/Dartboard/Dartboard.glb" -dest_files=["res://.godot/imported/Dartboard.glb-35f0707e0e9b18915b2d48c5c14ac862.scn"] - -[params] - -nodes/root_type="" -nodes/root_name="" -nodes/root_script=null -mesh_library/use_node_names_as_mesh_names=false -array_mesh/deduplicate_surfaces=true -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=2 -gltf/embedded_image_handling=1 -gltf/texture_map_mode=1 diff --git a/Models/Dartboard/Dartboard_Spider.png b/Models/Dartboard/Dartboard_Spider.png deleted file mode 100644 index 6c26bd4..0000000 Binary files a/Models/Dartboard/Dartboard_Spider.png and /dev/null differ diff --git a/Models/Dartboard/Textures/Coffee.png b/Models/Dartboard/Textures/Coffee.png deleted file mode 100644 index 998206b..0000000 Binary files a/Models/Dartboard/Textures/Coffee.png and /dev/null differ diff --git a/Models/Dartboard/Textures/Cork.png b/Models/Dartboard/Textures/Cork.png deleted file mode 100644 index 090f376..0000000 Binary files a/Models/Dartboard/Textures/Cork.png and /dev/null differ diff --git a/Models/Dartboard/Textures/Cork.png.import b/Models/Dartboard/Textures/Cork.png.import deleted file mode 100644 index 283ae19..0000000 --- a/Models/Dartboard/Textures/Cork.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://blvifdtblwcxg" -path="res://.godot/imported/Cork.png-8b577bb6a5aa8a82bae563118e794e18.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://Models/Dartboard/Textures/Cork.png" -dest_files=["res://.godot/imported/Cork.png-8b577bb6a5aa8a82bae563118e794e18.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/Models/Dartboard/Textures/Flowers.jpg b/Models/Dartboard/Textures/Flowers.jpg deleted file mode 100644 index d81be46..0000000 Binary files a/Models/Dartboard/Textures/Flowers.jpg and /dev/null differ diff --git a/Models/Dartboard/Textures/Flowers.jpg.import b/Models/Dartboard/Textures/Flowers.jpg.import deleted file mode 100644 index 04af584..0000000 --- a/Models/Dartboard/Textures/Flowers.jpg.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dxxon6pdl5aw4" -path="res://.godot/imported/Flowers.jpg-4755265eb848ca410e8aa3e15ab13280.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://Models/Dartboard/Textures/Flowers.jpg" -dest_files=["res://.godot/imported/Flowers.jpg-4755265eb848ca410e8aa3e15ab13280.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/Models/Dartboard/Textures/Green-Cork-Sector.png b/Models/Dartboard/Textures/Green-Cork-Sector.png deleted file mode 100644 index cc1e471..0000000 Binary files a/Models/Dartboard/Textures/Green-Cork-Sector.png and /dev/null differ diff --git a/Models/Dartboard/Textures/Green-Cork-Sector.png.import b/Models/Dartboard/Textures/Green-Cork-Sector.png.import deleted file mode 100644 index b260b30..0000000 --- a/Models/Dartboard/Textures/Green-Cork-Sector.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://l3ub5fmxsrwc" -path="res://.godot/imported/Green-Cork-Sector.png-21c4d4fd42f5a3cb24b7fd4da30825f7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://Models/Dartboard/Textures/Green-Cork-Sector.png" -dest_files=["res://.godot/imported/Green-Cork-Sector.png-21c4d4fd42f5a3cb24b7fd4da30825f7.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/Models/Dartboard/Textures/Green.png b/Models/Dartboard/Textures/Green.png deleted file mode 100644 index b63714c..0000000 Binary files a/Models/Dartboard/Textures/Green.png and /dev/null differ diff --git a/Models/Dartboard/Textures/Green.png.import b/Models/Dartboard/Textures/Green.png.import deleted file mode 100644 index bf524f8..0000000 --- a/Models/Dartboard/Textures/Green.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c2qvwu0v2uolj" -path="res://.godot/imported/Green.png-6f1f5b0c58d2ec51c6b638c11ba4264b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://Models/Dartboard/Textures/Green.png" -dest_files=["res://.godot/imported/Green.png-6f1f5b0c58d2ec51c6b638c11ba4264b.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/Models/Dartboard/Textures/Red-Black-Sector.png b/Models/Dartboard/Textures/Red-Black-Sector.png deleted file mode 100644 index 2cfd995..0000000 Binary files a/Models/Dartboard/Textures/Red-Black-Sector.png and /dev/null differ diff --git a/Models/Dartboard/Textures/Red-Black-Sector.png.import b/Models/Dartboard/Textures/Red-Black-Sector.png.import deleted file mode 100644 index 7959ca0..0000000 --- a/Models/Dartboard/Textures/Red-Black-Sector.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bewdyudac4bjw" -path="res://.godot/imported/Red-Black-Sector.png-243923859b1e205de71bccd1f89cdbe6.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://Models/Dartboard/Textures/Red-Black-Sector.png" -dest_files=["res://.godot/imported/Red-Black-Sector.png-243923859b1e205de71bccd1f89cdbe6.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/Models/Dartboard/Textures/Red.png b/Models/Dartboard/Textures/Red.png deleted file mode 100644 index d3ddab7..0000000 Binary files a/Models/Dartboard/Textures/Red.png and /dev/null differ diff --git a/Models/Dartboard/Textures/Red.png.import b/Models/Dartboard/Textures/Red.png.import deleted file mode 100644 index 08eda5c..0000000 --- a/Models/Dartboard/Textures/Red.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b1lclw6s66ou7" -path="res://.godot/imported/Red.png-5fe46449e66850590891dfad1c596ebf.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://Models/Dartboard/Textures/Red.png" -dest_files=["res://.godot/imported/Red.png-5fe46449e66850590891dfad1c596ebf.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/Models/Dartboard/Textures/Spider.png b/Models/Dartboard/Textures/Spider.png deleted file mode 100644 index 6c26bd4..0000000 Binary files a/Models/Dartboard/Textures/Spider.png and /dev/null differ diff --git a/Models/Dartboard/Textures/Spider.png.import b/Models/Dartboard/Textures/Spider.png.import deleted file mode 100644 index 52b7b5a..0000000 --- a/Models/Dartboard/Textures/Spider.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b3qw07lguggu6" -path="res://.godot/imported/Spider.png-3f1c947c2e5bcf6b7d7e259d62e6005a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://Models/Dartboard/Textures/Spider.png" -dest_files=["res://.godot/imported/Spider.png-3f1c947c2e5bcf6b7d7e259d62e6005a.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/Models/Dartboard/Textures/Stars.jpg b/Models/Dartboard/Textures/Stars.jpg deleted file mode 100644 index 873c7ca..0000000 Binary files a/Models/Dartboard/Textures/Stars.jpg and /dev/null differ diff --git a/Models/Dartboard/Textures/Stars.jpg.import b/Models/Dartboard/Textures/Stars.jpg.import deleted file mode 100644 index 3f62466..0000000 --- a/Models/Dartboard/Textures/Stars.jpg.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ccoht16d1pkr3" -path="res://.godot/imported/Stars.jpg-9cc50027cae80115a1f7344b30169970.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://Models/Dartboard/Textures/Stars.jpg" -dest_files=["res://.godot/imported/Stars.jpg-9cc50027cae80115a1f7344b30169970.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/Models/Dartboard/Textures/bulls.png b/Models/Dartboard/Textures/bulls.png deleted file mode 100644 index f946f37..0000000 Binary files a/Models/Dartboard/Textures/bulls.png and /dev/null differ diff --git a/Models/Dartboard/Textures/flat_tire-fire.png b/Models/Dartboard/Textures/flat_tire-fire.png deleted file mode 100644 index bf93d29..0000000 Binary files a/Models/Dartboard/Textures/flat_tire-fire.png and /dev/null differ diff --git a/Models/Dartboard/Textures/flat_tire-fire.png.import b/Models/Dartboard/Textures/flat_tire-fire.png.import deleted file mode 100644 index 05ac9dd..0000000 --- a/Models/Dartboard/Textures/flat_tire-fire.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dtamlt3msrj04" -path="res://.godot/imported/flat_tire-fire.png-934cda684e012e3a39a7204520eb1a02.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://Models/Dartboard/Textures/flat_tire-fire.png" -dest_files=["res://.godot/imported/flat_tire-fire.png-934cda684e012e3a39a7204520eb1a02.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/Models/Dartboard/Textures/flat_tire-purple.png b/Models/Dartboard/Textures/flat_tire-purple.png deleted file mode 100644 index 813ce35..0000000 Binary files a/Models/Dartboard/Textures/flat_tire-purple.png and /dev/null differ diff --git a/Models/Dartboard/Textures/flat_tire.kra b/Models/Dartboard/Textures/flat_tire.kra deleted file mode 100644 index 2e69adc..0000000 Binary files a/Models/Dartboard/Textures/flat_tire.kra and /dev/null differ diff --git a/Models/Dartboard/Textures/flat_tire.kra~ b/Models/Dartboard/Textures/flat_tire.kra~ deleted file mode 100644 index 2ab092a..0000000 Binary files a/Models/Dartboard/Textures/flat_tire.kra~ and /dev/null differ diff --git a/Models/Dartboard/Textures/flat_tire.png b/Models/Dartboard/Textures/flat_tire.png deleted file mode 100644 index 223facb..0000000 Binary files a/Models/Dartboard/Textures/flat_tire.png and /dev/null differ diff --git a/Models/Dartboard/Textures/neon-bulls.kra b/Models/Dartboard/Textures/neon-bulls.kra deleted file mode 100644 index 8a6d96a..0000000 Binary files a/Models/Dartboard/Textures/neon-bulls.kra and /dev/null differ diff --git a/Models/Dartboard/Textures/neon-bulls.png b/Models/Dartboard/Textures/neon-bulls.png deleted file mode 100644 index db47e6c..0000000 Binary files a/Models/Dartboard/Textures/neon-bulls.png and /dev/null differ diff --git a/Models/Dartboard/Textures/neon-green-heiro-sector.kra b/Models/Dartboard/Textures/neon-green-heiro-sector.kra deleted file mode 100644 index cc99b58..0000000 Binary files a/Models/Dartboard/Textures/neon-green-heiro-sector.kra and /dev/null differ diff --git a/Models/Dartboard/Textures/neon-green-hiero.png b/Models/Dartboard/Textures/neon-green-hiero.png deleted file mode 100644 index 1878677..0000000 Binary files a/Models/Dartboard/Textures/neon-green-hiero.png and /dev/null differ diff --git a/Models/Dartboard/Textures/neon-hiero-sector.kra b/Models/Dartboard/Textures/neon-hiero-sector.kra deleted file mode 100644 index 23892f3..0000000 Binary files a/Models/Dartboard/Textures/neon-hiero-sector.kra and /dev/null differ diff --git a/Models/Dartboard/Textures/neon-hiro-sector.png b/Models/Dartboard/Textures/neon-hiro-sector.png deleted file mode 100644 index dab9a25..0000000 Binary files a/Models/Dartboard/Textures/neon-hiro-sector.png and /dev/null differ diff --git a/Modifiers/coffee.tres b/Modifiers/coffee.tres deleted file mode 100644 index 89d4c07..0000000 --- a/Modifiers/coffee.tres +++ /dev/null @@ -1,13 +0,0 @@ -[gd_resource type="Resource" script_class="Modifier" format=3 uid="uid://ccyxtrth046pt"] - -[ext_resource type="Script" uid="uid://duh0lxb7gdimr" path="res://Scripts/Modifier.gd" id="1_6fe4u"] -[ext_resource type="Texture2D" uid="uid://b1vf3204p4ys6" path="res://Models/Dartboard/Textures/Coffee.png" id="2_6fe4u"] - -[resource] -script = ExtResource("1_6fe4u") -id = "0" -title = "Stars" -description = "Adds 40 to your score" -texture = ExtResource("2_6fe4u") -score_add = 40 -metadata/_custom_type_script = "uid://duh0lxb7gdimr" diff --git a/Modifiers/flowers.tres b/Modifiers/flowers.tres deleted file mode 100644 index e91e00f..0000000 --- a/Modifiers/flowers.tres +++ /dev/null @@ -1,13 +0,0 @@ -[gd_resource type="Resource" script_class="Modifier" format=3 uid="uid://bu11ohgune4yf"] - -[ext_resource type="Script" uid="uid://duh0lxb7gdimr" path="res://Scripts/Modifier.gd" id="1_urlsx"] -[ext_resource type="Texture2D" uid="uid://dxxon6pdl5aw4" path="res://Models/Dartboard/Textures/Flowers.jpg" id="2_urlsx"] - -[resource] -script = ExtResource("1_urlsx") -id = "0" -title = "Stars" -description = "Adds 40 to your score" -texture = ExtResource("2_urlsx") -score_add = 40 -metadata/_custom_type_script = "uid://duh0lxb7gdimr" diff --git a/Modifiers/stars_x5.tres b/Modifiers/stars_x5.tres deleted file mode 100644 index bc71417..0000000 --- a/Modifiers/stars_x5.tres +++ /dev/null @@ -1,13 +0,0 @@ -[gd_resource type="Resource" script_class="Modifier" format=3 uid="uid://bigyh63smlbh5"] - -[ext_resource type="Script" uid="uid://duh0lxb7gdimr" path="res://Scripts/Modifier.gd" id="1_oxvfs"] -[ext_resource type="Texture2D" uid="uid://ccoht16d1pkr3" path="res://Models/Dartboard/Textures/Stars.jpg" id="2_5aq3x"] - -[resource] -script = ExtResource("1_oxvfs") -id = "0" -title = "Stars" -description = "Adds 40 to your score" -texture = ExtResource("2_5aq3x") -score_add = 40 -metadata/_custom_type_script = "uid://duh0lxb7gdimr" diff --git a/README.md b/README.md index 473a0f4..04aac90 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,160 @@ +# DartGame + +A 3D darts game where the core loop is **dragging modifiers onto board sectors** to create +compounding scoring interactions. Balatro's joker system, applied to a dartboard. + +Built in **Godot 4**. Modding is a first-class concern, not an afterthought — our own +content ships through the same loader community mods will use. + +--- + +## ⚠️ Install `git-lfs` BEFORE you clone + +Clone without it and you'll get **130-byte text pointers** where your textures and models +should be. Godot will throw import errors that look completely baffling and you will lose +an hour figuring out why. + +**NixOS** — `configuration.nix`: +```nix +environment.systemPackages = with pkgs; [ git git-lfs ]; +``` + +Or declaratively via Home Manager (also writes the LFS filter config, so a fresh machine is +correct with no imperative step): +```nix +programs.git = { + enable = true; + lfs.enable = true; +}; +``` + +**Debian/Ubuntu** — `sudo apt install git-lfs` +**macOS** — `brew install git-lfs` + +Then, once per machine: +```bash +git lfs install +``` + +--- + +## Setup + +```bash +git clone /DartGame.git +cd DartGame +git lfs pull +``` + +**Verify LFS worked.** Open `game/core/board/dartboard.glb` in a text editor. If it's +readable text starting with `version https://git-lfs...`, LFS did **not** run. Stop and fix +it before opening the project. + +### Tooling + +```bash +# GDScript formatter + linter +nix-shell -p gdtoolkit_4 # or: pipx install "gdtoolkit==4.*" + +# Pre-commit hooks +pre-commit install +``` + +### Open the project + +Point Godot 4 at `game/project.godot`. + +--- + +## Where things live + +| | Nextcloud | This repo | +|---|---|---| +| `.blend`, `.kra`, `.psd` | ✅ | ❌ **never** | +| `.glb`, `.png` (exported) | ❌ | ✅ (LFS) | +| Code, scenes, `.tres` | ❌ | ✅ | +| Moodboards, references | ✅ | ❌ | + +Source files live in the **company Nextcloud share**, not here. They churn constantly, never +merge, and 99% of their revisions have no corresponding code change — they'd bloat LFS +history forever, on every clone. + +Exported artifacts **do** live here, because they must version in lockstep with the code +that references them. If a UV layout changes and a script needs updating, those belong in +one commit. + +`SOURCES.md` maps each repo artifact back to its Nextcloud source. + +--- + +## Layout + +``` +game/ +├── core/ ← THE ENGINE. Contains zero game content. Ever. +│ ├── board/ dartboard scene, mesh, sector logic +│ ├── dart/ dart scene, physics +│ ├── scoring/ ScorePacket pipeline +│ ├── game/ GameContext ← the mod API +│ ├── modding/ loader, registry, base classes, primitives +│ ├── ui/ modifier tray, drag-and-drop +│ └── debug/ hit_simulator.tscn ← you'll use this daily +├── content/official/ ← OUR CONTENT, loaded as a mod like any other +│ ├── skins/ +│ ├── modifiers/ +│ └── modes/ +└── shared/ fonts, shaders +``` + +### The two rules + +**1. Nothing in `core/` knows about any specific content.** +About to write `if modifier.id == "mjolnir"` in `core/`? Stop — you need a new primitive. + +**2. `content/official/` must be deletable.** +Delete it, and the game boots to an empty state without crashing. That's the proof the mod +pipeline is real. If it can't, we don't have a mod system — we have a plugin folder. + +--- + +## Docs + +Full documentation lives in the Obsidian vault at +`Nextcloud/DartGame/documentation/`. Start with **Build Plan**. + +--- + +## Contributing + +**Branches:** `feat/`, `fix/`, `chore/` off `main`. `main` is protected and always runnable. + +**Commits:** Conventional Commits. +``` +feat(modding): add ModRegistry namespaced lookup +fix(scoring): ScorePacket.total() ignored final_override +``` + +**Before you open a PR:** +- [ ] `gdformat --check game/` passes +- [ ] `gdlint game/` passes +- [ ] Nothing in `core/` references a specific content ID +- [ ] New content is one self-contained folder +- [ ] If an asset changed: source updated in Nextcloud, `SOURCES.md` current + +### ⚠️ Moving files + +**Commit first.** Godot's refactoring is fragile. Move files from **inside the Godot +editor's FileSystem dock**, never your file manager, so references get fixed up. + +If things break after a move or a branch switch: +```bash +rm -rf game/.godot/ +``` +then Project → Reload Current Project. If it's worse than that, `git restore .` — which only +works if you committed first. + +--- + +## Status + +**Pre-alpha.** Currently in Phase 0 (repo hygiene). See [`docs/build_plan.md`](docs/build_plan.md). diff --git a/SOURCES.md b/SOURCES.md new file mode 100644 index 0000000..7f610f4 --- /dev/null +++ b/SOURCES.md @@ -0,0 +1,65 @@ +# Sources + +Every binary artifact in this repo was exported from a source file in Nextcloud. This maps +one to the other. + +**Nextcloud share:** `DartGame/sources/` + +> ⚠️ **Keep this current.** It is the only thing linking the two halves of the project. A +> programmer looking at `dartboard.glb` has no other way to find out where it came from. + +--- + +## Models + +| Repo artifact | Nextcloud source | Last export | +|---|---|---| +| `game/core/board/dartboard.glb` | `sources/dartboard/dartboard.blend` | 2026-07-11 | +| `game/core/dart/dart.glb` | `sources/dart/dart.blend` | 2026-07-11 | + +## Skins — bullseye + +| Repo artifact | Nextcloud source | Last export | +|---|---|---| +| `game/content/official/skins/bullseye/neon_bulls.png` | `sources/dartboard/textures/neon_bulls.kra` | 2026-07-11 | + +## Skins — sectors + +| Repo artifact | Nextcloud source | Last export | +|---|---|---| +| `game/content/official/skins/sectors/neon_hiero_sector.png` | `sources/dartboard/textures/neon_hiero_sector.kra` | 2026-07-11 | + +## Skins — flat tire + +| Repo artifact | Nextcloud source | Last export | +|---|---|---| +| `game/content/official/skins/flat_tire/fire.png` | `sources/dartboard/textures/flat_tire.kra` | 2026-07-11 | + +## Skins — flights + +| Repo artifact | Nextcloud source | Last export | +|---|---|---| +| `game/content/official/skins/flights/default.png` | `sources/dart/textures/wings_default.kra` | 2026-07-11 | + +--- + +## Fallback textures + +Single default textures that ship with the mesh so the editor isn't pink. Not skins — these +live in `core/`, not `content/`. + +| Repo artifact | Nextcloud source | +|---|---| +| `game/core/board/dartboard_default.png` | `sources/dartboard/textures/cork.kra` | +| `game/core/dart/dart_default.png` | `sources/dart/textures/dart_default.kra` | + +--- + +## When you re-export + +1. Export from the Nextcloud source +2. Drop the artifact into the repo path above +3. **Update the "Last export" date in this file** +4. Commit the artifact + this file together + +If a row is missing, the artifact has no traceable source. Add it, or find out why it exists. diff --git a/Scenes/Dart.tscn b/Scenes/Dart.tscn deleted file mode 100644 index d765ddb..0000000 --- a/Scenes/Dart.tscn +++ /dev/null @@ -1,23 +0,0 @@ -[gd_scene format=3 uid="uid://bswbcehkkqbk0"] - -[ext_resource type="Script" uid="uid://8kk531f88oqw" path="res://Scenes/DartPhysics.gd" id="1_s1kro"] -[ext_resource type="PackedScene" uid="uid://cjq45anerhxnk" path="res://models/Dart.glb" id="2_mlvfh"] - -[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_xxti7"] -radius = 0.27441406 -height = 2.3862305 - -[node name="Dart" type="Node3D" unique_id=367982453] - -[node name="RigidBody3D" type="RigidBody3D" parent="." unique_id=1993396351] -transform = Transform3D(1, 0, 0, 0, 1.0000001, 0, 0, 0, 1.0000001, 0, 0, 0) -center_of_mass_mode = 1 -script = ExtResource("1_s1kro") -angle_of_plane = -25.0 - -[node name="CollisionShape3D" type="CollisionShape3D" parent="RigidBody3D" unique_id=1030334431] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.10033989, 0) -shape = SubResource("CapsuleShape3D_xxti7") - -[node name="Dart2" parent="RigidBody3D" unique_id=1655536183 instance=ExtResource("2_mlvfh")] -transform = Transform3D(0.4, 0, 0, 0, 0.39999995, 0, 0, 0, 0.39999995, 0, -1.4526575, 0.015561234) diff --git a/Scenes/DartPhysics.gd b/Scenes/DartPhysics.gd deleted file mode 100644 index 73563cc..0000000 --- a/Scenes/DartPhysics.gd +++ /dev/null @@ -1,161 +0,0 @@ -extends RigidBody3D - -class_name Dart - -#states -var in_flight: bool = false -var dragging: bool = false - -#drag -var drag_plane: Plane -var drag_offset: Vector3 = Vector3.ZERO -var target_pos: Vector3 = Vector3.ZERO - -# velocity tracking for release throw -var position_history: Array[Vector3] = [] -var time_history: Array[float] = [] -const HISTORY_LENGTH = 6 - -# drag "stiffness" tuning -@export var drag_follow_speed: float = 20.0 # how fast it chases the mouse -@export var max_drag_speed: float = 42.0 # clamp so it doesn't go insane -@export_range(-180,180) var angle_of_plane: float = 15.0 -@export var throw_force_multiplier: float = 0.8 # scale raw throw velocity down if it's too fast -@export var max_throw_speed: float = 42.0 # hard cap so fast flicks don't kill the arc -@export var flight_gravity_scale: float = 4.0 # higher = more visible arc -@export var nose_align_speed: float = 1.0 # how fast dart rotates to face velocity -@export var dart_forward_axis: Vector3 = Vector3.FORWARD - -func _ready(): - freeze_mode = RigidBody3D.FREEZE_MODE_STATIC - freeze = true - -func start_drag(camera: Camera3D, mouse_pos: Vector2, hit_point: Vector3): - dragging = true - in_flight = false - freeze = false - - # keep it physics-active — don't freeze - gravity_scale = 0.0 # optional: ignore gravity while held so it doesn't sag - linear_damp = 5.0 # optional: a bit of damping for stability while dragged - angular_damp = 10.0 - - #drag_plane = Plane(camera.global_transform.basis.z, hit_point) - var base_normal = camera.global_transform.basis.z - var tilt = base_normal.rotated(camera.global_transform.basis.x, deg_to_rad(angle_of_plane)) # tilt adjustable around camera's right axis - drag_plane = Plane(tilt.normalized(), hit_point) - drag_offset = global_position - hit_point - - target_pos = global_position #fixes a bug where dart drops until mouse is moved. - - position_history.clear() - time_history.clear() - -func update_drag(camera: Camera3D, mouse_pos: Vector2): - if not dragging: - return - - var ray_origin = camera.project_ray_origin(mouse_pos) - var ray_dir = camera.project_ray_normal(mouse_pos) - - var intersection = drag_plane.intersects_ray(ray_origin, ray_dir) - if intersection: - target_pos = intersection + drag_offset - -func _align_dart_to_velocity(delta: float): - if linear_velocity.length() < 0.5: - return - - var vel_dir = linear_velocity.normalized() - var current_forward = global_transform.basis * dart_forward_axis - var rotation_axis = current_forward.cross(vel_dir) - - if rotation_axis.length() < 0.001: - return - - rotation_axis = rotation_axis.normalized() - var angle = current_forward.angle_to(vel_dir) - var rotate_amount = min(angle, nose_align_speed * delta) - - global_transform.basis = global_transform.basis.rotated(rotation_axis, rotate_amount) - global_transform.basis = global_transform.basis.orthonormalized() - -func _physics_process(delta): - if dragging: - # chase the target position with velocity instead of teleporting - var to_target = target_pos - global_position - var desired_velocity = to_target * drag_follow_speed - - if desired_velocity.length() > max_drag_speed: - desired_velocity = desired_velocity.normalized() * max_drag_speed - - linear_velocity = desired_velocity - angular_velocity = angular_velocity.lerp(Vector3.ZERO, 0.2) # optional: damp spin while dragging - - # track actual position for momentum calc on release - position_history.append(global_position) - time_history.append(Time.get_ticks_msec() / 1000.0) - if position_history.size() > HISTORY_LENGTH: - position_history.pop_front() - time_history.pop_front() - elif in_flight: - # Debug: confirm Y velocity is dropping (becoming negative) each frame - print("local +X world dir: ", global_transform.basis.x) - print("local +Y world dir: ", global_transform.basis.y) - print("local +Z world dir: ", global_transform.basis.z) - print("velocity dir: ", linear_velocity.normalized()) - - # Align dart nose to face velocity direction (tip points the way it's flying) - if linear_velocity.length() > 0.5: - _align_dart_to_velocity(delta) - else: - in_flight = false - angular_velocity = Vector3.ZERO - # If your dart tip points along +Z, use global_position + linear_velocity - # If it points along -Z, negate the direction below - var look_target = global_position + linear_velocity.normalized() - var up_ref = Vector3.UP - - # Avoid gimbal lock when flying straight up/down - if abs(linear_velocity.normalized().dot(Vector3.UP)) > 0.99: - up_ref = Vector3.FORWARD - - var target_basis = Basis.looking_at(linear_velocity.normalized(), up_ref) - global_transform.basis = global_transform.basis.slerp( - target_basis, nose_align_speed * delta - ) - -func release_drag(): - if not dragging: - return - dragging = false - in_flight = true - - gravity_scale = flight_gravity_scale - angular_damp = 0.0 - linear_damp = 0.0 # reset to whatever your normal dart damping is - - var velocity = calculate_throw_velocity() * throw_force_multiplier - if velocity.length() > max_throw_speed: - velocity = velocity.normalized() * max_throw_speed - linear_velocity = velocity - # angular_velocity left as-is from physics, or compute your own spin here - - print("throw speed: %.2f" % velocity.length()) - print("gravity_scale: ", gravity_scale) - print("linear_damp: ", linear_damp) - -func calculate_throw_velocity() -> Vector3: - if position_history.size() < 2: - return linear_velocity # fallback to whatever physics already had - - var start_pos = position_history[0] - var end_pos = position_history[position_history.size() - 1] - var start_time = time_history[0] - var end_time = time_history[time_history.size() - 1] - - var dt = end_time - start_time - if dt <= 0.0: - return linear_velocity - - return (end_pos - start_pos) / dt diff --git a/Scenes/DartPhysics.gd.uid b/Scenes/DartPhysics.gd.uid deleted file mode 100644 index c6d8fdc..0000000 --- a/Scenes/DartPhysics.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://8kk531f88oqw diff --git a/Scenes/Dartboard-Proto.tscn b/Scenes/Dartboard-Proto.tscn deleted file mode 100644 index e707777..0000000 --- a/Scenes/Dartboard-Proto.tscn +++ /dev/null @@ -1,49 +0,0 @@ -[gd_scene format=3 uid="uid://cqe6bo8v564dc"] - -[ext_resource type="Script" uid="uid://d1i0lhibtflvq" path="res://Scripts/Main.gd" id="1_fq6v0"] -[ext_resource type="Script" uid="uid://x5kcjofb5pek" path="res://Scripts/DropCatcher.gd" id="3_qdhrm"] -[ext_resource type="Script" uid="uid://dnek55fao0l72" path="res://Scripts/ModifierTray.gd" id="5_kax6v"] -[ext_resource type="PackedScene" uid="uid://6nml3641dpce" path="res://Models/Dartboard/Dartboard.glb" id="5_thh7l"] - -[node name="DartboardProto" type="Node3D" unique_id=1829621191 node_paths=PackedStringArray("dartboard_root")] -script = ExtResource("1_fq6v0") -dartboard_root = NodePath("Dartboard") - -[node name="Camera3D" type="Camera3D" parent="." unique_id=393502700] -transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, 2.6578834, 0.6292654, 0) - -[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1020512688] - -[node name="Dartboard" parent="." unique_id=1632971704 instance=ExtResource("5_thh7l")] -transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0.16272092, 1.2674973, 0) - -[node name="CanvasLayer" type="CanvasLayer" parent="." unique_id=80012783] - -[node name="DropCatcher" type="Control" parent="CanvasLayer" unique_id=1371111637 node_paths=PackedStringArray("camera", "main")] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("3_qdhrm") -camera = NodePath("../../Camera3D") -main = NodePath("../..") -reverse_direction = true -triple_max = 0.5 -outer_max = 0.7 - -[node name="TextureTray" type="HBoxContainer" parent="CanvasLayer/DropCatcher" unique_id=799936408] -layout_mode = 0 -offset_right = 40.0 -offset_bottom = 40.0 - -[node name="ModifierTray" type="Control" parent="CanvasLayer" unique_id=2127296352 node_paths=PackedStringArray("drop_catcher")] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("5_kax6v") -drop_catcher = NodePath("../DropCatcher") diff --git a/Scenes/camera_3d.gd b/Scenes/camera_3d.gd deleted file mode 100644 index c9c8ddf..0000000 --- a/Scenes/camera_3d.gd +++ /dev/null @@ -1,27 +0,0 @@ -extends Camera3D - -var held_dart: Dart = null - -func _unhandled_input(event): - if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: - if event.pressed: - try_grab_dart(event.position) - else: - if held_dart: - held_dart.release_drag() - held_dart = null - elif event is InputEventMouseMotion and held_dart: - held_dart.update_drag(self, event.position) - -func try_grab_dart(mouse_pos: Vector2): - var ray_origin = project_ray_origin(mouse_pos) - var ray_dir = project_ray_normal(mouse_pos) - var ray_end = ray_origin + ray_dir * 1000.0 - - var space_state = get_world_3d().direct_space_state - var query = PhysicsRayQueryParameters3D.create(ray_origin, ray_end) - var result = space_state.intersect_ray(query) - - if result and result.collider is Dart: - held_dart = result.collider - held_dart.start_drag(self, mouse_pos, result.position) diff --git a/Scenes/main.gd b/Scenes/main.gd deleted file mode 100644 index 7b1663a..0000000 --- a/Scenes/main.gd +++ /dev/null @@ -1,5 +0,0 @@ -extends Node3D - -func _unhandled_input(event): - if event.is_action_pressed("restart"): - get_tree().reload_current_scene() diff --git a/Scenes/main.tscn b/Scenes/main.tscn deleted file mode 100644 index 17c6be3..0000000 --- a/Scenes/main.tscn +++ /dev/null @@ -1,40 +0,0 @@ -[gd_scene format=3 uid="uid://doh7p84eej78c"] - -[ext_resource type="Script" uid="uid://geqmah8kbko0" path="res://Scenes/main.gd" id="1_8gbba"] -[ext_resource type="Script" uid="uid://ds3uiri3oc05v" path="res://Scenes/camera_3d.gd" id="1_bo1nx"] -[ext_resource type="PackedScene" uid="uid://bswbcehkkqbk0" path="res://Scenes/Dart.tscn" id="1_jjgbg"] - -[sub_resource type="BoxShape3D" id="BoxShape3D_qu08v"] -size = Vector3(1, 0.01, 1) - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_6q475"] -albedo_color = Color(0, 0.42745098, 0.05490196, 1) - -[sub_resource type="BoxMesh" id="BoxMesh_xxti7"] -material = SubResource("StandardMaterial3D_6q475") -size = Vector3(1, 0.01, 1) - -[node name="Main" type="Node3D" unique_id=819165214] -script = ExtResource("1_8gbba") - -[node name="Camera3D" type="Camera3D" parent="." unique_id=1570426839] -transform = Transform3D(-1, 2.4096988e-08, -8.4036174e-08, 0, 0.9612618, 0.2756374, 8.742278e-08, 0.2756374, -0.9612618, 0, 5.0674033, -6.36445) -fov = 90.0 -script = ExtResource("1_bo1nx") - -[node name="Dart" parent="." unique_id=367982453 instance=ExtResource("1_jjgbg")] -transform = Transform3D(1, 0, 0, 0, 0.8363807, -0.5481493, 0, 0.5481492, 0.8363808, 0, 4.3246593, 0) - -[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1891469178] -transform = Transform3D(-0.789482, 0.24223976, -0.56394875, -0.56595325, 0.06825608, 0.821607, 0.23751883, 0.9678125, 0.083209395, -46.816067, 15.942318, -50.370865) - -[node name="StaticBody3D" type="StaticBody3D" parent="." unique_id=889230389] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 63.39778) - -[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" unique_id=229129629] -transform = Transform3D(100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0) -shape = SubResource("BoxShape3D_qu08v") - -[node name="MeshInstance3D" type="MeshInstance3D" parent="StaticBody3D/CollisionShape3D" unique_id=849495197] -mesh = SubResource("BoxMesh_xxti7") -skeleton = NodePath("") diff --git a/Scripts/DropCatcher.gd b/Scripts/DropCatcher.gd deleted file mode 100644 index a5ddc1a..0000000 --- a/Scripts/DropCatcher.gd +++ /dev/null @@ -1,156 +0,0 @@ -extends Control -# DropCatcher.gd (manual-drag version) -# No longer uses Godot's built-in _drop_data. Instead it exposes -# paint_at_screen_pos(), which the trapezoid calls on release. -# This Control no longer needs to catch mouse events at all, so it can be -# tiny/invisible — but keep it in the tree so it can reach the camera & board. - -@export var camera: Camera3D -@export var main: Node # the ROOT node (DartboardProto) - -const RAY_LENGTH := 1000.0 -var dartboard: MeshInstance3D - -# Standard dartboard number sequence, clockwise starting from the TOP (12 o'clock). -const DART_NUMBERS := [20, 1, 18, 4, 13, 6, 10, 15, 2, 17, - 3, 19, 7, 16, 8, 11, 14, 9, 12, 5] - -# Calibration: rotate which sector counts as "top". If the wrong number gets -# hit, bump this by 1 until it lines up. Range 0-19. -@export var sector_offset := 0 -# If your board's numbers go counter-clockwise in 3D, flip this. -@export var reverse_direction := false - -# --- Radial band boundaries (fractions of outer radius, 0=center 1=rim) --- -# Tune these in the Inspector by reading the norm= prints for each ring. -@export var bull_inner_max := 0.04 # <= this = inner bull (50) -@export var bull_outer_max := 0.09 # <= this = outer bull (25) -@export var inner_max := 0.45 # <= this = inner single -@export var triple_max := 0.55 # <= this = triple ring -@export var outer_max := 0.80 # <= this = outer single; above = double - -# Stores which modifier is applied to each surface index: { surface_index: Modifier } -var applied_modifiers: Dictionary = {} - -func _ready() -> void: - # Don't block mouse input; the trapezoids handle their own dragging. - mouse_filter = Control.MOUSE_FILTER_IGNORE - print("DropCatcher ready. camera=", camera, " main=", main) - -func _get_board() -> MeshInstance3D: - if dartboard == null and main != null and "dartboard" in main: - dartboard = main.dartboard - return dartboard - -# Public: try to apply a modifier (paint its texture + store its rule) at a -# screen position. Returns true if it hit the board, false if it missed. -func apply_modifier_at_screen_pos(screen_pos: Vector2, modifier: Resource) -> bool: - var board := _get_board() - if board == null: - push_error("DropCatcher: no dartboard mesh (is 'main' set?).") - return false - if camera == null: - push_error("DropCatcher: camera export not set.") - return false - if modifier == null: - return false - - var ray_origin := camera.project_ray_origin(screen_pos) - var ray_dir := camera.project_ray_normal(screen_pos) - var ray_end := ray_origin + ray_dir * RAY_LENGTH - - var space_state := get_viewport().world_3d.direct_space_state - var query := PhysicsRayQueryParameters3D.create(ray_origin, ray_end) - query.collide_with_areas = false - query.collide_with_bodies = true - var result := space_state.intersect_ray(query) - if result.is_empty(): - print(" drop missed the board") - return false - - var surface_index := _surface_from_hit(result, board) - if surface_index < 0: - return false - - _paint_surface(board, surface_index, modifier.texture) - applied_modifiers[surface_index] = modifier # remember the scoring rule - print(" applied '", modifier.id, "' to surface ", surface_index) - return true - -# Call this when a dart lands on a surface to get the modified score. -func score_for_surface(surface_index: int, base_value: int) -> int: - if applied_modifiers.has(surface_index): - return applied_modifiers[surface_index].apply_score(base_value) - return base_value - -func _surface_from_hit(result: Dictionary, board: MeshInstance3D) -> int: - var hit_point: Vector3 = result.get("position", Vector3.ZERO) - var local := board.to_local(hit_point) - var aabb := board.get_aabb() - var center := aabb.position + aabb.size * 0.5 - # Board disc lies in the X/Y plane (thin on Z). Measure radius/angle in X/Y. - var dx := local.x - center.x - var dy := local.y - center.y - var radius := Vector2(dx, dy).length() - var outer_radius : float = max(aabb.size.x, aabb.size.y) * 0.5 - var norm := radius / outer_radius if outer_radius > 0.0 else 0.0 - print(" local=", local, " dx=", "%.3f" % dx, " dy=", "%.3f" % dy, " norm=", "%.3f" % norm) - - # --- RADIAL BAND --- - # These thresholds are fractions of the outer radius. TUNE to match your art: - # the real proportions of a dartboard, from center outward. - var seg_name := "" - if norm <= bull_inner_max: - seg_name = "bull_inner" # inner bull (50) - elif norm <= bull_outer_max: - seg_name = "bull_outer" # outer bull (25) - elif norm > 1.0: - print(" outside board") - return -1 - else: - # --- ANGULAR SECTOR --- - # atan2 gives angle of the hit point. We map it to one of 20 sectors, - # then index into the dartboard number sequence. - var angle := atan2(dx, dy) # -PI..PI, 0 = straight up (+y = top) - # Convert to 0..1 going clockwise from top. Adjust the rotation so 0 = top. - var t := angle / (2.0 * PI) - t = fposmod(t, 1.0) - if reverse_direction: - t = 1.0 - t - var sector_index := int(floor(t * 20.0 + 0.5)) % 20 - sector_index = (sector_index + sector_offset) % 20 - var number : int = DART_NUMBERS[sector_index] - - # Which ring band within the sector. - var band := "" - if norm <= inner_max: - band = "inner" # inner single - elif norm <= triple_max: - band = "triple" # triple ring - elif norm <= outer_max: - band = "outer" # outer single - else: - band = "double" # double ring - seg_name = "seg_%d_%s" % [number, band] - - print(" norm=", "%.3f" % norm, " -> ", seg_name) - return _index_of_surface_named(board, seg_name) - -func _index_of_surface_named(board: MeshInstance3D, target_name: String) -> int: - var mesh := board.mesh - for i in mesh.get_surface_count(): - var mat := mesh.surface_get_material(i) - if mat and mat.resource_name == target_name: - return i - return -1 - -func _paint_surface(board: MeshInstance3D, surface_index: int, tex: Texture2D) -> void: - # Always build a fresh StandardMaterial3D so the texture shows as an IMAGE, - # not tinted by the old base color. If the segment looks like a flat color - # instead of the pattern, the mesh is missing proper UVs on that face. - var new_mat := StandardMaterial3D.new() - new_mat.albedo_color = Color.WHITE # white so texture isn't tinted - new_mat.albedo_texture = tex - new_mat.texture_filter = BaseMaterial3D.TEXTURE_FILTER_LINEAR - new_mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - board.set_surface_override_material(surface_index, new_mat) diff --git a/Scripts/Main.gd b/Scripts/Main.gd deleted file mode 100644 index ec733f1..0000000 --- a/Scripts/Main.gd +++ /dev/null @@ -1,61 +0,0 @@ -extends Node3D -# Attach to the ROOT node (DartboardProto). -# Leave `dartboard_root` empty to auto-search, or drag the glb node in. - -@export var dartboard_root: Node - -var dartboard: MeshInstance3D - -func _ready() -> void: - dartboard = _find_mesh_instance(dartboard_root if dartboard_root else self) - if dartboard == null: - push_error("Could not find a MeshInstance3D. Check that the glb is in the scene.") - return - print("Found dartboard mesh node: ", dartboard.name) - _print_surfaces() - _ensure_collision() - -func _find_mesh_instance(node: Node) -> MeshInstance3D: - if node is MeshInstance3D and node.mesh != null: - return node - for child in node.get_children(): - var found := _find_mesh_instance(child) - if found: - return found - return null - -func _print_surfaces() -> void: - var mesh := dartboard.mesh - print("=== Dartboard surfaces ===") - for i in mesh.get_surface_count(): - var mat := mesh.surface_get_material(i) - var mat_name := mat.resource_name if mat else "(no material)" - print("Surface ", i, " material name: '", mat_name, "'") - print("==========================") - var aabb := dartboard.get_aabb() - print("Board local size (x,y,z): ", aabb.size) - -# CHEAP collision: one box that matches the board's bounding box. -# This replaces create_trimesh_collision(), which was making it run at ~3 FPS -# because it built a collision triangle for every face of the board. -func _ensure_collision() -> void: - # Remove any existing auto-added body so we don't stack shapes on re-runs. - for child in dartboard.get_children(): - if child is StaticBody3D and child.name == "AutoBoardBody": - child.queue_free() - - var body := StaticBody3D.new() - body.name = "AutoBoardBody" - - var col := CollisionShape3D.new() - var box := BoxShape3D.new() - # Match the mesh's bounding box. Use the AABB size directly as the box size. - var aabb := dartboard.get_aabb() - box.size = aabb.size - col.shape = box - # Center the box on the mesh's bounding-box center (not always the origin). - col.position = aabb.position + aabb.size * 0.5 - - body.add_child(col) - dartboard.add_child(body) - print("Created cheap box collision for the dartboard.") diff --git a/Scripts/Main.gd.uid b/Scripts/Main.gd.uid deleted file mode 100644 index d52721e..0000000 --- a/Scripts/Main.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d1i0lhibtflvq diff --git a/Scripts/ModifierCatalog.gd b/Scripts/ModifierCatalog.gd deleted file mode 100644 index e9f6445..0000000 --- a/Scripts/ModifierCatalog.gd +++ /dev/null @@ -1,84 +0,0 @@ -extends Node -# ModifierCatalog.gd -# Holds the master list of every modifier in the game and picks random sets -# for each round. Register this as an AUTOLOAD (Project > Project Settings > -# Autoload) with the name "ModifierCatalog" so any script can reach it globally. -# -# Two ways to fill the catalog: -# A) Drop .tres Modifier files into res://Modifiers/ and they auto-load (below). -# B) Build them in code in _register_builtins() for quick prototyping. - -var modifiers: Array[Modifier] = [] -var _by_id: Dictionary = {} # id -> Modifier, for fast lookup - -func _ready() -> void: - _load_from_folder("res://Modifiers/") - if modifiers.is_empty(): - # Fallback so the prototype works before you author .tres files. - _register_builtins() - _reindex() - print("ModifierCatalog loaded ", modifiers.size(), " modifiers.") - -# Load every .tres Modifier resource from a folder. -func _load_from_folder(path: String) -> void: - var dir := DirAccess.open(path) - if dir == null: - return - dir.list_dir_begin() - var fname := dir.get_next() - while fname != "": - if not dir.current_is_dir() and fname.ends_with(".tres"): - var res := load(path + fname) - if res is Modifier: - modifiers.append(res) - fname = dir.get_next() - dir.list_dir_end() - -# Quick code-defined modifiers for prototyping. Replace texture paths with yours. -func _register_builtins() -> void: - modifiers.append(_make("stars_x5", "Stars", "Multiplies this segment's value by 5.", - "res://Models/Dartboard/Dartboard-Proto_Red.png", 5.0, 0)) - modifiers.append(_make("double", "Double", "Doubles this segment's value.", - "res://Models/Dartboard/Dartboard-Proto_Green.png", 2.0, 0)) - modifiers.append(_make("plus10", "Bonus +10", "Adds 10 points to this segment.", - "res://Models/Dartboard/Dartboard-Proto_Cork.png", 1.0, 10)) - -func _make(id: String, title: String, desc: String, tex_path: String, - mult: float, add: int) -> Modifier: - var m := Modifier.new() - m.id = id - m.title = title - m.description = desc - m.texture = load(tex_path) - m.score_mult = mult - m.score_add = add - return m - -func _reindex() -> void: - _by_id.clear() - for m in modifiers: - _by_id[m.id] = m - -func get_by_id(id: String) -> Modifier: - return _by_id.get(id) - -# Pick `count` distinct random modifiers, respecting weight. Returns an Array. -func pick_random(count: int) -> Array[Modifier]: - var pool := modifiers.duplicate() - var chosen: Array[Modifier] = [] - count = min(count, pool.size()) - for _i in count: - var total := 0.0 - for m in pool: - total += max(m.weight, 0.0001) - var r := randf() * total - var acc := 0.0 - var picked_index := 0 - for j in pool.size(): - acc += max(pool[j].weight, 0.0001) - if r <= acc: - picked_index = j - break - chosen.append(pool[picked_index]) - pool.remove_at(picked_index) # distinct: don't pick the same one twice - return chosen diff --git a/Scripts/camera_3d.gd b/Scripts/camera_3d.gd deleted file mode 100644 index 6052b06..0000000 --- a/Scripts/camera_3d.gd +++ /dev/null @@ -1,15 +0,0 @@ -extends Camera3D - -const RAY_LENGTH = 1000 - -func ray_cast(): - var space_state = get_world_3d().direct_space_state - var cam = $"." - var mousepos = get_viewport().get_mouse_position() - var origin = cam.project_ray_origin(mousepos) - var end = origin + cam.project_ray_normal(mousepos) * RAY_LENGTH - var query = PhysicsRayQueryParameters3D.create(origin,end) - query.collide_with_areas = true - var result = space_state.intersect_ray(query) - result = result.get("collider") - return result diff --git a/Scripts/camera_3d.gd.uid b/Scripts/camera_3d.gd.uid deleted file mode 100644 index 27e151f..0000000 --- a/Scripts/camera_3d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ckbdoamrm313u diff --git a/Scripts/dart.gd b/Scripts/dart.gd deleted file mode 100644 index 121daee..0000000 --- a/Scripts/dart.gd +++ /dev/null @@ -1,50 +0,0 @@ -extends Node3D - -var draggingCollider -var mousePosition -var doDrag = false - -func _input(event): - var intersect - - if event is InputEventMouse: - intersect = get_mouse_intersect(event.position) - if intersect: mousePosition = intersect.position - #snap on collider - #if intersect: mousePosition = intersect.collider.global_position - - if event is InputEventMouseButton: - var leftButtonPressed = event.button_index == MOUSE_BUTTON_LEFT && event.pressed - var leftButtonReleased = event.button_index == MOUSE_BUTTON_LEFT && !event.pressed - - if leftButtonReleased: - doDrag = false - drag_and_drop(intersect) - elif leftButtonPressed: - doDrag = true - drag_and_drop(intersect) - - -func _process(delta): - if draggingCollider: - draggingCollider.global_position = mousePosition - -func drag_and_drop(intersect): - var canMove = intersect.collider in get_tree().get_nodes_in_group("Dart") - if !draggingCollider && doDrag && canMove: - draggingCollider = intersect.collider - elif draggingCollider: - draggingCollider = null - -func get_mouse_intersect(mousePosition): - var currentCamera = get_viewport().get_camera_3d() - var params = PhysicsRayQueryParameters3D.new() - - params.from = currentCamera.project_ray_origin(mousePosition) - params.to = currentCamera.project_position(mousePosition, 1000) - if draggingCollider: params.exclude = [draggingCollider] - - var worldspace = get_world_3d().direct_space_state - var result = worldspace.intersect_ray(params) - - return result diff --git a/Scripts/mesh_instance_3d.gd b/Scripts/mesh_instance_3d.gd deleted file mode 100644 index f4ebe81..0000000 --- a/Scripts/mesh_instance_3d.gd +++ /dev/null @@ -1,16 +0,0 @@ -extends MeshInstance3D - -@onready var camera = get_node("Camera3D") -@onready var area = get_node("../../../Dart") - -func _input(event): - if Input.is_action_just_pressed("leftClick"): - print(camera.ray_cast().position) - - if camera.ray_cast() != null and Input.is_action_pressed("midleclic"): - var mousepos = get_viewport().get_mouse_position() - var origin = camera.projectray_origin(mousepos) - var end = camera.project_ray_normal(mousepos) - var depth = origin.distence_to(area.global_position) - var final_position = origin + end * depth - area.global_position=final_position diff --git a/Scripts/mesh_instance_3d.gd.uid b/Scripts/mesh_instance_3d.gd.uid deleted file mode 100644 index 5bd89f0..0000000 --- a/Scripts/mesh_instance_3d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cc5yy1yc3j2uu diff --git a/game/content/official/mod.json b/game/content/official/mod.json new file mode 100644 index 0000000..4ffc723 --- /dev/null +++ b/game/content/official/mod.json @@ -0,0 +1,9 @@ +{ + "id": "official", + "display_name": "DartGame", + "author": "Ced Games", + "version": "0.1.0", + "api_version": 1, + "depends": [], + "description": "The base game content." +} diff --git a/game/content/official/skins/bulls/neon_hiero.png b/game/content/official/skins/bulls/neon_hiero.png new file mode 100644 index 0000000..8c670d7 --- /dev/null +++ b/game/content/official/skins/bulls/neon_hiero.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9fcc634139aaafef8e25e4fbfd399df1451cc5ee916fc8239b7f441d8a0b9635 +size 42264 diff --git a/Models/Dartboard/Textures/Coffee.png.import b/game/content/official/skins/bulls/neon_hiero.png.import similarity index 72% rename from Models/Dartboard/Textures/Coffee.png.import rename to game/content/official/skins/bulls/neon_hiero.png.import index 3306685..4717880 100644 --- a/Models/Dartboard/Textures/Coffee.png.import +++ b/game/content/official/skins/bulls/neon_hiero.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://b1vf3204p4ys6" -path="res://.godot/imported/Coffee.png-7ec89259677377dfb36274d8ce0e9258.ctex" +uid="uid://bayaus0tgltb3" +path="res://.godot/imported/neon_hiero.png-401e600b4e3a81c5e49b654215a0e850.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://Models/Dartboard/Textures/Coffee.png" -dest_files=["res://.godot/imported/Coffee.png-7ec89259677377dfb36274d8ce0e9258.ctex"] +source_file="res://content/official/skins/bulls/neon_hiero.png" +dest_files=["res://.godot/imported/neon_hiero.png-401e600b4e3a81c5e49b654215a0e850.ctex"] [params] diff --git a/game/content/official/skins/flat_tire/ocean_fire.png b/game/content/official/skins/flat_tire/ocean_fire.png new file mode 100644 index 0000000..5d61e77 --- /dev/null +++ b/game/content/official/skins/flat_tire/ocean_fire.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:821299e23175e9be91ac21bd37603d4c656b5e5689d8a939742bb45711318b0a +size 796873 diff --git a/Models/Dart/Textures/Wings-Red-Blue.png.import b/game/content/official/skins/flat_tire/ocean_fire.png.import similarity index 72% rename from Models/Dart/Textures/Wings-Red-Blue.png.import rename to game/content/official/skins/flat_tire/ocean_fire.png.import index 9aae953..69b6226 100644 --- a/Models/Dart/Textures/Wings-Red-Blue.png.import +++ b/game/content/official/skins/flat_tire/ocean_fire.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://ch4b1pnokuu8d" -path="res://.godot/imported/Wings-Red-Blue.png-701faf0c1b6c3af11eb52058dfda7798.ctex" +uid="uid://b672fbyuxxktw" +path="res://.godot/imported/ocean_fire.png-b1f0d5fea08640de091cb5cf724309e6.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://Models/Dart/Textures/Wings-Red-Blue.png" -dest_files=["res://.godot/imported/Wings-Red-Blue.png-701faf0c1b6c3af11eb52058dfda7798.ctex"] +source_file="res://content/official/skins/flat_tire/ocean_fire.png" +dest_files=["res://.godot/imported/ocean_fire.png-b1f0d5fea08640de091cb5cf724309e6.ctex"] [params] diff --git a/game/content/official/skins/flat_tire/toon_purple.png b/game/content/official/skins/flat_tire/toon_purple.png new file mode 100644 index 0000000..70bbb90 --- /dev/null +++ b/game/content/official/skins/flat_tire/toon_purple.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3fe6f0d2e6f8db52624ab8ce067ff85625d16362ac04214ff23b909551743b3e +size 793421 diff --git a/Models/Dart/Textures/Dart-Default.png.import b/game/content/official/skins/flat_tire/toon_purple.png.import similarity index 72% rename from Models/Dart/Textures/Dart-Default.png.import rename to game/content/official/skins/flat_tire/toon_purple.png.import index a79f5d2..e95e71a 100644 --- a/Models/Dart/Textures/Dart-Default.png.import +++ b/game/content/official/skins/flat_tire/toon_purple.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://c7jxj25ophbsb" -path="res://.godot/imported/Dart-Default.png-2feb9f56821a29d976ec19a662a6977f.ctex" +uid="uid://btg3hosfx1sdg" +path="res://.godot/imported/toon_purple.png-f1a192acdf1c762039bd65e86672f7e4.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://Models/Dart/Textures/Dart-Default.png" -dest_files=["res://.godot/imported/Dart-Default.png-2feb9f56821a29d976ec19a662a6977f.ctex"] +source_file="res://content/official/skins/flat_tire/toon_purple.png" +dest_files=["res://.godot/imported/toon_purple.png-f1a192acdf1c762039bd65e86672f7e4.ctex"] [params] diff --git a/game/content/official/skins/sectors/neon_hiero_black.png b/game/content/official/skins/sectors/neon_hiero_black.png new file mode 100644 index 0000000..31377f0 --- /dev/null +++ b/game/content/official/skins/sectors/neon_hiero_black.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8fba53689270afc2b920e4635c3bc87385c890e01a2c10983ad573b25cd41aa7 +size 125902 diff --git a/Models/Dart/Textures/Wings-Default.png.import b/game/content/official/skins/sectors/neon_hiero_black.png.import similarity index 71% rename from Models/Dart/Textures/Wings-Default.png.import rename to game/content/official/skins/sectors/neon_hiero_black.png.import index f0f6e60..12c20d6 100644 --- a/Models/Dart/Textures/Wings-Default.png.import +++ b/game/content/official/skins/sectors/neon_hiero_black.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://bhbtrcw8xbp1g" -path="res://.godot/imported/Wings-Default.png-b4a7a92ebd237d86daaae21adc10d873.ctex" +uid="uid://brqn2ve8pm3i8" +path="res://.godot/imported/neon_hiero_black.png-7709dfdedde53a261eb17c86736a737f.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://Models/Dart/Textures/Wings-Default.png" -dest_files=["res://.godot/imported/Wings-Default.png-b4a7a92ebd237d86daaae21adc10d873.ctex"] +source_file="res://content/official/skins/sectors/neon_hiero_black.png" +dest_files=["res://.godot/imported/neon_hiero_black.png-7709dfdedde53a261eb17c86736a737f.ctex"] [params] diff --git a/game/content/official/skins/sectors/neon_hiero_white.png b/game/content/official/skins/sectors/neon_hiero_white.png new file mode 100644 index 0000000..6b2f965 --- /dev/null +++ b/game/content/official/skins/sectors/neon_hiero_white.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35d1949f8e2dda1c5c885fd5471a1f9918b2e64d0a9f4c0657bb432aacea12f1 +size 164550 diff --git a/game/content/official/skins/sectors/neon_hiero_white.png.import b/game/content/official/skins/sectors/neon_hiero_white.png.import new file mode 100644 index 0000000..a011e29 --- /dev/null +++ b/game/content/official/skins/sectors/neon_hiero_white.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bataamlsyyup6" +path="res://.godot/imported/neon_hiero_white.png-c93ce5ab952a3d2618c297fc1cae11f4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://content/official/skins/sectors/neon_hiero_white.png" +dest_files=["res://.godot/imported/neon_hiero_white.png-c93ce5ab952a3d2618c297fc1cae11f4.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/game/core/board/dartboard.gd b/game/core/board/dartboard.gd new file mode 100644 index 0000000..42823ed --- /dev/null +++ b/game/core/board/dartboard.gd @@ -0,0 +1,173 @@ +class_name Dartboard +extends StaticBody3D + +## The board. 21 material slots: sector_1 .. sector_20, plus "bulls". +## +## Owns the face -> surface -> slot mapping, which is what makes hit detection +## survive the board moving, rotating, or having its sectors remapped. Ask the +## geometry which sector was hit; don't calculate it from an angle. + +## Every slot on the board, in the order Blender exported them (order doesn't +## matter — we index by name). +const BULL_SLOT := &"bulls" + +@onready var mesh_instance: MeshInstance3D = $Model/dartboard + +## StringName -> surface index +var _slot_to_surface: Dictionary = {} +## global face index -> StringName +var _face_to_slot: Dictionary = {} + +var _outer_radius: float = 0.0 + + +func _ready() -> void: + _index_slots() + _index_faces() + _cache_radius() + + +# --- Indexing ----------------------------------------------------------- + +func _index_slots() -> void: + var mesh := mesh_instance.mesh + if mesh == null: + push_error("Dartboard has no mesh.") + return + + for i in mesh.get_surface_count(): + var mat := mesh.surface_get_material(i) + if mat == null: + push_warning("Surface %d has no material — can't be skinned or hit." % i) + continue + + var slot := StringName(mat.resource_name) + if slot == &"": + push_warning("Surface %d's material has no name." % i) + continue + + _slot_to_surface[slot] = i + + print("Dartboard: indexed %d slots." % _slot_to_surface.size()) + if _slot_to_surface.size() != 21: + push_warning("Expected 21 slots (20 sectors + bulls), got %d." % _slot_to_surface.size()) + + +## Build a global-face-index -> slot map. +## +## The physics engine reports face_index as an index into the WHOLE trimesh, +## but the mesh stores faces per-surface. So we walk the surfaces in order, +## accumulating a running face count, and record which range belongs to which. +## +## This assumes the ConcavePolygonShape3D was built from the mesh with surfaces +## in the same order — which is what create_trimesh_shape() does. +func _index_faces() -> void: + var mesh := mesh_instance.mesh + if mesh == null: + return + + var running := 0 + for i in mesh.get_surface_count(): + var arrays := mesh.surface_get_arrays(i) + if arrays.is_empty(): + continue + + var indices: PackedInt32Array = arrays[Mesh.ARRAY_INDEX] + var verts: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX] + + # Triangle count: from the index buffer if present, else from vertices. + var tri_count := (indices.size() / 3) if indices.size() > 0 else (verts.size() / 3) + + var mat := mesh.surface_get_material(i) + var slot := StringName(mat.resource_name) if mat else &"" + + for f in tri_count: + _face_to_slot[running + f] = slot + + running += tri_count + + print("Dartboard: mapped %d faces." % _face_to_slot.size()) + + +func _cache_radius() -> void: + var aabb := mesh_instance.get_aabb() + # The disc's two large axes. The third is the board's thickness. + var sizes := [aabb.size.x, aabb.size.y, aabb.size.z] + sizes.sort() + _outer_radius = sizes[2] * 0.5 # largest dimension = diameter + + +# --- Public ------------------------------------------------------------- + +## Which slot does this trimesh face belong to? +func slot_for_face(face_index: int) -> StringName: + return _face_to_slot.get(face_index, &"") + + +## Paint a texture onto one slot. Used for both skins and modifier overlays. +func paint_slot(slot: StringName, texture: Texture2D) -> void: + if not _slot_to_surface.has(slot): + push_warning("No slot named '%s'." % slot) + return + + var surface: int = _slot_to_surface[slot] + var mat := mesh_instance.get_active_material(surface) + if mat == null: + return + + # Duplicate, or we mutate the shared material from the .glb — which leaks + # to every instance AND can get written back to disk in the editor. + var unique := mat.duplicate() as StandardMaterial3D + unique.albedo_texture = texture + unique.albedo_color = Color.WHITE # don't tint the texture + mesh_instance.set_surface_override_material(surface, unique) + + +## Reset a slot to its imported material. +func clear_slot(slot: StringName) -> void: + if not _slot_to_surface.has(slot): + return + mesh_instance.set_surface_override_material(_slot_to_surface[slot], null) + + +func get_slots() -> Array[StringName]: + var out: Array[StringName] = [] + out.assign(_slot_to_surface.keys()) + return out + + +## Board radius in local units. +func outer_radius() -> float: + return _outer_radius + + +## Project a LOCAL point onto the board's face plane, returning 2D coords +## where +Y is "up" on the board (toward the 20). +## +## Which two axes those are depends on how the .glb imported. glTF is +Y up, +## so a board modeled facing +Z in Blender usually lands facing +Z here, with +## the disc in the X/Y plane. If sector detection is 90 degrees off, this is +## the function to fix. +func planar_coords(local_point: Vector3) -> Vector2: + var aabb := mesh_instance.get_aabb() + var center := aabb.position + aabb.size * 0.5 + + # Identify the thin axis — that's the board's normal. + var s := aabb.size + if s.z <= s.x and s.z <= s.y: + return Vector2(local_point.x - center.x, local_point.y - center.y) + elif s.y <= s.x and s.y <= s.z: + return Vector2(local_point.x - center.x, local_point.z - center.z) + else: + return Vector2(local_point.z - center.z, local_point.y - center.y) + + +## Debug: what did Blender actually export? +func print_slots() -> void: + var mesh := mesh_instance.mesh + print("=== Dartboard slots ===") + for i in mesh.get_surface_count(): + var mat := mesh.surface_get_material(i) + print(" surface %2d: '%s'" % [i, mat.resource_name if mat else "(none)"]) + print(" radius: %.4f aabb: %s" % [_outer_radius, mesh_instance.get_aabb().size]) + print("=======================") diff --git a/game/core/board/dartboard.gd.uid b/game/core/board/dartboard.gd.uid new file mode 100644 index 0000000..645c493 --- /dev/null +++ b/game/core/board/dartboard.gd.uid @@ -0,0 +1 @@ +uid://cme5xqn2hlrlu diff --git a/game/core/board/dartboard.glb b/game/core/board/dartboard.glb new file mode 100644 index 0000000..1eda64f --- /dev/null +++ b/game/core/board/dartboard.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:512007534371386119ac2624b4818129663b33131f73a6d93a3fe6cd7453677f +size 3302888 diff --git a/models/Dart.glb.import b/game/core/board/dartboard.glb.import similarity index 79% rename from models/Dart.glb.import rename to game/core/board/dartboard.glb.import index f8bf431..bba1735 100644 --- a/models/Dart.glb.import +++ b/game/core/board/dartboard.glb.import @@ -3,13 +3,13 @@ importer="scene" importer_version=1 type="PackedScene" -uid="uid://cjq45anerhxnk" -path="res://.godot/imported/Dart.glb-e68d17366fac688e4c81cf4cc62e1175.scn" +uid="uid://djr5vbnb652ax" +path="res://.godot/imported/dartboard.glb-8db0957180c245aae0575b1ad098f883.scn" [deps] -source_file="res://models/Dart.glb" -dest_files=["res://.godot/imported/Dart.glb-e68d17366fac688e4c81cf4cc62e1175.scn"] +source_file="res://core/board/dartboard.glb" +dest_files=["res://.godot/imported/dartboard.glb-8db0957180c245aae0575b1ad098f883.scn"] [params] diff --git a/game/core/board/dartboard.tscn b/game/core/board/dartboard.tscn new file mode 100644 index 0000000..9c37f9d --- /dev/null +++ b/game/core/board/dartboard.tscn @@ -0,0 +1,27 @@ +[gd_scene format=3 uid="uid://dojbd5wl7ntp0"] + +[ext_resource type="Script" uid="uid://cme5xqn2hlrlu" path="res://core/board/dartboard.gd" id="1"] +[ext_resource type="PackedScene" uid="uid://djr5vbnb652ax" path="res://core/board/dartboard.glb" id="2"] +[ext_resource type="Shape3D" uid="uid://vr03k1qlo10y" path="res://core/board/dartboard_collision.res" id="3_6aacy"] +[ext_resource type="Shape3D" uid="uid://c0vqtoe8q7yly" path="res://core/board/spider_collision.res" id="4_khw4q"] + +[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_uomu6"] +friction = 0.15 +bounce = 0.6 + +[node name="Dartboard" type="StaticBody3D" unique_id=838863701] +script = ExtResource("1") + +[node name="Model" parent="." unique_id=1556270899 instance=ExtResource("2")] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1180985747] +shape = ExtResource("3_6aacy") + +[node name="SpiderBody" type="StaticBody3D" parent="." unique_id=216948518] +collision_layer = 8 +physics_material_override = SubResource("PhysicsMaterial_uomu6") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="SpiderBody" unique_id=1618627145] +shape = ExtResource("4_khw4q") + +[editable path="Model"] diff --git a/game/core/board/dartboard_bulls.png b/game/core/board/dartboard_bulls.png new file mode 100644 index 0000000..406e927 --- /dev/null +++ b/game/core/board/dartboard_bulls.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96af139a4f95a0ae94a76f8ba2b4a619d3c2bcedbe43e3f971b6f0c200c3ef50 +size 47075 diff --git a/Models/Dart/Dart_Dart-Default.png.import b/game/core/board/dartboard_bulls.png.import similarity index 70% rename from Models/Dart/Dart_Dart-Default.png.import rename to game/core/board/dartboard_bulls.png.import index e5bb83e..16f2b1c 100644 --- a/Models/Dart/Dart_Dart-Default.png.import +++ b/game/core/board/dartboard_bulls.png.import @@ -2,20 +2,20 @@ importer="texture" type="CompressedTexture2D" -uid="uid://bobnv6cyi7dc6" -path.s3tc="res://.godot/imported/Dart_Dart-Default.png-4bd6068152c7966988ca2c23bd03ba76.s3tc.ctex" +uid="uid://dj6wb70lh5s4f" +path.s3tc="res://.godot/imported/dartboard_bulls.png-354417d2f083e713950eed8be5c54f73.s3tc.ctex" metadata={ "imported_formats": ["s3tc_bptc"], "vram_texture": true } generator_parameters={ -"md5": "9c4718c8d2830abe8cc9971ef621b46a" +"md5": "ce1804f3e86fea26503097d5e278c919" } [deps] -source_file="res://Models/Dart/Dart_Dart-Default.png" -dest_files=["res://.godot/imported/Dart_Dart-Default.png-4bd6068152c7966988ca2c23bd03ba76.s3tc.ctex"] +source_file="res://core/board/dartboard_bulls.png" +dest_files=["res://.godot/imported/dartboard_bulls.png-354417d2f083e713950eed8be5c54f73.s3tc.ctex"] [params] diff --git a/game/core/board/dartboard_collision.res b/game/core/board/dartboard_collision.res new file mode 100644 index 0000000..459f628 --- /dev/null +++ b/game/core/board/dartboard_collision.res @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62834a912d71d0f484016f45726c49018835e44aea681d9b89338f5c986560f7 +size 11264 diff --git a/game/core/board/dartboard_flat_tire.png b/game/core/board/dartboard_flat_tire.png new file mode 100644 index 0000000..86d7a9a --- /dev/null +++ b/game/core/board/dartboard_flat_tire.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0699110a7fdc5c57a4e7c76b28b304bf03bd5c6df97bcbab79e829e0396db73c +size 542135 diff --git a/Models/Dart/Dart_Wings-Default.png.import b/game/core/board/dartboard_flat_tire.png.import similarity index 69% rename from Models/Dart/Dart_Wings-Default.png.import rename to game/core/board/dartboard_flat_tire.png.import index c9b8036..2a87b29 100644 --- a/Models/Dart/Dart_Wings-Default.png.import +++ b/game/core/board/dartboard_flat_tire.png.import @@ -2,20 +2,20 @@ importer="texture" type="CompressedTexture2D" -uid="uid://bqxi7x76uv4tq" -path.s3tc="res://.godot/imported/Dart_Wings-Default.png-358040735cbc551a0d2abb04506c708a.s3tc.ctex" +uid="uid://da2elnsphlc5i" +path.s3tc="res://.godot/imported/dartboard_flat_tire.png-97f4bd426c06f71b009cd942664be6fa.s3tc.ctex" metadata={ "imported_formats": ["s3tc_bptc"], "vram_texture": true } generator_parameters={ -"md5": "52ee9a89e7c6ed5f537103a41115551e" +"md5": "d24ebe44ff702bdbd5528c9d29427568" } [deps] -source_file="res://Models/Dart/Dart_Wings-Default.png" -dest_files=["res://.godot/imported/Dart_Wings-Default.png-358040735cbc551a0d2abb04506c708a.s3tc.ctex"] +source_file="res://core/board/dartboard_flat_tire.png" +dest_files=["res://.godot/imported/dartboard_flat_tire.png-97f4bd426c06f71b009cd942664be6fa.s3tc.ctex"] [params] diff --git a/game/core/board/dartboard_sector_black.png b/game/core/board/dartboard_sector_black.png new file mode 100644 index 0000000..b2d5206 --- /dev/null +++ b/game/core/board/dartboard_sector_black.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9be6a2881158d0f154193898d615dc66153042941db2100766a1fd7cc979ce3a +size 82769 diff --git a/Models/Dartboard/Dartboard-Proto_Cork.png.import b/game/core/board/dartboard_sector_black.png.import similarity index 69% rename from Models/Dartboard/Dartboard-Proto_Cork.png.import rename to game/core/board/dartboard_sector_black.png.import index f8e4fbb..50daf5b 100644 --- a/Models/Dartboard/Dartboard-Proto_Cork.png.import +++ b/game/core/board/dartboard_sector_black.png.import @@ -2,20 +2,20 @@ importer="texture" type="CompressedTexture2D" -uid="uid://dk6gnbvgumq7c" -path.s3tc="res://.godot/imported/Dartboard-Proto_Cork.png-9700f4c0b675dee65dc4e1c14aa931b3.s3tc.ctex" +uid="uid://cjw6x7ig1ogbo" +path.s3tc="res://.godot/imported/dartboard_sector_black.png-39f98bf69c481faad6b8976a0994ecb5.s3tc.ctex" metadata={ "imported_formats": ["s3tc_bptc"], "vram_texture": true } generator_parameters={ -"md5": "5b186b11689f911ad6691488292c3475" +"md5": "831beecb2a48df4a1f6850e3e8c938dd" } [deps] -source_file="res://Models/Dartboard/Dartboard-Proto_Cork.png" -dest_files=["res://.godot/imported/Dartboard-Proto_Cork.png-9700f4c0b675dee65dc4e1c14aa931b3.s3tc.ctex"] +source_file="res://core/board/dartboard_sector_black.png" +dest_files=["res://.godot/imported/dartboard_sector_black.png-39f98bf69c481faad6b8976a0994ecb5.s3tc.ctex"] [params] diff --git a/game/core/board/dartboard_sector_white.png b/game/core/board/dartboard_sector_white.png new file mode 100644 index 0000000..2eb24a9 --- /dev/null +++ b/game/core/board/dartboard_sector_white.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5b594f8f1091c6120c9f6452f5c7ac01ac0a3b78d41de45309d94692ea5f541 +size 65277 diff --git a/Models/Dartboard/Dartboard-Proto_Red.png.import b/game/core/board/dartboard_sector_white.png.import similarity index 69% rename from Models/Dartboard/Dartboard-Proto_Red.png.import rename to game/core/board/dartboard_sector_white.png.import index 1e79333..35e0fd7 100644 --- a/Models/Dartboard/Dartboard-Proto_Red.png.import +++ b/game/core/board/dartboard_sector_white.png.import @@ -2,20 +2,20 @@ importer="texture" type="CompressedTexture2D" -uid="uid://cvv4akpwsudu3" -path.s3tc="res://.godot/imported/Dartboard-Proto_Red.png-e757930c4a42a8dc67547b3409641a91.s3tc.ctex" +uid="uid://cry28pcmt01gk" +path.s3tc="res://.godot/imported/dartboard_sector_white.png-6dbf28d122f3327d568bcbb29e7f70a0.s3tc.ctex" metadata={ "imported_formats": ["s3tc_bptc"], "vram_texture": true } generator_parameters={ -"md5": "e46ac968aab4da0b0c65bc59957f2f96" +"md5": "aa25e4080cfa45ac8064cbf217904fb3" } [deps] -source_file="res://Models/Dartboard/Dartboard-Proto_Red.png" -dest_files=["res://.godot/imported/Dartboard-Proto_Red.png-e757930c4a42a8dc67547b3409641a91.s3tc.ctex"] +source_file="res://core/board/dartboard_sector_white.png" +dest_files=["res://.godot/imported/dartboard_sector_white.png-6dbf28d122f3327d568bcbb29e7f70a0.s3tc.ctex"] [params] diff --git a/game/core/board/dartboard_spider.png b/game/core/board/dartboard_spider.png new file mode 100644 index 0000000..68cd8c4 --- /dev/null +++ b/game/core/board/dartboard_spider.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae6e4c0aa62bd2adab08ae15e3b71c0132686061ab3e757063c4d8b0333b6586 +size 76036 diff --git a/Models/Dartboard/Dartboard_Spider.png.import b/game/core/board/dartboard_spider.png.import similarity index 73% rename from Models/Dartboard/Dartboard_Spider.png.import rename to game/core/board/dartboard_spider.png.import index b66d1a6..a3e4c8a 100644 --- a/Models/Dartboard/Dartboard_Spider.png.import +++ b/game/core/board/dartboard_spider.png.import @@ -2,8 +2,8 @@ importer="texture" type="CompressedTexture2D" -uid="uid://ctr7mydgfca75" -path.s3tc="res://.godot/imported/Dartboard_Spider.png-3a7e01e42d10301e2794b3c6268069b4.s3tc.ctex" +uid="uid://b87cl0ullks7x" +path.s3tc="res://.godot/imported/dartboard_spider.png-c5fe87c929f66762aaaaefebd3359c9d.s3tc.ctex" metadata={ "imported_formats": ["s3tc_bptc"], "vram_texture": true @@ -14,8 +14,8 @@ generator_parameters={ [deps] -source_file="res://Models/Dartboard/Dartboard_Spider.png" -dest_files=["res://.godot/imported/Dartboard_Spider.png-3a7e01e42d10301e2794b3c6268069b4.s3tc.ctex"] +source_file="res://core/board/dartboard_spider.png" +dest_files=["res://.godot/imported/dartboard_spider.png-c5fe87c929f66762aaaaefebd3359c9d.s3tc.ctex"] [params] diff --git a/game/core/board/spider_collision.res b/game/core/board/spider_collision.res new file mode 100644 index 0000000..ad10cc7 --- /dev/null +++ b/game/core/board/spider_collision.res @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f50e8bc8571800197ed955cc05c92eca75154474f75f073ce754d25afc3544c +size 812039 diff --git a/game/core/dart/dart.gd b/game/core/dart/dart.gd new file mode 100644 index 0000000..35b52e4 --- /dev/null +++ b/game/core/dart/dart.gd @@ -0,0 +1,192 @@ +class_name Dart +extends RigidBody3D + +## A single dart. Dragged from the tray, thrown at the board. +## +## Lifecycle: FROZEN -> DRAGGING -> IN_FLIGHT -> LANDED +## The scene root (main.gd) routes mouse input here; the dart does not +## hunt for the camera or raycast for itself. + +signal landed(dart: Dart, hit_point: Vector3) + +enum State { IDLE, DRAGGING, IN_FLIGHT, LANDED } + +# --- Tuning ------------------------------------------------------------- + +@export_group("Drag") +## How hard the dart chases the cursor while held. +@export var drag_follow_speed: float = 20.0 +## Clamp so a fast flick doesn't launch it across the room mid-drag. +@export var max_drag_speed: float = 42.0 +## Tilt of the drag plane relative to the camera, in degrees. +@export_range(-180.0, 180.0) var drag_plane_angle: float = 15.0 +@export var drag_linear_damp: float = 5.0 +@export var drag_angular_damp: float = 10.0 + +@export_group("Throw") +@export var forward_impulse: float = 8.0 + +## Scale the raw flick velocity down. Raw mouse speed is usually too fast. +@export var throw_force_multiplier: float = 0.5 +@export var max_throw_speed: float = 42.0 +## Higher = more visible arc. Real gravity looks too floaty at dart scale. +@export var flight_gravity_scale: float = 2.0 + +@export_group("Flight") +## How fast the nose swings to face the direction of travel. +@export var nose_align_speed: float = 1.0 +## Which local axis is the dart's tip. Check this against the model. +@export var forward_axis: Vector3 = Vector3.FORWARD +## Below this speed the dart is considered landed. +@export var landed_speed_threshold: float = 0.5 + +# --- State -------------------------------------------------------------- + +var state: State = State.IDLE + +var _drag_plane: Plane +var _drag_offset: Vector3 = Vector3.ZERO +var _target_pos: Vector3 = Vector3.ZERO + +## Sampled positions, used to compute throw velocity on release. +const HISTORY_LENGTH := 6 +var _pos_history: Array[Vector3] = [] +var _time_history: Array[float] = [] + + +func _ready() -> void: + freeze_mode = RigidBody3D.FREEZE_MODE_STATIC + freeze = true + add_to_group(&"dart") + + +# --- Public API (called by main.gd) -------------------------------------- + +func begin_drag(camera: Camera3D, hit_point: Vector3) -> void: + state = State.DRAGGING + freeze = false + + gravity_scale = 0.0 # don't sag while held + linear_damp = drag_linear_damp + angular_damp = drag_angular_damp + + # The plane the dart slides along while dragged. Tilted off the camera's + # view axis so pulling back also pulls the dart down, which feels natural. + var base_normal := camera.global_transform.basis.z + var tilted := base_normal.rotated( + camera.global_transform.basis.x, + deg_to_rad(drag_plane_angle) + ) + _drag_plane = Plane(tilted.normalized(), hit_point) + _drag_offset = global_position - hit_point + + # Seed the target to the current position. Without this the dart drops + # to the plane origin until the mouse first moves. + _target_pos = global_position + + _pos_history.clear() + _time_history.clear() + + +func update_drag(camera: Camera3D, mouse_pos: Vector2) -> void: + if state != State.DRAGGING: + return + + var ray_origin := camera.project_ray_origin(mouse_pos) + var ray_dir := camera.project_ray_normal(mouse_pos) + var hit = _drag_plane.intersects_ray(ray_origin, ray_dir) + if hit != null: + _target_pos = hit + _drag_offset + +func release_drag() -> void: + if state != State.DRAGGING: + return + state = State.IN_FLIGHT + gravity_scale = flight_gravity_scale + linear_damp = 0.0 + angular_damp = 0.0 + + # The flick gives aim (up/down/left/right). It CANNOT give forward speed — + # the drag plane faces the camera, so motion toward the board is ~zero. + var flick := _calculate_throw_velocity() * throw_force_multiplier + + # The forward component has to come from somewhere. Use the camera's + # forward, so "throw" always means "toward what you're looking at". + var cam := get_viewport().get_camera_3d() + var forward := -cam.global_transform.basis.z * forward_impulse + + var throw := flick + forward + if throw.length() > max_throw_speed: + throw = throw.normalized() * max_throw_speed + linear_velocity = throw + + var raw := _calculate_throw_velocity() + print("flick: %s forward: %s final: %s (%.1f m/s)" % [flick, forward, throw, throw.length()]) + + +# --- Physics ------------------------------------------------------------ + +func _physics_process(delta: float) -> void: + match state: + State.DRAGGING: + _process_drag() + State.IN_FLIGHT: + _process_flight(delta) + + +func _process_drag() -> void: + # Chase the target with velocity rather than teleporting, so the dart + # still collides with things and carries momentum into the throw. + var to_target := _target_pos - global_position + var desired := to_target * drag_follow_speed + if desired.length() > max_drag_speed: + desired = desired.normalized() * max_drag_speed + + linear_velocity = desired + angular_velocity = angular_velocity.lerp(Vector3.ZERO, 0.2) + + _pos_history.append(global_position) + _time_history.append(Time.get_ticks_msec() / 1000.0) + if _pos_history.size() > HISTORY_LENGTH: + _pos_history.pop_front() + _time_history.pop_front() + + +func _process_flight(delta: float) -> void: + if linear_velocity.length() > landed_speed_threshold: + _align_to_velocity(delta) + else: + _on_landed() + + +func _align_to_velocity(delta: float) -> void: + var vel_dir := linear_velocity.normalized() + var current_forward := global_transform.basis * forward_axis + var axis := current_forward.cross(vel_dir) + + if axis.length() < 0.001: + return # already aligned, or exactly opposed + + axis = axis.normalized() + var angle := current_forward.angle_to(vel_dir) + var step := minf(angle, nose_align_speed * delta) + + global_transform.basis = global_transform.basis.rotated(axis, step) + global_transform.basis = global_transform.basis.orthonormalized() + + +func _on_landed() -> void: + state = State.LANDED + angular_velocity = Vector3.ZERO + landed.emit(self, global_position) + + +func _calculate_throw_velocity() -> Vector3: + if _pos_history.size() < 2: + return linear_velocity + + var dt: float = _time_history[-1] - _time_history[0] + if dt <= 0.0: + return linear_velocity + + return (_pos_history[-1] - _pos_history[0]) / dt diff --git a/Scripts/dart.gd.uid b/game/core/dart/dart.gd.uid similarity index 100% rename from Scripts/dart.gd.uid rename to game/core/dart/dart.gd.uid diff --git a/game/core/dart/dart.glb b/game/core/dart/dart.glb new file mode 100644 index 0000000..927043c --- /dev/null +++ b/game/core/dart/dart.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4277db576f3609691259c85f8f3e555f4697d8338cc1a9de9748284cfa451363 +size 192556 diff --git a/Models/Dart/Dart.glb.import b/game/core/dart/dart.glb.import similarity index 82% rename from Models/Dart/Dart.glb.import rename to game/core/dart/dart.glb.import index 5105045..269cb26 100644 --- a/Models/Dart/Dart.glb.import +++ b/game/core/dart/dart.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://fp0gcwcyfd7g" -path="res://.godot/imported/Dart.glb-82b423f0f21d37c1bf28626083e1030e.scn" +path="res://.godot/imported/dart.glb-ca8e61ccf0bb4431c3c990bf6c68da95.scn" [deps] -source_file="res://Models/Dart/Dart.glb" -dest_files=["res://.godot/imported/Dart.glb-82b423f0f21d37c1bf28626083e1030e.scn"] +source_file="res://core/dart/dart.glb" +dest_files=["res://.godot/imported/dart.glb-ca8e61ccf0bb4431c3c990bf6c68da95.scn"] [params] diff --git a/game/core/dart/dart.tscn b/game/core/dart/dart.tscn new file mode 100644 index 0000000..60c8905 --- /dev/null +++ b/game/core/dart/dart.tscn @@ -0,0 +1,21 @@ +[gd_scene format=3 uid="uid://fshohiewm7et"] + +[ext_resource type="Script" uid="uid://sueo33rxr07e" path="res://core/dart/dart.gd" id="1"] +[ext_resource type="PackedScene" uid="uid://fp0gcwcyfd7g" path="res://core/dart/dart.glb" id="2"] + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1"] +radius = 0.008 +height = 0.15 + +[node name="Dart" type="RigidBody3D" unique_id=1124867376] +collision_layer = 2 +script = ExtResource("1") + +[node name="MeshInstance3D" parent="." unique_id=936158903 instance=ExtResource("2")] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=2015440784] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.07, 0) +shape = SubResource("CapsuleShape3D_1") + +[node name="Tip" type="Marker3D" parent="." unique_id=2014607155] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.14, 0) diff --git a/game/core/dart/dart_body.png b/game/core/dart/dart_body.png new file mode 100644 index 0000000..3066be6 --- /dev/null +++ b/game/core/dart/dart_body.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f60ac560c1c7ed907968d11bbc33fedd055a151a2ac05ea2983f6aa4e31d1117 +size 26167 diff --git a/models/Dart_Dart-Default.png.import b/game/core/dart/dart_body.png.import similarity index 74% rename from models/Dart_Dart-Default.png.import rename to game/core/dart/dart_body.png.import index 19becea..bd5eb8f 100644 --- a/models/Dart_Dart-Default.png.import +++ b/game/core/dart/dart_body.png.import @@ -2,8 +2,8 @@ importer="texture" type="CompressedTexture2D" -uid="uid://62njxkpga6e8" -path.s3tc="res://.godot/imported/Dart_Dart-Default.png-ffb5dce2e6bbf58fe2b00949ee100702.s3tc.ctex" +uid="uid://b3n3th3102f2g" +path.s3tc="res://.godot/imported/dart_body.png-b1ba77c6cead7a089d94545960115fac.s3tc.ctex" metadata={ "imported_formats": ["s3tc_bptc"], "vram_texture": true @@ -14,8 +14,8 @@ generator_parameters={ [deps] -source_file="res://models/Dart_Dart-Default.png" -dest_files=["res://.godot/imported/Dart_Dart-Default.png-ffb5dce2e6bbf58fe2b00949ee100702.s3tc.ctex"] +source_file="res://core/dart/dart_body.png" +dest_files=["res://.godot/imported/dart_body.png-b1ba77c6cead7a089d94545960115fac.s3tc.ctex"] [params] diff --git a/game/core/dart/dart_wings.png b/game/core/dart/dart_wings.png new file mode 100644 index 0000000..6abdb22 --- /dev/null +++ b/game/core/dart/dart_wings.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a64fe4aa5bd83a5eee4a336ffe8b1ad8b87cd58aaf67741b23de53f8789e2b2 +size 31950 diff --git a/models/Dart_Wings-Default.png.import b/game/core/dart/dart_wings.png.import similarity index 74% rename from models/Dart_Wings-Default.png.import rename to game/core/dart/dart_wings.png.import index 9f407bf..79b34dc 100644 --- a/models/Dart_Wings-Default.png.import +++ b/game/core/dart/dart_wings.png.import @@ -2,8 +2,8 @@ importer="texture" type="CompressedTexture2D" -uid="uid://b7bsi4ury2lve" -path.s3tc="res://.godot/imported/Dart_Wings-Default.png-dcf030c3d00e4d9573d0a3e9c88fff0a.s3tc.ctex" +uid="uid://c85g6b4hhn83g" +path.s3tc="res://.godot/imported/dart_wings.png-45f87827353eb4dc5f134b80f5e80ea7.s3tc.ctex" metadata={ "imported_formats": ["s3tc_bptc"], "vram_texture": true @@ -14,8 +14,8 @@ generator_parameters={ [deps] -source_file="res://models/Dart_Wings-Default.png" -dest_files=["res://.godot/imported/Dart_Wings-Default.png-dcf030c3d00e4d9573d0a3e9c88fff0a.s3tc.ctex"] +source_file="res://core/dart/dart_wings.png" +dest_files=["res://.godot/imported/dart_wings.png-45f87827353eb4dc5f134b80f5e80ea7.s3tc.ctex"] [params] diff --git a/game/core/modding/mod_registry.gd b/game/core/modding/mod_registry.gd new file mode 100644 index 0000000..5c5bcec --- /dev/null +++ b/game/core/modding/mod_registry.gd @@ -0,0 +1,92 @@ +extends Node + +## Loads modifier definitions and serves them by id. +## +## ⚠️ PROTOTYPE. This is scaffolding, not the real mod loader. +## +## What's wrong with it, to be fixed in Phase 3: +## - DirAccess cannot walk into a PCK. This works in the editor and silently +## returns NOTHING in an exported build. Needs a build-time manifest. +## - No namespacing. Ids are bare strings, so two mods can collide. +## - No mod.json, no api_version, no dependency resolution. +## - Only reads content/official/. Doesn't touch user://mods/. +## +## Autoload name is ModRegistry (PascalCase), so call sites read as +## ModRegistry.get_by_id(...) rather than looking like a local variable. + +const MODIFIER_DIR := "res://content/official/modifiers/" + +var modifiers: Array[Modifier] = [] +var _by_id: Dictionary = {} + + +func _ready() -> void: + _load_from_folder(MODIFIER_DIR) + _reindex() + print("ModRegistry: loaded %d modifiers." % modifiers.size()) + + +## Recursive, because each modifier now lives in its own folder: +## modifiers/mjolnir/mjolnir.tres +func _load_from_folder(path: String) -> void: + var dir := DirAccess.open(path) + if dir == null: + push_warning("ModRegistry: can't open %s" % path) + return + + dir.list_dir_begin() + var fname := dir.get_next() + while fname != "": + var full := path.path_join(fname) + if dir.current_is_dir(): + if not fname.begins_with("."): + _load_from_folder(full) + elif fname.ends_with(".tres"): + var res := load(full) + if res is Modifier: + modifiers.append(res) + else: + push_warning("ModRegistry: %s is not a Modifier" % full) + fname = dir.get_next() + dir.list_dir_end() + + +func _reindex() -> void: + _by_id.clear() + for m in modifiers: + if m.id.is_empty(): + push_warning("ModRegistry: modifier with empty id, skipping.") + continue + if _by_id.has(m.id): + push_warning("ModRegistry: duplicate id '%s'." % m.id) + _by_id[m.id] = m + + +func get_by_id(id: String) -> Modifier: + return _by_id.get(id) + + +## Pick `count` distinct modifiers, weighted by rarity. +func pick_random(count: int) -> Array[Modifier]: + var pool := modifiers.duplicate() + var chosen: Array[Modifier] = [] + count = mini(count, pool.size()) + + for _i in count: + var total := 0.0 + for m in pool: + total += maxf(m.weight, 0.0001) + + var r := randf() * total + var acc := 0.0 + var picked := 0 + for j in pool.size(): + acc += maxf(pool[j].weight, 0.0001) + if r <= acc: + picked = j + break + + chosen.append(pool[picked]) + pool.remove_at(picked) # distinct — don't offer the same one twice + + return chosen diff --git a/Scripts/ModifierCatalog.gd.uid b/game/core/modding/mod_registry.gd.uid similarity index 100% rename from Scripts/ModifierCatalog.gd.uid rename to game/core/modding/mod_registry.gd.uid diff --git a/Scripts/Modifier.gd b/game/core/modding/modifier.gd similarity index 100% rename from Scripts/Modifier.gd rename to game/core/modding/modifier.gd diff --git a/Scripts/Modifier.gd.uid b/game/core/modding/modifier.gd.uid similarity index 100% rename from Scripts/Modifier.gd.uid rename to game/core/modding/modifier.gd.uid diff --git a/game/core/ui/drop_catcher.gd b/game/core/ui/drop_catcher.gd new file mode 100644 index 0000000..6dd0531 --- /dev/null +++ b/game/core/ui/drop_catcher.gd @@ -0,0 +1,215 @@ +extends Control + +## Resolves a screen position (or a dart's world position) to a board sector, +## and applies modifiers there. +## +## THE BOARD HAS 21 MATERIAL SLOTS: sector_1 .. sector_20, plus "bulls". +## The bull slot covers inner AND outer bull — they move together. +## +## Two ways to find which sector was hit: +## +## A) BY FACE INDEX (default, robust) +## Raycast returns face_index. Map face -> surface. The surface's material +## name IS the sector. No trigonometry. +## Survives the board rotating, tilting, or having its sectors remapped, +## because we're asking the geometry, not calculating from an angle. +## Requires ConcavePolygonShape3D (trimesh) collision. +## +## B) BY ANGLE (fallback) +## atan2 on the local hit point. Cheap, works with a box collider. +## Survives rotation (to_local undoes the transform) but NOT sector +## remapping — if Mjolnir makes every sector a 20, the angle still says +## "this is the 6". +## +## Use A. It's the only one that supports a moving/mutating board, which is the +## whole point of the modifier system. + +const RAY_LENGTH := 1000.0 + +enum Ring { MISS, INNER_BULL, OUTER_BULL, INNER_SINGLE, TRIPLE, OUTER_SINGLE, DOUBLE } +enum Method { FACE_INDEX, ANGLE } + +@export var camera: Camera3D +@export var dartboard: Dartboard + +@export_group("Resolution") +@export var method: Method = Method.FACE_INDEX + +@export_group("Angle fallback (only used if method = ANGLE)") +## Clockwise from 12 o'clock. +const DART_NUMBERS := [20, 1, 18, 4, 13, 6, 10, 15, 2, 17, + 3, 19, 7, 16, 8, 11, 14, 9, 12, 5] +@export_range(0, 19) var sector_offset := 0 +@export var reverse_direction := false + +@export_group("Ring radii (fraction of outer radius)") +## Rings are ALWAYS resolved by radius, even in FACE_INDEX mode — the surface +## tells us WHICH sector, the radius tells us WHICH RING within it. +@export var bull_inner_max := 0.04 +@export var bull_outer_max := 0.09 +@export var inner_max := 0.45 +@export var triple_max := 0.55 +@export var outer_max := 0.80 + +## sector number (1-20), or 0 for bull -> Modifier +var applied: Dictionary = {} + + +func _ready() -> void: + mouse_filter = Control.MOUSE_FILTER_IGNORE + + +# --- Public ------------------------------------------------------------- + +## Drop a modifier at a screen position. True if it landed on the board. +func apply_modifier_at_screen_pos(screen_pos: Vector2, modifier: Modifier) -> bool: + if modifier == null: + return false + if camera == null or dartboard == null: + push_error("DropCatcher: camera and dartboard exports must be set.") + return false + + var hit := _raycast(screen_pos) + if hit.is_empty(): + return false + + var slot := _slot_from_hit(hit) + if slot == &"": + return false + + dartboard.paint_slot(slot, modifier.texture) + applied[slot] = modifier + print("applied '%s' to %s" % [modifier.id, slot]) + return true + + +## Score a dart that landed at a world point. +func score_dart(world_point: Vector3, face_index: int = -1) -> int: + var slot := _slot_from_world(world_point, face_index) + var ring := _ring_from_radius(_norm_radius(world_point)) + var base := _base_score(slot, ring) + + if applied.has(slot): + return (applied[slot] as Modifier).apply_score(base) + return base + + +## Full breakdown of a hit. This is what Phase 2's ScoringEngine will consume. +func resolve_hit(world_point: Vector3, face_index: int = -1) -> Dictionary: + var slot := _slot_from_world(world_point, face_index) + var ring := _ring_from_radius(_norm_radius(world_point)) + return { + "slot": slot, # &"sector_20" / &"bulls" / &"" + "sector": _sector_number(slot), # 1-20, or 0 for bull/miss + "ring": ring, + "base_score": _base_score(slot, ring), + "modifier": applied.get(slot), + } + + +# --- Slot resolution ---------------------------------------------------- + +func _slot_from_hit(hit: Dictionary) -> StringName: + var point: Vector3 = hit.get("position", Vector3.ZERO) + var face: int = hit.get("face_index", -1) + return _slot_from_world(point, face) + + +func _slot_from_world(world_point: Vector3, face_index: int) -> StringName: + # The bull is a slot in its own right — check radius first, since the bull + # surface may be small enough that face lookup is fiddly at the very center. + var norm := _norm_radius(world_point) + if norm > 1.0: + return &"" + if norm <= bull_outer_max: + return &"bulls" + + if method == Method.FACE_INDEX and face_index >= 0: + var slot := dartboard.slot_for_face(face_index) + if slot != &"": + return slot + push_warning("Face %d didn't map to a slot; falling back to angle." % face_index) + + return _slot_from_angle(world_point) + + +## Fallback. Works under rotation, NOT under sector remapping. +func _slot_from_angle(world_point: Vector3) -> StringName: + var local := dartboard.to_local(world_point) + var planar := dartboard.planar_coords(local) + + var t := fposmod(atan2(planar.x, planar.y) / TAU, 1.0) + if reverse_direction: + t = 1.0 - t + + var idx := int(floor(t * 20.0 + 0.5)) % 20 + idx = (idx + sector_offset) % 20 + return StringName("sector_%d" % DART_NUMBERS[idx]) + + +# --- Rings & scoring ---------------------------------------------------- + +## Distance from board center, as a fraction of the outer radius. +func _norm_radius(world_point: Vector3) -> float: + var local := dartboard.to_local(world_point) + var planar := dartboard.planar_coords(local) + var outer := dartboard.outer_radius() + return planar.length() / outer if outer > 0.0 else 999.0 + + +func _ring_from_radius(norm: float) -> Ring: + if norm > 1.0: + return Ring.MISS + if norm <= bull_inner_max: + return Ring.INNER_BULL + if norm <= bull_outer_max: + return Ring.OUTER_BULL + if norm <= inner_max: + return Ring.INNER_SINGLE + if norm <= triple_max: + return Ring.TRIPLE + if norm <= outer_max: + return Ring.OUTER_SINGLE + return Ring.DOUBLE + + +func _sector_number(slot: StringName) -> int: + var s := String(slot) + if not s.begins_with("sector_"): + return 0 + return s.trim_prefix("sector_").to_int() + + +func _base_score(slot: StringName, ring: Ring) -> int: + match ring: + Ring.MISS: + return 0 + Ring.INNER_BULL: + return 50 + Ring.OUTER_BULL: + return 25 + + var n := _sector_number(slot) + if n == 0: + return 0 + + match ring: + Ring.TRIPLE: + return n * 3 + Ring.DOUBLE: + return n * 2 + _: + return n + + +# --- Raycast ------------------------------------------------------------ + +func _raycast(screen_pos: Vector2) -> Dictionary: + var origin := camera.project_ray_origin(screen_pos) + var params := PhysicsRayQueryParameters3D.create( + origin, + origin + camera.project_ray_normal(screen_pos) * RAY_LENGTH + ) + params.collide_with_areas = false + params.collide_with_bodies = true + return get_viewport().world_3d.direct_space_state.intersect_ray(params) diff --git a/Scripts/DropCatcher.gd.uid b/game/core/ui/drop_catcher.gd.uid similarity index 100% rename from Scripts/DropCatcher.gd.uid rename to game/core/ui/drop_catcher.gd.uid diff --git a/Scripts/ModifierTray.gd b/game/core/ui/modifier_tray.gd similarity index 59% rename from Scripts/ModifierTray.gd rename to game/core/ui/modifier_tray.gd index 9d6009e..13a9adf 100644 --- a/Scripts/ModifierTray.gd +++ b/game/core/ui/modifier_tray.gd @@ -1,40 +1,40 @@ extends Control -# ModifierTray.gd (catalog-driven) -# Each round, asks ModifierCatalog for 3 random modifiers and spawns a draggable -# trapezoid for each at the bottom-center. Dropping one onto the board applies it -# and consumes the round's pieces. + +## Offers a set of random modifiers each round as draggable pieces. +## Dropping one on the board applies it and consumes the whole set. + +const SectorSwatch := preload("res://core/ui/sector_swatch.gd") @export var drop_catcher: Control @export var pieces_per_round := 3 - @export var piece_size := Vector2(90, 110) @export var spacing := 24.0 @export var bottom_margin := 30.0 -const TrapezoidSwatch := preload("res://Scripts/TrapezoidSwatch.gd") - var _pieces: Array[Control] = [] + func _ready() -> void: mouse_filter = Control.MOUSE_FILTER_IGNORE spawn_round() -# Offer a fresh set of random modifier pieces for a new round. + func spawn_round() -> void: _clear_pieces() - # ModifierCatalog is an autoload singleton (set it up in Project Settings). - var choices: Array = ModifierCatalog.pick_random(pieces_per_round) + + # ModRegistry is the autoload. (Was "ModifierCatalog" — renamed.) + var choices: Array = ModRegistry.pick_random(pieces_per_round) if choices.is_empty(): - push_warning("ModifierTray: catalog returned no modifiers.") + push_warning("ModifierTray: registry returned no modifiers.") return for mod in choices: var piece := Control.new() - piece.set_script(TrapezoidSwatch) + piece.set_script(SectorSwatch) piece.custom_minimum_size = piece_size piece.size = piece_size - piece.modifier = mod # carries the WHOLE modifier - piece.paint_texture = mod.texture # convenience for drawing + piece.modifier = mod + piece.paint_texture = mod.texture piece.drop_catcher = drop_catcher piece.tray = self add_child(piece) @@ -42,28 +42,34 @@ func spawn_round() -> void: _layout_pieces() + func _layout_pieces() -> void: var count := _pieces.size() if count == 0: return + var total_w := count * piece_size.x + (count - 1) * spacing var screen := get_viewport_rect().size var start_x := (screen.x - total_w) * 0.5 var y := screen.y - piece_size.y - bottom_margin + for i in count: _pieces[i].position = Vector2(start_x + i * (piece_size.x + spacing), y) -# Called by a piece when successfully used: remove the whole set. + +## Called by a piece when it lands successfully — the whole set is spent. func consume() -> void: _clear_pieces() + func _clear_pieces() -> void: for p in _pieces: if is_instance_valid(p): p.queue_free() _pieces.clear() -# TESTING ONLY: press SPACE to roll a new round of pieces. + +# TESTING ONLY — SPACE rolls a new set. func _unhandled_input(event: InputEvent) -> void: if event is InputEventKey and event.pressed and event.keycode == KEY_SPACE: spawn_round() diff --git a/Scripts/ModifierTray.gd.uid b/game/core/ui/modifier_tray.gd.uid similarity index 100% rename from Scripts/ModifierTray.gd.uid rename to game/core/ui/modifier_tray.gd.uid diff --git a/Scripts/TrapezoidSwatch.gd b/game/core/ui/sector_swatch.gd similarity index 53% rename from Scripts/TrapezoidSwatch.gd rename to game/core/ui/sector_swatch.gd index d64d396..5c1dc82 100644 --- a/Scripts/TrapezoidSwatch.gd +++ b/game/core/ui/sector_swatch.gd @@ -1,25 +1,27 @@ extends Control -# TrapezoidSwatch.gd (manual-drag version) -# The trapezoid node ITSELF follows the cursor while dragging (no ghost). -# On release over the board, it tells DropCatcher to paint the hit segment, -# then asks the tray to consume the round's modifiers. + +## A draggable modifier piece in the tray. Follows the cursor directly (no +## ghost). On release over the board it asks DropCatcher to apply itself. +## +## Was TrapezoidSwatch.gd — renamed because modifiers now attach to whole +## sectors, not individual segments. @export var paint_texture: Texture2D: set(value): paint_texture = value queue_redraw() + @export_range(0.0, 1.0) var top_width_ratio := 0.55 # Set by the tray when it spawns this piece. -var drop_catcher: Control # the DropCatcher node (does the 3D raycast+paint) -var tray: Node # the ModifierTray (so we can consume on use) - -# The full modifier this piece carries (texture + title + scoring rule). -var modifier: Resource +var drop_catcher: Control +var tray: Node +var modifier: Modifier var _dragging := false -var _home_position := Vector2.ZERO # where it sits in the tray -var _drag_offset := Vector2.ZERO # cursor-to-corner offset so it doesn't snap +var _home_position := Vector2.ZERO +var _drag_offset := Vector2.ZERO + func _ready() -> void: mouse_filter = Control.MOUSE_FILTER_STOP @@ -27,26 +29,32 @@ func _ready() -> void: custom_minimum_size = Vector2(90, 110) size = custom_minimum_size + func _draw() -> void: var w := size.x var h := size.y var inset := w * (1.0 - top_width_ratio) * 0.5 + var points := PackedVector2Array([ Vector2(inset, 0), Vector2(w - inset, 0), Vector2(w, h), Vector2(0, h), ]) + if paint_texture != null: var uvs := PackedVector2Array([ Vector2(inset / w, 0), Vector2((w - inset) / w, 0), Vector2(1, 1), Vector2(0, 1), ]) - draw_polygon(points, PackedColorArray([Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE]), uvs, paint_texture) + var white := PackedColorArray([Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE]) + draw_polygon(points, white, uvs, paint_texture) else: draw_colored_polygon(points, Color(0.8, 0.8, 0.8)) + var outline := points outline.append(points[0]) draw_polyline(outline, Color(0, 0, 0, 0.6), 2.0) + func _gui_input(event: InputEvent) -> void: if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: if event.pressed: @@ -54,16 +62,18 @@ func _gui_input(event: InputEvent) -> void: else: _end_drag() + func _start_drag() -> void: _dragging = true _home_position = global_position _drag_offset = global_position - get_global_mouse_position() - # top_level lets us move by global_position freely, ignoring the container - # layout, WITHOUT reparenting (reparenting mid-drag breaks the release event). + # top_level lets us move by global_position without reparenting. + # Reparenting mid-drag breaks the release event. top_level = true - z_index = 100 # float above everything during drag + z_index = 100 modulate.a = 0.85 + func _end_drag() -> void: if not _dragging: return @@ -71,27 +81,27 @@ func _end_drag() -> void: modulate.a = 1.0 z_index = 0 - # Ask the DropCatcher to try painting wherever we released. - var painted := false - print("PIECE released. drop_catcher=", drop_catcher, " modifier=", modifier) + var applied := false if drop_catcher == null: - push_error("Piece has no drop_catcher reference! (tray export not set?)") - elif not drop_catcher.has_method("apply_modifier_at_screen_pos"): + push_error("SectorSwatch has no drop_catcher (tray export not set?).") + elif not drop_catcher.has_method(&"apply_modifier_at_screen_pos"): push_error("drop_catcher has no apply_modifier_at_screen_pos method.") else: - painted = drop_catcher.apply_modifier_at_screen_pos(get_global_mouse_position(), modifier) + applied = drop_catcher.apply_modifier_at_screen_pos( + get_global_mouse_position(), modifier + ) - if painted: - # Used successfully: consume this round's modifier choices. - if tray and tray.has_method("consume"): + if applied: + if tray != null and tray.has_method(&"consume"): tray.consume() else: queue_free() else: - # Missed the board: snap back home. + # Missed — snap home. top_level = false global_position = _home_position + func _process(_delta: float) -> void: if _dragging: global_position = get_global_mouse_position() + _drag_offset diff --git a/Scripts/TrapezoidSwatch.gd.uid b/game/core/ui/sector_swatch.gd.uid similarity index 100% rename from Scripts/TrapezoidSwatch.gd.uid rename to game/core/ui/sector_swatch.gd.uid diff --git a/icon.svg b/game/icon.svg similarity index 100% rename from icon.svg rename to game/icon.svg diff --git a/icon.svg.import b/game/icon.svg.import similarity index 100% rename from icon.svg.import rename to game/icon.svg.import diff --git a/project.godot b/game/project.godot similarity index 94% rename from project.godot rename to game/project.godot index 0dde64d..1efb211 100644 --- a/project.godot +++ b/game/project.godot @@ -15,13 +15,13 @@ compatibility/default_parent_skeleton_in_mesh_instance_3d=true [application] config/name="Dart Game" -run/main_scene="uid://cqe6bo8v564dc" +run/main_scene="uid://doh7p84eej78c" config/features=PackedStringArray("4.7", "Mobile") config/icon="res://icon.svg" [autoload] -ModifierCatalog="*uid://btm4dwci50xmu" +ModRegistry="*uid://btm4dwci50xmu" [display] @@ -34,7 +34,7 @@ import/blender/enabled=false [global_group] -Dart="All throwable darts" +darts="All throwable darts" [input] diff --git a/game/scenes/camera_3d.gd b/game/scenes/camera_3d.gd new file mode 100644 index 0000000..fa72f9b --- /dev/null +++ b/game/scenes/camera_3d.gd @@ -0,0 +1,56 @@ +extends Camera3D + +## Owns dart input. The camera does the raycast because the raycast IS a +## camera operation — projecting a screen point into the world. +## +## The dart exposes begin_drag / update_drag / release_drag and never looks +## for the camera itself. This script decides who to call them on. + +const RAY_LENGTH := 1000.0 + +var _held_dart: Dart = null + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseButton: + var mb := event as InputEventMouseButton + if mb.button_index != MOUSE_BUTTON_LEFT: + return + if mb.pressed: + _try_grab(mb.position) + else: + _release() + + elif event is InputEventMouseMotion and _held_dart != null: + _held_dart.update_drag(self, (event as InputEventMouseMotion).position) + + +func _try_grab(screen_pos: Vector2) -> void: + var hit := _raycast(screen_pos) + if hit.is_empty(): + return + + var body = hit.get("collider") + if body is Dart: + _held_dart = body as Dart + # NOTE: two args, not three. The old start_drag(camera, mouse_pos, point) + # passed mouse_pos but never used it — begin_drag only needs the hit point. + _held_dart.begin_drag(self, hit["position"]) + + +func _release() -> void: + if _held_dart == null: + return + _held_dart.release_drag() + _held_dart = null + + +func _raycast(screen_pos: Vector2) -> Dictionary: + var params := PhysicsRayQueryParameters3D.create( + project_ray_origin(screen_pos), + project_ray_origin(screen_pos) + project_ray_normal(screen_pos) * RAY_LENGTH + ) + if _held_dart != null: + params.exclude = [_held_dart.get_rid()] + + return get_world_3d().direct_space_state.intersect_ray(params) diff --git a/Scenes/camera_3d.gd.uid b/game/scenes/camera_3d.gd.uid similarity index 100% rename from Scenes/camera_3d.gd.uid rename to game/scenes/camera_3d.gd.uid diff --git a/game/scenes/main.gd b/game/scenes/main.gd new file mode 100644 index 0000000..51eead2 --- /dev/null +++ b/game/scenes/main.gd @@ -0,0 +1,12 @@ +extends Node3D + +## Scene root. Deliberately tiny. +## +## Dart input lives in camera_3d.gd (the raycast is a camera operation). +## Board behaviour lives in dartboard.gd. Modifier UI lives in core/ui/. +## This script wires nothing and owns nothing — it's just the tree root. + + +func _unhandled_input(event: InputEvent) -> void: + if event.is_action_pressed(&"restart"): + get_tree().reload_current_scene() diff --git a/Scenes/main.gd.uid b/game/scenes/main.gd.uid similarity index 100% rename from Scenes/main.gd.uid rename to game/scenes/main.gd.uid diff --git a/game/scenes/main.tscn b/game/scenes/main.tscn new file mode 100644 index 0000000..685c8c9 --- /dev/null +++ b/game/scenes/main.tscn @@ -0,0 +1,43 @@ +[gd_scene format=3 uid="uid://doh7p84eej78c"] + +[ext_resource type="Script" uid="uid://geqmah8kbko0" path="res://scenes/main.gd" id="1_sugp2"] +[ext_resource type="Script" uid="uid://ds3uiri3oc05v" path="res://scenes/camera_3d.gd" id="2_jyhfs"] +[ext_resource type="PackedScene" uid="uid://fshohiewm7et" path="res://core/dart/dart.tscn" id="3_tbgi4"] +[ext_resource type="PackedScene" uid="uid://dojbd5wl7ntp0" path="res://core/board/dartboard.tscn" id="3_tefeu"] +[ext_resource type="Script" uid="uid://x5kcjofb5pek" path="res://core/ui/drop_catcher.gd" id="5_o6xl0"] +[ext_resource type="Script" uid="uid://dnek55fao0l72" path="res://core/ui/modifier_tray.gd" id="6_tipki"] + +[node name="Main" type="Node3D" unique_id=819165214] +script = ExtResource("1_sugp2") + +[node name="Camera3D" type="Camera3D" parent="." unique_id=1570426839] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.3, 2.37) +fov = 30.0 +script = ExtResource("2_jyhfs") + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1891469178] +transform = Transform3D(-0.789482, 0.24223976, -0.56394875, -0.56595325, 0.06825608, 0.821607, 0.23751883, 0.9678125, 0.08320943, -46.816067, 15.942318, -50.370865) + +[node name="Dartboard" parent="." unique_id=408060787 instance=ExtResource("3_tefeu")] + +[node name="Dart" parent="." unique_id=367982453 instance=ExtResource("3_tbgi4")] +transform = Transform3D(1, 0, 0, 0, 0.83676445, 0.5475633, 0, -0.54756325, 0.8367645, 0, -0.43, 1.8) + +[node name="UI" type="CanvasLayer" parent="." unique_id=1068293458] + +[node name="DropCatcher" type="Control" parent="UI" unique_id=1874461265 node_paths=PackedStringArray("camera", "dartboard")] +layout_mode = 3 +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0 +script = ExtResource("5_o6xl0") +camera = NodePath("../../Camera3D") +dartboard = NodePath("../../Dartboard") + +[node name="ModifierTray" type="Control" parent="UI" unique_id=1639987503 node_paths=PackedStringArray("drop_catcher")] +layout_mode = 3 +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0 +script = ExtResource("6_tipki") +drop_catcher = NodePath("../DropCatcher") diff --git a/models/Dart.glb b/models/Dart.glb deleted file mode 100644 index 30d5418..0000000 Binary files a/models/Dart.glb and /dev/null differ diff --git a/models/Dart_Dart-Default.png b/models/Dart_Dart-Default.png deleted file mode 100644 index bfbaad5..0000000 Binary files a/models/Dart_Dart-Default.png and /dev/null differ diff --git a/models/Dart_Wings-Default.png b/models/Dart_Wings-Default.png deleted file mode 100644 index 6c07cdc..0000000 Binary files a/models/Dart_Wings-Default.png and /dev/null differ