Compare commits
18 Commits
c365f76d80
..
0.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 79ea5bb2be | |||
| 981ebf1910 | |||
| 01d6ecf475 | |||
| 931ddf0eeb | |||
| 50073b2574 | |||
| 07f8a71f2c | |||
| 34dc5b026e | |||
| 5c1e881a53 | |||
| 4efc6763f0 | |||
| 76d4fee33c | |||
| 271be0b26b | |||
| 98c6f1285a | |||
| 4d66df8c7e | |||
| 41f18cb5d6 | |||
| 6b6a926715 | |||
| dae7ec06da | |||
| 1eb06876e9 | |||
| 1021a07b04 |
@@ -2,4 +2,4 @@ disable:
|
||||
- class-definitions-order
|
||||
- no-else-return
|
||||
max-line-length: 120
|
||||
max-file-lines: 1200
|
||||
max-file-lines: 3000
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
[gd_resource type="Animation" format=3 uid="uid://bq71flatfddll"]
|
||||
|
||||
[resource]
|
||||
resource_name = "Bear_fx_smash_hit"
|
||||
length = 0.23333333
|
||||
tracks/0/type = "position_3d"
|
||||
tracks/0/imported = true
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Bear_fx_smash_hit")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = PackedFloat32Array(0, 1, 0, -0.51246816, 7.1560388, 0.033333335, 1, 0, -0.51246816, 7.1560388, 0.06666667, 1, 1.2735307, -1.4730668, 5.139501, 0.1, 1, 1.3610363, 0.27301335, 5.141279, 0.13333334, 1, 1.3735371, 2.1639488, 5.153728, 0.16666667, 1, 1.3573295, -0.04170864, 5.1945124, 0.2, 1, 1.3061407, -0.3338372, 5.1877995, 0.23333333, 1, 1.2735307, -0.37556988, 5.1810856)
|
||||
tracks/1/type = "rotation_3d"
|
||||
tracks/1/imported = true
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("Bear_fx_smash_hit")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = PackedFloat32Array(0, 1, 0, 0, 0, 1, 0.033333335, 1, 0, 0, 0, 1, 0.06666667, 1, 0.045591418, -0.036703378, -0.0016762356, 0.9982843, 0.1, 1, 0.06741002, -0.02538766, 0.014408795, 0.99729824, 0.13333334, 1, 0.05603578, -0.017236687, 0.029419938, 0.99784636, 0.16666667, 1, -0.071329094, -0.014488678, 0.036211126, 0.9966901, 0.23333333, 1, -0.039237745, -0.015645763, 0.035726424, 0.99846846)
|
||||
tracks/2/type = "scale_3d"
|
||||
tracks/2/imported = true
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("Bear_fx_smash_hit")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = PackedFloat32Array(0, 1, 0, 0, 0, 0.033333335, 1, 0, 0, 0, 0.06666667, 1, 0.55657715, 0.55657715, 0.5565772, 0.23333333, 1, 0.55657715, 0.55657715, 0.55657715)
|
||||
tracks/3/type = "position_3d"
|
||||
tracks/3/imported = true
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("Bear_fx_jump_smash")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = PackedFloat32Array(0, 1, 0, -0.51246816, 0)
|
||||
tracks/4/type = "scale_3d"
|
||||
tracks/4/imported = true
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("Bear_fx_jump_smash")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = PackedFloat32Array(0, 1, 0, 0, 0)
|
||||
tracks/5/type = "position_3d"
|
||||
tracks/5/imported = true
|
||||
tracks/5/enabled = true
|
||||
tracks/5/path = NodePath("Bear_fx_claw_attack_R")
|
||||
tracks/5/interp = 1
|
||||
tracks/5/loop_wrap = true
|
||||
tracks/5/keys = PackedFloat32Array(0, 1, -3.188013, 1.0970955, 1.7545929)
|
||||
tracks/6/type = "rotation_3d"
|
||||
tracks/6/imported = true
|
||||
tracks/6/enabled = true
|
||||
tracks/6/path = NodePath("Bear_fx_claw_attack_R")
|
||||
tracks/6/interp = 1
|
||||
tracks/6/loop_wrap = true
|
||||
tracks/6/keys = PackedFloat32Array(0, 1, 0, 0, 0, 1)
|
||||
tracks/7/type = "scale_3d"
|
||||
tracks/7/imported = true
|
||||
tracks/7/enabled = true
|
||||
tracks/7/path = NodePath("Bear_fx_claw_attack_R")
|
||||
tracks/7/interp = 1
|
||||
tracks/7/loop_wrap = true
|
||||
tracks/7/keys = PackedFloat32Array(0, 1, 0, 0, 0)
|
||||
tracks/8/type = "position_3d"
|
||||
tracks/8/imported = true
|
||||
tracks/8/enabled = true
|
||||
tracks/8/path = NodePath("Bear_fx_claw_attack_L")
|
||||
tracks/8/interp = 1
|
||||
tracks/8/loop_wrap = true
|
||||
tracks/8/keys = PackedFloat32Array(0, 1, -3.188013, 1.0970955, 1.7545929)
|
||||
tracks/9/type = "rotation_3d"
|
||||
tracks/9/imported = true
|
||||
tracks/9/enabled = true
|
||||
tracks/9/path = NodePath("Bear_fx_claw_attack_L")
|
||||
tracks/9/interp = 1
|
||||
tracks/9/loop_wrap = true
|
||||
tracks/9/keys = PackedFloat32Array(0, 1, 0, 0, 0, 1)
|
||||
tracks/10/type = "scale_3d"
|
||||
tracks/10/imported = true
|
||||
tracks/10/enabled = true
|
||||
tracks/10/path = NodePath("Bear_fx_claw_attack_L")
|
||||
tracks/10/interp = 1
|
||||
tracks/10/loop_wrap = true
|
||||
tracks/10/keys = PackedFloat32Array(0, 1, 0, 0, 0)
|
||||
tracks/11/type = "method"
|
||||
tracks/11/imported = false
|
||||
tracks/11/enabled = true
|
||||
tracks/11/path = NodePath("..")
|
||||
tracks/11/interp = 1
|
||||
tracks/11/loop_wrap = true
|
||||
tracks/11/keys = {
|
||||
"times": PackedFloat32Array(),
|
||||
"transitions": PackedFloat32Array(),
|
||||
"values": []
|
||||
}
|
||||
+617
-620
File diff suppressed because it is too large
Load Diff
+659
-671
File diff suppressed because it is too large
Load Diff
+640
-643
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,45 @@
|
||||
[remap]
|
||||
|
||||
importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://dctmlh4hnuux1"
|
||||
path="res://.godot/imported/Lobby_underground.glb-55ed49331d7074ef560bfa0a498b89a7.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Lobby_underground.glb"
|
||||
dest_files=["res://.godot/imported/Lobby_underground.glb-55ed49331d7074ef560bfa0a498b89a7.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
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 166 KiB |
@@ -0,0 +1,45 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dc4gf36fgsabp"
|
||||
path.s3tc="res://.godot/imported/Lobby_underground_rock.png-76733dc5212e6c79a91e71ce008ebf6f.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/Lobby_underground_rock.png-76733dc5212e6c79a91e71ce008ebf6f.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "de3796fe2c1123ae5ba27a0532fda6bd"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Lobby_underground_rock.png"
|
||||
dest_files=["res://.godot/imported/Lobby_underground_rock.png-76733dc5212e6c79a91e71ce008ebf6f.s3tc.ctex", "res://.godot/imported/Lobby_underground_rock.png-76733dc5212e6c79a91e71ce008ebf6f.etc2.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
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,45 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://v0hdo12xule3"
|
||||
path.s3tc="res://.godot/imported/Lobby_underground_rock_B.jpg-c5e86461201f99688c8146fff239a62b.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/Lobby_underground_rock_B.jpg-c5e86461201f99688c8146fff239a62b.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "335b739e743244a64c47e2564a9a3652"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Lobby_underground_rock_B.jpg"
|
||||
dest_files=["res://.godot/imported/Lobby_underground_rock_B.jpg-c5e86461201f99688c8146fff239a62b.s3tc.ctex", "res://.godot/imported/Lobby_underground_rock_B.jpg-c5e86461201f99688c8146fff239a62b.etc2.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
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 183 KiB |
@@ -0,0 +1,45 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dcy7fdio5k84j"
|
||||
path.s3tc="res://.godot/imported/Lobby_underground_rock_B.png-3133a2540f4e1417fb5588bad79e38c8.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/Lobby_underground_rock_B.png-3133a2540f4e1417fb5588bad79e38c8.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "16ea5e4b01e9b3952b950ff65535e5d5"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Lobby_underground_rock_B.png"
|
||||
dest_files=["res://.godot/imported/Lobby_underground_rock_B.png-3133a2540f4e1417fb5588bad79e38c8.s3tc.ctex", "res://.godot/imported/Lobby_underground_rock_B.png-3133a2540f4e1417fb5588bad79e38c8.etc2.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
|
||||
Binary file not shown.
@@ -3,13 +3,13 @@
|
||||
importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://2e6fbder27w1"
|
||||
path="res://.godot/imported/cubes_fx_test.glb-29490ce7011d666c1c4917a1a92679e4.scn"
|
||||
uid="uid://dnltsqmuqcxh1"
|
||||
path="res://.godot/imported/Barrel.glb-8809615fbcbd5dc5b64a229316967555.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/fx/cubes_fx_test.glb"
|
||||
dest_files=["res://.godot/imported/cubes_fx_test.glb-29490ce7011d666c1c4917a1a92679e4.scn"]
|
||||
source_file="res://Assets/breakables/Barrel.glb"
|
||||
dest_files=["res://.godot/imported/Barrel.glb-8809615fbcbd5dc5b64a229316967555.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
Binary file not shown.
+2060
-1
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
extends Node3D
|
||||
## Lobby geometry — watches the run state and raises the bear-gate grid once the arena has
|
||||
## been cleared. The DP flag stays as a designer override for testing the animation.
|
||||
|
||||
var bear_gate_open := false
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if bear_gate_open:
|
||||
return
|
||||
if Run.bear_gate_open() or DP.b("gate_unlocked_bear"):
|
||||
bear_gate_open = true
|
||||
$AnimationPlayer.play("Gate_opening")
|
||||
if DP.b("gamepad_vibration"):
|
||||
Input.start_joy_vibration(0, 0.5, .5, 7)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cwbf7jfkr8j10
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
[ext_resource type="Script" uid="uid://cn7fhjkro7637" path="res://bear.gd" id="1_beargd"]
|
||||
[ext_resource type="PackedScene" uid="uid://cofv5dbavesis" path="res://Assets/Bear.glb" id="2_bearglb"]
|
||||
[ext_resource type="Script" uid="uid://bsbed05ifr18s" path="res://bear_test_cube.gd" id="3_rog1v"]
|
||||
[ext_resource type="PackedScene" uid="uid://bdbx0wwa73rhp" path="res://Assets/fx/Bear_FX.glb" id="4_rog1v"]
|
||||
[ext_resource type="PackedScene" uid="uid://bdbx0wwa73rhp" path="res://Assets/fx/Bear_FX.glb" id="3_bearfx"]
|
||||
[ext_resource type="Material" uid="uid://blpkmyikjnhbo" path="res://Materials/M_bear_claw_fx.tres" id="4_clawfx"]
|
||||
[ext_resource type="PackedScene" path="res://BearAttackHitboxes.tscn" id="5_hitboxes"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_body"]
|
||||
radius = 1.0
|
||||
@@ -29,259 +30,15 @@ shape = SubResource("CapsuleShape3D_hit")
|
||||
|
||||
[node name="bear_model" parent="." unique_id=359217823 instance=ExtResource("2_bearglb")]
|
||||
|
||||
[node name="Skeleton3D" parent="bear_model/bear-rig" parent_id_path=PackedInt32Array(359217823, 1619621659) index="0" unique_id=1324818366]
|
||||
bones/1/position = Vector3(0.04601016, 1.9209582, 0.9051311)
|
||||
bones/1/rotation = Quaternion(0.5270001, -0.011489415, -0.05297156, 0.848135)
|
||||
bones/2/rotation = Quaternion(0.29015693, 0.002787927, 0.00639222, 0.9569537)
|
||||
bones/2/scale = Vector3(0.9999999, 1.0000008, 0.99999934)
|
||||
bones/3/rotation = Quaternion(0.06707396, 0.012082217, 0.011868715, 0.9976043)
|
||||
bones/4/rotation = Quaternion(0.3487565, 0.010761848, 0.013076123, 0.93706036)
|
||||
bones/5/rotation = Quaternion(0.15472108, -0.21109715, -0.09227382, 0.96072114)
|
||||
bones/6/rotation = Quaternion(0.4204113, 0.23492317, -0.11518617, 0.86879086)
|
||||
bones/7/rotation = Quaternion(0.76830006, 0.36476925, -0.4668917, -0.24222025)
|
||||
bones/8/rotation = Quaternion(0.5460264, -0.71257937, 0.40870878, -0.16444752)
|
||||
bones/9/rotation = Quaternion(-0.02719195, -0.14156067, -0.26938534, 0.9521832)
|
||||
bones/10/rotation = Quaternion(-0.12630412, -0.39785445, -0.057911687, 0.90686566)
|
||||
bones/11/rotation = Quaternion(0.70209646, -0.35357565, 0.59454584, -0.16899753)
|
||||
bones/12/rotation = Quaternion(0.5294657, 0.7712517, -0.33475664, -0.1130258)
|
||||
bones/13/rotation = Quaternion(-0.04075809, 0.17025389, 0.28913936, 0.94114333)
|
||||
bones/14/rotation = Quaternion(-0.03496992, 0.2568669, -0.0008229511, 0.9658136)
|
||||
bones/15/rotation = Quaternion(0.9957146, -0.032195006, 0.031220285, 0.08087847)
|
||||
bones/16/rotation = Quaternion(0.9367782, -0.012506716, 0.033659726, 0.3480767)
|
||||
bones/17/rotation = Quaternion(-0.860235, -0.08192984, 0.009118035, 0.50319016)
|
||||
bones/17/scale = Vector3(0.9999998, 1.0000002, 1)
|
||||
bones/19/rotation = Quaternion(-4.514978e-15, 1, 7.4505806e-08, -5.523351e-07)
|
||||
bones/20/rotation = Quaternion(0.9729887, -0.014750167, 0.014303936, 0.22993676)
|
||||
bones/21/rotation = Quaternion(0.9366144, -0.00601367, 0.016095275, 0.34994036)
|
||||
bones/22/rotation = Quaternion(-0.7732739, -0.06955802, 0.0075612683, 0.6302)
|
||||
bones/22/scale = Vector3(0.9999997, 0.9999998, 0.9999999)
|
||||
bones/24/rotation = Quaternion(6.628114e-12, 0.99999994, 5.2154085e-08, -0.00035543842)
|
||||
bones/25/position = Vector3(1.0117401, 1.3159828, 3.9725027)
|
||||
bones/25/rotation = Quaternion(-0.27285534, 0.9274522, 0.08017836, 0.2428039)
|
||||
bones/25/scale = Vector3(1.0000001, 12.140265, 1.0000001)
|
||||
bones/26/position = Vector3(-0.9025072, 1.4953425, 4.006362)
|
||||
bones/26/rotation = Quaternion(0.5100001, 0.6936306, 0.15438241, -0.48470873)
|
||||
bones/26/scale = Vector3(0.99999994, 11.348344, 1)
|
||||
bones/27/position = Vector3(0.70899034, 1.0356265, 0.611243)
|
||||
bones/27/rotation = Quaternion(0.7965308, 0.01196337, -0.0119632045, 0.6043613)
|
||||
bones/27/scale = Vector3(0.99999994, 29.328602, 1)
|
||||
bones/28/position = Vector3(-0.9047001, 1.0118608, 0.8510791)
|
||||
bones/28/rotation = Quaternion(0.776662, 0.010376095, -0.010376263, 0.6297467)
|
||||
bones/28/scale = Vector3(1, 26.535925, 1)
|
||||
bones/30/position = Vector3(0.07262612, 0.67294323, -1.1644177)
|
||||
bones/30/rotation = Quaternion(-0.7183768, 0.04937226, -0.02237074, 0.69353926)
|
||||
bones/31/position = Vector3(5.9604645e-08, -1.4631644, 0.23291233)
|
||||
bones/31/rotation = Quaternion(1.1641533e-09, 1.8335415e-09, 2.328307e-10, 1)
|
||||
bones/31/scale = Vector3(0.99999994, 0.9999999, 0.99999994)
|
||||
bones/32/position = Vector3(-0.0331195, -2.362161, -0.036310136)
|
||||
bones/32/rotation = Quaternion(0.20497073, -0.020519394, -0.033738203, 0.9779712)
|
||||
bones/32/scale = Vector3(0.9999999, 0.9999999, 0.99999994)
|
||||
bones/33/position = Vector3(8.195639e-08, -1.4631642, 0.23291235)
|
||||
bones/33/rotation = Quaternion(-8.288772e-08, 3.4342527e-09, -4.1909525e-09, 1)
|
||||
bones/33/scale = Vector3(0.9999998, 0.9999998, 0.99999994)
|
||||
bones/35/position = Vector3(-7.893884e-09, -1.0594703, 5.2079617e-08)
|
||||
bones/35/rotation = Quaternion(0.99971783, 1.2737803e-07, 5.365157e-06, -0.023754692)
|
||||
bones/35/scale = Vector3(0.99999976, 0.9999998, 1.0000012)
|
||||
bones/39/position = Vector3(0.8199172, 0.25251278, 0.47214246)
|
||||
bones/39/rotation = Quaternion(0.9961935, -0.035078514, -0.0045541152, 0.07967066)
|
||||
bones/39/scale = Vector3(1.0000004, 0.9999996, 0.9999991)
|
||||
bones/40/rotation = Quaternion(0.93738276, 1.2575202e-07, 3.4991626e-08, 0.3483009)
|
||||
bones/40/scale = Vector3(1.0000004, 1.0000001, 1.0000001)
|
||||
bones/41/rotation = Quaternion(-0.860235, -0.081929855, 0.009117997, 0.5031899)
|
||||
bones/41/scale = Vector3(0.99999946, 0.99999976, 0.9999996)
|
||||
bones/42/position = Vector3(-1.9729964e-07, 0.56145483, 7.283501e-08)
|
||||
bones/46/scale = Vector3(0.99999946, 0.99999964, 0.9999999)
|
||||
bones/48/rotation = Quaternion(9.8842406e-08, -0.054423165, -1.786034e-08, 0.998518)
|
||||
bones/48/scale = Vector3(0.9999993, 0.9999996, 0.9999999)
|
||||
bones/50/scale = Vector3(0.99999994, 0.99999994, 0.9999998)
|
||||
bones/51/rotation = Quaternion(-6.30798e-08, 0.026635498, 6.253992e-09, 0.99964523)
|
||||
bones/51/scale = Vector3(0.9999999, 0.99999964, 0.99999964)
|
||||
bones/53/position = Vector3(-0.8199191, 0.25251284, 0.47213903)
|
||||
bones/53/rotation = Quaternion(0.9730908, -0.0186988, -0.0024160824, 0.22964936)
|
||||
bones/53/scale = Vector3(1, 0.99999875, 0.99999946)
|
||||
bones/54/rotation = Quaternion(0.9367526, -1.1281111e-07, -3.6940495e-08, 0.34999225)
|
||||
bones/55/rotation = Quaternion(-0.77327377, -0.06955799, 0.007561261, 0.6302002)
|
||||
bones/55/scale = Vector3(1.0000002, 1, 1.0000002)
|
||||
bones/56/position = Vector3(-5.9126133e-08, 0.5614537, 7.70865e-07)
|
||||
bones/57/rotation = Quaternion(0.70073944, -0.70073956, -0.094679825, -0.09467953)
|
||||
bones/60/scale = Vector3(1.0000004, 1.0000004, 1.0000002)
|
||||
bones/62/rotation = Quaternion(5.8764627e-08, -0.042629674, 2.4442278e-08, 0.99909097)
|
||||
bones/62/scale = Vector3(1.0000002, 1.0000002, 1.0000001)
|
||||
bones/64/scale = Vector3(1.0000004, 1.0000004, 1)
|
||||
bones/65/rotation = Quaternion(8.029546e-08, 0.01272784, 4.3857337e-08, 0.999919)
|
||||
bones/65/scale = Vector3(1.0000002, 1.0000004, 1.0000004)
|
||||
bones/67/rotation = Quaternion(0.7179022, -7.671307e-07, 7.885642e-07, 0.696144)
|
||||
bones/67/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/68/rotation = Quaternion(0.9776482, 2.0029378e-07, 1.0460874e-06, -0.2102479)
|
||||
bones/68/scale = Vector3(1.0000004, 1.0000004, 0.9999982)
|
||||
bones/69/position = Vector3(-2.4645832e-08, -6.861796e-09, 7.455772e-08)
|
||||
bones/69/rotation = Quaternion(-0.8315212, 2.5276703e-08, -9.3330055e-09, 0.5554931)
|
||||
bones/69/scale = Vector3(1, 1.0000001, 1.0000002)
|
||||
bones/70/rotation = Quaternion(0.67750055, 8.820757e-08, 7.575834e-08, 0.7355223)
|
||||
bones/70/scale = Vector3(1, 1, 1)
|
||||
bones/71/scale = Vector3(0.9999999, 1, 0.9999999)
|
||||
bones/72/rotation = Quaternion(-2.1641608e-07, -4.6565607e-10, -4.6576065e-10, 1)
|
||||
bones/75/rotation = Quaternion(0.25299338, 0.020847347, 0.028576687, 0.9668212)
|
||||
bones/76/position = Vector3(1.01587794e-07, -1.5306958e-07, -4.3554866e-07)
|
||||
bones/76/rotation = Quaternion(-0.5206146, -3.634943e-08, 7.6474e-08, 0.8537919)
|
||||
bones/77/rotation = Quaternion(0.9373828, 1.2785249e-07, 3.3241214e-08, 0.3483008)
|
||||
bones/78/position = Vector3(0.8199172, 0.25251257, 0.47214243)
|
||||
bones/78/rotation = Quaternion(0.99571455, -0.032195, 0.031220287, 0.08087897)
|
||||
bones/78/scale = Vector3(1.0000004, 0.9999997, 0.99999905)
|
||||
bones/80/rotation = Quaternion(0.7179022, -7.6713064e-07, 7.885641e-07, 0.696144)
|
||||
bones/80/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/81/rotation = Quaternion(0.97764814, 1.9846473e-07, 1.0426893e-06, -0.21024783)
|
||||
bones/81/scale = Vector3(1.0000004, 1.0000002, 0.9999982)
|
||||
bones/82/position = Vector3(6.103571e-08, 8.8816435e-08, -3.6955274e-09)
|
||||
bones/82/rotation = Quaternion(-0.8315211, 2.3407136e-08, -1.2821512e-08, 0.5554932)
|
||||
bones/82/scale = Vector3(0.99999994, 0.99999994, 1)
|
||||
bones/83/rotation = Quaternion(0.6775009, -8.600083e-08, -8.977273e-08, 0.735522)
|
||||
bones/83/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/84/scale = Vector3(0.99999994, 1.0000001, 0.9999999)
|
||||
bones/85/rotation = Quaternion(2.6833732e-07, -9.313788e-10, -2.5612494e-09, 1)
|
||||
bones/85/scale = Vector3(1.0000001, 1, 1.0000001)
|
||||
bones/87/rotation = Quaternion(-0.5230753, 0.20132942, 0.026226493, 0.8277505)
|
||||
bones/88/rotation = Quaternion(0.10320552, 0.011111915, 0.015231778, 0.99448144)
|
||||
bones/89/position = Vector3(2.953037e-07, 4.9207458e-08, -4.3015167e-08)
|
||||
bones/89/rotation = Quaternion(-0.5201237, 5.177172e-08, -1.16139375e-07, 0.8540909)
|
||||
bones/90/rotation = Quaternion(0.9367527, -1.0975643e-07, -3.3382268e-08, 0.34999216)
|
||||
bones/91/position = Vector3(-0.8199192, 0.2525128, 0.47213912)
|
||||
bones/91/rotation = Quaternion(0.9729887, -0.0147501845, 0.014303951, 0.22993667)
|
||||
bones/91/scale = Vector3(1.0000002, 0.999999, 0.99999964)
|
||||
bones/96/position = Vector3(-0.016559705, -1.9126627, 0.09830098)
|
||||
bones/96/rotation = Quaternion(0.10305436, -0.010316663, -0.016962789, 0.99447757)
|
||||
bones/96/scale = Vector3(0.9999998, 1, 1)
|
||||
bones/97/rotation = Quaternion(0.997074, -1.2813135e-07, 1.666339e-06, -0.07644201)
|
||||
bones/98/position = Vector3(0.0013585633, -0.23419222, 0.016214281)
|
||||
bones/98/rotation = Quaternion(-0.15130657, -0.005602528, -0.008209973, 0.98843694)
|
||||
bones/98/scale = Vector3(1.0000001, 1.0000006, 1.0000029)
|
||||
bones/101/position = Vector3(-0.016559973, 1.4684486, 0.06451648)
|
||||
bones/101/rotation = Quaternion(0.99944556, 0.016124567, -0.011581497, -0.02673253)
|
||||
bones/101/scale = Vector3(1.0000001, 0.9999993, 0.99999183)
|
||||
bones/102/rotation = Quaternion(0.95545256, -6.924111e-08, 2.2887033e-07, -0.29514462)
|
||||
bones/103/position = Vector3(-0.00705543, 0.6694702, -0.06780842)
|
||||
bones/103/rotation = Quaternion(0.15471841, -0.21109664, -0.09227309, 0.9607217)
|
||||
bones/103/scale = Vector3(1.0000005, 1.0000286, 1.0000087)
|
||||
bones/104/rotation = Quaternion(0.420411, 0.23492327, -0.115186565, 0.86879104)
|
||||
bones/104/scale = Vector3(0.9999993, 0.9999884, 0.9999856)
|
||||
bones/105/rotation = Quaternion(0.91976035, -0.013162326, 0.0148637965, 0.39197809)
|
||||
bones/105/scale = Vector3(1, 1.0000005, 1.0000114)
|
||||
bones/106/position = Vector3(-0.010389687, -0.091948025, 0.0016658108)
|
||||
bones/106/rotation = Quaternion(0.82734275, 0.15726796, -0.14167279, -0.52028793)
|
||||
bones/107/rotation = Quaternion(0.77328545, 0.16233337, -0.107321426, 0.6034564)
|
||||
bones/107/scale = Vector3(0.9999966, 0.99997723, 0.9999995)
|
||||
bones/108/position = Vector3(-1.1340098e-08, 7.923448e-07, 9.0939814e-08)
|
||||
bones/108/rotation = Quaternion(0.42463258, 0.043219328, 0.08968367, -0.89987564)
|
||||
bones/110/rotation = Quaternion(5.443812e-06, 3.6259098e-09, -1.2069942e-06, 1)
|
||||
bones/110/scale = Vector3(0.99999994, 0.99999976, 1.0000001)
|
||||
bones/113/position = Vector3(0.08179821, 0.64012206, 0.7106584)
|
||||
bones/113/rotation = Quaternion(0.7683008, 0.36476624, -0.46689337, -0.24221936)
|
||||
bones/114/position = Vector3(0.08595797, 0.6463289, -0.32087424)
|
||||
bones/114/rotation = Quaternion(0.5615046, -0.7056476, 0.3871702, -0.19202453)
|
||||
bones/114/scale = Vector3(1.0000049, 1.0000027, 1.0000052)
|
||||
bones/115/rotation = Quaternion(-0.037640397, -0.10443457, -0.2681242, 0.9569672)
|
||||
bones/115/scale = Vector3(0.9999974, 1.0000036, 0.99999976)
|
||||
bones/116/rotation = Quaternion(-0.12630361, -0.39785278, -0.057911348, 0.90686655)
|
||||
bones/116/scale = Vector3(1.0000005, 0.9999972, 1.0000013)
|
||||
bones/119/scale = Vector3(1.0000043, 0.9999975, 0.99999744)
|
||||
bones/121/rotation = Quaternion(-2.7027176e-07, -0.20424414, 2.9341666e-07, 0.97892)
|
||||
bones/121/scale = Vector3(1.0000037, 0.99999774, 0.9999977)
|
||||
bones/123/scale = Vector3(1.000003, 0.9999977, 0.99999917)
|
||||
bones/124/rotation = Quaternion(1.2542905e-06, -0.033494003, 5.941339e-07, 0.999439)
|
||||
bones/124/scale = Vector3(1.0000037, 0.9999978, 0.99999875)
|
||||
bones/126/rotation = Quaternion(-0.51635414, -0.1681693, 0.6340872, 0.5504825)
|
||||
bones/126/scale = Vector3(1.0000056, 1.0000031, 1.0000038)
|
||||
bones/127/rotation = Quaternion(-0.24332374, 0.12663902, 0.6612198, 0.6982439)
|
||||
bones/127/scale = Vector3(1.0000057, 1.0000007, 1.0000064)
|
||||
bones/128/position = Vector3(3.0230987e-07, -5.5011895e-07, -6.94335e-08)
|
||||
bones/128/rotation = Quaternion(0.17027588, 0.93388194, -0.2967173, 0.104064964)
|
||||
bones/129/rotation = Quaternion(-0.037640374, -0.10443452, -0.26812422, 0.9569671)
|
||||
bones/131/rotation = Quaternion(-0.54023695, -0.3639527, 0.10910668, 0.7508517)
|
||||
bones/132/rotation = Quaternion(-0.13163939, 0.9186296, -0.34996635, -0.12772812)
|
||||
bones/133/rotation = Quaternion(-0.012778445, 0.011854936, 0.00015161023, 0.99984807)
|
||||
bones/133/scale = Vector3(1.0422997, 1.0422999, 1.0422992)
|
||||
bones/134/rotation = Quaternion(0.02152282, -2.7759576e-08, -1.5735115e-07, 0.99976844)
|
||||
bones/134/scale = Vector3(0.98826313, 0.9882641, 0.9882627)
|
||||
bones/135/position = Vector3(0.08595812, 0.646329, -0.3208742)
|
||||
bones/135/rotation = Quaternion(0.5460276, -0.7125794, 0.40870702, -0.16444758)
|
||||
bones/135/scale = Vector3(1.000007, 1.0000004, 1.0000051)
|
||||
bones/137/position = Vector3(-0.09762837, 0.6401221, 0.7106583)
|
||||
bones/137/rotation = Quaternion(0.7020965, -0.35357338, 0.5945473, -0.16899663)
|
||||
bones/138/position = Vector3(-0.08595776, 0.646329, -0.3208746)
|
||||
bones/138/rotation = Quaternion(0.5492876, 0.7627154, -0.30113, -0.16083841)
|
||||
bones/138/scale = Vector3(1.0000051, 1.0000018, 1.0000046)
|
||||
bones/139/rotation = Quaternion(-0.058682628, 0.11130926, 0.28603986, 0.94991994)
|
||||
bones/139/scale = Vector3(0.9999983, 1.0000024, 0.9999992)
|
||||
bones/140/rotation = Quaternion(-0.034969915, 0.25686622, -0.0008231461, 0.96581376)
|
||||
bones/140/scale = Vector3(1.0000031, 0.9999977, 0.9999988)
|
||||
bones/143/scale = Vector3(1.000005, 0.99999815, 0.9999967)
|
||||
bones/145/rotation = Quaternion(-4.0431777e-07, 0.1295653, -5.1404834e-07, 0.99157095)
|
||||
bones/145/scale = Vector3(1.0000045, 0.99999803, 0.9999968)
|
||||
bones/147/scale = Vector3(1.0000035, 0.99999845, 0.9999981)
|
||||
bones/148/rotation = Quaternion(1.9343124e-06, 0.025161995, -3.222267e-07, 0.9996834)
|
||||
bones/148/scale = Vector3(1.000004, 0.9999991, 0.999998)
|
||||
bones/150/rotation = Quaternion(-0.5163542, 0.16816999, -0.6340877, 0.5504816)
|
||||
bones/150/scale = Vector3(1.0000052, 1.0000039, 1.0000025)
|
||||
bones/151/rotation = Quaternion(-0.24332343, -0.1266389, -0.6612192, 0.6982446)
|
||||
bones/151/scale = Vector3(1.0000049, 1.0000005, 1.0000063)
|
||||
bones/152/position = Vector3(-2.0525843e-07, -4.4378166e-07, 2.2242949e-07)
|
||||
bones/152/rotation = Quaternion(-0.1980554, 0.9486651, -0.20058647, -0.14343536)
|
||||
bones/153/rotation = Quaternion(-0.058682676, 0.11130926, 0.2860399, 0.94991994)
|
||||
bones/155/rotation = Quaternion(-0.48170745, 0.21343125, -0.09362694, 0.84477156)
|
||||
bones/155/scale = Vector3(0.99999994, 1, 0.9999998)
|
||||
bones/156/rotation = Quaternion(0.2123156, 0.9450362, -0.15822437, 0.19181721)
|
||||
bones/157/rotation = Quaternion(-0.01277751, -0.011854968, -0.0001513001, 0.9998481)
|
||||
bones/157/scale = Vector3(1.0423003, 1.0422994, 1.0423005)
|
||||
bones/158/rotation = Quaternion(0.021521209, -2.5687226e-07, -2.570953e-07, 0.9997684)
|
||||
bones/158/scale = Vector3(0.9882631, 0.98826426, 0.9882618)
|
||||
bones/159/position = Vector3(-0.085957706, 0.6463291, -0.32087478)
|
||||
bones/159/rotation = Quaternion(0.5294669, 0.7712517, -0.33475488, -0.1130262)
|
||||
bones/159/scale = Vector3(1.0000075, 1.0000001, 1.0000042)
|
||||
bones/161/position = Vector3(0.08179821, 0.64012206, 0.7106584)
|
||||
bones/161/rotation = Quaternion(0.7683008, 0.36476624, -0.46689337, -0.24221936)
|
||||
bones/162/position = Vector3(-0.09762837, 0.6401221, 0.7106583)
|
||||
bones/162/rotation = Quaternion(0.7020965, -0.35357338, 0.5945473, -0.16899663)
|
||||
bones/165/position = Vector3(-1.5017577e-08, 0.26895812, -1.6243575e-08)
|
||||
bones/165/rotation = Quaternion(-0.019247467, -0.20323175, 0.97894067, -0.0012537595)
|
||||
bones/166/position = Vector3(0.016703974, -2.2814677, 2.0323193)
|
||||
bones/167/position = Vector3(0.7698192, 2.760036, -1.7026894)
|
||||
bones/167/rotation = Quaternion(-0.93479383, -0.013274327, 0.31412983, 0.16524744)
|
||||
bones/167/scale = Vector3(0.9999947, 0.9999997, 1.0000055)
|
||||
bones/168/position = Vector3(0.18381567, -0.9622623, 0.9894084)
|
||||
bones/168/rotation = Quaternion(0.93622446, 1.3019375e-07, -0.34127164, -0.08377019)
|
||||
bones/168/scale = Vector3(1.0000024, 1.0000011, 1.0000095)
|
||||
bones/170/position = Vector3(0.748137, 0.69556385, 3.7252903e-09)
|
||||
bones/170/rotation = Quaternion(0.019250846, -0.20323181, 0.9789406, 0.001253055)
|
||||
bones/171/position = Vector3(0.381392, -2.057497, 2.0762825)
|
||||
bones/172/position = Vector3(-0.9278099, 2.7545004, -1.5181485)
|
||||
bones/172/rotation = Quaternion(-0.91823035, 0.06278634, -0.38804358, 0.04830265)
|
||||
bones/172/scale = Vector3(0.99999493, 0.9999995, 1.0000055)
|
||||
bones/173/position = Vector3(0.18381546, -0.96226203, 0.9894083)
|
||||
bones/173/rotation = Quaternion(0.9362244, 3.755922e-07, 0.3412715, -0.0837717)
|
||||
bones/173/scale = Vector3(1.0000001, 1.0000001, 0.9999949)
|
||||
bones/183/position = Vector3(-1.982537e-07, 5.9604563e-08, -1.517833e-08)
|
||||
bones/185/rotation = Quaternion(5.4077844e-07, -0.20349081, 0.97907686, -1.12395135e-07)
|
||||
bones/186/position = Vector3(0.78680634, 2.8457582, -0.41063747)
|
||||
bones/186/rotation = Quaternion(-0.9983755, 0.019092962, -0.050729975, -0.017562928)
|
||||
bones/186/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/187/rotation = Quaternion(0.15451065, -2.0305349e-09, -2.0850066e-09, 0.9879911)
|
||||
bones/187/scale = Vector3(1.0000002, 0.99999994, 0.9999999)
|
||||
bones/197/position = Vector3(7.903883e-08, 1.4901151e-07, 8.8932055e-08)
|
||||
bones/199/rotation = Quaternion(0.00034800146, -0.20349097, 0.9790768, -7.2328476e-05)
|
||||
bones/200/position = Vector3(-0.84339374, 2.905353, -0.57784474)
|
||||
bones/200/rotation = Quaternion(-0.9983755, 0.019092962, -0.050729975, -0.017562928)
|
||||
bones/200/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/201/rotation = Quaternion(0.15451066, -1.9585848e-09, -2.5450761e-09, 0.9879911)
|
||||
bones/201/scale = Vector3(1.0000002, 0.99999994, 0.99999994)
|
||||
[node name="Bear_FX" parent="bear_model" unique_id=2070553519 instance=ExtResource("3_bearfx")]
|
||||
|
||||
[node name="test_cube" type="Node3D" parent="." unique_id=646988893]
|
||||
script = ExtResource("3_rog1v")
|
||||
[node name="Bear_fx_claw_attack_R" parent="bear_model/Bear_FX" index="2" unique_id=1939248432]
|
||||
surface_material_override/0 = ExtResource("4_clawfx")
|
||||
|
||||
[node name="Bear_FX" parent="test_cube" unique_id=1183391245 instance=ExtResource("4_rog1v")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.1459732, 0, -1.528423)
|
||||
[node name="Bear_fx_claw_attack_L" parent="bear_model/Bear_FX" index="3" unique_id=834640978]
|
||||
surface_material_override/0 = ExtResource("4_clawfx")
|
||||
|
||||
[node name="Bear_fx_claw_attack_R" parent="test_cube/Bear_FX" index="1" unique_id=941189652]
|
||||
transform = Transform3D(0.26165774, 0.06970292, -0.23443498, -0.046572562, 0.18028688, 0.0016228362, 0.22878301, 0.056650188, 0.2721929, -0.40204993, 0.29855162, 0.917461)
|
||||
[node name="AttackHitboxes" parent="bear_model" instance=ExtResource("5_hitboxes")]
|
||||
|
||||
[editable path="bear_model"]
|
||||
[editable path="test_cube/Bear_FX"]
|
||||
[editable path="bear_model/Bear_FX"]
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
[gd_scene format=3 uid="uid://o8ocjfprxa7u"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cn7fhjkro7637" path="res://bear.gd" id="1_beargd"]
|
||||
[ext_resource type="PackedScene" uid="uid://cofv5dbavesis" path="res://Assets/Bear.glb" id="2_bearglb"]
|
||||
[ext_resource type="Script" uid="uid://bsbed05ifr18s" path="res://bear_test_cube.gd" id="3_rog1v"]
|
||||
[ext_resource type="PackedScene" uid="uid://bdbx0wwa73rhp" path="res://Assets/fx/Bear_FX.glb" id="4_rog1v"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_body"]
|
||||
radius = 1.0
|
||||
height = 2.4
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_hit"]
|
||||
radius = 1.3
|
||||
height = 2.7
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_bfebr"]
|
||||
size = Vector3(6.2019043, 8.561401, 7.0739746)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_rog1v"]
|
||||
size = Vector3(14.399288, 51.902206, 5.741211)
|
||||
|
||||
[node name="Bear" type="CharacterBody3D" unique_id=1573237287]
|
||||
script = ExtResource("1_beargd")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=830443382]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2, 0)
|
||||
shape = SubResource("CapsuleShape3D_body")
|
||||
|
||||
[node name="HitArea" type="Area3D" parent="." unique_id=365327397]
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="HitArea" unique_id=2111867348]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.35, 0)
|
||||
shape = SubResource("CapsuleShape3D_hit")
|
||||
|
||||
[node name="bear_model" parent="." unique_id=359217823 instance=ExtResource("2_bearglb")]
|
||||
|
||||
[node name="test_cube" type="Node3D" parent="bear_model" unique_id=646988893]
|
||||
script = ExtResource("3_rog1v")
|
||||
|
||||
[node name="Bear_FX" parent="bear_model/test_cube" unique_id=1183391245 instance=ExtResource("4_rog1v")]
|
||||
|
||||
[node name="Bear_fx_jump_smash" parent="bear_model/test_cube/Bear_FX" index="0" unique_id=750478984]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_claw_attack_R" parent="bear_model/test_cube/Bear_FX" index="1" unique_id=88064381]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_claw_attack_L" parent="bear_model/test_cube/Bear_FX" index="2" unique_id=1378755061]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_smash_hit" parent="bear_model/test_cube/Bear_FX" index="3" unique_id=1711579105]
|
||||
transform = Transform3D(0.55488384, -0.039024748, -0.018949924, 0.041069064, 0.55086076, 0.06814586, 0.013977209, -0.06933683, 0.5520644, 1.327292, -0.21312934, 5.190573)
|
||||
|
||||
[node name="RigidBody3D" type="AnimatableBody3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit" index="0" unique_id=1764208051]
|
||||
transform = Transform3D(1.0000001, -1.21071935e-08, -1.8626451e-08, -9.313226e-10, 0.99999994, 7.450581e-09, 3.7252903e-09, -1.4901161e-08, 0.99999994, 0, 0, 0)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
|
||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit/RigidBody3D" unique_id=1779197150]
|
||||
transform = Transform3D(0.99993557, -0.00749125, -0.010078691, 0.0077760145, 0.999569, 0.028562747, 0.009858355, -0.028639637, 0.9995405, -1.5136471, 0.9093375, 35.591957)
|
||||
shape = SubResource("BoxShape3D_bfebr")
|
||||
disabled = true
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit/RigidBody3D" unique_id=1276552823]
|
||||
transform = Transform3D(0.9935104, -0.040698394, -0.10621016, -0.108634494, -0.06290151, -0.9920882, 0.03369555, 0.99719334, -0.06691426, -1.6357545, -0.5093044, 12.68803)
|
||||
shape = SubResource("BoxShape3D_rog1v")
|
||||
|
||||
[node name="Skeleton3D" parent="bear_model/bear-rig" parent_id_path=PackedInt32Array(359217823, 1017999212) index="0" unique_id=1624609914]
|
||||
bones/1/position = Vector3(0.00851878, 0.24701798, 1.2888045)
|
||||
bones/1/rotation = Quaternion(0.29791054, -0.060797628, -0.056875575, 0.9509564)
|
||||
bones/2/rotation = Quaternion(0.084239505, -0.026013458, 0.009274505, 0.9960628)
|
||||
bones/2/scale = Vector3(0.9999999, 1.0000008, 0.99999934)
|
||||
bones/3/rotation = Quaternion(-0.14812404, -0.039577905, 0.049865585, 0.98691756)
|
||||
bones/4/rotation = Quaternion(-0.40577498, -0.03082885, 0.05040324, 0.9120612)
|
||||
bones/5/rotation = Quaternion(0.27801633, 0.0014148077, 0.015671793, 0.96044755)
|
||||
bones/6/rotation = Quaternion(0.50370073, 0.13519946, -0.093789615, 0.8480627)
|
||||
bones/7/rotation = Quaternion(0.75079185, 0.54212743, -0.37154716, 0.06604591)
|
||||
bones/8/rotation = Quaternion(0.22344273, -0.32689556, 0.65874565, -0.63973963)
|
||||
bones/9/rotation = Quaternion(0.026405705, -0.27415153, -0.3226086, 0.9055757)
|
||||
bones/10/rotation = Quaternion(0.030285481, -0.31167626, -0.037417818, 0.94896823)
|
||||
bones/11/rotation = Quaternion(0.751943, -0.5788067, 0.30500817, 0.080837056)
|
||||
bones/12/rotation = Quaternion(0.28422552, 0.2936944, -0.68526876, -0.6027987)
|
||||
bones/13/rotation = Quaternion(0.020711409, 0.24585825, 0.3386082, 0.9080029)
|
||||
bones/14/rotation = Quaternion(0.098969, 0.19860524, -0.007872087, 0.97503805)
|
||||
bones/15/rotation = Quaternion(0.6979166, 0.16086513, -0.15598965, 0.680222)
|
||||
bones/16/rotation = Quaternion(0.89734674, 0.09874082, -0.25790086, 0.34424722)
|
||||
bones/17/rotation = Quaternion(-0.13802421, 0.26758972, 0.081159085, 0.9501359)
|
||||
bones/17/scale = Vector3(0.9999998, 1.0000002, 1)
|
||||
bones/19/rotation = Quaternion(-4.514978e-15, 1, 7.4505806e-08, -5.523351e-07)
|
||||
bones/20/rotation = Quaternion(-0.49266306, -0.27058616, 0.262383, 0.7843606)
|
||||
bones/21/rotation = Quaternion(0.0016915401, 0.70246154, -0.001669446, 0.7117178)
|
||||
bones/22/rotation = Quaternion(-0.5496364, -0.3220462, -0.22350304, 0.73772115)
|
||||
bones/22/scale = Vector3(0.9999997, 0.9999998, 0.9999999)
|
||||
bones/23/rotation = Quaternion(-0.00015351747, 0.902104, -0.4315187, 0.00032039074)
|
||||
bones/24/rotation = Quaternion(6.628114e-12, 0.99999994, 5.2154085e-08, -0.00035543842)
|
||||
bones/25/position = Vector3(1.0191536, 3.5353048, 3.5049686)
|
||||
bones/25/rotation = Quaternion(-0.087474234, 0.16733547, 0.98056763, 0.053239316)
|
||||
bones/25/scale = Vector3(1, 17.518272, 1.0000001)
|
||||
bones/26/position = Vector3(-1.0831825, 3.749937, 2.5891113)
|
||||
bones/26/rotation = Quaternion(0.016340872, 0.19671263, 0.9801456, 0.01875816)
|
||||
bones/26/scale = Vector3(1.0000001, 18.765795, 1)
|
||||
bones/27/position = Vector3(1.0193456, -0.43209565, 2.5343885)
|
||||
bones/27/rotation = Quaternion(0.61800283, -0.11976056, 0.11976072, 0.7677157)
|
||||
bones/27/scale = Vector3(0.99999994, 16.85072, 1)
|
||||
bones/28/position = Vector3(-0.8340287, 1.0348616, 1.282705)
|
||||
bones/28/rotation = Quaternion(0.82860446, -0.029359974, 0.02935981, 0.5582926)
|
||||
bones/28/scale = Vector3(0.99999994, 32.068844, 1)
|
||||
bones/30/position = Vector3(0.032563455, -0.8335703, -0.9236449)
|
||||
bones/30/rotation = Quaternion(-0.8670657, 0.042821795, -0.07139772, 0.4911883)
|
||||
bones/31/position = Vector3(2.3450447e-08, -1.4631646, 0.23291242)
|
||||
bones/31/rotation = Quaternion(-6.0737464e-09, 4.8699293e-09, -1.4618977e-09, 1)
|
||||
bones/31/scale = Vector3(0.99999994, 0.9999999, 0.99999994)
|
||||
bones/32/position = Vector3(-0.04394375, -1.087056, 0.096768975)
|
||||
bones/32/rotation = Quaternion(-0.8343034, 0.119118, -0.061490715, 0.5347595)
|
||||
bones/32/scale = Vector3(0.9999999, 0.99999976, 0.99999964)
|
||||
bones/33/position = Vector3(3.977649e-08, -1.4631644, 0.23291251)
|
||||
bones/33/rotation = Quaternion(-8.833673e-08, -2.419923e-08, -6.733043e-09, 1)
|
||||
bones/33/scale = Vector3(0.9999998, 0.9999998, 0.99999994)
|
||||
bones/35/position = Vector3(1.0184407e-08, -1.0594703, -5.9146995e-08)
|
||||
bones/35/rotation = Quaternion(0.99971783, 1.3593646e-07, 5.3695976e-06, -0.023754615)
|
||||
bones/35/scale = Vector3(0.99999976, 0.9999998, 1.0000012)
|
||||
bones/39/position = Vector3(0.8199172, 0.25251278, 0.47214246)
|
||||
bones/39/rotation = Quaternion(0.71402234, 0.34199142, 0.043267474, 0.60937834)
|
||||
bones/39/scale = Vector3(1.0000004, 0.9999996, 0.9999991)
|
||||
bones/40/rotation = Quaternion(0.9336719, 1.2799235e-07, 3.7337827e-08, 0.3581296)
|
||||
bones/40/scale = Vector3(1.0000004, 1.0000001, 1.0000001)
|
||||
bones/41/rotation = Quaternion(-0.13802455, 0.26758966, 0.08115916, 0.9501359)
|
||||
bones/41/scale = Vector3(0.99999946, 0.99999976, 0.9999996)
|
||||
bones/42/position = Vector3(-1.9729964e-07, 0.56145483, 7.283501e-08)
|
||||
bones/46/scale = Vector3(0.99999946, 0.99999964, 0.9999999)
|
||||
bones/48/rotation = Quaternion(-2.9741386e-07, 0.13593404, 1.01778824e-07, 0.9907179)
|
||||
bones/48/scale = Vector3(0.9999993, 0.9999996, 0.9999999)
|
||||
bones/50/scale = Vector3(0.99999994, 0.99999994, 0.9999998)
|
||||
bones/51/rotation = Quaternion(-2.5567479e-08, -0.20499781, -2.3086146e-08, 0.9787625)
|
||||
bones/51/scale = Vector3(0.9999999, 0.99999964, 0.99999964)
|
||||
bones/53/position = Vector3(-0.8199191, 0.25251284, 0.47213903)
|
||||
bones/53/rotation = Quaternion(-0.5351706, 0.35860845, -0.15898216, 0.74814254)
|
||||
bones/53/scale = Vector3(1, 0.99999875, 0.99999946)
|
||||
bones/54/rotation = Quaternion(0.0023762286, -4.7362324e-08, -6.475868e-08, 0.9999972)
|
||||
bones/55/rotation = Quaternion(-0.54963607, -0.322046, -0.22350314, 0.73772144)
|
||||
bones/55/scale = Vector3(1.0000002, 1, 1.0000002)
|
||||
bones/56/position = Vector3(0.0013532753, 0.57868266, 0.05537574)
|
||||
bones/56/rotation = Quaternion(-0.00015348212, 0.90210384, -0.43151882, 0.0003204293)
|
||||
bones/57/rotation = Quaternion(0.70073944, -0.70073956, -0.094679825, -0.09467953)
|
||||
bones/60/scale = Vector3(1.0000004, 1.0000004, 1.0000002)
|
||||
bones/62/rotation = Quaternion(-1.7092354e-08, -0.18223058, 2.6700846e-08, 0.98325586)
|
||||
bones/62/scale = Vector3(1.0000002, 1.0000002, 1.0000001)
|
||||
bones/64/scale = Vector3(1.0000004, 1.0000004, 1)
|
||||
bones/65/rotation = Quaternion(-1.0345744e-08, -0.3796584, -4.0675246e-08, 0.9251268)
|
||||
bones/65/scale = Vector3(1.0000002, 1.0000004, 1.0000004)
|
||||
bones/67/rotation = Quaternion(0.7179022, -7.671307e-07, 7.885642e-07, 0.696144)
|
||||
bones/67/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/68/rotation = Quaternion(0.9776482, 2.0029378e-07, 1.0460874e-06, -0.2102479)
|
||||
bones/68/scale = Vector3(1.0000004, 1.0000004, 0.9999982)
|
||||
bones/69/position = Vector3(-2.4645832e-08, -6.861796e-09, 7.455772e-08)
|
||||
bones/69/rotation = Quaternion(-0.8315212, 2.5276703e-08, -9.3330055e-09, 0.5554931)
|
||||
bones/69/scale = Vector3(1, 1.0000001, 1.0000002)
|
||||
bones/70/rotation = Quaternion(0.67750055, 8.820757e-08, 7.575834e-08, 0.7355223)
|
||||
bones/70/scale = Vector3(1, 1, 1)
|
||||
bones/71/scale = Vector3(0.9999999, 1, 0.9999999)
|
||||
bones/72/rotation = Quaternion(-2.1641608e-07, -4.6565607e-10, -4.6576065e-10, 1)
|
||||
bones/75/rotation = Quaternion(-0.34314692, -0.20321459, -0.2785586, 0.8737043)
|
||||
bones/76/position = Vector3(1.01587794e-07, -1.5306958e-07, -4.3554866e-07)
|
||||
bones/76/rotation = Quaternion(-0.51764834, -7.167482e-08, 1.7163823e-07, 0.85559356)
|
||||
bones/77/rotation = Quaternion(0.93367195, 1.2110854e-07, 3.8556042e-08, 0.35812962)
|
||||
bones/78/position = Vector3(0.8199172, 0.25251257, 0.47214243)
|
||||
bones/78/rotation = Quaternion(0.6979164, 0.16086517, -0.15598962, 0.6802223)
|
||||
bones/78/scale = Vector3(1.0000004, 0.9999997, 0.99999905)
|
||||
bones/80/rotation = Quaternion(0.7179022, -7.6713064e-07, 7.885641e-07, 0.696144)
|
||||
bones/80/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/81/rotation = Quaternion(0.97764814, 1.9846473e-07, 1.0426893e-06, -0.21024783)
|
||||
bones/81/scale = Vector3(1.0000004, 1.0000002, 0.9999982)
|
||||
bones/82/position = Vector3(6.103571e-08, 8.8816435e-08, -3.6955274e-09)
|
||||
bones/82/rotation = Quaternion(-0.8315211, 2.3407136e-08, -1.2821512e-08, 0.5554932)
|
||||
bones/82/scale = Vector3(0.99999994, 0.99999994, 1)
|
||||
bones/83/rotation = Quaternion(0.6775009, -8.600083e-08, -8.977273e-08, 0.735522)
|
||||
bones/83/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/84/scale = Vector3(0.99999994, 1.0000001, 0.9999999)
|
||||
bones/85/rotation = Quaternion(2.6833732e-07, -9.313788e-10, -2.5612494e-09, 1)
|
||||
bones/85/scale = Vector3(1.0000001, 1, 1.0000001)
|
||||
bones/87/rotation = Quaternion(-0.5230753, 0.20132942, 0.026226493, 0.8277505)
|
||||
bones/88/rotation = Quaternion(0.61967987, 0.23118778, 0.3169036, 0.679795)
|
||||
bones/89/position = Vector3(2.953037e-07, 4.9207458e-08, -4.3015167e-08)
|
||||
bones/89/rotation = Quaternion(-0.001144886, -2.973514e-08, 2.817069e-08, 0.9999994)
|
||||
bones/90/rotation = Quaternion(0.0023764072, -4.0769752e-08, -7.0690255e-08, 0.99999726)
|
||||
bones/91/position = Vector3(-0.8199192, 0.2525128, 0.47213912)
|
||||
bones/91/rotation = Quaternion(-0.49266297, -0.27058598, 0.2623832, 0.78436047)
|
||||
bones/91/scale = Vector3(1.0000002, 0.999999, 0.99999964)
|
||||
bones/96/position = Vector3(-0.021971898, -1.2751104, 0.16484088)
|
||||
bones/96/rotation = Quaternion(-0.47603267, 0.067788206, -0.035077166, 0.8761091)
|
||||
bones/96/scale = Vector3(0.9999999, 0.9999999, 0.99999976)
|
||||
bones/97/rotation = Quaternion(0.997074, -1.2813135e-07, 1.666339e-06, -0.07644201)
|
||||
bones/98/position = Vector3(0.01993539, 0.08757691, 0.045667563)
|
||||
bones/98/rotation = Quaternion(0.1475291, 0.03397043, -0.019923227, 0.9882734)
|
||||
bones/98/scale = Vector3(1, 1.0000011, 1.0000023)
|
||||
bones/101/position = Vector3(-0.021972047, 0.8282039, 0.0959422)
|
||||
bones/101/rotation = Quaternion(0.8371564, 0.04015539, 0.06490996, 0.5416119)
|
||||
bones/101/scale = Vector3(1, 1.0000066, 0.99998474)
|
||||
bones/102/rotation = Quaternion(0.95545256, -6.924111e-08, 2.2887033e-07, -0.29514462)
|
||||
bones/103/position = Vector3(0.17285576, 0.72785676, 1.0822707)
|
||||
bones/103/rotation = Quaternion(0.27801546, 0.0014157619, 0.015671493, 0.9604477)
|
||||
bones/103/scale = Vector3(1.0000002, 1.000013, 1.0000246)
|
||||
bones/104/rotation = Quaternion(0.5037003, 0.13519715, -0.093790196, 0.84806323)
|
||||
bones/104/scale = Vector3(1.0000721, 1.0000457, 0.99993384)
|
||||
bones/105/rotation = Quaternion(0.97757924, -0.053521663, -0.054415643, -0.19624804)
|
||||
bones/105/scale = Vector3(1.0000001, 1.0000083, 1.0000036)
|
||||
bones/106/position = Vector3(0.023142539, -0.54231995, -0.9607401)
|
||||
bones/106/rotation = Quaternion(0.99272084, -0.08158898, -0.03307842, -0.08218607)
|
||||
bones/107/rotation = Quaternion(0.903578, -0.12777254, -0.05477002, -0.4052421)
|
||||
bones/107/scale = Vector3(0.9999992, 0.9999624, 1.0000123)
|
||||
bones/108/position = Vector3(-1.1340098e-08, 7.923448e-07, 9.0939814e-08)
|
||||
bones/108/rotation = Quaternion(0.98967296, 0.0031370325, 0.10343237, -0.09919364)
|
||||
bones/110/rotation = Quaternion(9.815354e-07, 7.072085e-10, -9.586452e-08, 1)
|
||||
bones/110/scale = Vector3(0.99999994, 0.99999976, 1.0000001)
|
||||
bones/113/position = Vector3(0.07716276, 0.6410925, 0.71644557)
|
||||
bones/113/rotation = Quaternion(0.75079244, 0.54212654, -0.3715475, 0.0660462)
|
||||
bones/114/position = Vector3(-0.031743176, 0.60466695, -0.39704067)
|
||||
bones/114/rotation = Quaternion(0.4176498, -0.11118397, 0.55639553, -0.70966953)
|
||||
bones/114/scale = Vector3(1.0000015, 1.0000038, 1.0000079)
|
||||
bones/115/rotation = Quaternion(-0.07547326, 0.02173067, -0.31477332, 0.945912)
|
||||
bones/115/scale = Vector3(0.9999974, 1.0000036, 0.99999976)
|
||||
bones/116/rotation = Quaternion(0.03028559, -0.3116764, -0.037417784, 0.9489682)
|
||||
bones/116/scale = Vector3(1.0000005, 0.9999972, 1.0000013)
|
||||
bones/119/scale = Vector3(1.0000043, 0.9999975, 0.99999744)
|
||||
bones/121/rotation = Quaternion(-4.820391e-08, -0.1579088, -2.0880496e-08, 0.98745376)
|
||||
bones/121/scale = Vector3(1.0000037, 0.99999774, 0.9999977)
|
||||
bones/123/scale = Vector3(1.000003, 0.9999977, 0.99999917)
|
||||
bones/124/rotation = Quaternion(-3.1036683e-07, 0.17317644, 6.989145e-08, 0.9848908)
|
||||
bones/124/scale = Vector3(1.0000037, 0.9999978, 0.99999875)
|
||||
bones/126/rotation = Quaternion(-0.5163543, -0.16816929, 0.6340875, 0.550482)
|
||||
bones/126/scale = Vector3(1.0000015, 1.000007, 1.000004)
|
||||
bones/127/rotation = Quaternion(-0.24332331, 0.12663932, 0.6612194, 0.6982444)
|
||||
bones/127/scale = Vector3(1.0000017, 1.0000014, 1.0000097)
|
||||
bones/128/position = Vector3(-0.008928956, 0.128764, -0.06877987)
|
||||
bones/128/rotation = Quaternion(0.025037244, 0.39930493, -0.88358396, 0.24332726)
|
||||
bones/129/rotation = Quaternion(-0.07547334, 0.021730714, -0.31477335, 0.94591194)
|
||||
bones/131/rotation = Quaternion(-0.41802245, -0.28161782, 0.08442414, 0.85954714)
|
||||
bones/132/rotation = Quaternion(-0.5281791, -0.34319904, -0.62196887, -0.46518382)
|
||||
bones/133/rotation = Quaternion(-0.012777329, 0.011854946, 0.00015161165, 0.9998482)
|
||||
bones/133/scale = Vector3(1.0423008, 1.0423008, 1.0423006)
|
||||
bones/134/rotation = Quaternion(0.02152103, -3.688601e-08, -1.5255387e-07, 0.99976844)
|
||||
bones/134/scale = Vector3(0.9882629, 0.9882634, 0.98826265)
|
||||
bones/135/position = Vector3(-0.0317431, 0.60466677, -0.39704087)
|
||||
bones/135/rotation = Quaternion(0.22344373, -0.32689255, 0.658746, -0.6397405)
|
||||
bones/135/scale = Vector3(1.0000048, 1.0000036, 1.0000046)
|
||||
bones/137/position = Vector3(-0.33244255, 0.70370555, 0.67530614)
|
||||
bones/137/rotation = Quaternion(0.7519437, -0.5788053, 0.30500948, 0.08083551)
|
||||
bones/138/position = Vector3(-0.19594865, 0.65740275, -0.22511396)
|
||||
bones/138/rotation = Quaternion(0.36201134, 0.22157827, -0.6475769, -0.63284683)
|
||||
bones/138/scale = Vector3(1.0000019, 1.0000045, 1.0000057)
|
||||
bones/139/rotation = Quaternion(-0.018797327, 0.13857716, 0.33871746, 0.9304373)
|
||||
bones/139/scale = Vector3(0.9999983, 1.0000024, 0.9999992)
|
||||
bones/140/rotation = Quaternion(0.09896898, 0.1986053, -0.00787212, 0.975038)
|
||||
bones/140/scale = Vector3(1.0000031, 0.9999977, 0.9999988)
|
||||
bones/143/scale = Vector3(1.000005, 0.99999815, 0.9999967)
|
||||
bones/145/rotation = Quaternion(-1.7910523e-07, 0.10005118, -9.714451e-08, 0.9949823)
|
||||
bones/145/scale = Vector3(1.0000045, 0.99999803, 0.9999968)
|
||||
bones/147/scale = Vector3(1.0000035, 0.99999845, 0.9999981)
|
||||
bones/148/rotation = Quaternion(2.0844507e-07, 0.011625211, 4.5709146e-07, 0.9999325)
|
||||
bones/148/scale = Vector3(1.000004, 0.9999991, 0.999998)
|
||||
bones/150/rotation = Quaternion(-0.51635444, 0.16816957, -0.63408744, 0.55048186)
|
||||
bones/150/scale = Vector3(1.000001, 1.0000067, 1.000004)
|
||||
bones/151/rotation = Quaternion(-0.24332346, -0.12663896, -0.6612195, 0.6982443)
|
||||
bones/151/scale = Vector3(1.0000011, 1.0000017, 1.0000095)
|
||||
bones/152/position = Vector3(0.027921734, -0.124764316, 0.07102555)
|
||||
bones/152/rotation = Quaternion(-0.12973516, 0.47151387, -0.86254627, -0.12983702)
|
||||
bones/153/rotation = Quaternion(-0.018797398, 0.13857722, 0.33871746, 0.9304373)
|
||||
bones/155/rotation = Quaternion(-0.36541468, 0.16190512, -0.07102372, 0.91390073)
|
||||
bones/155/scale = Vector3(0.99999994, 1, 0.9999998)
|
||||
bones/156/rotation = Quaternion(0.68045896, -0.19169958, -0.3896983, 0.59022206)
|
||||
bones/157/rotation = Quaternion(-0.01277751, -0.011854968, -0.0001513001, 0.9998481)
|
||||
bones/157/scale = Vector3(1.0423003, 1.0422994, 1.0423005)
|
||||
bones/158/rotation = Quaternion(0.021521209, -2.5687226e-07, -2.570953e-07, 0.9997684)
|
||||
bones/158/scale = Vector3(0.9882631, 0.98826426, 0.9882618)
|
||||
bones/159/position = Vector3(-0.19594839, 0.65740275, -0.2251139)
|
||||
bones/159/rotation = Quaternion(0.28422734, 0.29369113, -0.68527013, -0.60279787)
|
||||
bones/159/scale = Vector3(1.0000027, 1.0000043, 1.0000049)
|
||||
bones/161/position = Vector3(0.07716276, 0.6410925, 0.71644557)
|
||||
bones/161/rotation = Quaternion(0.75079244, 0.54212654, -0.3715475, 0.0660462)
|
||||
bones/162/position = Vector3(-0.33244255, 0.70370555, 0.67530614)
|
||||
bones/162/rotation = Quaternion(0.7519437, -0.5788053, 0.30500948, 0.08083551)
|
||||
bones/165/position = Vector3(-1.5017577e-08, 0.26895812, -1.6243575e-08)
|
||||
bones/165/rotation = Quaternion(-0.019247467, -0.20323175, 0.97894067, -0.0012537595)
|
||||
bones/166/position = Vector3(0.0034187725, -3.131728, 0.9674823)
|
||||
bones/167/position = Vector3(0.209171, 5.0901713, -2.6670303)
|
||||
bones/167/rotation = Quaternion(0.16656846, 0.015223213, 0.18356222, 0.9686734)
|
||||
bones/167/scale = Vector3(0.9999988, 0.9999987, 1.0000023)
|
||||
bones/168/position = Vector3(0.18381567, -0.9622623, 0.9894084)
|
||||
bones/168/rotation = Quaternion(0.9362244, -6.2652596e-08, -0.34127164, -0.083770975)
|
||||
bones/168/scale = Vector3(1.0000011, 1.0000015, 1.0000101)
|
||||
bones/170/position = Vector3(0.748137, 0.69556385, 3.7252903e-09)
|
||||
bones/170/rotation = Quaternion(0.019250846, -0.20323181, 0.9789406, 0.001253055)
|
||||
bones/171/position = Vector3(0.6322718, -2.6572587, 0.6064028)
|
||||
bones/172/position = Vector3(-1.5122895, 4.4686184, -2.7014794)
|
||||
bones/172/rotation = Quaternion(0.21553025, -0.03620148, 0.11066054, 0.9695311)
|
||||
bones/172/scale = Vector3(0.99999887, 0.9999985, 1.0000024)
|
||||
bones/173/position = Vector3(0.18381546, -0.96226203, 0.9894083)
|
||||
bones/173/rotation = Quaternion(0.93622434, -2.9748788e-08, 0.34127158, -0.083771475)
|
||||
bones/173/scale = Vector3(0.999999, 1.0000014, 0.99999464)
|
||||
bones/175/position = Vector3(0.2542465, -2.2077389, 0.9589075)
|
||||
bones/175/rotation = Quaternion(-0.008919476, -0.00021326332, -0.000697989, 0.99996)
|
||||
bones/183/position = Vector3(-1.982537e-07, 5.9604563e-08, -1.517833e-08)
|
||||
bones/185/rotation = Quaternion(5.4077844e-07, -0.20349081, 0.97907686, -1.12395135e-07)
|
||||
bones/186/position = Vector3(0.57634556, 3.7607954, 0.15364014)
|
||||
bones/186/rotation = Quaternion(-0.9604305, -0.020206233, -0.08076539, -0.26578543)
|
||||
bones/186/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/187/rotation = Quaternion(0.15451065, -2.0305349e-09, -2.0850066e-09, 0.9879911)
|
||||
bones/187/scale = Vector3(1.0000002, 0.99999994, 0.9999999)
|
||||
bones/197/position = Vector3(-0.0011225368, -0.015787723, -0.051779967)
|
||||
bones/199/rotation = Quaternion(0.00034800146, -0.20349097, 0.9790768, -7.2328476e-05)
|
||||
bones/200/position = Vector3(-1.0407574, 3.6267605, -0.083099455)
|
||||
bones/200/rotation = Quaternion(-0.9604305, -0.020206233, -0.08076539, -0.26578543)
|
||||
bones/200/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/201/rotation = Quaternion(0.15451066, -1.9585848e-09, -2.5450761e-09, 0.9879911)
|
||||
bones/201/scale = Vector3(1.0000002, 0.99999994, 0.99999994)
|
||||
|
||||
[editable path="bear_model"]
|
||||
[editable path="bear_model/test_cube/Bear_FX"]
|
||||
@@ -0,0 +1,319 @@
|
||||
[gd_scene format=3 uid="uid://o8ocjfprxa7u"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cn7fhjkro7637" path="res://bear.gd" id="1_beargd"]
|
||||
[ext_resource type="PackedScene" uid="uid://cofv5dbavesis" path="res://Assets/Bear.glb" id="2_bearglb"]
|
||||
[ext_resource type="Script" uid="uid://bsbed05ifr18s" path="res://bear_test_cube.gd" id="3_rog1v"]
|
||||
[ext_resource type="PackedScene" uid="uid://bdbx0wwa73rhp" path="res://Assets/fx/Bear_FX.glb" id="4_rog1v"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_body"]
|
||||
radius = 1.0
|
||||
height = 2.4
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_hit"]
|
||||
radius = 1.3
|
||||
height = 2.7
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_bfebr"]
|
||||
size = Vector3(6.2019043, 8.561401, 7.0739746)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_rog1v"]
|
||||
size = Vector3(14.399288, 51.902206, 5.741211)
|
||||
|
||||
[node name="Bear" type="CharacterBody3D" unique_id=1573237287]
|
||||
script = ExtResource("1_beargd")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=830443382]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2, 0)
|
||||
shape = SubResource("CapsuleShape3D_body")
|
||||
|
||||
[node name="HitArea" type="Area3D" parent="." unique_id=365327397]
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="HitArea" unique_id=2111867348]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.35, 0)
|
||||
shape = SubResource("CapsuleShape3D_hit")
|
||||
|
||||
[node name="bear_model" parent="." unique_id=359217823 instance=ExtResource("2_bearglb")]
|
||||
|
||||
[node name="test_cube" type="Node3D" parent="bear_model" unique_id=646988893]
|
||||
script = ExtResource("3_rog1v")
|
||||
|
||||
[node name="Bear_FX" parent="bear_model/test_cube" unique_id=1183391245 instance=ExtResource("4_rog1v")]
|
||||
|
||||
[node name="Bear_fx_jump_smash" parent="bear_model/test_cube/Bear_FX" index="0" unique_id=750478984]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_claw_attack_R" parent="bear_model/test_cube/Bear_FX" index="1" unique_id=88064381]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_claw_attack_L" parent="bear_model/test_cube/Bear_FX" index="2" unique_id=1378755061]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_smash_hit" parent="bear_model/test_cube/Bear_FX" index="3" unique_id=1711579105]
|
||||
transform = Transform3D(0.55488384, -0.039024748, -0.018949924, 0.041069064, 0.55086076, 0.06814586, 0.013977209, -0.06933683, 0.5520644, 1.327292, -0.21312934, 5.190573)
|
||||
|
||||
[node name="RigidBody3D" type="AnimatableBody3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit" index="0" unique_id=1764208051]
|
||||
transform = Transform3D(1.0000001, -1.21071935e-08, -1.8626451e-08, -9.313226e-10, 0.99999994, 7.450581e-09, 3.7252903e-09, -1.4901161e-08, 0.99999994, 0, 0, 0)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
|
||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit/RigidBody3D" unique_id=1779197150]
|
||||
transform = Transform3D(0.99993557, -0.00749125, -0.010078691, 0.0077760145, 0.999569, 0.028562747, 0.009858355, -0.028639637, 0.9995405, -1.5136471, 0.9093375, 35.591957)
|
||||
shape = SubResource("BoxShape3D_bfebr")
|
||||
disabled = true
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit/RigidBody3D" unique_id=1276552823]
|
||||
transform = Transform3D(0.9935104, -0.040698394, -0.10621016, -0.108634494, -0.06290151, -0.9920882, 0.03369555, 0.99719334, -0.06691426, -1.6357545, -0.5093044, 12.68803)
|
||||
shape = SubResource("BoxShape3D_rog1v")
|
||||
|
||||
[node name="Skeleton3D" parent="bear_model/bear-rig" parent_id_path=PackedInt32Array(359217823, 1017999212) index="0" unique_id=1624609914]
|
||||
bones/1/position = Vector3(0.00851878, 0.24701798, 1.2888045)
|
||||
bones/1/rotation = Quaternion(0.29791054, -0.060797628, -0.056875575, 0.9509564)
|
||||
bones/2/rotation = Quaternion(0.084239505, -0.026013458, 0.009274505, 0.9960628)
|
||||
bones/2/scale = Vector3(0.9999999, 1.0000008, 0.99999934)
|
||||
bones/3/rotation = Quaternion(-0.14812404, -0.039577905, 0.049865585, 0.98691756)
|
||||
bones/4/rotation = Quaternion(-0.40577498, -0.03082885, 0.05040324, 0.9120612)
|
||||
bones/5/rotation = Quaternion(0.27801633, 0.0014148077, 0.015671793, 0.96044755)
|
||||
bones/6/rotation = Quaternion(0.50370073, 0.13519946, -0.093789615, 0.8480627)
|
||||
bones/7/rotation = Quaternion(0.75079185, 0.54212743, -0.37154716, 0.06604591)
|
||||
bones/8/rotation = Quaternion(0.22344273, -0.32689556, 0.65874565, -0.63973963)
|
||||
bones/9/rotation = Quaternion(0.026405705, -0.27415153, -0.3226086, 0.9055757)
|
||||
bones/10/rotation = Quaternion(0.030285481, -0.31167626, -0.037417818, 0.94896823)
|
||||
bones/11/rotation = Quaternion(0.751943, -0.5788067, 0.30500817, 0.080837056)
|
||||
bones/12/rotation = Quaternion(0.28422552, 0.2936944, -0.68526876, -0.6027987)
|
||||
bones/13/rotation = Quaternion(0.020711409, 0.24585825, 0.3386082, 0.9080029)
|
||||
bones/14/rotation = Quaternion(0.098969, 0.19860524, -0.007872087, 0.97503805)
|
||||
bones/15/rotation = Quaternion(0.6979166, 0.16086513, -0.15598965, 0.680222)
|
||||
bones/16/rotation = Quaternion(0.89734674, 0.09874082, -0.25790086, 0.34424722)
|
||||
bones/17/rotation = Quaternion(-0.13802421, 0.26758972, 0.081159085, 0.9501359)
|
||||
bones/17/scale = Vector3(0.9999998, 1.0000002, 1)
|
||||
bones/19/rotation = Quaternion(-4.514978e-15, 1, 7.4505806e-08, -5.523351e-07)
|
||||
bones/20/rotation = Quaternion(-0.49266306, -0.27058616, 0.262383, 0.7843606)
|
||||
bones/21/rotation = Quaternion(0.0016915401, 0.70246154, -0.001669446, 0.7117178)
|
||||
bones/22/rotation = Quaternion(-0.5496364, -0.3220462, -0.22350304, 0.73772115)
|
||||
bones/22/scale = Vector3(0.9999997, 0.9999998, 0.9999999)
|
||||
bones/23/rotation = Quaternion(-0.00015351747, 0.902104, -0.4315187, 0.00032039074)
|
||||
bones/24/rotation = Quaternion(6.628114e-12, 0.99999994, 5.2154085e-08, -0.00035543842)
|
||||
bones/25/position = Vector3(1.0191536, 3.5353048, 3.5049686)
|
||||
bones/25/rotation = Quaternion(-0.087474234, 0.16733547, 0.98056763, 0.053239316)
|
||||
bones/25/scale = Vector3(1, 17.518272, 1.0000001)
|
||||
bones/26/position = Vector3(-1.0831825, 3.749937, 2.5891113)
|
||||
bones/26/rotation = Quaternion(0.016340872, 0.19671263, 0.9801456, 0.01875816)
|
||||
bones/26/scale = Vector3(1.0000001, 18.765795, 1)
|
||||
bones/27/position = Vector3(1.0193456, -0.43209565, 2.5343885)
|
||||
bones/27/rotation = Quaternion(0.61800283, -0.11976056, 0.11976072, 0.7677157)
|
||||
bones/27/scale = Vector3(0.99999994, 16.85072, 1)
|
||||
bones/28/position = Vector3(-0.8340287, 1.0348616, 1.282705)
|
||||
bones/28/rotation = Quaternion(0.82860446, -0.029359974, 0.02935981, 0.5582926)
|
||||
bones/28/scale = Vector3(0.99999994, 32.068844, 1)
|
||||
bones/30/position = Vector3(0.032563455, -0.8335703, -0.9236449)
|
||||
bones/30/rotation = Quaternion(-0.8670657, 0.042821795, -0.07139772, 0.4911883)
|
||||
bones/31/position = Vector3(2.3450447e-08, -1.4631646, 0.23291242)
|
||||
bones/31/rotation = Quaternion(-6.0737464e-09, 4.8699293e-09, -1.4618977e-09, 1)
|
||||
bones/31/scale = Vector3(0.99999994, 0.9999999, 0.99999994)
|
||||
bones/32/position = Vector3(-0.04394375, -1.087056, 0.096768975)
|
||||
bones/32/rotation = Quaternion(-0.8343034, 0.119118, -0.061490715, 0.5347595)
|
||||
bones/32/scale = Vector3(0.9999999, 0.99999976, 0.99999964)
|
||||
bones/33/position = Vector3(3.977649e-08, -1.4631644, 0.23291251)
|
||||
bones/33/rotation = Quaternion(-8.833673e-08, -2.419923e-08, -6.733043e-09, 1)
|
||||
bones/33/scale = Vector3(0.9999998, 0.9999998, 0.99999994)
|
||||
bones/35/position = Vector3(1.0184407e-08, -1.0594703, -5.9146995e-08)
|
||||
bones/35/rotation = Quaternion(0.99971783, 1.3593646e-07, 5.3695976e-06, -0.023754615)
|
||||
bones/35/scale = Vector3(0.99999976, 0.9999998, 1.0000012)
|
||||
bones/39/position = Vector3(0.8199172, 0.25251278, 0.47214246)
|
||||
bones/39/rotation = Quaternion(0.71402234, 0.34199142, 0.043267474, 0.60937834)
|
||||
bones/39/scale = Vector3(1.0000004, 0.9999996, 0.9999991)
|
||||
bones/40/rotation = Quaternion(0.9336719, 1.2799235e-07, 3.7337827e-08, 0.3581296)
|
||||
bones/40/scale = Vector3(1.0000004, 1.0000001, 1.0000001)
|
||||
bones/41/rotation = Quaternion(-0.13802455, 0.26758966, 0.08115916, 0.9501359)
|
||||
bones/41/scale = Vector3(0.99999946, 0.99999976, 0.9999996)
|
||||
bones/42/position = Vector3(-1.9729964e-07, 0.56145483, 7.283501e-08)
|
||||
bones/46/scale = Vector3(0.99999946, 0.99999964, 0.9999999)
|
||||
bones/48/rotation = Quaternion(-2.9741386e-07, 0.13593404, 1.01778824e-07, 0.9907179)
|
||||
bones/48/scale = Vector3(0.9999993, 0.9999996, 0.9999999)
|
||||
bones/50/scale = Vector3(0.99999994, 0.99999994, 0.9999998)
|
||||
bones/51/rotation = Quaternion(-2.5567479e-08, -0.20499781, -2.3086146e-08, 0.9787625)
|
||||
bones/51/scale = Vector3(0.9999999, 0.99999964, 0.99999964)
|
||||
bones/53/position = Vector3(-0.8199191, 0.25251284, 0.47213903)
|
||||
bones/53/rotation = Quaternion(-0.5351706, 0.35860845, -0.15898216, 0.74814254)
|
||||
bones/53/scale = Vector3(1, 0.99999875, 0.99999946)
|
||||
bones/54/rotation = Quaternion(0.0023762286, -4.7362324e-08, -6.475868e-08, 0.9999972)
|
||||
bones/55/rotation = Quaternion(-0.54963607, -0.322046, -0.22350314, 0.73772144)
|
||||
bones/55/scale = Vector3(1.0000002, 1, 1.0000002)
|
||||
bones/56/position = Vector3(0.0013532753, 0.57868266, 0.05537574)
|
||||
bones/56/rotation = Quaternion(-0.00015348212, 0.90210384, -0.43151882, 0.0003204293)
|
||||
bones/57/rotation = Quaternion(0.70073944, -0.70073956, -0.094679825, -0.09467953)
|
||||
bones/60/scale = Vector3(1.0000004, 1.0000004, 1.0000002)
|
||||
bones/62/rotation = Quaternion(-1.7092354e-08, -0.18223058, 2.6700846e-08, 0.98325586)
|
||||
bones/62/scale = Vector3(1.0000002, 1.0000002, 1.0000001)
|
||||
bones/64/scale = Vector3(1.0000004, 1.0000004, 1)
|
||||
bones/65/rotation = Quaternion(-1.0345744e-08, -0.3796584, -4.0675246e-08, 0.9251268)
|
||||
bones/65/scale = Vector3(1.0000002, 1.0000004, 1.0000004)
|
||||
bones/67/rotation = Quaternion(0.7179022, -7.671307e-07, 7.885642e-07, 0.696144)
|
||||
bones/67/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/68/rotation = Quaternion(0.9776482, 2.0029378e-07, 1.0460874e-06, -0.2102479)
|
||||
bones/68/scale = Vector3(1.0000004, 1.0000004, 0.9999982)
|
||||
bones/69/position = Vector3(-2.4645832e-08, -6.861796e-09, 7.455772e-08)
|
||||
bones/69/rotation = Quaternion(-0.8315212, 2.5276703e-08, -9.3330055e-09, 0.5554931)
|
||||
bones/69/scale = Vector3(1, 1.0000001, 1.0000002)
|
||||
bones/70/rotation = Quaternion(0.67750055, 8.820757e-08, 7.575834e-08, 0.7355223)
|
||||
bones/70/scale = Vector3(1, 1, 1)
|
||||
bones/71/scale = Vector3(0.9999999, 1, 0.9999999)
|
||||
bones/72/rotation = Quaternion(-2.1641608e-07, -4.6565607e-10, -4.6576065e-10, 1)
|
||||
bones/75/rotation = Quaternion(-0.34314692, -0.20321459, -0.2785586, 0.8737043)
|
||||
bones/76/position = Vector3(1.01587794e-07, -1.5306958e-07, -4.3554866e-07)
|
||||
bones/76/rotation = Quaternion(-0.51764834, -7.167482e-08, 1.7163823e-07, 0.85559356)
|
||||
bones/77/rotation = Quaternion(0.93367195, 1.2110854e-07, 3.8556042e-08, 0.35812962)
|
||||
bones/78/position = Vector3(0.8199172, 0.25251257, 0.47214243)
|
||||
bones/78/rotation = Quaternion(0.6979164, 0.16086517, -0.15598962, 0.6802223)
|
||||
bones/78/scale = Vector3(1.0000004, 0.9999997, 0.99999905)
|
||||
bones/80/rotation = Quaternion(0.7179022, -7.6713064e-07, 7.885641e-07, 0.696144)
|
||||
bones/80/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/81/rotation = Quaternion(0.97764814, 1.9846473e-07, 1.0426893e-06, -0.21024783)
|
||||
bones/81/scale = Vector3(1.0000004, 1.0000002, 0.9999982)
|
||||
bones/82/position = Vector3(6.103571e-08, 8.8816435e-08, -3.6955274e-09)
|
||||
bones/82/rotation = Quaternion(-0.8315211, 2.3407136e-08, -1.2821512e-08, 0.5554932)
|
||||
bones/82/scale = Vector3(0.99999994, 0.99999994, 1)
|
||||
bones/83/rotation = Quaternion(0.6775009, -8.600083e-08, -8.977273e-08, 0.735522)
|
||||
bones/83/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/84/scale = Vector3(0.99999994, 1.0000001, 0.9999999)
|
||||
bones/85/rotation = Quaternion(2.6833732e-07, -9.313788e-10, -2.5612494e-09, 1)
|
||||
bones/85/scale = Vector3(1.0000001, 1, 1.0000001)
|
||||
bones/87/rotation = Quaternion(-0.5230753, 0.20132942, 0.026226493, 0.8277505)
|
||||
bones/88/rotation = Quaternion(0.61967987, 0.23118778, 0.3169036, 0.679795)
|
||||
bones/89/position = Vector3(2.953037e-07, 4.9207458e-08, -4.3015167e-08)
|
||||
bones/89/rotation = Quaternion(-0.001144886, -2.973514e-08, 2.817069e-08, 0.9999994)
|
||||
bones/90/rotation = Quaternion(0.0023764072, -4.0769752e-08, -7.0690255e-08, 0.99999726)
|
||||
bones/91/position = Vector3(-0.8199192, 0.2525128, 0.47213912)
|
||||
bones/91/rotation = Quaternion(-0.49266297, -0.27058598, 0.2623832, 0.78436047)
|
||||
bones/91/scale = Vector3(1.0000002, 0.999999, 0.99999964)
|
||||
bones/96/position = Vector3(-0.021971898, -1.2751104, 0.16484088)
|
||||
bones/96/rotation = Quaternion(-0.47603267, 0.067788206, -0.035077166, 0.8761091)
|
||||
bones/96/scale = Vector3(0.9999999, 0.9999999, 0.99999976)
|
||||
bones/97/rotation = Quaternion(0.997074, -1.2813135e-07, 1.666339e-06, -0.07644201)
|
||||
bones/98/position = Vector3(0.01993539, 0.08757691, 0.045667563)
|
||||
bones/98/rotation = Quaternion(0.1475291, 0.03397043, -0.019923227, 0.9882734)
|
||||
bones/98/scale = Vector3(1, 1.0000011, 1.0000023)
|
||||
bones/101/position = Vector3(-0.021972047, 0.8282039, 0.0959422)
|
||||
bones/101/rotation = Quaternion(0.8371564, 0.04015539, 0.06490996, 0.5416119)
|
||||
bones/101/scale = Vector3(1, 1.0000066, 0.99998474)
|
||||
bones/102/rotation = Quaternion(0.95545256, -6.924111e-08, 2.2887033e-07, -0.29514462)
|
||||
bones/103/position = Vector3(0.17285576, 0.72785676, 1.0822707)
|
||||
bones/103/rotation = Quaternion(0.27801546, 0.0014157619, 0.015671493, 0.9604477)
|
||||
bones/103/scale = Vector3(1.0000002, 1.000013, 1.0000246)
|
||||
bones/104/rotation = Quaternion(0.5037003, 0.13519715, -0.093790196, 0.84806323)
|
||||
bones/104/scale = Vector3(1.0000721, 1.0000457, 0.99993384)
|
||||
bones/105/rotation = Quaternion(0.97757924, -0.053521663, -0.054415643, -0.19624804)
|
||||
bones/105/scale = Vector3(1.0000001, 1.0000083, 1.0000036)
|
||||
bones/106/position = Vector3(0.023142539, -0.54231995, -0.9607401)
|
||||
bones/106/rotation = Quaternion(0.99272084, -0.08158898, -0.03307842, -0.08218607)
|
||||
bones/107/rotation = Quaternion(0.903578, -0.12777254, -0.05477002, -0.4052421)
|
||||
bones/107/scale = Vector3(0.9999992, 0.9999624, 1.0000123)
|
||||
bones/108/position = Vector3(-1.1340098e-08, 7.923448e-07, 9.0939814e-08)
|
||||
bones/108/rotation = Quaternion(0.98967296, 0.0031370325, 0.10343237, -0.09919364)
|
||||
bones/110/rotation = Quaternion(9.815354e-07, 7.072085e-10, -9.586452e-08, 1)
|
||||
bones/110/scale = Vector3(0.99999994, 0.99999976, 1.0000001)
|
||||
bones/113/position = Vector3(0.07716276, 0.6410925, 0.71644557)
|
||||
bones/113/rotation = Quaternion(0.75079244, 0.54212654, -0.3715475, 0.0660462)
|
||||
bones/114/position = Vector3(-0.031743176, 0.60466695, -0.39704067)
|
||||
bones/114/rotation = Quaternion(0.4176498, -0.11118397, 0.55639553, -0.70966953)
|
||||
bones/114/scale = Vector3(1.0000015, 1.0000038, 1.0000079)
|
||||
bones/115/rotation = Quaternion(-0.07547326, 0.02173067, -0.31477332, 0.945912)
|
||||
bones/115/scale = Vector3(0.9999974, 1.0000036, 0.99999976)
|
||||
bones/116/rotation = Quaternion(0.03028559, -0.3116764, -0.037417784, 0.9489682)
|
||||
bones/116/scale = Vector3(1.0000005, 0.9999972, 1.0000013)
|
||||
bones/119/scale = Vector3(1.0000043, 0.9999975, 0.99999744)
|
||||
bones/121/rotation = Quaternion(-4.820391e-08, -0.1579088, -2.0880496e-08, 0.98745376)
|
||||
bones/121/scale = Vector3(1.0000037, 0.99999774, 0.9999977)
|
||||
bones/123/scale = Vector3(1.000003, 0.9999977, 0.99999917)
|
||||
bones/124/rotation = Quaternion(-3.1036683e-07, 0.17317644, 6.989145e-08, 0.9848908)
|
||||
bones/124/scale = Vector3(1.0000037, 0.9999978, 0.99999875)
|
||||
bones/126/rotation = Quaternion(-0.5163543, -0.16816929, 0.6340875, 0.550482)
|
||||
bones/126/scale = Vector3(1.0000015, 1.000007, 1.000004)
|
||||
bones/127/rotation = Quaternion(-0.24332331, 0.12663932, 0.6612194, 0.6982444)
|
||||
bones/127/scale = Vector3(1.0000017, 1.0000014, 1.0000097)
|
||||
bones/128/position = Vector3(-0.008928956, 0.128764, -0.06877987)
|
||||
bones/128/rotation = Quaternion(0.025037244, 0.39930493, -0.88358396, 0.24332726)
|
||||
bones/129/rotation = Quaternion(-0.07547334, 0.021730714, -0.31477335, 0.94591194)
|
||||
bones/131/rotation = Quaternion(-0.41802245, -0.28161782, 0.08442414, 0.85954714)
|
||||
bones/132/rotation = Quaternion(-0.5281791, -0.34319904, -0.62196887, -0.46518382)
|
||||
bones/133/rotation = Quaternion(-0.012777329, 0.011854946, 0.00015161165, 0.9998482)
|
||||
bones/133/scale = Vector3(1.0423008, 1.0423008, 1.0423006)
|
||||
bones/134/rotation = Quaternion(0.02152103, -3.688601e-08, -1.5255387e-07, 0.99976844)
|
||||
bones/134/scale = Vector3(0.9882629, 0.9882634, 0.98826265)
|
||||
bones/135/position = Vector3(-0.0317431, 0.60466677, -0.39704087)
|
||||
bones/135/rotation = Quaternion(0.22344373, -0.32689255, 0.658746, -0.6397405)
|
||||
bones/135/scale = Vector3(1.0000048, 1.0000036, 1.0000046)
|
||||
bones/137/position = Vector3(-0.33244255, 0.70370555, 0.67530614)
|
||||
bones/137/rotation = Quaternion(0.7519437, -0.5788053, 0.30500948, 0.08083551)
|
||||
bones/138/position = Vector3(-0.19594865, 0.65740275, -0.22511396)
|
||||
bones/138/rotation = Quaternion(0.36201134, 0.22157827, -0.6475769, -0.63284683)
|
||||
bones/138/scale = Vector3(1.0000019, 1.0000045, 1.0000057)
|
||||
bones/139/rotation = Quaternion(-0.018797327, 0.13857716, 0.33871746, 0.9304373)
|
||||
bones/139/scale = Vector3(0.9999983, 1.0000024, 0.9999992)
|
||||
bones/140/rotation = Quaternion(0.09896898, 0.1986053, -0.00787212, 0.975038)
|
||||
bones/140/scale = Vector3(1.0000031, 0.9999977, 0.9999988)
|
||||
bones/143/scale = Vector3(1.000005, 0.99999815, 0.9999967)
|
||||
bones/145/rotation = Quaternion(-1.7910523e-07, 0.10005118, -9.714451e-08, 0.9949823)
|
||||
bones/145/scale = Vector3(1.0000045, 0.99999803, 0.9999968)
|
||||
bones/147/scale = Vector3(1.0000035, 0.99999845, 0.9999981)
|
||||
bones/148/rotation = Quaternion(2.0844507e-07, 0.011625211, 4.5709146e-07, 0.9999325)
|
||||
bones/148/scale = Vector3(1.000004, 0.9999991, 0.999998)
|
||||
bones/150/rotation = Quaternion(-0.51635444, 0.16816957, -0.63408744, 0.55048186)
|
||||
bones/150/scale = Vector3(1.000001, 1.0000067, 1.000004)
|
||||
bones/151/rotation = Quaternion(-0.24332346, -0.12663896, -0.6612195, 0.6982443)
|
||||
bones/151/scale = Vector3(1.0000011, 1.0000017, 1.0000095)
|
||||
bones/152/position = Vector3(0.027921734, -0.124764316, 0.07102555)
|
||||
bones/152/rotation = Quaternion(-0.12973516, 0.47151387, -0.86254627, -0.12983702)
|
||||
bones/153/rotation = Quaternion(-0.018797398, 0.13857722, 0.33871746, 0.9304373)
|
||||
bones/155/rotation = Quaternion(-0.36541468, 0.16190512, -0.07102372, 0.91390073)
|
||||
bones/155/scale = Vector3(0.99999994, 1, 0.9999998)
|
||||
bones/156/rotation = Quaternion(0.68045896, -0.19169958, -0.3896983, 0.59022206)
|
||||
bones/157/rotation = Quaternion(-0.01277751, -0.011854968, -0.0001513001, 0.9998481)
|
||||
bones/157/scale = Vector3(1.0423003, 1.0422994, 1.0423005)
|
||||
bones/158/rotation = Quaternion(0.021521209, -2.5687226e-07, -2.570953e-07, 0.9997684)
|
||||
bones/158/scale = Vector3(0.9882631, 0.98826426, 0.9882618)
|
||||
bones/159/position = Vector3(-0.19594839, 0.65740275, -0.2251139)
|
||||
bones/159/rotation = Quaternion(0.28422734, 0.29369113, -0.68527013, -0.60279787)
|
||||
bones/159/scale = Vector3(1.0000027, 1.0000043, 1.0000049)
|
||||
bones/161/position = Vector3(0.07716276, 0.6410925, 0.71644557)
|
||||
bones/161/rotation = Quaternion(0.75079244, 0.54212654, -0.3715475, 0.0660462)
|
||||
bones/162/position = Vector3(-0.33244255, 0.70370555, 0.67530614)
|
||||
bones/162/rotation = Quaternion(0.7519437, -0.5788053, 0.30500948, 0.08083551)
|
||||
bones/165/position = Vector3(-1.5017577e-08, 0.26895812, -1.6243575e-08)
|
||||
bones/165/rotation = Quaternion(-0.019247467, -0.20323175, 0.97894067, -0.0012537595)
|
||||
bones/166/position = Vector3(0.0034187725, -3.131728, 0.9674823)
|
||||
bones/167/position = Vector3(0.209171, 5.0901713, -2.6670303)
|
||||
bones/167/rotation = Quaternion(0.16656846, 0.015223213, 0.18356222, 0.9686734)
|
||||
bones/167/scale = Vector3(0.9999988, 0.9999987, 1.0000023)
|
||||
bones/168/position = Vector3(0.18381567, -0.9622623, 0.9894084)
|
||||
bones/168/rotation = Quaternion(0.9362244, -6.2652596e-08, -0.34127164, -0.083770975)
|
||||
bones/168/scale = Vector3(1.0000011, 1.0000015, 1.0000101)
|
||||
bones/170/position = Vector3(0.748137, 0.69556385, 3.7252903e-09)
|
||||
bones/170/rotation = Quaternion(0.019250846, -0.20323181, 0.9789406, 0.001253055)
|
||||
bones/171/position = Vector3(0.6322718, -2.6572587, 0.6064028)
|
||||
bones/172/position = Vector3(-1.5122895, 4.4686184, -2.7014794)
|
||||
bones/172/rotation = Quaternion(0.21553025, -0.03620148, 0.11066054, 0.9695311)
|
||||
bones/172/scale = Vector3(0.99999887, 0.9999985, 1.0000024)
|
||||
bones/173/position = Vector3(0.18381546, -0.96226203, 0.9894083)
|
||||
bones/173/rotation = Quaternion(0.93622434, -2.9748788e-08, 0.34127158, -0.083771475)
|
||||
bones/173/scale = Vector3(0.999999, 1.0000014, 0.99999464)
|
||||
bones/175/position = Vector3(0.2542465, -2.2077389, 0.9589075)
|
||||
bones/175/rotation = Quaternion(-0.008919476, -0.00021326332, -0.000697989, 0.99996)
|
||||
bones/183/position = Vector3(-1.982537e-07, 5.9604563e-08, -1.517833e-08)
|
||||
bones/185/rotation = Quaternion(5.4077844e-07, -0.20349081, 0.97907686, -1.12395135e-07)
|
||||
bones/186/position = Vector3(0.57634556, 3.7607954, 0.15364014)
|
||||
bones/186/rotation = Quaternion(-0.9604305, -0.020206233, -0.08076539, -0.26578543)
|
||||
bones/186/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/187/rotation = Quaternion(0.15451065, -2.0305349e-09, -2.0850066e-09, 0.9879911)
|
||||
bones/187/scale = Vector3(1.0000002, 0.99999994, 0.9999999)
|
||||
bones/197/position = Vector3(-0.0011225368, -0.015787723, -0.051779967)
|
||||
bones/199/rotation = Quaternion(0.00034800146, -0.20349097, 0.9790768, -7.2328476e-05)
|
||||
bones/200/position = Vector3(-1.0407574, 3.6267605, -0.083099455)
|
||||
bones/200/rotation = Quaternion(-0.9604305, -0.020206233, -0.08076539, -0.26578543)
|
||||
bones/200/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/201/rotation = Quaternion(0.15451066, -1.9585848e-09, -2.5450761e-09, 0.9879911)
|
||||
bones/201/scale = Vector3(1.0000002, 0.99999994, 0.99999994)
|
||||
|
||||
[editable path="bear_model"]
|
||||
[editable path="bear_model/test_cube/Bear_FX"]
|
||||
@@ -0,0 +1,319 @@
|
||||
[gd_scene format=3 uid="uid://o8ocjfprxa7u"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cn7fhjkro7637" path="res://bear.gd" id="1_beargd"]
|
||||
[ext_resource type="PackedScene" uid="uid://cofv5dbavesis" path="res://Assets/Bear.glb" id="2_bearglb"]
|
||||
[ext_resource type="Script" uid="uid://bsbed05ifr18s" path="res://bear_test_cube.gd" id="3_rog1v"]
|
||||
[ext_resource type="PackedScene" uid="uid://bdbx0wwa73rhp" path="res://Assets/fx/Bear_FX.glb" id="4_rog1v"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_body"]
|
||||
radius = 1.0
|
||||
height = 2.4
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_hit"]
|
||||
radius = 1.3
|
||||
height = 2.7
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_bfebr"]
|
||||
size = Vector3(6.2019043, 8.561401, 7.0739746)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_rog1v"]
|
||||
size = Vector3(14.399288, 51.902206, 5.741211)
|
||||
|
||||
[node name="Bear" type="CharacterBody3D" unique_id=1573237287]
|
||||
script = ExtResource("1_beargd")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=830443382]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2, 0)
|
||||
shape = SubResource("CapsuleShape3D_body")
|
||||
|
||||
[node name="HitArea" type="Area3D" parent="." unique_id=365327397]
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="HitArea" unique_id=2111867348]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.35, 0)
|
||||
shape = SubResource("CapsuleShape3D_hit")
|
||||
|
||||
[node name="bear_model" parent="." unique_id=359217823 instance=ExtResource("2_bearglb")]
|
||||
|
||||
[node name="test_cube" type="Node3D" parent="bear_model" unique_id=646988893]
|
||||
script = ExtResource("3_rog1v")
|
||||
|
||||
[node name="Bear_FX" parent="bear_model/test_cube" unique_id=1183391245 instance=ExtResource("4_rog1v")]
|
||||
|
||||
[node name="Bear_fx_jump_smash" parent="bear_model/test_cube/Bear_FX" index="0" unique_id=750478984]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_claw_attack_R" parent="bear_model/test_cube/Bear_FX" index="1" unique_id=88064381]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_claw_attack_L" parent="bear_model/test_cube/Bear_FX" index="2" unique_id=1378755061]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_smash_hit" parent="bear_model/test_cube/Bear_FX" index="3" unique_id=1711579105]
|
||||
transform = Transform3D(0.55488384, -0.039024748, -0.018949924, 0.041069064, 0.55086076, 0.06814586, 0.013977209, -0.06933683, 0.5520644, 1.327292, -0.21312934, 5.190573)
|
||||
|
||||
[node name="RigidBody3D" type="AnimatableBody3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit" index="0" unique_id=1764208051]
|
||||
transform = Transform3D(1.0000001, -1.21071935e-08, -1.8626451e-08, -9.313226e-10, 0.99999994, 7.450581e-09, 3.7252903e-09, -1.4901161e-08, 0.99999994, 0, 0, 0)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
|
||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit/RigidBody3D" unique_id=1779197150]
|
||||
transform = Transform3D(0.99993557, -0.00749125, -0.010078691, 0.0077760145, 0.999569, 0.028562747, 0.009858355, -0.028639637, 0.9995405, -1.5136471, 0.9093375, 35.591957)
|
||||
shape = SubResource("BoxShape3D_bfebr")
|
||||
disabled = true
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit/RigidBody3D" unique_id=1276552823]
|
||||
transform = Transform3D(0.9935104, -0.040698394, -0.10621016, -0.108634494, -0.06290151, -0.9920882, 0.03369555, 0.99719334, -0.06691426, -1.6357545, -0.5093044, 12.68803)
|
||||
shape = SubResource("BoxShape3D_rog1v")
|
||||
|
||||
[node name="Skeleton3D" parent="bear_model/bear-rig" parent_id_path=PackedInt32Array(359217823, 1017999212) index="0" unique_id=1624609914]
|
||||
bones/1/position = Vector3(0.00851878, 0.24701798, 1.2888045)
|
||||
bones/1/rotation = Quaternion(0.29791054, -0.060797628, -0.056875575, 0.9509564)
|
||||
bones/2/rotation = Quaternion(0.084239505, -0.026013458, 0.009274505, 0.9960628)
|
||||
bones/2/scale = Vector3(0.9999999, 1.0000008, 0.99999934)
|
||||
bones/3/rotation = Quaternion(-0.14812404, -0.039577905, 0.049865585, 0.98691756)
|
||||
bones/4/rotation = Quaternion(-0.40577498, -0.03082885, 0.05040324, 0.9120612)
|
||||
bones/5/rotation = Quaternion(0.27801633, 0.0014148077, 0.015671793, 0.96044755)
|
||||
bones/6/rotation = Quaternion(0.50370073, 0.13519946, -0.093789615, 0.8480627)
|
||||
bones/7/rotation = Quaternion(0.75079185, 0.54212743, -0.37154716, 0.06604591)
|
||||
bones/8/rotation = Quaternion(0.22344273, -0.32689556, 0.65874565, -0.63973963)
|
||||
bones/9/rotation = Quaternion(0.026405705, -0.27415153, -0.3226086, 0.9055757)
|
||||
bones/10/rotation = Quaternion(0.030285481, -0.31167626, -0.037417818, 0.94896823)
|
||||
bones/11/rotation = Quaternion(0.751943, -0.5788067, 0.30500817, 0.080837056)
|
||||
bones/12/rotation = Quaternion(0.28422552, 0.2936944, -0.68526876, -0.6027987)
|
||||
bones/13/rotation = Quaternion(0.020711409, 0.24585825, 0.3386082, 0.9080029)
|
||||
bones/14/rotation = Quaternion(0.098969, 0.19860524, -0.007872087, 0.97503805)
|
||||
bones/15/rotation = Quaternion(0.6979166, 0.16086513, -0.15598965, 0.680222)
|
||||
bones/16/rotation = Quaternion(0.89734674, 0.09874082, -0.25790086, 0.34424722)
|
||||
bones/17/rotation = Quaternion(-0.13802421, 0.26758972, 0.081159085, 0.9501359)
|
||||
bones/17/scale = Vector3(0.9999998, 1.0000002, 1)
|
||||
bones/19/rotation = Quaternion(-4.514978e-15, 1, 7.4505806e-08, -5.523351e-07)
|
||||
bones/20/rotation = Quaternion(-0.49266306, -0.27058616, 0.262383, 0.7843606)
|
||||
bones/21/rotation = Quaternion(0.0016915401, 0.70246154, -0.001669446, 0.7117178)
|
||||
bones/22/rotation = Quaternion(-0.5496364, -0.3220462, -0.22350304, 0.73772115)
|
||||
bones/22/scale = Vector3(0.9999997, 0.9999998, 0.9999999)
|
||||
bones/23/rotation = Quaternion(-0.00015351747, 0.902104, -0.4315187, 0.00032039074)
|
||||
bones/24/rotation = Quaternion(6.628114e-12, 0.99999994, 5.2154085e-08, -0.00035543842)
|
||||
bones/25/position = Vector3(1.0191536, 3.5353048, 3.5049686)
|
||||
bones/25/rotation = Quaternion(-0.087474234, 0.16733547, 0.98056763, 0.053239316)
|
||||
bones/25/scale = Vector3(1, 17.518272, 1.0000001)
|
||||
bones/26/position = Vector3(-1.0831825, 3.749937, 2.5891113)
|
||||
bones/26/rotation = Quaternion(0.016340872, 0.19671263, 0.9801456, 0.01875816)
|
||||
bones/26/scale = Vector3(1.0000001, 18.765795, 1)
|
||||
bones/27/position = Vector3(1.0193456, -0.43209565, 2.5343885)
|
||||
bones/27/rotation = Quaternion(0.61800283, -0.11976056, 0.11976072, 0.7677157)
|
||||
bones/27/scale = Vector3(0.99999994, 16.85072, 1)
|
||||
bones/28/position = Vector3(-0.8340287, 1.0348616, 1.282705)
|
||||
bones/28/rotation = Quaternion(0.82860446, -0.029359974, 0.02935981, 0.5582926)
|
||||
bones/28/scale = Vector3(0.99999994, 32.068844, 1)
|
||||
bones/30/position = Vector3(0.032563455, -0.8335703, -0.9236449)
|
||||
bones/30/rotation = Quaternion(-0.8670657, 0.042821795, -0.07139772, 0.4911883)
|
||||
bones/31/position = Vector3(2.3450447e-08, -1.4631646, 0.23291242)
|
||||
bones/31/rotation = Quaternion(-6.0737464e-09, 4.8699293e-09, -1.4618977e-09, 1)
|
||||
bones/31/scale = Vector3(0.99999994, 0.9999999, 0.99999994)
|
||||
bones/32/position = Vector3(-0.04394375, -1.087056, 0.096768975)
|
||||
bones/32/rotation = Quaternion(-0.8343034, 0.119118, -0.061490715, 0.5347595)
|
||||
bones/32/scale = Vector3(0.9999999, 0.99999976, 0.99999964)
|
||||
bones/33/position = Vector3(3.977649e-08, -1.4631644, 0.23291251)
|
||||
bones/33/rotation = Quaternion(-8.833673e-08, -2.419923e-08, -6.733043e-09, 1)
|
||||
bones/33/scale = Vector3(0.9999998, 0.9999998, 0.99999994)
|
||||
bones/35/position = Vector3(1.0184407e-08, -1.0594703, -5.9146995e-08)
|
||||
bones/35/rotation = Quaternion(0.99971783, 1.3593646e-07, 5.3695976e-06, -0.023754615)
|
||||
bones/35/scale = Vector3(0.99999976, 0.9999998, 1.0000012)
|
||||
bones/39/position = Vector3(0.8199172, 0.25251278, 0.47214246)
|
||||
bones/39/rotation = Quaternion(0.71402234, 0.34199142, 0.043267474, 0.60937834)
|
||||
bones/39/scale = Vector3(1.0000004, 0.9999996, 0.9999991)
|
||||
bones/40/rotation = Quaternion(0.9336719, 1.2799235e-07, 3.7337827e-08, 0.3581296)
|
||||
bones/40/scale = Vector3(1.0000004, 1.0000001, 1.0000001)
|
||||
bones/41/rotation = Quaternion(-0.13802455, 0.26758966, 0.08115916, 0.9501359)
|
||||
bones/41/scale = Vector3(0.99999946, 0.99999976, 0.9999996)
|
||||
bones/42/position = Vector3(-1.9729964e-07, 0.56145483, 7.283501e-08)
|
||||
bones/46/scale = Vector3(0.99999946, 0.99999964, 0.9999999)
|
||||
bones/48/rotation = Quaternion(-2.9741386e-07, 0.13593404, 1.01778824e-07, 0.9907179)
|
||||
bones/48/scale = Vector3(0.9999993, 0.9999996, 0.9999999)
|
||||
bones/50/scale = Vector3(0.99999994, 0.99999994, 0.9999998)
|
||||
bones/51/rotation = Quaternion(-2.5567479e-08, -0.20499781, -2.3086146e-08, 0.9787625)
|
||||
bones/51/scale = Vector3(0.9999999, 0.99999964, 0.99999964)
|
||||
bones/53/position = Vector3(-0.8199191, 0.25251284, 0.47213903)
|
||||
bones/53/rotation = Quaternion(-0.5351706, 0.35860845, -0.15898216, 0.74814254)
|
||||
bones/53/scale = Vector3(1, 0.99999875, 0.99999946)
|
||||
bones/54/rotation = Quaternion(0.0023762286, -4.7362324e-08, -6.475868e-08, 0.9999972)
|
||||
bones/55/rotation = Quaternion(-0.54963607, -0.322046, -0.22350314, 0.73772144)
|
||||
bones/55/scale = Vector3(1.0000002, 1, 1.0000002)
|
||||
bones/56/position = Vector3(0.0013532753, 0.57868266, 0.05537574)
|
||||
bones/56/rotation = Quaternion(-0.00015348212, 0.90210384, -0.43151882, 0.0003204293)
|
||||
bones/57/rotation = Quaternion(0.70073944, -0.70073956, -0.094679825, -0.09467953)
|
||||
bones/60/scale = Vector3(1.0000004, 1.0000004, 1.0000002)
|
||||
bones/62/rotation = Quaternion(-1.7092354e-08, -0.18223058, 2.6700846e-08, 0.98325586)
|
||||
bones/62/scale = Vector3(1.0000002, 1.0000002, 1.0000001)
|
||||
bones/64/scale = Vector3(1.0000004, 1.0000004, 1)
|
||||
bones/65/rotation = Quaternion(-1.0345744e-08, -0.3796584, -4.0675246e-08, 0.9251268)
|
||||
bones/65/scale = Vector3(1.0000002, 1.0000004, 1.0000004)
|
||||
bones/67/rotation = Quaternion(0.7179022, -7.671307e-07, 7.885642e-07, 0.696144)
|
||||
bones/67/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/68/rotation = Quaternion(0.9776482, 2.0029378e-07, 1.0460874e-06, -0.2102479)
|
||||
bones/68/scale = Vector3(1.0000004, 1.0000004, 0.9999982)
|
||||
bones/69/position = Vector3(-2.4645832e-08, -6.861796e-09, 7.455772e-08)
|
||||
bones/69/rotation = Quaternion(-0.8315212, 2.5276703e-08, -9.3330055e-09, 0.5554931)
|
||||
bones/69/scale = Vector3(1, 1.0000001, 1.0000002)
|
||||
bones/70/rotation = Quaternion(0.67750055, 8.820757e-08, 7.575834e-08, 0.7355223)
|
||||
bones/70/scale = Vector3(1, 1, 1)
|
||||
bones/71/scale = Vector3(0.9999999, 1, 0.9999999)
|
||||
bones/72/rotation = Quaternion(-2.1641608e-07, -4.6565607e-10, -4.6576065e-10, 1)
|
||||
bones/75/rotation = Quaternion(-0.34314692, -0.20321459, -0.2785586, 0.8737043)
|
||||
bones/76/position = Vector3(1.01587794e-07, -1.5306958e-07, -4.3554866e-07)
|
||||
bones/76/rotation = Quaternion(-0.51764834, -7.167482e-08, 1.7163823e-07, 0.85559356)
|
||||
bones/77/rotation = Quaternion(0.93367195, 1.2110854e-07, 3.8556042e-08, 0.35812962)
|
||||
bones/78/position = Vector3(0.8199172, 0.25251257, 0.47214243)
|
||||
bones/78/rotation = Quaternion(0.6979164, 0.16086517, -0.15598962, 0.6802223)
|
||||
bones/78/scale = Vector3(1.0000004, 0.9999997, 0.99999905)
|
||||
bones/80/rotation = Quaternion(0.7179022, -7.6713064e-07, 7.885641e-07, 0.696144)
|
||||
bones/80/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/81/rotation = Quaternion(0.97764814, 1.9846473e-07, 1.0426893e-06, -0.21024783)
|
||||
bones/81/scale = Vector3(1.0000004, 1.0000002, 0.9999982)
|
||||
bones/82/position = Vector3(6.103571e-08, 8.8816435e-08, -3.6955274e-09)
|
||||
bones/82/rotation = Quaternion(-0.8315211, 2.3407136e-08, -1.2821512e-08, 0.5554932)
|
||||
bones/82/scale = Vector3(0.99999994, 0.99999994, 1)
|
||||
bones/83/rotation = Quaternion(0.6775009, -8.600083e-08, -8.977273e-08, 0.735522)
|
||||
bones/83/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/84/scale = Vector3(0.99999994, 1.0000001, 0.9999999)
|
||||
bones/85/rotation = Quaternion(2.6833732e-07, -9.313788e-10, -2.5612494e-09, 1)
|
||||
bones/85/scale = Vector3(1.0000001, 1, 1.0000001)
|
||||
bones/87/rotation = Quaternion(-0.5230753, 0.20132942, 0.026226493, 0.8277505)
|
||||
bones/88/rotation = Quaternion(0.61967987, 0.23118778, 0.3169036, 0.679795)
|
||||
bones/89/position = Vector3(2.953037e-07, 4.9207458e-08, -4.3015167e-08)
|
||||
bones/89/rotation = Quaternion(-0.001144886, -2.973514e-08, 2.817069e-08, 0.9999994)
|
||||
bones/90/rotation = Quaternion(0.0023764072, -4.0769752e-08, -7.0690255e-08, 0.99999726)
|
||||
bones/91/position = Vector3(-0.8199192, 0.2525128, 0.47213912)
|
||||
bones/91/rotation = Quaternion(-0.49266297, -0.27058598, 0.2623832, 0.78436047)
|
||||
bones/91/scale = Vector3(1.0000002, 0.999999, 0.99999964)
|
||||
bones/96/position = Vector3(-0.021971898, -1.2751104, 0.16484088)
|
||||
bones/96/rotation = Quaternion(-0.47603267, 0.067788206, -0.035077166, 0.8761091)
|
||||
bones/96/scale = Vector3(0.9999999, 0.9999999, 0.99999976)
|
||||
bones/97/rotation = Quaternion(0.997074, -1.2813135e-07, 1.666339e-06, -0.07644201)
|
||||
bones/98/position = Vector3(0.01993539, 0.08757691, 0.045667563)
|
||||
bones/98/rotation = Quaternion(0.1475291, 0.03397043, -0.019923227, 0.9882734)
|
||||
bones/98/scale = Vector3(1, 1.0000011, 1.0000023)
|
||||
bones/101/position = Vector3(-0.021972047, 0.8282039, 0.0959422)
|
||||
bones/101/rotation = Quaternion(0.8371564, 0.04015539, 0.06490996, 0.5416119)
|
||||
bones/101/scale = Vector3(1, 1.0000066, 0.99998474)
|
||||
bones/102/rotation = Quaternion(0.95545256, -6.924111e-08, 2.2887033e-07, -0.29514462)
|
||||
bones/103/position = Vector3(0.17285576, 0.72785676, 1.0822707)
|
||||
bones/103/rotation = Quaternion(0.27801546, 0.0014157619, 0.015671493, 0.9604477)
|
||||
bones/103/scale = Vector3(1.0000002, 1.000013, 1.0000246)
|
||||
bones/104/rotation = Quaternion(0.5037003, 0.13519715, -0.093790196, 0.84806323)
|
||||
bones/104/scale = Vector3(1.0000721, 1.0000457, 0.99993384)
|
||||
bones/105/rotation = Quaternion(0.97757924, -0.053521663, -0.054415643, -0.19624804)
|
||||
bones/105/scale = Vector3(1.0000001, 1.0000083, 1.0000036)
|
||||
bones/106/position = Vector3(0.023142539, -0.54231995, -0.9607401)
|
||||
bones/106/rotation = Quaternion(0.99272084, -0.08158898, -0.03307842, -0.08218607)
|
||||
bones/107/rotation = Quaternion(0.903578, -0.12777254, -0.05477002, -0.4052421)
|
||||
bones/107/scale = Vector3(0.9999992, 0.9999624, 1.0000123)
|
||||
bones/108/position = Vector3(-1.1340098e-08, 7.923448e-07, 9.0939814e-08)
|
||||
bones/108/rotation = Quaternion(0.98967296, 0.0031370325, 0.10343237, -0.09919364)
|
||||
bones/110/rotation = Quaternion(9.815354e-07, 7.072085e-10, -9.586452e-08, 1)
|
||||
bones/110/scale = Vector3(0.99999994, 0.99999976, 1.0000001)
|
||||
bones/113/position = Vector3(0.07716276, 0.6410925, 0.71644557)
|
||||
bones/113/rotation = Quaternion(0.75079244, 0.54212654, -0.3715475, 0.0660462)
|
||||
bones/114/position = Vector3(-0.031743176, 0.60466695, -0.39704067)
|
||||
bones/114/rotation = Quaternion(0.4176498, -0.11118397, 0.55639553, -0.70966953)
|
||||
bones/114/scale = Vector3(1.0000015, 1.0000038, 1.0000079)
|
||||
bones/115/rotation = Quaternion(-0.07547326, 0.02173067, -0.31477332, 0.945912)
|
||||
bones/115/scale = Vector3(0.9999974, 1.0000036, 0.99999976)
|
||||
bones/116/rotation = Quaternion(0.03028559, -0.3116764, -0.037417784, 0.9489682)
|
||||
bones/116/scale = Vector3(1.0000005, 0.9999972, 1.0000013)
|
||||
bones/119/scale = Vector3(1.0000043, 0.9999975, 0.99999744)
|
||||
bones/121/rotation = Quaternion(-4.820391e-08, -0.1579088, -2.0880496e-08, 0.98745376)
|
||||
bones/121/scale = Vector3(1.0000037, 0.99999774, 0.9999977)
|
||||
bones/123/scale = Vector3(1.000003, 0.9999977, 0.99999917)
|
||||
bones/124/rotation = Quaternion(-3.1036683e-07, 0.17317644, 6.989145e-08, 0.9848908)
|
||||
bones/124/scale = Vector3(1.0000037, 0.9999978, 0.99999875)
|
||||
bones/126/rotation = Quaternion(-0.5163543, -0.16816929, 0.6340875, 0.550482)
|
||||
bones/126/scale = Vector3(1.0000015, 1.000007, 1.000004)
|
||||
bones/127/rotation = Quaternion(-0.24332331, 0.12663932, 0.6612194, 0.6982444)
|
||||
bones/127/scale = Vector3(1.0000017, 1.0000014, 1.0000097)
|
||||
bones/128/position = Vector3(-0.008928956, 0.128764, -0.06877987)
|
||||
bones/128/rotation = Quaternion(0.025037244, 0.39930493, -0.88358396, 0.24332726)
|
||||
bones/129/rotation = Quaternion(-0.07547334, 0.021730714, -0.31477335, 0.94591194)
|
||||
bones/131/rotation = Quaternion(-0.41802245, -0.28161782, 0.08442414, 0.85954714)
|
||||
bones/132/rotation = Quaternion(-0.5281791, -0.34319904, -0.62196887, -0.46518382)
|
||||
bones/133/rotation = Quaternion(-0.012777329, 0.011854946, 0.00015161165, 0.9998482)
|
||||
bones/133/scale = Vector3(1.0423008, 1.0423008, 1.0423006)
|
||||
bones/134/rotation = Quaternion(0.02152103, -3.688601e-08, -1.5255387e-07, 0.99976844)
|
||||
bones/134/scale = Vector3(0.9882629, 0.9882634, 0.98826265)
|
||||
bones/135/position = Vector3(-0.0317431, 0.60466677, -0.39704087)
|
||||
bones/135/rotation = Quaternion(0.22344373, -0.32689255, 0.658746, -0.6397405)
|
||||
bones/135/scale = Vector3(1.0000048, 1.0000036, 1.0000046)
|
||||
bones/137/position = Vector3(-0.33244255, 0.70370555, 0.67530614)
|
||||
bones/137/rotation = Quaternion(0.7519437, -0.5788053, 0.30500948, 0.08083551)
|
||||
bones/138/position = Vector3(-0.19594865, 0.65740275, -0.22511396)
|
||||
bones/138/rotation = Quaternion(0.36201134, 0.22157827, -0.6475769, -0.63284683)
|
||||
bones/138/scale = Vector3(1.0000019, 1.0000045, 1.0000057)
|
||||
bones/139/rotation = Quaternion(-0.018797327, 0.13857716, 0.33871746, 0.9304373)
|
||||
bones/139/scale = Vector3(0.9999983, 1.0000024, 0.9999992)
|
||||
bones/140/rotation = Quaternion(0.09896898, 0.1986053, -0.00787212, 0.975038)
|
||||
bones/140/scale = Vector3(1.0000031, 0.9999977, 0.9999988)
|
||||
bones/143/scale = Vector3(1.000005, 0.99999815, 0.9999967)
|
||||
bones/145/rotation = Quaternion(-1.7910523e-07, 0.10005118, -9.714451e-08, 0.9949823)
|
||||
bones/145/scale = Vector3(1.0000045, 0.99999803, 0.9999968)
|
||||
bones/147/scale = Vector3(1.0000035, 0.99999845, 0.9999981)
|
||||
bones/148/rotation = Quaternion(2.0844507e-07, 0.011625211, 4.5709146e-07, 0.9999325)
|
||||
bones/148/scale = Vector3(1.000004, 0.9999991, 0.999998)
|
||||
bones/150/rotation = Quaternion(-0.51635444, 0.16816957, -0.63408744, 0.55048186)
|
||||
bones/150/scale = Vector3(1.000001, 1.0000067, 1.000004)
|
||||
bones/151/rotation = Quaternion(-0.24332346, -0.12663896, -0.6612195, 0.6982443)
|
||||
bones/151/scale = Vector3(1.0000011, 1.0000017, 1.0000095)
|
||||
bones/152/position = Vector3(0.027921734, -0.124764316, 0.07102555)
|
||||
bones/152/rotation = Quaternion(-0.12973516, 0.47151387, -0.86254627, -0.12983702)
|
||||
bones/153/rotation = Quaternion(-0.018797398, 0.13857722, 0.33871746, 0.9304373)
|
||||
bones/155/rotation = Quaternion(-0.36541468, 0.16190512, -0.07102372, 0.91390073)
|
||||
bones/155/scale = Vector3(0.99999994, 1, 0.9999998)
|
||||
bones/156/rotation = Quaternion(0.68045896, -0.19169958, -0.3896983, 0.59022206)
|
||||
bones/157/rotation = Quaternion(-0.01277751, -0.011854968, -0.0001513001, 0.9998481)
|
||||
bones/157/scale = Vector3(1.0423003, 1.0422994, 1.0423005)
|
||||
bones/158/rotation = Quaternion(0.021521209, -2.5687226e-07, -2.570953e-07, 0.9997684)
|
||||
bones/158/scale = Vector3(0.9882631, 0.98826426, 0.9882618)
|
||||
bones/159/position = Vector3(-0.19594839, 0.65740275, -0.2251139)
|
||||
bones/159/rotation = Quaternion(0.28422734, 0.29369113, -0.68527013, -0.60279787)
|
||||
bones/159/scale = Vector3(1.0000027, 1.0000043, 1.0000049)
|
||||
bones/161/position = Vector3(0.07716276, 0.6410925, 0.71644557)
|
||||
bones/161/rotation = Quaternion(0.75079244, 0.54212654, -0.3715475, 0.0660462)
|
||||
bones/162/position = Vector3(-0.33244255, 0.70370555, 0.67530614)
|
||||
bones/162/rotation = Quaternion(0.7519437, -0.5788053, 0.30500948, 0.08083551)
|
||||
bones/165/position = Vector3(-1.5017577e-08, 0.26895812, -1.6243575e-08)
|
||||
bones/165/rotation = Quaternion(-0.019247467, -0.20323175, 0.97894067, -0.0012537595)
|
||||
bones/166/position = Vector3(0.0034187725, -3.131728, 0.9674823)
|
||||
bones/167/position = Vector3(0.209171, 5.0901713, -2.6670303)
|
||||
bones/167/rotation = Quaternion(0.16656846, 0.015223213, 0.18356222, 0.9686734)
|
||||
bones/167/scale = Vector3(0.9999988, 0.9999987, 1.0000023)
|
||||
bones/168/position = Vector3(0.18381567, -0.9622623, 0.9894084)
|
||||
bones/168/rotation = Quaternion(0.9362244, -6.2652596e-08, -0.34127164, -0.083770975)
|
||||
bones/168/scale = Vector3(1.0000011, 1.0000015, 1.0000101)
|
||||
bones/170/position = Vector3(0.748137, 0.69556385, 3.7252903e-09)
|
||||
bones/170/rotation = Quaternion(0.019250846, -0.20323181, 0.9789406, 0.001253055)
|
||||
bones/171/position = Vector3(0.6322718, -2.6572587, 0.6064028)
|
||||
bones/172/position = Vector3(-1.5122895, 4.4686184, -2.7014794)
|
||||
bones/172/rotation = Quaternion(0.21553025, -0.03620148, 0.11066054, 0.9695311)
|
||||
bones/172/scale = Vector3(0.99999887, 0.9999985, 1.0000024)
|
||||
bones/173/position = Vector3(0.18381546, -0.96226203, 0.9894083)
|
||||
bones/173/rotation = Quaternion(0.93622434, -2.9748788e-08, 0.34127158, -0.083771475)
|
||||
bones/173/scale = Vector3(0.999999, 1.0000014, 0.99999464)
|
||||
bones/175/position = Vector3(0.2542465, -2.2077389, 0.9589075)
|
||||
bones/175/rotation = Quaternion(-0.008919476, -0.00021326332, -0.000697989, 0.99996)
|
||||
bones/183/position = Vector3(-1.982537e-07, 5.9604563e-08, -1.517833e-08)
|
||||
bones/185/rotation = Quaternion(5.4077844e-07, -0.20349081, 0.97907686, -1.12395135e-07)
|
||||
bones/186/position = Vector3(0.57634556, 3.7607954, 0.15364014)
|
||||
bones/186/rotation = Quaternion(-0.9604305, -0.020206233, -0.08076539, -0.26578543)
|
||||
bones/186/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/187/rotation = Quaternion(0.15451065, -2.0305349e-09, -2.0850066e-09, 0.9879911)
|
||||
bones/187/scale = Vector3(1.0000002, 0.99999994, 0.9999999)
|
||||
bones/197/position = Vector3(-0.0011225368, -0.015787723, -0.051779967)
|
||||
bones/199/rotation = Quaternion(0.00034800146, -0.20349097, 0.9790768, -7.2328476e-05)
|
||||
bones/200/position = Vector3(-1.0407574, 3.6267605, -0.083099455)
|
||||
bones/200/rotation = Quaternion(-0.9604305, -0.020206233, -0.08076539, -0.26578543)
|
||||
bones/200/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/201/rotation = Quaternion(0.15451066, -1.9585848e-09, -2.5450761e-09, 0.9879911)
|
||||
bones/201/scale = Vector3(1.0000002, 0.99999994, 0.99999994)
|
||||
|
||||
[editable path="bear_model"]
|
||||
[editable path="bear_model/test_cube/Bear_FX"]
|
||||
@@ -0,0 +1,319 @@
|
||||
[gd_scene format=3 uid="uid://o8ocjfprxa7u"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cn7fhjkro7637" path="res://bear.gd" id="1_beargd"]
|
||||
[ext_resource type="PackedScene" uid="uid://cofv5dbavesis" path="res://Assets/Bear.glb" id="2_bearglb"]
|
||||
[ext_resource type="Script" uid="uid://bsbed05ifr18s" path="res://bear_test_cube.gd" id="3_rog1v"]
|
||||
[ext_resource type="PackedScene" uid="uid://bdbx0wwa73rhp" path="res://Assets/fx/Bear_FX.glb" id="4_rog1v"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_body"]
|
||||
radius = 1.0
|
||||
height = 2.4
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_hit"]
|
||||
radius = 1.3
|
||||
height = 2.7
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_bfebr"]
|
||||
size = Vector3(6.2019043, 8.561401, 7.0739746)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_rog1v"]
|
||||
size = Vector3(14.399288, 51.902206, 5.741211)
|
||||
|
||||
[node name="Bear" type="CharacterBody3D" unique_id=1573237287]
|
||||
script = ExtResource("1_beargd")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=830443382]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2, 0)
|
||||
shape = SubResource("CapsuleShape3D_body")
|
||||
|
||||
[node name="HitArea" type="Area3D" parent="." unique_id=365327397]
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="HitArea" unique_id=2111867348]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.35, 0)
|
||||
shape = SubResource("CapsuleShape3D_hit")
|
||||
|
||||
[node name="bear_model" parent="." unique_id=359217823 instance=ExtResource("2_bearglb")]
|
||||
|
||||
[node name="test_cube" type="Node3D" parent="bear_model" unique_id=646988893]
|
||||
script = ExtResource("3_rog1v")
|
||||
|
||||
[node name="Bear_FX" parent="bear_model/test_cube" unique_id=1183391245 instance=ExtResource("4_rog1v")]
|
||||
|
||||
[node name="Bear_fx_jump_smash" parent="bear_model/test_cube/Bear_FX" index="0" unique_id=750478984]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_claw_attack_R" parent="bear_model/test_cube/Bear_FX" index="1" unique_id=88064381]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_claw_attack_L" parent="bear_model/test_cube/Bear_FX" index="2" unique_id=1378755061]
|
||||
visible = false
|
||||
|
||||
[node name="Bear_fx_smash_hit" parent="bear_model/test_cube/Bear_FX" index="3" unique_id=1711579105]
|
||||
transform = Transform3D(0.55488384, -0.039024748, -0.018949924, 0.041069064, 0.55086076, 0.06814586, 0.013977209, -0.06933683, 0.5520644, 1.327292, -0.21312934, 5.190573)
|
||||
|
||||
[node name="RigidBody3D" type="AnimatableBody3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit" index="0" unique_id=1764208051]
|
||||
transform = Transform3D(1.0000001, -1.21071935e-08, -1.8626451e-08, -9.313226e-10, 0.99999994, 7.450581e-09, 3.7252903e-09, -1.4901161e-08, 0.99999994, 0, 0, 0)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
|
||||
[node name="CollisionShape3D2" type="CollisionShape3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit/RigidBody3D" unique_id=1779197150]
|
||||
transform = Transform3D(0.99993557, -0.00749125, -0.010078691, 0.0077760145, 0.999569, 0.028562747, 0.009858355, -0.028639637, 0.9995405, -1.5136471, 0.9093375, 35.591957)
|
||||
shape = SubResource("BoxShape3D_bfebr")
|
||||
disabled = true
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="bear_model/test_cube/Bear_FX/Bear_fx_smash_hit/RigidBody3D" unique_id=1276552823]
|
||||
transform = Transform3D(0.9935104, -0.040698394, -0.10621016, -0.108634494, -0.06290151, -0.9920882, 0.03369555, 0.99719334, -0.06691426, -1.6357545, -0.5093044, 12.68803)
|
||||
shape = SubResource("BoxShape3D_rog1v")
|
||||
|
||||
[node name="Skeleton3D" parent="bear_model/bear-rig" parent_id_path=PackedInt32Array(359217823, 1017999212) index="0" unique_id=1624609914]
|
||||
bones/1/position = Vector3(0.00851878, 0.24701798, 1.2888045)
|
||||
bones/1/rotation = Quaternion(0.29791054, -0.060797628, -0.056875575, 0.9509564)
|
||||
bones/2/rotation = Quaternion(0.084239505, -0.026013458, 0.009274505, 0.9960628)
|
||||
bones/2/scale = Vector3(0.9999999, 1.0000008, 0.99999934)
|
||||
bones/3/rotation = Quaternion(-0.14812404, -0.039577905, 0.049865585, 0.98691756)
|
||||
bones/4/rotation = Quaternion(-0.40577498, -0.03082885, 0.05040324, 0.9120612)
|
||||
bones/5/rotation = Quaternion(0.27801633, 0.0014148077, 0.015671793, 0.96044755)
|
||||
bones/6/rotation = Quaternion(0.50370073, 0.13519946, -0.093789615, 0.8480627)
|
||||
bones/7/rotation = Quaternion(0.75079185, 0.54212743, -0.37154716, 0.06604591)
|
||||
bones/8/rotation = Quaternion(0.22344273, -0.32689556, 0.65874565, -0.63973963)
|
||||
bones/9/rotation = Quaternion(0.026405705, -0.27415153, -0.3226086, 0.9055757)
|
||||
bones/10/rotation = Quaternion(0.030285481, -0.31167626, -0.037417818, 0.94896823)
|
||||
bones/11/rotation = Quaternion(0.751943, -0.5788067, 0.30500817, 0.080837056)
|
||||
bones/12/rotation = Quaternion(0.28422552, 0.2936944, -0.68526876, -0.6027987)
|
||||
bones/13/rotation = Quaternion(0.020711409, 0.24585825, 0.3386082, 0.9080029)
|
||||
bones/14/rotation = Quaternion(0.098969, 0.19860524, -0.007872087, 0.97503805)
|
||||
bones/15/rotation = Quaternion(0.6979166, 0.16086513, -0.15598965, 0.680222)
|
||||
bones/16/rotation = Quaternion(0.89734674, 0.09874082, -0.25790086, 0.34424722)
|
||||
bones/17/rotation = Quaternion(-0.13802421, 0.26758972, 0.081159085, 0.9501359)
|
||||
bones/17/scale = Vector3(0.9999998, 1.0000002, 1)
|
||||
bones/19/rotation = Quaternion(-4.514978e-15, 1, 7.4505806e-08, -5.523351e-07)
|
||||
bones/20/rotation = Quaternion(-0.49266306, -0.27058616, 0.262383, 0.7843606)
|
||||
bones/21/rotation = Quaternion(0.0016915401, 0.70246154, -0.001669446, 0.7117178)
|
||||
bones/22/rotation = Quaternion(-0.5496364, -0.3220462, -0.22350304, 0.73772115)
|
||||
bones/22/scale = Vector3(0.9999997, 0.9999998, 0.9999999)
|
||||
bones/23/rotation = Quaternion(-0.00015351747, 0.902104, -0.4315187, 0.00032039074)
|
||||
bones/24/rotation = Quaternion(6.628114e-12, 0.99999994, 5.2154085e-08, -0.00035543842)
|
||||
bones/25/position = Vector3(1.0191536, 3.5353048, 3.5049686)
|
||||
bones/25/rotation = Quaternion(-0.087474234, 0.16733547, 0.98056763, 0.053239316)
|
||||
bones/25/scale = Vector3(1, 17.518272, 1.0000001)
|
||||
bones/26/position = Vector3(-1.0831825, 3.749937, 2.5891113)
|
||||
bones/26/rotation = Quaternion(0.016340872, 0.19671263, 0.9801456, 0.01875816)
|
||||
bones/26/scale = Vector3(1.0000001, 18.765795, 1)
|
||||
bones/27/position = Vector3(1.0193456, -0.43209565, 2.5343885)
|
||||
bones/27/rotation = Quaternion(0.61800283, -0.11976056, 0.11976072, 0.7677157)
|
||||
bones/27/scale = Vector3(0.99999994, 16.85072, 1)
|
||||
bones/28/position = Vector3(-0.8340287, 1.0348616, 1.282705)
|
||||
bones/28/rotation = Quaternion(0.82860446, -0.029359974, 0.02935981, 0.5582926)
|
||||
bones/28/scale = Vector3(0.99999994, 32.068844, 1)
|
||||
bones/30/position = Vector3(0.032563455, -0.8335703, -0.9236449)
|
||||
bones/30/rotation = Quaternion(-0.8670657, 0.042821795, -0.07139772, 0.4911883)
|
||||
bones/31/position = Vector3(2.3450447e-08, -1.4631646, 0.23291242)
|
||||
bones/31/rotation = Quaternion(-6.0737464e-09, 4.8699293e-09, -1.4618977e-09, 1)
|
||||
bones/31/scale = Vector3(0.99999994, 0.9999999, 0.99999994)
|
||||
bones/32/position = Vector3(-0.04394375, -1.087056, 0.096768975)
|
||||
bones/32/rotation = Quaternion(-0.8343034, 0.119118, -0.061490715, 0.5347595)
|
||||
bones/32/scale = Vector3(0.9999999, 0.99999976, 0.99999964)
|
||||
bones/33/position = Vector3(3.977649e-08, -1.4631644, 0.23291251)
|
||||
bones/33/rotation = Quaternion(-8.833673e-08, -2.419923e-08, -6.733043e-09, 1)
|
||||
bones/33/scale = Vector3(0.9999998, 0.9999998, 0.99999994)
|
||||
bones/35/position = Vector3(1.0184407e-08, -1.0594703, -5.9146995e-08)
|
||||
bones/35/rotation = Quaternion(0.99971783, 1.3593646e-07, 5.3695976e-06, -0.023754615)
|
||||
bones/35/scale = Vector3(0.99999976, 0.9999998, 1.0000012)
|
||||
bones/39/position = Vector3(0.8199172, 0.25251278, 0.47214246)
|
||||
bones/39/rotation = Quaternion(0.71402234, 0.34199142, 0.043267474, 0.60937834)
|
||||
bones/39/scale = Vector3(1.0000004, 0.9999996, 0.9999991)
|
||||
bones/40/rotation = Quaternion(0.9336719, 1.2799235e-07, 3.7337827e-08, 0.3581296)
|
||||
bones/40/scale = Vector3(1.0000004, 1.0000001, 1.0000001)
|
||||
bones/41/rotation = Quaternion(-0.13802455, 0.26758966, 0.08115916, 0.9501359)
|
||||
bones/41/scale = Vector3(0.99999946, 0.99999976, 0.9999996)
|
||||
bones/42/position = Vector3(-1.9729964e-07, 0.56145483, 7.283501e-08)
|
||||
bones/46/scale = Vector3(0.99999946, 0.99999964, 0.9999999)
|
||||
bones/48/rotation = Quaternion(-2.9741386e-07, 0.13593404, 1.01778824e-07, 0.9907179)
|
||||
bones/48/scale = Vector3(0.9999993, 0.9999996, 0.9999999)
|
||||
bones/50/scale = Vector3(0.99999994, 0.99999994, 0.9999998)
|
||||
bones/51/rotation = Quaternion(-2.5567479e-08, -0.20499781, -2.3086146e-08, 0.9787625)
|
||||
bones/51/scale = Vector3(0.9999999, 0.99999964, 0.99999964)
|
||||
bones/53/position = Vector3(-0.8199191, 0.25251284, 0.47213903)
|
||||
bones/53/rotation = Quaternion(-0.5351706, 0.35860845, -0.15898216, 0.74814254)
|
||||
bones/53/scale = Vector3(1, 0.99999875, 0.99999946)
|
||||
bones/54/rotation = Quaternion(0.0023762286, -4.7362324e-08, -6.475868e-08, 0.9999972)
|
||||
bones/55/rotation = Quaternion(-0.54963607, -0.322046, -0.22350314, 0.73772144)
|
||||
bones/55/scale = Vector3(1.0000002, 1, 1.0000002)
|
||||
bones/56/position = Vector3(0.0013532753, 0.57868266, 0.05537574)
|
||||
bones/56/rotation = Quaternion(-0.00015348212, 0.90210384, -0.43151882, 0.0003204293)
|
||||
bones/57/rotation = Quaternion(0.70073944, -0.70073956, -0.094679825, -0.09467953)
|
||||
bones/60/scale = Vector3(1.0000004, 1.0000004, 1.0000002)
|
||||
bones/62/rotation = Quaternion(-1.7092354e-08, -0.18223058, 2.6700846e-08, 0.98325586)
|
||||
bones/62/scale = Vector3(1.0000002, 1.0000002, 1.0000001)
|
||||
bones/64/scale = Vector3(1.0000004, 1.0000004, 1)
|
||||
bones/65/rotation = Quaternion(-1.0345744e-08, -0.3796584, -4.0675246e-08, 0.9251268)
|
||||
bones/65/scale = Vector3(1.0000002, 1.0000004, 1.0000004)
|
||||
bones/67/rotation = Quaternion(0.7179022, -7.671307e-07, 7.885642e-07, 0.696144)
|
||||
bones/67/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/68/rotation = Quaternion(0.9776482, 2.0029378e-07, 1.0460874e-06, -0.2102479)
|
||||
bones/68/scale = Vector3(1.0000004, 1.0000004, 0.9999982)
|
||||
bones/69/position = Vector3(-2.4645832e-08, -6.861796e-09, 7.455772e-08)
|
||||
bones/69/rotation = Quaternion(-0.8315212, 2.5276703e-08, -9.3330055e-09, 0.5554931)
|
||||
bones/69/scale = Vector3(1, 1.0000001, 1.0000002)
|
||||
bones/70/rotation = Quaternion(0.67750055, 8.820757e-08, 7.575834e-08, 0.7355223)
|
||||
bones/70/scale = Vector3(1, 1, 1)
|
||||
bones/71/scale = Vector3(0.9999999, 1, 0.9999999)
|
||||
bones/72/rotation = Quaternion(-2.1641608e-07, -4.6565607e-10, -4.6576065e-10, 1)
|
||||
bones/75/rotation = Quaternion(-0.34314692, -0.20321459, -0.2785586, 0.8737043)
|
||||
bones/76/position = Vector3(1.01587794e-07, -1.5306958e-07, -4.3554866e-07)
|
||||
bones/76/rotation = Quaternion(-0.51764834, -7.167482e-08, 1.7163823e-07, 0.85559356)
|
||||
bones/77/rotation = Quaternion(0.93367195, 1.2110854e-07, 3.8556042e-08, 0.35812962)
|
||||
bones/78/position = Vector3(0.8199172, 0.25251257, 0.47214243)
|
||||
bones/78/rotation = Quaternion(0.6979164, 0.16086517, -0.15598962, 0.6802223)
|
||||
bones/78/scale = Vector3(1.0000004, 0.9999997, 0.99999905)
|
||||
bones/80/rotation = Quaternion(0.7179022, -7.6713064e-07, 7.885641e-07, 0.696144)
|
||||
bones/80/scale = Vector3(1.0000004, 0.9999986, 0.99999994)
|
||||
bones/81/rotation = Quaternion(0.97764814, 1.9846473e-07, 1.0426893e-06, -0.21024783)
|
||||
bones/81/scale = Vector3(1.0000004, 1.0000002, 0.9999982)
|
||||
bones/82/position = Vector3(6.103571e-08, 8.8816435e-08, -3.6955274e-09)
|
||||
bones/82/rotation = Quaternion(-0.8315211, 2.3407136e-08, -1.2821512e-08, 0.5554932)
|
||||
bones/82/scale = Vector3(0.99999994, 0.99999994, 1)
|
||||
bones/83/rotation = Quaternion(0.6775009, -8.600083e-08, -8.977273e-08, 0.735522)
|
||||
bones/83/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/84/scale = Vector3(0.99999994, 1.0000001, 0.9999999)
|
||||
bones/85/rotation = Quaternion(2.6833732e-07, -9.313788e-10, -2.5612494e-09, 1)
|
||||
bones/85/scale = Vector3(1.0000001, 1, 1.0000001)
|
||||
bones/87/rotation = Quaternion(-0.5230753, 0.20132942, 0.026226493, 0.8277505)
|
||||
bones/88/rotation = Quaternion(0.61967987, 0.23118778, 0.3169036, 0.679795)
|
||||
bones/89/position = Vector3(2.953037e-07, 4.9207458e-08, -4.3015167e-08)
|
||||
bones/89/rotation = Quaternion(-0.001144886, -2.973514e-08, 2.817069e-08, 0.9999994)
|
||||
bones/90/rotation = Quaternion(0.0023764072, -4.0769752e-08, -7.0690255e-08, 0.99999726)
|
||||
bones/91/position = Vector3(-0.8199192, 0.2525128, 0.47213912)
|
||||
bones/91/rotation = Quaternion(-0.49266297, -0.27058598, 0.2623832, 0.78436047)
|
||||
bones/91/scale = Vector3(1.0000002, 0.999999, 0.99999964)
|
||||
bones/96/position = Vector3(-0.021971898, -1.2751104, 0.16484088)
|
||||
bones/96/rotation = Quaternion(-0.47603267, 0.067788206, -0.035077166, 0.8761091)
|
||||
bones/96/scale = Vector3(0.9999999, 0.9999999, 0.99999976)
|
||||
bones/97/rotation = Quaternion(0.997074, -1.2813135e-07, 1.666339e-06, -0.07644201)
|
||||
bones/98/position = Vector3(0.01993539, 0.08757691, 0.045667563)
|
||||
bones/98/rotation = Quaternion(0.1475291, 0.03397043, -0.019923227, 0.9882734)
|
||||
bones/98/scale = Vector3(1, 1.0000011, 1.0000023)
|
||||
bones/101/position = Vector3(-0.021972047, 0.8282039, 0.0959422)
|
||||
bones/101/rotation = Quaternion(0.8371564, 0.04015539, 0.06490996, 0.5416119)
|
||||
bones/101/scale = Vector3(1, 1.0000066, 0.99998474)
|
||||
bones/102/rotation = Quaternion(0.95545256, -6.924111e-08, 2.2887033e-07, -0.29514462)
|
||||
bones/103/position = Vector3(0.17285576, 0.72785676, 1.0822707)
|
||||
bones/103/rotation = Quaternion(0.27801546, 0.0014157619, 0.015671493, 0.9604477)
|
||||
bones/103/scale = Vector3(1.0000002, 1.000013, 1.0000246)
|
||||
bones/104/rotation = Quaternion(0.5037003, 0.13519715, -0.093790196, 0.84806323)
|
||||
bones/104/scale = Vector3(1.0000721, 1.0000457, 0.99993384)
|
||||
bones/105/rotation = Quaternion(0.97757924, -0.053521663, -0.054415643, -0.19624804)
|
||||
bones/105/scale = Vector3(1.0000001, 1.0000083, 1.0000036)
|
||||
bones/106/position = Vector3(0.023142539, -0.54231995, -0.9607401)
|
||||
bones/106/rotation = Quaternion(0.99272084, -0.08158898, -0.03307842, -0.08218607)
|
||||
bones/107/rotation = Quaternion(0.903578, -0.12777254, -0.05477002, -0.4052421)
|
||||
bones/107/scale = Vector3(0.9999992, 0.9999624, 1.0000123)
|
||||
bones/108/position = Vector3(-1.1340098e-08, 7.923448e-07, 9.0939814e-08)
|
||||
bones/108/rotation = Quaternion(0.98967296, 0.0031370325, 0.10343237, -0.09919364)
|
||||
bones/110/rotation = Quaternion(9.815354e-07, 7.072085e-10, -9.586452e-08, 1)
|
||||
bones/110/scale = Vector3(0.99999994, 0.99999976, 1.0000001)
|
||||
bones/113/position = Vector3(0.07716276, 0.6410925, 0.71644557)
|
||||
bones/113/rotation = Quaternion(0.75079244, 0.54212654, -0.3715475, 0.0660462)
|
||||
bones/114/position = Vector3(-0.031743176, 0.60466695, -0.39704067)
|
||||
bones/114/rotation = Quaternion(0.4176498, -0.11118397, 0.55639553, -0.70966953)
|
||||
bones/114/scale = Vector3(1.0000015, 1.0000038, 1.0000079)
|
||||
bones/115/rotation = Quaternion(-0.07547326, 0.02173067, -0.31477332, 0.945912)
|
||||
bones/115/scale = Vector3(0.9999974, 1.0000036, 0.99999976)
|
||||
bones/116/rotation = Quaternion(0.03028559, -0.3116764, -0.037417784, 0.9489682)
|
||||
bones/116/scale = Vector3(1.0000005, 0.9999972, 1.0000013)
|
||||
bones/119/scale = Vector3(1.0000043, 0.9999975, 0.99999744)
|
||||
bones/121/rotation = Quaternion(-4.820391e-08, -0.1579088, -2.0880496e-08, 0.98745376)
|
||||
bones/121/scale = Vector3(1.0000037, 0.99999774, 0.9999977)
|
||||
bones/123/scale = Vector3(1.000003, 0.9999977, 0.99999917)
|
||||
bones/124/rotation = Quaternion(-3.1036683e-07, 0.17317644, 6.989145e-08, 0.9848908)
|
||||
bones/124/scale = Vector3(1.0000037, 0.9999978, 0.99999875)
|
||||
bones/126/rotation = Quaternion(-0.5163543, -0.16816929, 0.6340875, 0.550482)
|
||||
bones/126/scale = Vector3(1.0000015, 1.000007, 1.000004)
|
||||
bones/127/rotation = Quaternion(-0.24332331, 0.12663932, 0.6612194, 0.6982444)
|
||||
bones/127/scale = Vector3(1.0000017, 1.0000014, 1.0000097)
|
||||
bones/128/position = Vector3(-0.008928956, 0.128764, -0.06877987)
|
||||
bones/128/rotation = Quaternion(0.025037244, 0.39930493, -0.88358396, 0.24332726)
|
||||
bones/129/rotation = Quaternion(-0.07547334, 0.021730714, -0.31477335, 0.94591194)
|
||||
bones/131/rotation = Quaternion(-0.41802245, -0.28161782, 0.08442414, 0.85954714)
|
||||
bones/132/rotation = Quaternion(-0.5281791, -0.34319904, -0.62196887, -0.46518382)
|
||||
bones/133/rotation = Quaternion(-0.012777329, 0.011854946, 0.00015161165, 0.9998482)
|
||||
bones/133/scale = Vector3(1.0423008, 1.0423008, 1.0423006)
|
||||
bones/134/rotation = Quaternion(0.02152103, -3.688601e-08, -1.5255387e-07, 0.99976844)
|
||||
bones/134/scale = Vector3(0.9882629, 0.9882634, 0.98826265)
|
||||
bones/135/position = Vector3(-0.0317431, 0.60466677, -0.39704087)
|
||||
bones/135/rotation = Quaternion(0.22344373, -0.32689255, 0.658746, -0.6397405)
|
||||
bones/135/scale = Vector3(1.0000048, 1.0000036, 1.0000046)
|
||||
bones/137/position = Vector3(-0.33244255, 0.70370555, 0.67530614)
|
||||
bones/137/rotation = Quaternion(0.7519437, -0.5788053, 0.30500948, 0.08083551)
|
||||
bones/138/position = Vector3(-0.19594865, 0.65740275, -0.22511396)
|
||||
bones/138/rotation = Quaternion(0.36201134, 0.22157827, -0.6475769, -0.63284683)
|
||||
bones/138/scale = Vector3(1.0000019, 1.0000045, 1.0000057)
|
||||
bones/139/rotation = Quaternion(-0.018797327, 0.13857716, 0.33871746, 0.9304373)
|
||||
bones/139/scale = Vector3(0.9999983, 1.0000024, 0.9999992)
|
||||
bones/140/rotation = Quaternion(0.09896898, 0.1986053, -0.00787212, 0.975038)
|
||||
bones/140/scale = Vector3(1.0000031, 0.9999977, 0.9999988)
|
||||
bones/143/scale = Vector3(1.000005, 0.99999815, 0.9999967)
|
||||
bones/145/rotation = Quaternion(-1.7910523e-07, 0.10005118, -9.714451e-08, 0.9949823)
|
||||
bones/145/scale = Vector3(1.0000045, 0.99999803, 0.9999968)
|
||||
bones/147/scale = Vector3(1.0000035, 0.99999845, 0.9999981)
|
||||
bones/148/rotation = Quaternion(2.0844507e-07, 0.011625211, 4.5709146e-07, 0.9999325)
|
||||
bones/148/scale = Vector3(1.000004, 0.9999991, 0.999998)
|
||||
bones/150/rotation = Quaternion(-0.51635444, 0.16816957, -0.63408744, 0.55048186)
|
||||
bones/150/scale = Vector3(1.000001, 1.0000067, 1.000004)
|
||||
bones/151/rotation = Quaternion(-0.24332346, -0.12663896, -0.6612195, 0.6982443)
|
||||
bones/151/scale = Vector3(1.0000011, 1.0000017, 1.0000095)
|
||||
bones/152/position = Vector3(0.027921734, -0.124764316, 0.07102555)
|
||||
bones/152/rotation = Quaternion(-0.12973516, 0.47151387, -0.86254627, -0.12983702)
|
||||
bones/153/rotation = Quaternion(-0.018797398, 0.13857722, 0.33871746, 0.9304373)
|
||||
bones/155/rotation = Quaternion(-0.36541468, 0.16190512, -0.07102372, 0.91390073)
|
||||
bones/155/scale = Vector3(0.99999994, 1, 0.9999998)
|
||||
bones/156/rotation = Quaternion(0.68045896, -0.19169958, -0.3896983, 0.59022206)
|
||||
bones/157/rotation = Quaternion(-0.01277751, -0.011854968, -0.0001513001, 0.9998481)
|
||||
bones/157/scale = Vector3(1.0423003, 1.0422994, 1.0423005)
|
||||
bones/158/rotation = Quaternion(0.021521209, -2.5687226e-07, -2.570953e-07, 0.9997684)
|
||||
bones/158/scale = Vector3(0.9882631, 0.98826426, 0.9882618)
|
||||
bones/159/position = Vector3(-0.19594839, 0.65740275, -0.2251139)
|
||||
bones/159/rotation = Quaternion(0.28422734, 0.29369113, -0.68527013, -0.60279787)
|
||||
bones/159/scale = Vector3(1.0000027, 1.0000043, 1.0000049)
|
||||
bones/161/position = Vector3(0.07716276, 0.6410925, 0.71644557)
|
||||
bones/161/rotation = Quaternion(0.75079244, 0.54212654, -0.3715475, 0.0660462)
|
||||
bones/162/position = Vector3(-0.33244255, 0.70370555, 0.67530614)
|
||||
bones/162/rotation = Quaternion(0.7519437, -0.5788053, 0.30500948, 0.08083551)
|
||||
bones/165/position = Vector3(-1.5017577e-08, 0.26895812, -1.6243575e-08)
|
||||
bones/165/rotation = Quaternion(-0.019247467, -0.20323175, 0.97894067, -0.0012537595)
|
||||
bones/166/position = Vector3(0.0034187725, -3.131728, 0.9674823)
|
||||
bones/167/position = Vector3(0.209171, 5.0901713, -2.6670303)
|
||||
bones/167/rotation = Quaternion(0.16656846, 0.015223213, 0.18356222, 0.9686734)
|
||||
bones/167/scale = Vector3(0.9999988, 0.9999987, 1.0000023)
|
||||
bones/168/position = Vector3(0.18381567, -0.9622623, 0.9894084)
|
||||
bones/168/rotation = Quaternion(0.9362244, -6.2652596e-08, -0.34127164, -0.083770975)
|
||||
bones/168/scale = Vector3(1.0000011, 1.0000015, 1.0000101)
|
||||
bones/170/position = Vector3(0.748137, 0.69556385, 3.7252903e-09)
|
||||
bones/170/rotation = Quaternion(0.019250846, -0.20323181, 0.9789406, 0.001253055)
|
||||
bones/171/position = Vector3(0.6322718, -2.6572587, 0.6064028)
|
||||
bones/172/position = Vector3(-1.5122895, 4.4686184, -2.7014794)
|
||||
bones/172/rotation = Quaternion(0.21553025, -0.03620148, 0.11066054, 0.9695311)
|
||||
bones/172/scale = Vector3(0.99999887, 0.9999985, 1.0000024)
|
||||
bones/173/position = Vector3(0.18381546, -0.96226203, 0.9894083)
|
||||
bones/173/rotation = Quaternion(0.93622434, -2.9748788e-08, 0.34127158, -0.083771475)
|
||||
bones/173/scale = Vector3(0.999999, 1.0000014, 0.99999464)
|
||||
bones/175/position = Vector3(0.2542465, -2.2077389, 0.9589075)
|
||||
bones/175/rotation = Quaternion(-0.008919476, -0.00021326332, -0.000697989, 0.99996)
|
||||
bones/183/position = Vector3(-1.982537e-07, 5.9604563e-08, -1.517833e-08)
|
||||
bones/185/rotation = Quaternion(5.4077844e-07, -0.20349081, 0.97907686, -1.12395135e-07)
|
||||
bones/186/position = Vector3(0.57634556, 3.7607954, 0.15364014)
|
||||
bones/186/rotation = Quaternion(-0.9604305, -0.020206233, -0.08076539, -0.26578543)
|
||||
bones/186/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/187/rotation = Quaternion(0.15451065, -2.0305349e-09, -2.0850066e-09, 0.9879911)
|
||||
bones/187/scale = Vector3(1.0000002, 0.99999994, 0.9999999)
|
||||
bones/197/position = Vector3(-0.0011225368, -0.015787723, -0.051779967)
|
||||
bones/199/rotation = Quaternion(0.00034800146, -0.20349097, 0.9790768, -7.2328476e-05)
|
||||
bones/200/position = Vector3(-1.0407574, 3.6267605, -0.083099455)
|
||||
bones/200/rotation = Quaternion(-0.9604305, -0.020206233, -0.08076539, -0.26578543)
|
||||
bones/200/scale = Vector3(0.9999997, 0.99999994, 1)
|
||||
bones/201/rotation = Quaternion(0.15451066, -1.9585848e-09, -2.5450761e-09, 0.9879911)
|
||||
bones/201/scale = Vector3(1.0000002, 0.99999994, 0.99999994)
|
||||
|
||||
[editable path="bear_model"]
|
||||
[editable path="bear_model/test_cube/Bear_FX"]
|
||||
@@ -0,0 +1,70 @@
|
||||
[gd_scene format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://hitbox.gd" id="1_qxn4a"]
|
||||
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_6dow8"]
|
||||
height = 3.0
|
||||
radius = 4.0
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_tmmfg"]
|
||||
size = Vector3(2.6, 2.5, 20)
|
||||
|
||||
[sub_resource type="Animation" id="Animation_wcwtv"]
|
||||
length = 0.25
|
||||
tracks/0/type = "scale_3d"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("LeapSlamHitbox/CollisionShape3D")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = PackedFloat32Array(0, 1, 0.12, 1, 0.12, 0.06, 1, 1, 1, 1, 0.25, 1, 1, 1, 1)
|
||||
|
||||
[sub_resource type="Animation" id="Animation_bg5u7"]
|
||||
length = 0.3
|
||||
tracks/0/type = "scale_3d"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("SmashHitbox/CollisionShape3D")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = PackedFloat32Array(0, 1, 1, 1, 0.02, 0.1, 1, 1, 1, 1, 0.3, 1, 1, 1, 1)
|
||||
tracks/1/type = "position_3d"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("SmashHitbox/CollisionShape3D")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = PackedFloat32Array(0, 1, 0, 0.9, 0.2, 0.1, 1, 0, 0.9, 10, 0.3, 1, 0, 0.9, 10)
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_u1id2"]
|
||||
_data = {
|
||||
&"leap_slam": SubResource("Animation_wcwtv"),
|
||||
&"smash_travel": SubResource("Animation_bg5u7")
|
||||
}
|
||||
|
||||
[node name="AttackHitboxes" type="Node3D" unique_id=2010404706]
|
||||
|
||||
[node name="LeapSlamHitbox" type="Area3D" parent="." unique_id=1751893032]
|
||||
collision_layer = 0
|
||||
collision_mask = 2
|
||||
monitoring = false
|
||||
monitorable = false
|
||||
script = ExtResource("1_qxn4a")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="LeapSlamHitbox" unique_id=1320172052]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
|
||||
shape = SubResource("CylinderShape3D_6dow8")
|
||||
|
||||
[node name="SmashHitbox" type="Area3D" parent="." unique_id=1579648726]
|
||||
collision_layer = 0
|
||||
collision_mask = 2
|
||||
monitoring = false
|
||||
monitorable = false
|
||||
script = ExtResource("1_qxn4a")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="SmashHitbox" unique_id=528637962]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9, 10)
|
||||
shape = SubResource("BoxShape3D_tmmfg")
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=2139876757]
|
||||
libraries/ = SubResource("AnimationLibrary_u1id2")
|
||||
@@ -24,14 +24,20 @@ I am a **Godot 4.6+ expert**. I follow current best practices for GDScript, scen
|
||||
| `matador.gd` | Matador AI (wander / ragdoll state machine) |
|
||||
| `levels/matador_spawn.gd` | Arena spawner — one matador per designer-placed child `Node3D` spawn point (each enters with a jump-roll toward center); falls back to a programmatic spread if no spawn points are present. Also handles the split-on-death hydra logic |
|
||||
| `levels/bear_spawn.gd` | Bear-level spawner — instantiates `enemy_scene` at the arena center; emits the same `all_defeated` / `matador_killed` signals as `matador_spawn.gd` |
|
||||
| `Bear.tscn` / `bear.gd` | Dark-Souls-style bear boss (`CharacterBody3D`). Routine state machine (wind-up → active → recovery) picking telegraphed moves by range band: Double Swipe / Overhead Smash (close), Leap Slam (mid-far), plus Stalk (2-leg walk-in) / Prowl (4-leg lope) positioning. Melee steps in during the swing (`bear_lunge_speed`) + tracks the bull; the leap is frame-synced to JUMP_SMASH so the paws hit ground on the impact frame (`bear_leap_impact_frame`); slams kick up dust + shake. Combos chain, hyper-armour mid-swing + poise (`bear_stagger_cd`), phase 2 enrage under `bear_enrage_frac` HP. Never damages the bull by colliding — only swings/slams. Joins `&"matador"` so bull abilities already hit it. Tuning under the `Bear` DP section |
|
||||
| `Bear.tscn` / `bear.gd` | Dark-Souls-style bear boss (`CharacterBody3D`). Routine state machine (wind-up → active → recovery) picking telegraphed moves by range band: Double Swipe / Overhead Smash (close), Leap Slam (mid-far), plus Stalk (2-leg walk-in) / Prowl (4-leg lope) positioning. Melee steps in during the swing (`bear_lunge_speed`) + tracks the bull; the leap is frame-synced to JUMP_SMASH so the paws hit ground on the impact frame (`bear_leap_impact_frame`); slams kick up dust + shake. Combos chain, hyper-armour mid-swing + poise (`bear_stagger_cd`), phase 2 enrage under `bear_enrage_frac` HP. Never damages the bull by colliding — only swings/slams. A horns-first bull charge wounds it (`_sweep_bull_ram`: swept prev→now so a tunnelling/point-blank charge still lands, gated by `bear_ram_reach` + `bull_gore_arc`, edge-triggered = one charge per wound). Joins `&"matador"` so bull abilities already hit it. Tuning under the `Bear` DP section |
|
||||
| `BearAttackHitboxes.tscn` | The bear's attack colliders as a self-contained sub-scene (instanced under `bear_model`): a `LeapSlamHitbox` (Hitbox + cylinder = ground circle) and `SmashHitbox` (Hitbox + box = forward shockwave lane), plus an `AnimationPlayer` whose `leap_slam` / `smash_travel` clips author each collider's size + travel — scrub to tweak, like `Bear_FX`. `bear.gd` only fires the clip, arms the knock-up shaping, and sweeps for overlaps while it runs (see `_setup_attack_hitboxes` / `_start_attack_hitbox`) |
|
||||
| `Sword.tscn` / `hitbox.gd` | The matador's sword wrapper (glb + editor-tweakable `BladeHitbox`). `hitbox.gd` (`class_name Hitbox`, Area3D) is the shared attack collider: `activate()`/`deactivate()` gate an active window, `sweep()` catches bodies already inside (AoE), and knock-up can ramp by distance (`knock_up_min_dist`/`_max_dist`) for the bear's outer-ring launch / further-hit-flies-higher |
|
||||
| `levels/run_state.gd` | Run progression autoload (`Run`) — Slay-the-Spire map + player position across fights |
|
||||
| `levels/level_def.gd` | `LevelDef` resource — a level's name / map colour / `scene_path` (always the shell) / `level_scene` (the level module instanced into the shell) / optional `enemy_scene` (arena wave vs. a boss like the bear) |
|
||||
| `levels/map_node.gd` | `MapNode` — one runtime node on the run map (position, level, links) |
|
||||
| `levels/MapScreen.tscn` / `levels/map_screen.gd` | Between-fights map screen; win → pick a node → next level |
|
||||
| `crowd_marker.gd` | `CrowdMarker` (`@tool Node3D`, `class_name`) — designer drops one per billboard spectator via the editor's Add-Node dialog; picks one of six 60°-spaced facings from the `orientation` dropdown. Draws an editor-only preview (slab + forward arrow, never serialised) and joins the `&"crowd_marker"` group |
|
||||
| `crowd_billboards.gd` / `crowd_billboard.gdshader` | `MultiMeshInstance3D` that harvests every `CrowdMarker` (group `&"crowd_marker"`) into one draw call, using each marker's world position + chosen facing. Front/back sprite sheet baked by `tools/bake_crowd_sheet.gd`; falls back to a generated inward-facing ring when no markers are placed |
|
||||
| `debug_params.gd` | Runtime-tunable parameter registry (autoload `DP`) |
|
||||
| `debug_params.gd` | Runtime-tunable parameter registry (autoload `DP`). Mobile-relevant flags: `force_touch_controls`, `touch_debug` (also enabled on-device with `?debug=1` in the page URL — shows the live profiler overlay in `touch_controls.gd`), and `use_rigid_skin` (default **off** — native GPU skinning everywhere now that the 4.7 web templates fixed the Mali/ANGLE invisible-skinning bug; `rigid_skin.gd` is a retained opt-in fallback). Rigid-skin is gated through `Controls.rigid_skin_enabled()`, which a page URL param overrides for on-device A/B with no console: `?skin=1` forces the workaround on (for a device where native skinning still fails), `?noskin=1` forces native off. Turning the workaround off also removes its per-spawn SurfaceTool rebuild, which was the arena's matador-spawn lag |
|
||||
| `touch_controls.gd` | On-screen thumb UI for touch/web (`CanvasLayer`, instanced by `hud.gd`, self-gating on `Controls.use_touch_ui()`): a floating left-side joystick feeding the `move_*` actions + a right-side ability cluster, drawn/hit-tested in one IGNORE-filtered Control from raw `_input()`. The joystick self-heals — the latest left-zone touch re-acquires it (`_stick_index`), and a relayout / focus-out / vanished touch resets state so a dropped touchend can't strand a stuck stick. Ability buttons use grown hit-rects + a press flash. `_draw_debug()` (gated on `Controls.debug_overlay()` — DP `touch_debug` or `?debug=1`) is a live on-device profiler reading Godot's `Performance` monitors: FPS/frame-ms with a bottleneck verdict, `process`(main-thread GDScript) vs `physics`(ragdoll/Jolt) ms with 2 s peak-hold, draw calls/objects/primitives, node count, render resolution, and `crossOriginIsolated` — so a lag spike is pinned to CPU-script vs CPU-physics vs GPU-fill instead of guessed |
|
||||
| `web_start_gate.gd` | Autoload `WebStartGate` — "TAP TO PLAY" panel shown on web+touch before play; the tap drives `Controls.request_fullscreen_landscape()` so the fullscreen/orientation churn happens with no in-flight touch to lose. Re-armable: polls browser fullscreen state and returns if the player leaves it (iPhone Safari can't fullscreen, so it stops nagging once a request never takes) |
|
||||
| `mobile_hud.gd` | Mobile-only health readouts (`CanvasLayer`, instanced by `hud.gd` only on touch): big bull pip row top-left + a Souls-style bear boss bar top-centre (discovered via group `&"bear"`, tracks `health_changed`). The desktop bottom pip cluster is hidden on touch |
|
||||
| `orientation_guard.gd` | Autoload `OrientationGuard` — full-screen "rotate your device" prompt shown on touch devices while portrait |
|
||||
| `Assets/` | Raw 3D assets (`.glb`, `.fbx`) |
|
||||
| `Blender/` | Blender source files, animation scripts, FBX exports |
|
||||
| `Blender/create_matador_anims.py` | Creates walk + idle animations and exports FBX |
|
||||
@@ -103,9 +109,19 @@ bash run_tests.sh
|
||||
gdlint *.gd levels/*.gd tests/*.gd # GDScript lint (gdtoolkit, installed via uv)
|
||||
godot --headless --script tests/logic_test.gd # pure logic, ~2 s
|
||||
godot --headless --script tests/performance_test.gd # frame-budget regression guard, ~4 s
|
||||
godot --headless --script tests/ragdoll_perf_test.gd # on-hit spike breakdown: ragdoll build / sim-start / blood / mass hit, ~90 s
|
||||
godot --headless --script tests/gameplay_test.gd # full scene, bone sanity, ~4 s
|
||||
godot --headless --script tests/level_switch_test.gd # no arena geometry leaks into the bear level, ~2 s
|
||||
godot --headless --script tests/touch_controls_test.gd # joystick self-heals: relayout/focus-out/vanished-touch never strand a stuck stick, ~2 s
|
||||
godot --headless --script tests/rigid_skin_test.gd # web mesh conversion keeps every material (no bald / recoloured matadors), ~2 s
|
||||
godot --headless --script tests/bear_boss_test.gd # bear boss moveset: routines, leap landing, hyper-armour, ~10 s
|
||||
godot --headless --script tests/bear_fx_test.gd # bear attack-FX: each Bear_FX clip pops its mesh + self-hides, ~2 s
|
||||
godot --headless --script tests/bear_hitbox_test.gd # bear attack colliders: leap launches everywhere (ring_frac slider) + smash lane travel, ~3 s
|
||||
godot --headless --script tests/bear_ram_test.gd # a horns-first bull charge wounds the bear once; away/wide/slow spared, ~3 s
|
||||
godot --headless --script tests/matador_stab_test.gd # matador's BladeHitbox thrust gores a stationary bull, and a landed stab breaks it off to taunt (anti-spam), ~2 s
|
||||
godot --headless --script tests/matador_taunt_react_test.gd # a taunting matador answers a charge: spear from range, sword up close, ignores non-charges, ~2 s
|
||||
godot --headless --script tests/matador_charge_test.gd # bull's charge is swept (tunnel-proof) so a fast dash still gores; a committed charge pierces the survival roll, ~2 s
|
||||
godot --headless --script tests/matador_spear_test.gd # thrown spear masks the BULL layer and hits a stationary bull, ~2 s
|
||||
|
||||
# Gameplay test with real rendering (inspect frame strip visually):
|
||||
godot --script tests/gameplay_test.gd # opens a window, saves real screenshots
|
||||
|
||||
-137
@@ -1,137 +0,0 @@
|
||||
[gd_scene format=3 uid="uid://c4df4qgpc3d5g"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://eu2lqjhowj4t" path="res://Assets/Matador.glb" id="1_eicjn"]
|
||||
[ext_resource type="Script" uid="uid://dycnoiadljbb1" path="res://Assets/matador_intro_menu.gd" id="2_5jr0i"]
|
||||
[ext_resource type="PackedScene" uid="uid://dio67r8ambe7h" path="res://Assets/arena_placeholder_v01.glb" id="3_1v6n4"]
|
||||
[ext_resource type="PackedScene" uid="uid://dxe72ig8gfbcg" path="res://Assets/arena model2026.glb" id="3_5jr0i"]
|
||||
[ext_resource type="PackedScene" uid="uid://crtm0xtiql3r8" path="res://Player.tscn" id="4_eicjn"]
|
||||
[ext_resource type="Texture2D" uid="uid://3syhacswepyj" path="res://HDRI/kloppenheim_06_puresky_4k.hdr" id="6_1v6n4"]
|
||||
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_eicjn"]
|
||||
|
||||
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_w7j4y"]
|
||||
panorama = ExtResource("6_1v6n4")
|
||||
energy_multiplier = 5.6
|
||||
|
||||
[sub_resource type="Sky" id="Sky_3el7n"]
|
||||
sky_material = SubResource("PanoramaSkyMaterial_w7j4y")
|
||||
|
||||
[sub_resource type="Environment" id="Environment_5jr0i"]
|
||||
background_mode = 2
|
||||
background_energy_multiplier = 0.18
|
||||
sky = SubResource("Sky_3el7n")
|
||||
ambient_light_color = Color(0.31061712, 0.31061712, 0.3106171, 1)
|
||||
ambient_light_energy = 16.0
|
||||
ssao_enabled = true
|
||||
ssao_radius = 1.17
|
||||
ssao_intensity = 0.0
|
||||
glow_intensity = 0.34
|
||||
glow_strength = 0.29
|
||||
glow_bloom = 0.1
|
||||
fog_light_color = Color(2.211, 2.211, 2.211, 1)
|
||||
fog_light_energy = 0.01
|
||||
fog_density = 0.0399
|
||||
volumetric_fog_enabled = true
|
||||
volumetric_fog_density = 0.0005
|
||||
volumetric_fog_emission = Color(1, 1, 1, 1)
|
||||
volumetric_fog_emission_energy = 7.85
|
||||
volumetric_fog_anisotropy = 0.9
|
||||
volumetric_fog_length = 69.07
|
||||
|
||||
[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_5jr0i"]
|
||||
dof_blur_far_enabled = true
|
||||
dof_blur_far_distance = 26.01
|
||||
dof_blur_near_enabled = true
|
||||
dof_blur_near_distance = 2.6
|
||||
dof_blur_near_transition = 5.0
|
||||
|
||||
[node name="IntroMenu" type="Node3D" unique_id=2130618263]
|
||||
|
||||
[node name="Matador" parent="." unique_id=166852612 instance=ExtResource("1_eicjn")]
|
||||
transform = Transform3D(-0.56715536, 0, -0.8236109, 0, 1, 0, 0.8236109, 0, -0.56715536, 5.2114463, -0.08998108, 1.8927763)
|
||||
script = ExtResource("2_5jr0i")
|
||||
|
||||
[node name="Skeleton3D" parent="Matador/Armature" parent_id_path=PackedInt32Array(166852612, 1447304122) index="0" unique_id=357848305]
|
||||
bones/0/position = Vector3(0.056660548, 0.6424767, -0.0167365)
|
||||
bones/0/rotation = Quaternion(0.013179442, -0.2660563, 0.073319815, 0.9610747)
|
||||
bones/1/rotation = Quaternion(0.06234612, 0.049236443, 0.08183311, 0.99347484)
|
||||
bones/2/rotation = Quaternion(-0.073883414, -0.049860783, -0.17668208, 0.9802238)
|
||||
bones/3/rotation = Quaternion(0.1986702, -0.17794952, -0.71790075, 0.6430262)
|
||||
bones/4/rotation = Quaternion(0.34491858, -0.4473084, -0.25076818, 0.7861691)
|
||||
bones/5/rotation = Quaternion(0.2577085, 0.103201896, -0.6748433, 0.68375605)
|
||||
bones/6/rotation = Quaternion(1.7417646e-08, -1.0305205e-07, -0.05870078, 0.99827564)
|
||||
bones/7/rotation = Quaternion(0.24033272, 0.3103031, 0.5222128, 0.7571301)
|
||||
bones/8/rotation = Quaternion(5.5530215e-08, 1.2911333e-07, 0.055464897, 0.99846065)
|
||||
bones/9/rotation = Quaternion(-6.3051346e-09, -3.6333955e-07, 0.005667881, 0.999984)
|
||||
bones/10/rotation = Quaternion(2.5839595e-08, 9.468444e-08, 0.058700778, 0.99827564)
|
||||
bones/11/rotation = Quaternion(0.39202607, 0.47060946, 0.57993996, 0.53713304)
|
||||
bones/12/rotation = Quaternion(0.8712108, 0.008231261, 0.48523128, 0.073990606)
|
||||
bones/13/rotation = Quaternion(-0.056263044, 0.0027001738, 0.3080972, 0.9496859)
|
||||
bones/14/rotation = Quaternion(0.016082464, 0.024660494, -0.86586916, 0.4994036)
|
||||
bones/15/rotation = Quaternion(0.6067664, -0.3062479, -0.7163194, 0.15790276)
|
||||
bones/16/rotation = Quaternion(-0.0731876, -0.0023153822, -0.47496143, 0.87695485)
|
||||
bones/17/rotation = Quaternion(-0.11824294, -0.17776872, 0.80557114, 0.55269533)
|
||||
bones/18/rotation = Quaternion(0.5305965, -0.28927496, 0.76720744, -0.21489605)
|
||||
bones/20/position = Vector3(0.22012731, 0.38421977, 0.36399037)
|
||||
bones/21/position = Vector3(-0.23671798, 0.052281797, -0.027087089)
|
||||
bones/21/rotation = Quaternion(0.5078295, -0.4920459, -0.4920459, 0.50782955)
|
||||
bones/22/position = Vector3(-0.39721552, 0.31719273, 0.3595722)
|
||||
bones/23/position = Vector3(-0.9167187, 1.3206767, 0.42621902)
|
||||
bones/23/rotation = Quaternion(0.9993525, -0.0021175682, 0.03502641, -0.00795782)
|
||||
bones/24/rotation = Quaternion(0.08874816, -0.018719967, -0.04671622, 0.99478185)
|
||||
bones/25/rotation = Quaternion(0.09634846, -0.0268489, -0.04050248, 0.9941608)
|
||||
|
||||
[node name="matador" parent="Matador/Armature/Skeleton3D" index="0" unique_id=593562242]
|
||||
transform = Transform3D(0.8642424, 0, 0.50307554, 0, 1, 0, -0.50307554, 0, 0.8642424, 0, 0, 0)
|
||||
|
||||
[node name="Muleta" parent="Matador/Armature/Skeleton3D" index="1" unique_id=978680467]
|
||||
cast_shadow = 0
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1531255459]
|
||||
transform = Transform3D(0.42176014, 0.2362673, 0.8753835, -0.10687317, 0.97167695, -0.21076548, -0.900387, -0.0046625203, 0.4350652, 8.41945, 0.17132203, 2.0652685)
|
||||
fov = 41.6
|
||||
near = 0.001
|
||||
|
||||
[node name="arena model2026" parent="." unique_id=179544183 instance=ExtResource("3_5jr0i")]
|
||||
transform = Transform3D(-0.83746713, 0, 0.54648757, 0, 0.99999994, 0, -0.54648757, 0, -0.83746713, 3.8733478, -0.6, -1.1080065)
|
||||
|
||||
[node name="arena_placeholder_v01" parent="." unique_id=1343590504 instance=ExtResource("3_1v6n4")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.3344436, 0, -1.5401263)
|
||||
visible = false
|
||||
|
||||
[node name="StaticBody3D" type="StaticBody3D" parent="arena_placeholder_v01" unique_id=340133176]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="arena_placeholder_v01/StaticBody3D" unique_id=201484167]
|
||||
transform = Transform3D(-33.265, 4.9526625e-07, -2.9081186e-06, 5.0228755e-06, 3.28, 0, -2.9081186e-06, 4.329755e-14, 33.265, 0, -3.3065948, 0)
|
||||
shape = SubResource("CylinderShape3D_eicjn")
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=660229295]
|
||||
transform = Transform3D(0.9491592, 0.31479403, -0.0014368258, -0.28033537, 0.84731936, 0.45106864, 0.14321098, -0.4277331, 0.89248836, 1.1162033, 7.3956842, -4.480528)
|
||||
light_energy = 1.32
|
||||
shadow_enabled = true
|
||||
shadow_blur = 8.689
|
||||
|
||||
[node name="DirectionalLight3D2" type="DirectionalLight3D" parent="." unique_id=498871251]
|
||||
transform = Transform3D(0.835524, -0.5376153, 0.11344351, -0.48260456, -0.6193575, 0.6192651, -0.26266432, -0.572159, -0.7769435, 1.1162033, 7.3956842, -4.480528)
|
||||
visible = false
|
||||
light_energy = 0.415
|
||||
light_indirect_energy = 16.0
|
||||
light_volumetric_fog_energy = 1.11
|
||||
shadow_blur = 10.0
|
||||
|
||||
[node name="Player" parent="." unique_id=165510044 instance=ExtResource("4_eicjn")]
|
||||
transform = Transform3D(0.9563367, 0, 0.29226705, 0, 1, 0, -0.29226705, 0, 0.9563367, 3.0920272, 0.39692497, -4.302477)
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=114793752]
|
||||
environment = SubResource("Environment_5jr0i")
|
||||
camera_attributes = SubResource("CameraAttributesPractical_5jr0i")
|
||||
|
||||
[node name="SpotLight3D" type="SpotLight3D" parent="." unique_id=1428020323]
|
||||
transform = Transform3D(0.94930077, -0.05846006, -0.30888584, 0.21308771, 0.8420559, 0.4955155, 0.23113126, -0.53621286, 0.81182146, -20.807917, 10.690277, 20.135067)
|
||||
visible = false
|
||||
light_energy = 16.0
|
||||
light_volumetric_fog_energy = 16.0
|
||||
shadow_enabled = true
|
||||
spot_range = 84.316696
|
||||
|
||||
[editable path="Matador"]
|
||||
+7
-8
@@ -1,6 +1,6 @@
|
||||
[gd_scene format=3 uid="uid://matador_scene_v1"]
|
||||
[gd_scene format=3 uid="uid://d0te4mwbh33ag"]
|
||||
|
||||
[ext_resource type="Script" path="res://matador.gd" id="1_matgd"]
|
||||
[ext_resource type="Script" uid="uid://bvfa7xi0luysk" path="res://matador.gd" id="1_matgd"]
|
||||
[ext_resource type="PackedScene" uid="uid://eu2lqjhowj4t" path="res://Assets/Matador.glb" id="2_matfbx"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_body"]
|
||||
@@ -11,19 +11,18 @@ height = 1.2
|
||||
radius = 0.45
|
||||
height = 1.4
|
||||
|
||||
[node name="Matador" type="CharacterBody3D"]
|
||||
[node name="Matador" type="CharacterBody3D" unique_id=1781857630]
|
||||
script = ExtResource("1_matgd")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=2101651042]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.85, 0)
|
||||
shape = SubResource("CapsuleShape3D_body")
|
||||
|
||||
[node name="HitArea" type="Area3D" parent="."]
|
||||
monitoring = true
|
||||
[node name="HitArea" type="Area3D" parent="." unique_id=745037545]
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="HitArea"]
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="HitArea" unique_id=1497356275]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.85, 0)
|
||||
shape = SubResource("CapsuleShape3D_hit")
|
||||
|
||||
[node name="matador2" parent="." instance=ExtResource("2_matfbx")]
|
||||
[node name="matador2" parent="." unique_id=1487256381 instance=ExtResource("2_matfbx")]
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
[gd_resource type="StandardMaterial3D" format=3 uid="uid://b73nb47y8ppt"]
|
||||
|
||||
[resource]
|
||||
albedo_color = Color(0.26098922, 0.27367952, 0.27059656, 1)
|
||||
metallic = 1.0
|
||||
@@ -0,0 +1,14 @@
|
||||
shader_type spatial;
|
||||
|
||||
void vertex() {
|
||||
// Called for every vertex the material is visible on.
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
// Called for every pixel the material is visible on.
|
||||
}
|
||||
|
||||
//void light() {
|
||||
// // Called for every pixel for every light affecting the material.
|
||||
// // Uncomment to replace the default light processing function with this one.
|
||||
//}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bme1rkldtyrhu
|
||||
@@ -0,0 +1,4 @@
|
||||
[gd_resource type="StandardMaterial3D" format=3 uid="uid://isrp2y47xs5x"]
|
||||
|
||||
[resource]
|
||||
albedo_color = Color(0.49425018, 0.31969637, 0.21259204, 1)
|
||||
@@ -0,0 +1,5 @@
|
||||
[gd_resource type="StandardMaterial3D" format=3 uid="uid://blpkmyikjnhbo"]
|
||||
|
||||
[resource]
|
||||
emission_enabled = true
|
||||
emission = Color(0.4627451, 0.8117647, 0.9490196, 1)
|
||||
@@ -0,0 +1,5 @@
|
||||
[gd_resource type="StandardMaterial3D" format=3 uid="uid://dgmk764033feq"]
|
||||
|
||||
[resource]
|
||||
emission_enabled = true
|
||||
emission = Color(0.7096375, 0.3347874, 0.09943161, 1)
|
||||
+2
-1
@@ -9,7 +9,8 @@ radius = 0.7495117
|
||||
height = 1.845398
|
||||
|
||||
[node name="Player" type="CharacterBody3D" unique_id=165510044]
|
||||
collision_layer = 3
|
||||
collision_layer = 2
|
||||
collision_mask = 9
|
||||
script = ExtResource("1_xhfnw")
|
||||
|
||||
[node name="CollisionBull" type="CollisionShape3D" parent="." unique_id=571780801]
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
[gd_scene format=3 uid="uid://crtm0xtiql3r8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn777gguclud5" path="res://player.gd" id="1_xhfnw"]
|
||||
[ext_resource type="Script" uid="uid://cpyq2r5cq653g" path="res://camera_iso.gd" id="2_camera_iso"]
|
||||
[ext_resource type="PackedScene" uid="uid://bun14xmk20pcj" path="res://Assets/bull.fbx" id="4_e80uo"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_kne1u"]
|
||||
radius = 0.7495117
|
||||
height = 1.845398
|
||||
|
||||
[node name="Player" type="CharacterBody3D" unique_id=165510044]
|
||||
collision_layer = 2
|
||||
collision_mask = 9
|
||||
script = ExtResource("1_xhfnw")
|
||||
|
||||
[node name="CollisionBull" type="CollisionShape3D" parent="." unique_id=571780801]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.29183745, 0.3197594)
|
||||
shape = SubResource("CapsuleShape3D_kne1u")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1120161087]
|
||||
script = ExtResource("2_camera_iso")
|
||||
|
||||
[node name="bull" parent="." unique_id=1386495166 instance=ExtResource("4_e80uo")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.655, 0.23)
|
||||
|
||||
[node name="Skeleton3D" parent="bull/Armature" parent_id_path=PackedInt32Array(1386495166, 1942410469) index="0" unique_id=550138996]
|
||||
bones/0/position = Vector3(0, 0, 0.009963839)
|
||||
bones/0/rotation = Quaternion(0.7071068, 0, 0, 0.7071067)
|
||||
bones/0/scale = Vector3(1, 1, 1)
|
||||
bones/1/position = Vector3(0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/1/rotation = Quaternion(-0.00038647873, 0.06909673, 0.9868542, -0.14609687)
|
||||
bones/2/rotation = Quaternion(-0.06929122, 3.2175163e-07, -0.112670615, 0.99121344)
|
||||
bones/4/position = Vector3(0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/4/rotation = Quaternion(-0.24948503, 0.19590352, 0.9416978, -0.11217985)
|
||||
bones/4/scale = Vector3(1.0000001, 0.9999999, 1.0000001)
|
||||
bones/5/rotation = Quaternion(-0.58943665, -0.3660725, -0.22564478, 0.683842)
|
||||
bones/5/scale = Vector3(1, 1.0000001, 0.99999994)
|
||||
bones/6/rotation = Quaternion(0.52910197, 0.15997827, 0.120245, 0.8246207)
|
||||
bones/6/scale = Vector3(1, 1, 1.0000001)
|
||||
bones/17/position = Vector3(0, 0.0009373814, 0.007552617)
|
||||
bones/17/rotation = Quaternion(-9.4156974e-08, 0.7071068, 0.7071067, -9.4156974e-08)
|
||||
bones/19/position = Vector3(-0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/19/rotation = Quaternion(0.00038647873, 0.06909673, 0.9868542, 0.14609687)
|
||||
bones/20/rotation = Quaternion(-0.06929122, -3.2227587e-07, 0.11267061, 0.99121344)
|
||||
bones/22/position = Vector3(-0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/22/rotation = Quaternion(0.24948503, 0.19590352, 0.9416978, 0.11217985)
|
||||
bones/23/rotation = Quaternion(-0.58943665, 0.3660725, 0.22564478, 0.683842)
|
||||
bones/23/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/24/rotation = Quaternion(0.529102, -0.15997836, -0.120245025, 0.82462066)
|
||||
bones/24/scale = Vector3(1, 1.0000001, 1)
|
||||
|
||||
[editable path="bull"]
|
||||
@@ -0,0 +1,52 @@
|
||||
[gd_scene format=3 uid="uid://crtm0xtiql3r8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn777gguclud5" path="res://player.gd" id="1_xhfnw"]
|
||||
[ext_resource type="Script" uid="uid://cpyq2r5cq653g" path="res://camera_iso.gd" id="2_camera_iso"]
|
||||
[ext_resource type="PackedScene" uid="uid://bun14xmk20pcj" path="res://Assets/bull.fbx" id="4_e80uo"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_kne1u"]
|
||||
radius = 0.7495117
|
||||
height = 1.845398
|
||||
|
||||
[node name="Player" type="CharacterBody3D" unique_id=165510044]
|
||||
collision_layer = 2
|
||||
collision_mask = 9
|
||||
script = ExtResource("1_xhfnw")
|
||||
|
||||
[node name="CollisionBull" type="CollisionShape3D" parent="." unique_id=571780801]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.29183745, 0.3197594)
|
||||
shape = SubResource("CapsuleShape3D_kne1u")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1120161087]
|
||||
script = ExtResource("2_camera_iso")
|
||||
|
||||
[node name="bull" parent="." unique_id=1386495166 instance=ExtResource("4_e80uo")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.655, 0.23)
|
||||
|
||||
[node name="Skeleton3D" parent="bull/Armature" parent_id_path=PackedInt32Array(1386495166, 1942410469) index="0" unique_id=550138996]
|
||||
bones/0/position = Vector3(0, 0, 0.009963839)
|
||||
bones/0/rotation = Quaternion(0.7071068, 0, 0, 0.7071067)
|
||||
bones/0/scale = Vector3(1, 1, 1)
|
||||
bones/1/position = Vector3(0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/1/rotation = Quaternion(-0.00038647873, 0.06909673, 0.9868542, -0.14609687)
|
||||
bones/2/rotation = Quaternion(-0.06929122, 3.2175163e-07, -0.112670615, 0.99121344)
|
||||
bones/4/position = Vector3(0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/4/rotation = Quaternion(-0.24948503, 0.19590352, 0.9416978, -0.11217985)
|
||||
bones/4/scale = Vector3(1.0000001, 0.9999999, 1.0000001)
|
||||
bones/5/rotation = Quaternion(-0.58943665, -0.3660725, -0.22564478, 0.683842)
|
||||
bones/5/scale = Vector3(1, 1.0000001, 0.99999994)
|
||||
bones/6/rotation = Quaternion(0.52910197, 0.15997827, 0.120245, 0.8246207)
|
||||
bones/6/scale = Vector3(1, 1, 1.0000001)
|
||||
bones/17/position = Vector3(0, 0.0009373814, 0.007552617)
|
||||
bones/17/rotation = Quaternion(-9.4156974e-08, 0.7071068, 0.7071067, -9.4156974e-08)
|
||||
bones/19/position = Vector3(-0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/19/rotation = Quaternion(0.00038647873, 0.06909673, 0.9868542, 0.14609687)
|
||||
bones/20/rotation = Quaternion(-0.06929122, -3.2227587e-07, 0.11267061, 0.99121344)
|
||||
bones/22/position = Vector3(-0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/22/rotation = Quaternion(0.24948503, 0.19590352, 0.9416978, 0.11217985)
|
||||
bones/23/rotation = Quaternion(-0.58943665, 0.3660725, 0.22564478, 0.683842)
|
||||
bones/23/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/24/rotation = Quaternion(0.529102, -0.15997836, -0.120245025, 0.82462066)
|
||||
bones/24/scale = Vector3(1, 1.0000001, 1)
|
||||
|
||||
[editable path="bull"]
|
||||
@@ -0,0 +1,52 @@
|
||||
[gd_scene format=3 uid="uid://crtm0xtiql3r8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn777gguclud5" path="res://player.gd" id="1_xhfnw"]
|
||||
[ext_resource type="Script" uid="uid://cpyq2r5cq653g" path="res://camera_iso.gd" id="2_camera_iso"]
|
||||
[ext_resource type="PackedScene" uid="uid://bun14xmk20pcj" path="res://Assets/bull.fbx" id="4_e80uo"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_kne1u"]
|
||||
radius = 0.7495117
|
||||
height = 1.845398
|
||||
|
||||
[node name="Player" type="CharacterBody3D" unique_id=165510044]
|
||||
collision_layer = 2
|
||||
collision_mask = 9
|
||||
script = ExtResource("1_xhfnw")
|
||||
|
||||
[node name="CollisionBull" type="CollisionShape3D" parent="." unique_id=571780801]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.29183745, 0.3197594)
|
||||
shape = SubResource("CapsuleShape3D_kne1u")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1120161087]
|
||||
script = ExtResource("2_camera_iso")
|
||||
|
||||
[node name="bull" parent="." unique_id=1386495166 instance=ExtResource("4_e80uo")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.655, 0.23)
|
||||
|
||||
[node name="Skeleton3D" parent="bull/Armature" parent_id_path=PackedInt32Array(1386495166, 1942410469) index="0" unique_id=550138996]
|
||||
bones/0/position = Vector3(0, 0, 0.009963839)
|
||||
bones/0/rotation = Quaternion(0.7071068, 0, 0, 0.7071067)
|
||||
bones/0/scale = Vector3(1, 1, 1)
|
||||
bones/1/position = Vector3(0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/1/rotation = Quaternion(-0.00038647873, 0.06909673, 0.9868542, -0.14609687)
|
||||
bones/2/rotation = Quaternion(-0.06929122, 3.2175163e-07, -0.112670615, 0.99121344)
|
||||
bones/4/position = Vector3(0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/4/rotation = Quaternion(-0.24948503, 0.19590352, 0.9416978, -0.11217985)
|
||||
bones/4/scale = Vector3(1.0000001, 0.9999999, 1.0000001)
|
||||
bones/5/rotation = Quaternion(-0.58943665, -0.3660725, -0.22564478, 0.683842)
|
||||
bones/5/scale = Vector3(1, 1.0000001, 0.99999994)
|
||||
bones/6/rotation = Quaternion(0.52910197, 0.15997827, 0.120245, 0.8246207)
|
||||
bones/6/scale = Vector3(1, 1, 1.0000001)
|
||||
bones/17/position = Vector3(0, 0.0009373814, 0.007552617)
|
||||
bones/17/rotation = Quaternion(-9.4156974e-08, 0.7071068, 0.7071067, -9.4156974e-08)
|
||||
bones/19/position = Vector3(-0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/19/rotation = Quaternion(0.00038647873, 0.06909673, 0.9868542, 0.14609687)
|
||||
bones/20/rotation = Quaternion(-0.06929122, -3.2227587e-07, 0.11267061, 0.99121344)
|
||||
bones/22/position = Vector3(-0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/22/rotation = Quaternion(0.24948503, 0.19590352, 0.9416978, 0.11217985)
|
||||
bones/23/rotation = Quaternion(-0.58943665, 0.3660725, 0.22564478, 0.683842)
|
||||
bones/23/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/24/rotation = Quaternion(0.529102, -0.15997836, -0.120245025, 0.82462066)
|
||||
bones/24/scale = Vector3(1, 1.0000001, 1)
|
||||
|
||||
[editable path="bull"]
|
||||
@@ -0,0 +1,52 @@
|
||||
[gd_scene format=3 uid="uid://crtm0xtiql3r8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn777gguclud5" path="res://player.gd" id="1_xhfnw"]
|
||||
[ext_resource type="Script" uid="uid://cpyq2r5cq653g" path="res://camera_iso.gd" id="2_camera_iso"]
|
||||
[ext_resource type="PackedScene" uid="uid://bun14xmk20pcj" path="res://Assets/bull.fbx" id="4_e80uo"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_kne1u"]
|
||||
radius = 0.7495117
|
||||
height = 1.845398
|
||||
|
||||
[node name="Player" type="CharacterBody3D" unique_id=165510044]
|
||||
collision_layer = 2
|
||||
collision_mask = 9
|
||||
script = ExtResource("1_xhfnw")
|
||||
|
||||
[node name="CollisionBull" type="CollisionShape3D" parent="." unique_id=571780801]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.29183745, 0.3197594)
|
||||
shape = SubResource("CapsuleShape3D_kne1u")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1120161087]
|
||||
script = ExtResource("2_camera_iso")
|
||||
|
||||
[node name="bull" parent="." unique_id=1386495166 instance=ExtResource("4_e80uo")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.655, 0.23)
|
||||
|
||||
[node name="Skeleton3D" parent="bull/Armature" parent_id_path=PackedInt32Array(1386495166, 1942410469) index="0" unique_id=550138996]
|
||||
bones/0/position = Vector3(0, 0, 0.009963839)
|
||||
bones/0/rotation = Quaternion(0.7071068, 0, 0, 0.7071067)
|
||||
bones/0/scale = Vector3(1, 1, 1)
|
||||
bones/1/position = Vector3(0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/1/rotation = Quaternion(-0.00038647873, 0.06909673, 0.9868542, -0.14609687)
|
||||
bones/2/rotation = Quaternion(-0.06929122, 3.2175163e-07, -0.112670615, 0.99121344)
|
||||
bones/4/position = Vector3(0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/4/rotation = Quaternion(-0.24948503, 0.19590352, 0.9416978, -0.11217985)
|
||||
bones/4/scale = Vector3(1.0000001, 0.9999999, 1.0000001)
|
||||
bones/5/rotation = Quaternion(-0.58943665, -0.3660725, -0.22564478, 0.683842)
|
||||
bones/5/scale = Vector3(1, 1.0000001, 0.99999994)
|
||||
bones/6/rotation = Quaternion(0.52910197, 0.15997827, 0.120245, 0.8246207)
|
||||
bones/6/scale = Vector3(1, 1, 1.0000001)
|
||||
bones/17/position = Vector3(0, 0.0009373814, 0.007552617)
|
||||
bones/17/rotation = Quaternion(-9.4156974e-08, 0.7071068, 0.7071067, -9.4156974e-08)
|
||||
bones/19/position = Vector3(-0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/19/rotation = Quaternion(0.00038647873, 0.06909673, 0.9868542, 0.14609687)
|
||||
bones/20/rotation = Quaternion(-0.06929122, -3.2227587e-07, 0.11267061, 0.99121344)
|
||||
bones/22/position = Vector3(-0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/22/rotation = Quaternion(0.24948503, 0.19590352, 0.9416978, 0.11217985)
|
||||
bones/23/rotation = Quaternion(-0.58943665, 0.3660725, 0.22564478, 0.683842)
|
||||
bones/23/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/24/rotation = Quaternion(0.529102, -0.15997836, -0.120245025, 0.82462066)
|
||||
bones/24/scale = Vector3(1, 1.0000001, 1)
|
||||
|
||||
[editable path="bull"]
|
||||
@@ -0,0 +1,52 @@
|
||||
[gd_scene format=3 uid="uid://crtm0xtiql3r8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn777gguclud5" path="res://player.gd" id="1_xhfnw"]
|
||||
[ext_resource type="Script" uid="uid://cpyq2r5cq653g" path="res://camera_iso.gd" id="2_camera_iso"]
|
||||
[ext_resource type="PackedScene" uid="uid://bun14xmk20pcj" path="res://Assets/bull.fbx" id="4_e80uo"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_kne1u"]
|
||||
radius = 0.7495117
|
||||
height = 1.845398
|
||||
|
||||
[node name="Player" type="CharacterBody3D" unique_id=165510044]
|
||||
collision_layer = 2
|
||||
collision_mask = 9
|
||||
script = ExtResource("1_xhfnw")
|
||||
|
||||
[node name="CollisionBull" type="CollisionShape3D" parent="." unique_id=571780801]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.29183745, 0.3197594)
|
||||
shape = SubResource("CapsuleShape3D_kne1u")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1120161087]
|
||||
script = ExtResource("2_camera_iso")
|
||||
|
||||
[node name="bull" parent="." unique_id=1386495166 instance=ExtResource("4_e80uo")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.655, 0.23)
|
||||
|
||||
[node name="Skeleton3D" parent="bull/Armature" parent_id_path=PackedInt32Array(1386495166, 1942410469) index="0" unique_id=550138996]
|
||||
bones/0/position = Vector3(0, 0, 0.009963839)
|
||||
bones/0/rotation = Quaternion(0.7071068, 0, 0, 0.7071067)
|
||||
bones/0/scale = Vector3(1, 1, 1)
|
||||
bones/1/position = Vector3(0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/1/rotation = Quaternion(-0.00038647873, 0.06909673, 0.9868542, -0.14609687)
|
||||
bones/2/rotation = Quaternion(-0.06929122, 3.2175163e-07, -0.112670615, 0.99121344)
|
||||
bones/4/position = Vector3(0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/4/rotation = Quaternion(-0.24948503, 0.19590352, 0.9416978, -0.11217985)
|
||||
bones/4/scale = Vector3(1.0000001, 0.9999999, 1.0000001)
|
||||
bones/5/rotation = Quaternion(-0.58943665, -0.3660725, -0.22564478, 0.683842)
|
||||
bones/5/scale = Vector3(1, 1.0000001, 0.99999994)
|
||||
bones/6/rotation = Quaternion(0.52910197, 0.15997827, 0.120245, 0.8246207)
|
||||
bones/6/scale = Vector3(1, 1, 1.0000001)
|
||||
bones/17/position = Vector3(0, 0.0009373814, 0.007552617)
|
||||
bones/17/rotation = Quaternion(-9.4156974e-08, 0.7071068, 0.7071067, -9.4156974e-08)
|
||||
bones/19/position = Vector3(-0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/19/rotation = Quaternion(0.00038647873, 0.06909673, 0.9868542, 0.14609687)
|
||||
bones/20/rotation = Quaternion(-0.06929122, -3.2227587e-07, 0.11267061, 0.99121344)
|
||||
bones/22/position = Vector3(-0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/22/rotation = Quaternion(0.24948503, 0.19590352, 0.9416978, 0.11217985)
|
||||
bones/23/rotation = Quaternion(-0.58943665, 0.3660725, 0.22564478, 0.683842)
|
||||
bones/23/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/24/rotation = Quaternion(0.529102, -0.15997836, -0.120245025, 0.82462066)
|
||||
bones/24/scale = Vector3(1, 1.0000001, 1)
|
||||
|
||||
[editable path="bull"]
|
||||
@@ -0,0 +1,52 @@
|
||||
[gd_scene format=3 uid="uid://crtm0xtiql3r8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn777gguclud5" path="res://player.gd" id="1_xhfnw"]
|
||||
[ext_resource type="Script" uid="uid://cpyq2r5cq653g" path="res://camera_iso.gd" id="2_camera_iso"]
|
||||
[ext_resource type="PackedScene" uid="uid://bun14xmk20pcj" path="res://Assets/bull.fbx" id="4_e80uo"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_kne1u"]
|
||||
radius = 0.7495117
|
||||
height = 1.845398
|
||||
|
||||
[node name="Player" type="CharacterBody3D" unique_id=165510044]
|
||||
collision_layer = 2
|
||||
collision_mask = 9
|
||||
script = ExtResource("1_xhfnw")
|
||||
|
||||
[node name="CollisionBull" type="CollisionShape3D" parent="." unique_id=571780801]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.29183745, 0.3197594)
|
||||
shape = SubResource("CapsuleShape3D_kne1u")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1120161087]
|
||||
script = ExtResource("2_camera_iso")
|
||||
|
||||
[node name="bull" parent="." unique_id=1386495166 instance=ExtResource("4_e80uo")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.655, 0.23)
|
||||
|
||||
[node name="Skeleton3D" parent="bull/Armature" parent_id_path=PackedInt32Array(1386495166, 1942410469) index="0" unique_id=550138996]
|
||||
bones/0/position = Vector3(0, 0, 0.009963839)
|
||||
bones/0/rotation = Quaternion(0.7071068, 0, 0, 0.7071067)
|
||||
bones/0/scale = Vector3(1, 1, 1)
|
||||
bones/1/position = Vector3(0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/1/rotation = Quaternion(-0.00038647873, 0.06909673, 0.9868542, -0.14609687)
|
||||
bones/2/rotation = Quaternion(-0.06929122, 3.2175163e-07, -0.112670615, 0.99121344)
|
||||
bones/4/position = Vector3(0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/4/rotation = Quaternion(-0.24948503, 0.19590352, 0.9416978, -0.11217985)
|
||||
bones/4/scale = Vector3(1.0000001, 0.9999999, 1.0000001)
|
||||
bones/5/rotation = Quaternion(-0.58943665, -0.3660725, -0.22564478, 0.683842)
|
||||
bones/5/scale = Vector3(1, 1.0000001, 0.99999994)
|
||||
bones/6/rotation = Quaternion(0.52910197, 0.15997827, 0.120245, 0.8246207)
|
||||
bones/6/scale = Vector3(1, 1, 1.0000001)
|
||||
bones/17/position = Vector3(0, 0.0009373814, 0.007552617)
|
||||
bones/17/rotation = Quaternion(-9.4156974e-08, 0.7071068, 0.7071067, -9.4156974e-08)
|
||||
bones/19/position = Vector3(-0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/19/rotation = Quaternion(0.00038647873, 0.06909673, 0.9868542, 0.14609687)
|
||||
bones/20/rotation = Quaternion(-0.06929122, -3.2227587e-07, 0.11267061, 0.99121344)
|
||||
bones/22/position = Vector3(-0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/22/rotation = Quaternion(0.24948503, 0.19590352, 0.9416978, 0.11217985)
|
||||
bones/23/rotation = Quaternion(-0.58943665, 0.3660725, 0.22564478, 0.683842)
|
||||
bones/23/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/24/rotation = Quaternion(0.529102, -0.15997836, -0.120245025, 0.82462066)
|
||||
bones/24/scale = Vector3(1, 1.0000001, 1)
|
||||
|
||||
[editable path="bull"]
|
||||
@@ -0,0 +1,52 @@
|
||||
[gd_scene format=3 uid="uid://crtm0xtiql3r8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn777gguclud5" path="res://player.gd" id="1_xhfnw"]
|
||||
[ext_resource type="Script" uid="uid://cpyq2r5cq653g" path="res://camera_iso.gd" id="2_camera_iso"]
|
||||
[ext_resource type="PackedScene" uid="uid://bun14xmk20pcj" path="res://Assets/bull.fbx" id="4_e80uo"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_kne1u"]
|
||||
radius = 0.7495117
|
||||
height = 1.845398
|
||||
|
||||
[node name="Player" type="CharacterBody3D" unique_id=165510044]
|
||||
collision_layer = 2
|
||||
collision_mask = 9
|
||||
script = ExtResource("1_xhfnw")
|
||||
|
||||
[node name="CollisionBull" type="CollisionShape3D" parent="." unique_id=571780801]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.29183745, 0.3197594)
|
||||
shape = SubResource("CapsuleShape3D_kne1u")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1120161087]
|
||||
script = ExtResource("2_camera_iso")
|
||||
|
||||
[node name="bull" parent="." unique_id=1386495166 instance=ExtResource("4_e80uo")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.655, 0.23)
|
||||
|
||||
[node name="Skeleton3D" parent="bull/Armature" parent_id_path=PackedInt32Array(1386495166, 1942410469) index="0" unique_id=550138996]
|
||||
bones/0/position = Vector3(0, 0, 0.009963839)
|
||||
bones/0/rotation = Quaternion(0.7071068, 0, 0, 0.7071067)
|
||||
bones/0/scale = Vector3(1, 1, 1)
|
||||
bones/1/position = Vector3(0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/1/rotation = Quaternion(-0.00038647873, 0.06909673, 0.9868542, -0.14609687)
|
||||
bones/2/rotation = Quaternion(-0.06929122, 3.2175163e-07, -0.112670615, 0.99121344)
|
||||
bones/4/position = Vector3(0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/4/rotation = Quaternion(-0.24948503, 0.19590352, 0.9416978, -0.11217985)
|
||||
bones/4/scale = Vector3(1.0000001, 0.9999999, 1.0000001)
|
||||
bones/5/rotation = Quaternion(-0.58943665, -0.3660725, -0.22564478, 0.683842)
|
||||
bones/5/scale = Vector3(1, 1.0000001, 0.99999994)
|
||||
bones/6/rotation = Quaternion(0.52910197, 0.15997827, 0.120245, 0.8246207)
|
||||
bones/6/scale = Vector3(1, 1, 1.0000001)
|
||||
bones/17/position = Vector3(0, 0.0009373814, 0.007552617)
|
||||
bones/17/rotation = Quaternion(-9.4156974e-08, 0.7071068, 0.7071067, -9.4156974e-08)
|
||||
bones/19/position = Vector3(-0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/19/rotation = Quaternion(0.00038647873, 0.06909673, 0.9868542, 0.14609687)
|
||||
bones/20/rotation = Quaternion(-0.06929122, -3.2227587e-07, 0.11267061, 0.99121344)
|
||||
bones/22/position = Vector3(-0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/22/rotation = Quaternion(0.24948503, 0.19590352, 0.9416978, 0.11217985)
|
||||
bones/23/rotation = Quaternion(-0.58943665, 0.3660725, 0.22564478, 0.683842)
|
||||
bones/23/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/24/rotation = Quaternion(0.529102, -0.15997836, -0.120245025, 0.82462066)
|
||||
bones/24/scale = Vector3(1, 1.0000001, 1)
|
||||
|
||||
[editable path="bull"]
|
||||
@@ -0,0 +1,52 @@
|
||||
[gd_scene format=3 uid="uid://crtm0xtiql3r8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn777gguclud5" path="res://player.gd" id="1_xhfnw"]
|
||||
[ext_resource type="Script" uid="uid://cpyq2r5cq653g" path="res://camera_iso.gd" id="2_camera_iso"]
|
||||
[ext_resource type="PackedScene" uid="uid://bun14xmk20pcj" path="res://Assets/bull.fbx" id="4_e80uo"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_kne1u"]
|
||||
radius = 0.7495117
|
||||
height = 1.845398
|
||||
|
||||
[node name="Player" type="CharacterBody3D" unique_id=165510044]
|
||||
collision_layer = 2
|
||||
collision_mask = 9
|
||||
script = ExtResource("1_xhfnw")
|
||||
|
||||
[node name="CollisionBull" type="CollisionShape3D" parent="." unique_id=571780801]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.29183745, 0.3197594)
|
||||
shape = SubResource("CapsuleShape3D_kne1u")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=1120161087]
|
||||
script = ExtResource("2_camera_iso")
|
||||
|
||||
[node name="bull" parent="." unique_id=1386495166 instance=ExtResource("4_e80uo")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.655, 0.23)
|
||||
|
||||
[node name="Skeleton3D" parent="bull/Armature" parent_id_path=PackedInt32Array(1386495166, 1942410469) index="0" unique_id=550138996]
|
||||
bones/0/position = Vector3(0, 0, 0.009963839)
|
||||
bones/0/rotation = Quaternion(0.7071068, 0, 0, 0.7071067)
|
||||
bones/0/scale = Vector3(1, 1, 1)
|
||||
bones/1/position = Vector3(0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/1/rotation = Quaternion(-0.00038647873, 0.06909673, 0.9868542, -0.14609687)
|
||||
bones/2/rotation = Quaternion(-0.06929122, 3.2175163e-07, -0.112670615, 0.99121344)
|
||||
bones/4/position = Vector3(0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/4/rotation = Quaternion(-0.24948503, 0.19590352, 0.9416978, -0.11217985)
|
||||
bones/4/scale = Vector3(1.0000001, 0.9999999, 1.0000001)
|
||||
bones/5/rotation = Quaternion(-0.58943665, -0.3660725, -0.22564478, 0.683842)
|
||||
bones/5/scale = Vector3(1, 1.0000001, 0.99999994)
|
||||
bones/6/rotation = Quaternion(0.52910197, 0.15997827, 0.120245, 0.8246207)
|
||||
bones/6/scale = Vector3(1, 1, 1.0000001)
|
||||
bones/17/position = Vector3(0, 0.0009373814, 0.007552617)
|
||||
bones/17/rotation = Quaternion(-9.4156974e-08, 0.7071068, 0.7071067, -9.4156974e-08)
|
||||
bones/19/position = Vector3(-0.003526625, -0.0043296535, 0.0040827994)
|
||||
bones/19/rotation = Quaternion(0.00038647873, 0.06909673, 0.9868542, 0.14609687)
|
||||
bones/20/rotation = Quaternion(-0.06929122, -3.2227587e-07, 0.11267061, 0.99121344)
|
||||
bones/22/position = Vector3(-0.0045358227, -0.002137695, -0.004238624)
|
||||
bones/22/rotation = Quaternion(0.24948503, 0.19590352, 0.9416978, 0.11217985)
|
||||
bones/23/rotation = Quaternion(-0.58943665, 0.3660725, 0.22564478, 0.683842)
|
||||
bones/23/scale = Vector3(1, 1.0000001, 1)
|
||||
bones/24/rotation = Quaternion(0.529102, -0.15997836, -0.120245025, 0.82462066)
|
||||
bones/24/scale = Vector3(1, 1.0000001, 1)
|
||||
|
||||
[editable path="bull"]
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
[gd_scene format=3 uid="uid://c8spearwrap01"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://jepc74w8opbu" path="res://Assets/spear.glb" id="1_spearglb"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_shaft"]
|
||||
radius = 0.13
|
||||
height = 2.2
|
||||
|
||||
[node name="Spear" type="Node3D"]
|
||||
|
||||
[node name="spear" parent="." instance=ExtResource("1_spearglb")]
|
||||
|
||||
[node name="HitShape" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 0, 0.79)
|
||||
shape = SubResource("CapsuleShape3D_shaft")
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
[gd_scene format=3 uid="uid://c8swordwrap01"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://xyvank512l5n" path="res://Assets/sword.glb" id="1_swordglb"]
|
||||
[ext_resource type="Script" path="res://hitbox.gd" id="2_hitbox"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_blade"]
|
||||
radius = 0.18
|
||||
height = 1.3
|
||||
|
||||
[node name="Sword" type="Node3D"]
|
||||
|
||||
[node name="sword" parent="." instance=ExtResource("1_swordglb")]
|
||||
|
||||
[node name="BladeHitbox" type="Area3D" parent="."]
|
||||
script = ExtResource("2_hitbox")
|
||||
damage_cause = "gored"
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="BladeHitbox"]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 0, 0.8)
|
||||
shape = SubResource("CapsuleShape3D_blade")
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -26,7 +26,25 @@ var _phase: Phase = Phase.WINDUP
|
||||
var _bull: CharacterBody3D = null
|
||||
var _skeleton: Skeleton3D = null
|
||||
var _anim_player: AnimationPlayer = null
|
||||
# Separate player baked into Assets/fx/Bear_FX.glb: each clip scales one FX mesh up from 0
|
||||
# and back at its strike frame (self-hiding), so bear.gd just fires the matching clip.
|
||||
var _fx_player: AnimationPlayer = null
|
||||
var _fx_root: Node = null
|
||||
# Shaped attack colliders live in BearAttackHitboxes.tscn (under bear_model, so they track the
|
||||
# bear's facing): a ground-circle cylinder for the leap slam and a forward box lane for the smash.
|
||||
# Their sizes AND their travel/pop motion are authored in that scene's AnimationPlayer (clips
|
||||
# "leap_slam" / "smash_travel") — scrub them there to tweak. bear.gd only fires the clip, sets the
|
||||
# knock-up shaping, activates monitoring, and sweeps for overlaps while the clip runs.
|
||||
var _leap_hitbox: Hitbox = null
|
||||
var _smash_hitbox: Hitbox = null
|
||||
var _hitbox_anim: AnimationPlayer = null
|
||||
var _active_hitbox: Hitbox = null
|
||||
var _blood_burst: CPUParticles3D = null
|
||||
# Bull-ram tracking: the bull's position last frame (to sweep its travel) and whether it was mid-ram
|
||||
# last frame (edge-trigger so one charge = one wound, re-arming when the bull breaks off).
|
||||
var _bull_prev_pos: Vector3 = Vector3.ZERO
|
||||
var _bull_prev_seen: bool = false
|
||||
var _bull_ramming: bool = false
|
||||
|
||||
var _hp: int = 10
|
||||
var _enraged: bool = false
|
||||
@@ -78,9 +96,7 @@ const _BULL_STANDOFF: float = 1.9
|
||||
@onready var _mesh: Node3D = $bear_model
|
||||
@onready var _hit_area: Area3D = $HitArea
|
||||
var _dust: CPUParticles3D = null
|
||||
# Claw-slash bursts bound to the paw bones, fired one per hit of the 1-2 punch.
|
||||
var _claw_l: CPUParticles3D = null
|
||||
var _claw_r: CPUParticles3D = null
|
||||
|
||||
|
||||
|
||||
const RigidSkin = preload("res://rigid_skin.gd")
|
||||
@@ -93,9 +109,17 @@ func _ready() -> void:
|
||||
health_changed.emit(_hp, _hp)
|
||||
_skeleton = _find_skeleton(_mesh)
|
||||
_anim_player = _find_anim_player(_mesh)
|
||||
# Web (Mali/ANGLE) can't run Compatibility vertex-skinning; rebuild the bear as
|
||||
# non-skinned bone-attached pieces there. Desktop keeps smooth GPU skinning.
|
||||
if OS.has_feature("web"):
|
||||
_fx_root = _mesh.get_node_or_null("Bear_FX")
|
||||
if _fx_root:
|
||||
_fx_player = _fx_root.get_node_or_null("AnimationPlayer") as AnimationPlayer
|
||||
if _fx_player:
|
||||
# The smash/leap clips end held at full scale (Siim only ramped the claw clips back
|
||||
# down), so snap each effect back to 0 when its clip finishes — keeps them one-shot.
|
||||
_fx_player.animation_finished.connect(_on_fx_finished)
|
||||
# Native GPU skinning by default (the Mali/ANGLE invisible-skinning bug is fixed in the 4.7
|
||||
# web templates). The bear is a single dense organic mesh, so the rigid-skin fallback tears
|
||||
# seam holes as it animates — another reason native is the default. See rigid_skin_enabled().
|
||||
if Controls.rigid_skin_enabled():
|
||||
RigidSkin.convert_tree(self)
|
||||
if _anim_player:
|
||||
_anim_idle = _resolve_anim(["IDLE_ON4LEGS", "IDLE"])
|
||||
@@ -113,12 +137,11 @@ func _ready() -> void:
|
||||
for a in [_anim_swipe, _anim_smash, _anim_leap, _anim_death]:
|
||||
_set_no_loop(a)
|
||||
_anim_player.playback_default_blend_time = 0.12
|
||||
_hit_area.body_entered.connect(_on_body_entered)
|
||||
_blood_burst = preload("res://blood_burst.gd").new()
|
||||
add_child(_blood_burst)
|
||||
_dust = _make_slam_dust()
|
||||
add_child(_dust)
|
||||
_setup_claws()
|
||||
_setup_attack_hitboxes()
|
||||
_enter_neutral()
|
||||
|
||||
#take hit flashing
|
||||
@@ -166,8 +189,6 @@ func _clear_hit_flash() -> void:
|
||||
func _setup_claws() -> void:
|
||||
if _skeleton == null:
|
||||
return
|
||||
_claw_r = _attach_claw("hand_r")
|
||||
_claw_l = _attach_claw("hand_l")
|
||||
|
||||
|
||||
func _attach_claw(bone: String) -> CPUParticles3D:
|
||||
@@ -216,6 +237,9 @@ func _physics_process(delta: float) -> void:
|
||||
_acquire_bull()
|
||||
_update_enrage()
|
||||
_stagger_cd = maxf(0.0, _stagger_cd - delta)
|
||||
_tick_attack_hitbox()
|
||||
if _bull != null:
|
||||
_sweep_bull_ram()
|
||||
|
||||
match _state:
|
||||
State.NEUTRAL: _tick_neutral(delta)
|
||||
@@ -285,15 +309,19 @@ func _decide() -> void:
|
||||
|
||||
var dist := _flat_dist_to_bull()
|
||||
var options: Array
|
||||
|
||||
if dist <= DP.f("bear_close_range"):
|
||||
# In strike range: punch or overhead (both step in during the swing).
|
||||
options = [[State.SWIPE, 3.0], [State.SMASH, 3.0 if _enraged else 2.5]]
|
||||
elif dist <= DP.f("bear_mid_range"):
|
||||
# Mid: mostly walk the bull down on two legs; occasionally leap the gap.
|
||||
options = [[State.STALK, 3.0], [State.LEAP, 2.0 if _enraged else 1.5]]
|
||||
# Short range: claw attack
|
||||
options = [[State.SWIPE, 3.0]]
|
||||
|
||||
else:
|
||||
# Far: lope in on all fours, or spring across with a leap.
|
||||
options = [[State.PROWL, 3.0], [State.LEAP, 1.5]]
|
||||
# At distance: overhead smash 1/3 of the time, jump smash 2/3 — both close the gap as
|
||||
# they land, so the bear slams its way in rather than walking (stalk/prowl).
|
||||
options = [
|
||||
[State.SMASH, 1.0],
|
||||
[State.LEAP, 2.0]
|
||||
]
|
||||
|
||||
_start_routine(_weighted_pick(options))
|
||||
|
||||
|
||||
@@ -302,12 +330,21 @@ func _decide() -> void:
|
||||
func _range_allows(routine: State) -> bool:
|
||||
if _bull == null:
|
||||
return routine == State.PROWL
|
||||
|
||||
var dist := _flat_dist_to_bull()
|
||||
|
||||
match routine:
|
||||
State.SWIPE, State.SMASH:
|
||||
State.SWIPE:
|
||||
return dist <= DP.f("bear_close_range") * 1.4
|
||||
|
||||
State.LEAP:
|
||||
return dist <= DP.f("bear_mid_range") * 1.5
|
||||
|
||||
State.SMASH:
|
||||
# Smash can be started from any distance.
|
||||
# The attack itself will move toward the bull.
|
||||
return true
|
||||
|
||||
return true
|
||||
|
||||
|
||||
@@ -394,12 +431,12 @@ func _tick_swipe(delta: float) -> void:
|
||||
var frac := 1.0 - _phase_timer / maxf(_active_len, 0.001)
|
||||
if _hits_done == 0 and frac >= 0.25:
|
||||
_hits_done = 1
|
||||
_play_fx(_claw_fx_clip(0))
|
||||
_try_hit(DP.f("bear_swipe_reach"))
|
||||
_claw_slash(true) # first paw (right) rakes across
|
||||
elif _hits_done == 1 and frac >= 0.65:
|
||||
_hits_done = 2
|
||||
_play_fx(_claw_fx_clip(1))
|
||||
_try_hit(DP.f("bear_swipe_reach"))
|
||||
_claw_slash(false) # back-hand with the left paw
|
||||
if _phase_timer <= 0.0:
|
||||
_begin_recover(DP.f("bear_swipe_recover"))
|
||||
Phase.RECOVER:
|
||||
@@ -426,13 +463,16 @@ func _tick_smash(delta: float) -> void:
|
||||
if _phase_timer <= 0.0:
|
||||
_begin_attack_active(_anim_smash, 0.9)
|
||||
Phase.ACTIVE:
|
||||
# The overhead steps in less than the swipe — it's a commitment, not a rush.
|
||||
_lunge_and_track(DP.f("bear_lunge_speed") * 0.5, delta)
|
||||
# The overhead steps in less than the swipe — it's a commitment, not a rush. no rotation
|
||||
_lunge_and_track_no_rotation(DP.f("bear_lunge_speed") * 0.5, delta)
|
||||
_phase_timer -= delta
|
||||
var frac := 1.0 - _phase_timer / maxf(_active_len, 0.001)
|
||||
if _hits_done == 0 and frac >= 0.4:
|
||||
_hits_done = 1
|
||||
_slam(DP.f("bear_smash_radius"), 0.8)
|
||||
_play_fx(&"Bear_fx_smash_hit")
|
||||
_slam_dust()
|
||||
_shake(0.8)
|
||||
_begin_smash_hitbox() # plays the scene's "smash_travel" clip; swept in _tick_attack_hitbox
|
||||
if _phase_timer <= 0.0:
|
||||
_begin_recover(DP.f("bear_smash_recover"))
|
||||
Phase.RECOVER:
|
||||
@@ -483,7 +523,8 @@ func _tick_leap(delta: float) -> void:
|
||||
elif _leap_airborne or _phase_timer <= 0.0:
|
||||
velocity.x = 0.0
|
||||
velocity.z = 0.0
|
||||
_slam(DP.f("bear_slam_radius"), 0.7)
|
||||
_play_fx(&"Bear_fx_jump_smash")
|
||||
_fire_leap_hitbox()
|
||||
_phase = Phase.RECOVER
|
||||
_phase_timer = _scaled(DP.f("bear_leap_recover"))
|
||||
Phase.RECOVER:
|
||||
@@ -561,6 +602,20 @@ func _lunge_and_track(speed: float, delta: float) -> void:
|
||||
_decelerate(_PLANT_DECEL, delta)
|
||||
|
||||
|
||||
func _lunge_and_track_no_rotation(speed: float, delta: float) -> void:
|
||||
if _bull == null:
|
||||
_decelerate(_PLANT_DECEL, delta)
|
||||
return
|
||||
|
||||
var to_bull := _flat_to_bull()
|
||||
var dist := to_bull.length()
|
||||
|
||||
if speed > 0.0 and dist > _BULL_STANDOFF:
|
||||
_accelerate(to_bull / dist, speed, delta)
|
||||
else:
|
||||
_decelerate(_PLANT_DECEL, delta)
|
||||
|
||||
|
||||
# ── Hitting the bull ───────────────────────────────────────────────────────────────
|
||||
|
||||
# Directional strike: the bull is mauled inside `reach` of the bear that's facing it
|
||||
@@ -580,17 +635,83 @@ func _try_hit(reach: float) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
# Radial slam (smash / leap landing): hits any way the bull is, within `radius`, with a
|
||||
# ground-pound shake and a burst of dust kicked up at the paws. No facing arc — you're
|
||||
# caught if you're near where it comes down.
|
||||
func _slam(radius: float, shake: float) -> void:
|
||||
_slam_dust()
|
||||
if _bull == null:
|
||||
_shake(shake)
|
||||
# Grab the designer-authored collider sub-scene (BearAttackHitboxes.tscn instanced under
|
||||
# bear_model) and park both hitboxes deactivated. Shapes + travel are authored in that scene.
|
||||
func _setup_attack_hitboxes() -> void:
|
||||
var root := _mesh.get_node_or_null("AttackHitboxes") if _mesh else null
|
||||
if root == null:
|
||||
return
|
||||
if _flat_dist_to_bull() <= radius:
|
||||
_bull.call(&"take_sword_hit", "mauled")
|
||||
_shake(shake)
|
||||
_leap_hitbox = root.get_node_or_null("LeapSlamHitbox") as Hitbox
|
||||
_smash_hitbox = root.get_node_or_null("SmashHitbox") as Hitbox
|
||||
_hitbox_anim = root.get_node_or_null("AnimationPlayer") as AnimationPlayer
|
||||
if _hitbox_anim != null:
|
||||
# Advance the shape's travel in the physics step so it stays in lockstep with the sweep.
|
||||
_hitbox_anim.callback_mode_process = AnimationMixer.ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS
|
||||
if _leap_hitbox != null:
|
||||
_leap_hitbox.deactivate()
|
||||
if _smash_hitbox != null:
|
||||
_smash_hitbox.deactivate()
|
||||
|
||||
|
||||
# Leap landing: kick up dust + shake, launch the ground-circle collider clip, and arm it so the bull
|
||||
# is launched from ANYWHERE in the circle (bear_leap_ring_frac 0). Raise ring_frac to restore a
|
||||
# grounded inner zone that only mauls; the launch zone then starts at that fraction of the radius.
|
||||
func _fire_leap_hitbox() -> void:
|
||||
_slam_dust()
|
||||
_shake(0.7)
|
||||
if _leap_hitbox == null:
|
||||
return
|
||||
_leap_hitbox.knock_up = DP.f("bear_leap_knockup")
|
||||
_leap_hitbox.knock_up_min_dist = DP.f("bear_leap_ring_frac") * _shape_extent(_leap_hitbox, true)
|
||||
_leap_hitbox.knock_up_max_dist = 0.0 # binary: full-height launch everywhere it launches
|
||||
_start_attack_hitbox(_leap_hitbox, &"leap_slam")
|
||||
|
||||
|
||||
# Overhead smash: launch the lane clip; knock-up ramps 0→full with distance (further = higher),
|
||||
# maxing at the lane's authored full length so the shape and the launch curve stay in sync.
|
||||
func _begin_smash_hitbox() -> void:
|
||||
if _smash_hitbox == null:
|
||||
return
|
||||
_smash_hitbox.knock_up = DP.f("bear_smash_knockup")
|
||||
_smash_hitbox.knock_up_min_dist = 0.0
|
||||
_smash_hitbox.knock_up_max_dist = _shape_extent(_smash_hitbox, false)
|
||||
_start_attack_hitbox(_smash_hitbox, &"smash_travel")
|
||||
|
||||
|
||||
# Activate the hitbox and play its authored motion clip; _tick_attack_hitbox sweeps for overlaps
|
||||
# each frame while the clip runs, then deactivates when it ends.
|
||||
func _start_attack_hitbox(hb: Hitbox, clip: StringName) -> void:
|
||||
if _active_hitbox != null and _active_hitbox != hb:
|
||||
_active_hitbox.deactivate()
|
||||
hb.activate()
|
||||
_active_hitbox = hb
|
||||
if _hitbox_anim != null and _hitbox_anim.has_animation(clip):
|
||||
_hitbox_anim.play(clip)
|
||||
_hitbox_anim.seek(0.0, true)
|
||||
|
||||
|
||||
func _tick_attack_hitbox() -> void:
|
||||
if _active_hitbox == null:
|
||||
return
|
||||
_active_hitbox.sweep()
|
||||
# The clip drives the shape's travel; when it stops, the swing is over — close the hitbox.
|
||||
if _hitbox_anim == null or not _hitbox_anim.is_playing():
|
||||
_active_hitbox.deactivate()
|
||||
_active_hitbox = null
|
||||
|
||||
|
||||
# Full extent (planar) of a hitbox's authored shape, for the knock-up distance math: the circle's
|
||||
# radius (cylinder) or the lane's length (box half-size along local +Z, forward from the bear).
|
||||
func _shape_extent(hb: Hitbox, radial: bool) -> float:
|
||||
var cs := hb.get_node_or_null("CollisionShape3D") as CollisionShape3D
|
||||
if cs == null:
|
||||
return 0.0
|
||||
if radial and cs.shape is CylinderShape3D:
|
||||
return (cs.shape as CylinderShape3D).radius
|
||||
if not radial and cs.shape is BoxShape3D:
|
||||
# Box spans [0, size.z] because it's offset forward by half its length.
|
||||
return (cs.shape as BoxShape3D).size.z
|
||||
return 0.0
|
||||
|
||||
|
||||
# Kick up a one-shot ring of dust at the bear's feet where the slam lands.
|
||||
@@ -651,15 +772,6 @@ func _make_slam_dust() -> CPUParticles3D:
|
||||
return p
|
||||
|
||||
|
||||
# Fire the claw-slash burst on one paw for a swipe hit (right paw first, then left).
|
||||
func _claw_slash(right: bool) -> void:
|
||||
var claw := _claw_r if right else _claw_l
|
||||
if claw == null:
|
||||
return
|
||||
claw.restart()
|
||||
claw.emitting = true
|
||||
|
||||
|
||||
# A short fan of pale streaks raked from a paw — thin boxes aligned to their velocity so
|
||||
# they read as claw marks slashing outward. Built in code and parented to a hand bone.
|
||||
func _make_claw_slash() -> CPUParticles3D:
|
||||
@@ -723,18 +835,44 @@ func apply_ability_hit(hit_dir: Vector3, strength: float, _up_boost: float = 0.0
|
||||
_take_hit(hit_dir, strength)
|
||||
|
||||
|
||||
# Ramming: only a real charge from the bull wounds the bear; a gentle nudge is shrugged
|
||||
# off. The bear never damages the bull by colliding — only its swings/slams do.
|
||||
func _on_body_entered(body: Node3D) -> void:
|
||||
if _state == State.DEAD or not body.is_in_group(&"player"):
|
||||
# Only a horns-first charge wounds the bear. Swept (prev → now) so a tunnelling or point-blank charge
|
||||
# still lands where body_entered wouldn't; edge-triggered (_bull_ramming) so one charge = one wound.
|
||||
func _sweep_bull_ram() -> void:
|
||||
var now := _bull.global_position
|
||||
var seg_from := _bull_prev_pos if _bull_prev_seen else now
|
||||
_bull_prev_pos = now
|
||||
_bull_prev_seen = true
|
||||
if _state == State.DEAD:
|
||||
_bull_ramming = false
|
||||
return
|
||||
var player := body as CharacterBody3D
|
||||
if player.velocity.length() < DP.f("bear_hit_threshold"):
|
||||
return
|
||||
var flat := Vector3(player.velocity.x, 0.0, player.velocity.z)
|
||||
var dir := flat.normalized() if flat.length() > 0.5 else \
|
||||
(global_position - player.global_position).normalized()
|
||||
_take_hit(dir, player.velocity.length())
|
||||
var vel := Vector3(_bull.velocity.x, 0.0, _bull.velocity.z)
|
||||
var speed := vel.length()
|
||||
var ramming := false
|
||||
if speed >= DP.f("bear_hit_threshold") and _horns_first(seg_from):
|
||||
var a := Vector3(seg_from.x, 0.0, seg_from.z)
|
||||
var b := Vector3(now.x, 0.0, now.z)
|
||||
var p := Vector3(global_position.x, 0.0, global_position.z)
|
||||
if p.distance_to(Geometry3D.get_closest_point_to_segment(p, a, b)) <= DP.f("bear_ram_reach"):
|
||||
ramming = true
|
||||
if ramming and not _bull_ramming:
|
||||
var dir := vel.normalized() if speed > 0.5 else (global_position - now).normalized()
|
||||
_take_hit(dir, speed)
|
||||
_bull_ramming = ramming
|
||||
|
||||
|
||||
# Horns-first gate: wound only when the bull's velocity points within bull_gore_arc of the direction
|
||||
# from `from` to the bear. The dash ability skips the gate.
|
||||
func _horns_first(from: Vector3) -> bool:
|
||||
if _bull.has_method(&"is_dashing") and _bull.call(&"is_dashing"):
|
||||
return true # the dash ability is a committed lunge — it rams on contact, no angle gate
|
||||
var vel := Vector3(_bull.velocity.x, 0.0, _bull.velocity.z)
|
||||
if vel.length() < 0.5:
|
||||
return false
|
||||
var to_bear := global_position - from
|
||||
to_bear.y = 0.0
|
||||
if to_bear.length() < 0.01:
|
||||
return true
|
||||
return vel.normalized().dot(to_bear.normalized()) > cos(deg_to_rad(DP.f("bull_gore_arc")))
|
||||
|
||||
|
||||
func _take_hit(hit_dir: Vector3, strength: float) -> void:
|
||||
@@ -746,6 +884,7 @@ func _take_hit(hit_dir: Vector3, strength: float) -> void:
|
||||
hit_dir.y = 0.0
|
||||
hit_dir = hit_dir.normalized()
|
||||
_blood_burst.burst(global_position + Vector3(0.0, 1.4, 0.0), hit_dir)
|
||||
Gore.splat(global_position, hit_dir, 1.1)
|
||||
_shake(clampf(strength / 15.0, 0.4, 1.0))
|
||||
if _hp <= 0:
|
||||
_die(hit_dir)
|
||||
@@ -781,6 +920,7 @@ func _die(hit_dir: Vector3) -> void:
|
||||
_hit_area.monitoring = false
|
||||
velocity = Vector3.ZERO
|
||||
_blood_burst.burst(global_position + Vector3(0.0, 1.4, 0.0), hit_dir)
|
||||
Gore.splat(global_position, hit_dir, 1.4)
|
||||
_play(_anim_death)
|
||||
# No death clip on the rig — topple the beast onto its side (about the hit direction,
|
||||
# so it falls the way it was struck) and sink it away, then free.
|
||||
@@ -907,6 +1047,43 @@ func _play(anim_name: StringName) -> void:
|
||||
_anim_player.play(anim_name)
|
||||
|
||||
|
||||
# The two swipe hits map to the L/R claw-slash clips; bear_fx_claw_swap flips the order in
|
||||
# case the baked left/right clips read reversed in-game. hit 0 = first swing, 1 = second.
|
||||
func _claw_fx_clip(hit: int) -> StringName:
|
||||
var swap := DP.f("bear_fx_claw_swap") >= 0.5
|
||||
var first_left := not swap
|
||||
if (hit == 0) == first_left:
|
||||
return &"Bear_fx_claw_attack_L"
|
||||
return &"Bear_fx_claw_attack_R"
|
||||
|
||||
|
||||
# Fire a one-shot FX clip from the Bear_FX glb (crater / slash / debris). Each clip scales
|
||||
# its mesh up at the strike and back to 0 on its own, so this is a plain fire-and-forget.
|
||||
func _play_fx(clip: StringName) -> void:
|
||||
if _fx_player == null or not _fx_player.has_animation(clip):
|
||||
return
|
||||
if _fx_root is Node3D:
|
||||
(_fx_root as Node3D).rotation.y = deg_to_rad(DP.f("bear_fx_yaw"))
|
||||
_fx_player.play(clip)
|
||||
_fx_player.seek(0.0, true)
|
||||
|
||||
|
||||
func _on_fx_finished(anim: StringName) -> void:
|
||||
if _fx_root == null:
|
||||
return
|
||||
var mesh := _fx_root.get_node_or_null(NodePath(anim)) as Node3D
|
||||
if mesh == null:
|
||||
return
|
||||
# The crater clip only ramps up (it ends held at full scale with no shrink), so leave it on
|
||||
# the ground for a beat after the slam, then hide it. The others self-clear immediately.
|
||||
if anim == &"Bear_fx_jump_smash":
|
||||
var linger := DP.f("bear_fx_crater_linger")
|
||||
if linger > 0.0:
|
||||
get_tree().create_timer(linger).timeout.connect(func() -> void: mesh.scale = Vector3.ZERO)
|
||||
return
|
||||
mesh.scale = Vector3.ZERO
|
||||
|
||||
|
||||
# Restart a one-shot attack clip from its first frame at `speed` (even if already current).
|
||||
func _play_attack(anim_name: StringName, speed: float) -> void:
|
||||
if _anim_player == null or anim_name == &"":
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
extends Node3D
|
||||
|
||||
|
||||
func mesh_on():
|
||||
visible = true
|
||||
|
||||
func mesh_off():
|
||||
visible = false
|
||||
@@ -1 +0,0 @@
|
||||
uid://bsbed05ifr18s
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
extends MultiMeshInstance3D
|
||||
## A whole level's worth of persistent blood splats rendered in one draw call. Each stain
|
||||
## is a flat quad laid on the surface it hit — floor or a nearby wall — picked from a
|
||||
## procedurally-baked atlas of splat shapes and jittered per instance (random shape, yaw,
|
||||
## size, brightness) so no two read alike.
|
||||
##
|
||||
## The pool is a fixed ring buffer: new splats overwrite the oldest, so the instance count
|
||||
## and fill cost stay bounded no matter how long a fight runs — the property that keeps it
|
||||
## cheap on the web/mobile target. The game shell rebuilds this node into LevelRoot on every
|
||||
## level load, so the stains die with the level (exactly one level's worth, never leaked
|
||||
## into the next). Fire splats through the `Gore` autoload, not this node directly.
|
||||
|
||||
const PhysicsLayers = preload("res://physics_layers.gd")
|
||||
const SHADER_PATH := "res://blood_decals.gdshader"
|
||||
const GROUP := &"blood_decals"
|
||||
|
||||
# Atlas: ATLAS_CELLS distinct splat shapes packed into one row, CELL_PX square each.
|
||||
const ATLAS_CELLS := 8
|
||||
const CELL_PX := 64
|
||||
|
||||
var _rng := RandomNumberGenerator.new()
|
||||
var _mm: MultiMesh
|
||||
var _cap: int = 0
|
||||
var _next: int = 0 # ring-buffer write cursor
|
||||
var _filled: int = 0 # how many ring-buffer slots have ever been stamped, capped at _cap
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group(GROUP)
|
||||
_rng.randomize()
|
||||
_cap = maxi(int(DP.f("blood_cap")), 0)
|
||||
_build()
|
||||
|
||||
|
||||
func _build() -> void:
|
||||
var quad := QuadMesh.new()
|
||||
quad.size = Vector2.ONE # unit quad; the instance basis carries the real size
|
||||
|
||||
var mat := ShaderMaterial.new()
|
||||
mat.shader = load(SHADER_PATH) as Shader
|
||||
mat.set_shader_parameter("atlas", _bake_atlas())
|
||||
mat.set_shader_parameter("cells", ATLAS_CELLS)
|
||||
material_override = mat
|
||||
|
||||
_mm = MultiMesh.new()
|
||||
_mm.transform_format = MultiMesh.TRANSFORM_3D
|
||||
_mm.use_custom_data = true
|
||||
_mm.mesh = quad
|
||||
_mm.instance_count = _cap
|
||||
# Godot renders only the first `visible_instance_count` instances, so unstained slots simply
|
||||
# aren't drawn — no need to park them off-map. (Parking them via set_instance_transform doesn't
|
||||
# work anyway: MultiMesh's per-instance buffer lives server-side and isn't reliably readable
|
||||
# back through get_instance_transform, so a "hide by moving far away" scheme can't even be
|
||||
# verified, let alone trusted.) Starts at 0 and grows as splats land.
|
||||
_mm.visible_instance_count = 0
|
||||
multimesh = _mm
|
||||
|
||||
|
||||
## Stain the world at `world_pos`: one splat cluster on the floor beneath it, plus a splat
|
||||
## on any wall within `blood_wall_reach`. `dir` is the spray heading (used to seed the wall
|
||||
## fan); `size` is the base quad size in metres.
|
||||
func splat(world_pos: Vector3, dir: Vector3 = Vector3.ZERO, size: float = 0.6) -> void:
|
||||
if not is_instance_valid(_mm) or _cap <= 0:
|
||||
return
|
||||
var space := get_world_3d().direct_space_state
|
||||
if space == null:
|
||||
return
|
||||
|
||||
# Floor directly under the hit.
|
||||
var floor_hit := _ray(space, world_pos + Vector3.UP * 0.5, world_pos + Vector3.DOWN * 4.0)
|
||||
if not floor_hit.is_empty():
|
||||
_stamp_cluster(floor_hit.position, floor_hit.normal, size)
|
||||
|
||||
# Walls near the hit: a fan of outward rays, seeded on the spray heading. Only surfaces
|
||||
# within reach catch blood, so an open-arena hit stains nothing but the floor.
|
||||
var rays := maxi(int(DP.f("blood_wall_rays")), 0)
|
||||
if rays <= 0:
|
||||
return
|
||||
var reach := DP.f("blood_wall_reach")
|
||||
var seed_dir := Vector3(dir.x, 0.0, dir.z)
|
||||
seed_dir = seed_dir.normalized() if seed_dir.length_squared() > 0.01 else Vector3.FORWARD
|
||||
var origin := world_pos + Vector3.UP * 0.6
|
||||
for k in rays:
|
||||
var ang := TAU * (float(k) + 0.5) / float(rays)
|
||||
var out := seed_dir.rotated(Vector3.UP, ang)
|
||||
var wall_hit := _ray(space, origin, origin + out * reach)
|
||||
# Only stain near-vertical surfaces here; the floor is already handled above.
|
||||
if not wall_hit.is_empty() and absf((wall_hit.normal as Vector3).y) < 0.6:
|
||||
_stamp(wall_hit.position, wall_hit.normal, size * 0.85)
|
||||
|
||||
|
||||
func _ray(space: PhysicsDirectSpaceState3D, from: Vector3, to: Vector3) -> Dictionary:
|
||||
var q := PhysicsRayQueryParameters3D.create(
|
||||
from, to, PhysicsLayers.WORLD | PhysicsLayers.CORPSE
|
||||
)
|
||||
q.collide_with_bodies = true
|
||||
return space.intersect_ray(q)
|
||||
|
||||
|
||||
# A main splat plus a scatter of smaller droplets around it, all lying on the same surface.
|
||||
func _stamp_cluster(pos: Vector3, normal: Vector3, size: float) -> void:
|
||||
_stamp(pos, normal, size)
|
||||
var n := normal.normalized()
|
||||
if n.length_squared() < 0.5:
|
||||
n = Vector3.UP
|
||||
var up := Vector3.UP if absf(n.dot(Vector3.UP)) < 0.99 else Vector3.FORWARD
|
||||
var tx := up.cross(n).normalized()
|
||||
var ty := n.cross(tx).normalized()
|
||||
var count := maxi(int(DP.f("blood_satellites")), 0)
|
||||
for s in count:
|
||||
var rad := size * _rng.randf_range(0.4, 1.2)
|
||||
var a := _rng.randf() * TAU
|
||||
var off := tx * (cos(a) * rad) + ty * (sin(a) * rad)
|
||||
_stamp(pos + off, n, size * _rng.randf_range(0.25, 0.5))
|
||||
|
||||
|
||||
# Write one splat into the ring buffer, oriented flat on the surface and lifted a hair along
|
||||
# its normal (layered by write index) so coplanar quads don't z-fight the surface or each other.
|
||||
func _stamp(pos: Vector3, normal: Vector3, size: float) -> void:
|
||||
var n := normal.normalized()
|
||||
if n.length_squared() < 0.5:
|
||||
n = Vector3.UP
|
||||
var i := _next
|
||||
_next = (_next + 1) % _cap
|
||||
var eps := 0.015 + float(i) * 0.00015
|
||||
var yaw := _rng.randf() * TAU
|
||||
_mm.set_instance_transform(i, Transform3D(_surface_basis(n, yaw, size), pos + n * eps))
|
||||
var cell := float(_rng.randi_range(0, ATLAS_CELLS - 1))
|
||||
var shade := _rng.randf_range(0.6, 1.0)
|
||||
_mm.set_instance_custom_data(i, Color(cell, shade, 0.0, 0.0))
|
||||
_filled = mini(_filled + 1, _cap)
|
||||
_mm.visible_instance_count = _filled
|
||||
|
||||
|
||||
# Basis for a QuadMesh (face along local +Z) lying flat on a surface with the given normal,
|
||||
# spun by `yaw` about that normal and uniformly scaled to `size`.
|
||||
func _surface_basis(n: Vector3, yaw: float, size: float) -> Basis:
|
||||
var up := Vector3.UP if absf(n.dot(Vector3.UP)) < 0.99 else Vector3.FORWARD
|
||||
var x := up.cross(n).normalized()
|
||||
var y := n.cross(x).normalized()
|
||||
var c := cos(yaw)
|
||||
var s := sin(yaw)
|
||||
var b := Basis()
|
||||
b.x = (x * c + y * s) * size
|
||||
b.y = (y * c - x * s) * size
|
||||
b.z = n
|
||||
return b
|
||||
|
||||
|
||||
# ── Atlas baking ──────────────────────────────────────────────────────────────
|
||||
# Draw ATLAS_CELLS irregular blood shapes into one row. Each shape is a metaball field —
|
||||
# a big central blob, a few overlapping lobes and some flung droplets — thresholded to an
|
||||
# organic silhouette. Baked once per pool (once per level load, ~ms) with a fixed seed so
|
||||
# the shape set is deterministic and every level's stains match.
|
||||
|
||||
func _bake_atlas() -> ImageTexture:
|
||||
var img := Image.create(ATLAS_CELLS * CELL_PX, CELL_PX, false, Image.FORMAT_RGBA8)
|
||||
img.fill(Color(0.0, 0.0, 0.0, 0.0))
|
||||
var rng := RandomNumberGenerator.new()
|
||||
rng.seed = hash("bullosseum-blood")
|
||||
for c in ATLAS_CELLS:
|
||||
_draw_splat(img, c * CELL_PX, rng)
|
||||
return ImageTexture.create_from_image(img)
|
||||
|
||||
|
||||
func _draw_splat(img: Image, ox: int, rng: RandomNumberGenerator) -> void:
|
||||
var px := float(CELL_PX)
|
||||
var mid := px * 0.5
|
||||
# blobs are (centre_x, centre_y, radius) — a central mass, lobes, then far droplets.
|
||||
var blobs: Array[Vector3] = []
|
||||
blobs.append(Vector3(mid, mid, px * rng.randf_range(0.22, 0.30)))
|
||||
for i in rng.randi_range(3, 6):
|
||||
var a := rng.randf() * TAU
|
||||
var d := px * rng.randf_range(0.10, 0.34)
|
||||
blobs.append(Vector3(mid + cos(a) * d, mid + sin(a) * d, px * rng.randf_range(0.06, 0.16)))
|
||||
for i in rng.randi_range(2, 5):
|
||||
var a := rng.randf() * TAU
|
||||
var d := px * rng.randf_range(0.30, 0.46)
|
||||
blobs.append(Vector3(mid + cos(a) * d, mid + sin(a) * d, px * rng.randf_range(0.02, 0.05)))
|
||||
|
||||
for y in CELL_PX:
|
||||
for x in CELL_PX:
|
||||
var field := 0.0
|
||||
for b in blobs:
|
||||
var dx := float(x) - b.x
|
||||
var dy := float(y) - b.y
|
||||
field += (b.z * b.z) / (dx * dx + dy * dy + 1.0)
|
||||
var a := smoothstep(0.75, 1.15, field)
|
||||
if a <= 0.004:
|
||||
continue
|
||||
# Denser field (splat interior) reads a touch richer/darker than the thin edges.
|
||||
var t := clampf(field * 0.5, 0.0, 1.0)
|
||||
var col := Color(0.62 - 0.16 * t, 0.05 - 0.03 * t, 0.04 - 0.02 * t, a)
|
||||
img.set_pixel(ox + x, y, col)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cs8fhiasw7q7j
|
||||
@@ -0,0 +1,26 @@
|
||||
shader_type spatial;
|
||||
// Persistent blood splats, drawn as one MultiMesh of flat quads (see blood_decals.gd).
|
||||
// Unshaded and nearest-filtered to sit inside the PS1 look; alpha-blended so overlapping
|
||||
// splats pool darker. depth_draw_never + the small normal offset the pool bakes into each
|
||||
// transform keep the coplanar floor/wall quads from z-fighting the surface they stain.
|
||||
render_mode unshaded, cull_disabled, shadows_disabled, depth_draw_never, blend_mix;
|
||||
|
||||
uniform sampler2D atlas : source_color, filter_nearest;
|
||||
// Number of splat shapes packed side-by-side in the atlas (one row).
|
||||
uniform int cells = 8;
|
||||
|
||||
varying flat float v_cell;
|
||||
varying flat float v_shade;
|
||||
|
||||
void vertex() {
|
||||
// x = which atlas shape this instance uses; y = per-instance brightness (fresh vs old).
|
||||
v_cell = INSTANCE_CUSTOM.x;
|
||||
v_shade = INSTANCE_CUSTOM.y;
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
float u = (UV.x + v_cell) / float(cells);
|
||||
vec4 c = texture(atlas, vec2(u, UV.y));
|
||||
ALBEDO = c.rgb * v_shade;
|
||||
ALPHA = c.a;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cj5rmaywacvbj
|
||||
+126
-21
@@ -23,36 +23,115 @@ const REBINDABLE_ACTIONS: PackedStringArray = [
|
||||
|
||||
func _ready() -> void:
|
||||
load_saved()
|
||||
_install_web_fullscreen_hook()
|
||||
|
||||
|
||||
# ── Web fullscreen + landscape lock ─────────────────────────────────────────────
|
||||
# Browsers only allow requestFullscreen / screen.orientation.lock from inside a user
|
||||
# gesture, so we piggyback on the first tap/click of the web build to go fullscreen and
|
||||
# lock to landscape. One-shot; input still flows to the menu/game normally (never consumed).
|
||||
var _fs_triggered: bool = false
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if _fs_triggered or not OS.has_feature("web"):
|
||||
# The reliable way to force fullscreen on the web: install a NATIVE DOM listener that calls
|
||||
# requestFullscreen() synchronously inside the real user-gesture event — the same thing
|
||||
# three.js games do. Godot dispatches input from its rAF render loop, one hop removed from the
|
||||
# DOM event, so both Godot's window_set_mode and a JS call made from _input() run outside the
|
||||
# gesture's activation and some mobile browsers reject them. The listener below sidesteps that
|
||||
# entirely, and — left attached — re-enters fullscreen on the next tap if the player leaves it.
|
||||
# All of it is guarded, so iPhone Safari (no requestFullscreen) and desktop just no-op cleanly.
|
||||
func _install_web_fullscreen_hook() -> void:
|
||||
if not OS.has_feature("web"):
|
||||
return
|
||||
var gesture := (event is InputEventScreenTouch and (event as InputEventScreenTouch).pressed) \
|
||||
or (event is InputEventMouseButton and (event as InputEventMouseButton).pressed)
|
||||
if gesture:
|
||||
_fs_triggered = true
|
||||
request_fullscreen_landscape()
|
||||
JavaScriptBridge.eval("""
|
||||
(function(){
|
||||
if (window.__bullFSInit) return;
|
||||
window.__bullFSInit = true;
|
||||
window.__bull_fs = 'idle';
|
||||
// Armed = we should grab fullscreen on the next tap. Starts true so the first tap enters,
|
||||
// then disarms — so once the player is in (or deliberately leaves via Esc / back / swipe)
|
||||
// ordinary gameplay taps never yank them back in. WebStartGate re-arms via arm_fullscreen().
|
||||
window.__bullFSArmed = true;
|
||||
window.__bullFS = function(){
|
||||
try {
|
||||
if (document.fullscreenElement || document.webkitFullscreenElement) {
|
||||
window.__bull_fs = 'ok'; window.__bullFSArmed = false; return;
|
||||
}
|
||||
if (!window.__bullFSArmed) return;
|
||||
var c = document.getElementById('canvas') || document.querySelector('canvas')
|
||||
|| document.documentElement;
|
||||
var rf = c.requestFullscreen || c.webkitRequestFullscreen
|
||||
|| c.msRequestFullscreen || c.mozRequestFullScreen;
|
||||
if (!rf) { window.__bull_fs = 'no-api'; lock(); return; }
|
||||
window.__bull_fs = 'req';
|
||||
var p = rf.call(c);
|
||||
if (p && p.then) {
|
||||
p.then(function(){ window.__bull_fs = 'ok'; window.__bullFSArmed = false; lock(); },
|
||||
function(e){ window.__bull_fs = 'err:' + (e && e.name || e); });
|
||||
} else { window.__bull_fs = 'ok'; window.__bullFSArmed = false; lock(); }
|
||||
} catch(e){ window.__bull_fs = 'ex:' + (e && e.name || e); }
|
||||
function lock(){ try { if (screen.orientation && screen.orientation.lock)
|
||||
screen.orientation.lock('landscape').catch(function(){}); } catch(e){} }
|
||||
};
|
||||
// pointerup / touchend / click grant transient activation (pointerdown/touchstart do not).
|
||||
['pointerup','touchend','click'].forEach(function(ev){
|
||||
window.addEventListener(ev, function(){ window.__bullFS(); }, true);
|
||||
});
|
||||
})();
|
||||
""", true)
|
||||
|
||||
|
||||
## Enter browser fullscreen and lock to landscape. Must be called from a user-gesture
|
||||
## context (first tap, or a button press). No-op off web. Android Chrome/Brave honour the
|
||||
## orientation lock; iOS Safari ignores it (unsupported), so the .catch() swallows the reject.
|
||||
## Ask to enter fullscreen + landscape now (e.g. from WebStartGate's tap). The DOM listener
|
||||
## installed above normally beats this to it on the same gesture; this is the explicit path and
|
||||
## is a safe no-op if we're already fullscreen. No-op off web.
|
||||
func request_fullscreen_landscape() -> void:
|
||||
if not OS.has_feature("web"):
|
||||
return
|
||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
|
||||
JavaScriptBridge.eval(
|
||||
"(function(){function l(){try{if(screen.orientation&&screen.orientation.lock)"
|
||||
+ "screen.orientation.lock('landscape').catch(function(){});}catch(e){}}"
|
||||
+ "l();document.addEventListener('fullscreenchange',l,{once:true});})()", true)
|
||||
_install_web_fullscreen_hook()
|
||||
JavaScriptBridge.eval("if (window.__bullFS) window.__bullFS();", true)
|
||||
|
||||
|
||||
## Re-arm the "grab fullscreen on next tap" hook, so the next tap re-enters. WebStartGate calls
|
||||
## this whenever it shows itself (boot, or after the player left fullscreen). No-op off web.
|
||||
func arm_fullscreen() -> void:
|
||||
if OS.has_feature("web"):
|
||||
JavaScriptBridge.eval("window.__bullFSArmed = true;", true)
|
||||
|
||||
|
||||
## Whether the browser can go fullscreen at all. False on iPhone Safari (no requestFullscreen),
|
||||
## which lets WebStartGate stop prompting there instead of nagging forever. True off web (n/a).
|
||||
func fullscreen_supported() -> bool:
|
||||
if not OS.has_feature("web"):
|
||||
return true
|
||||
var r: Variant = JavaScriptBridge.eval(
|
||||
"(function(){var c=document.getElementById('canvas')||document.documentElement;"
|
||||
+ "return !!(c.requestFullscreen||c.webkitRequestFullscreen"
|
||||
+ "||c.msRequestFullscreen||c.mozRequestFullScreen)?1:0;})()", true)
|
||||
if r is bool:
|
||||
return r
|
||||
if r is int or r is float:
|
||||
return int(r) != 0
|
||||
return false
|
||||
|
||||
|
||||
## Is the browser currently fullscreen? No-op-ish off web (returns false).
|
||||
func is_browser_fullscreen() -> bool:
|
||||
if not OS.has_feature("web"):
|
||||
return false
|
||||
var r: Variant = JavaScriptBridge.eval(
|
||||
"(document.fullscreenElement||document.webkitFullscreenElement)?1:0", true)
|
||||
if r is bool:
|
||||
return r
|
||||
if r is int or r is float:
|
||||
return int(r) != 0
|
||||
return false
|
||||
|
||||
|
||||
## One-line web diagnostic for the on-device debug overlay: secure context, cross-origin
|
||||
## isolation (threads), last fullscreen attempt result, and whether we're fullscreen now.
|
||||
func fullscreen_status() -> String:
|
||||
if not OS.has_feature("web"):
|
||||
return "native"
|
||||
var r: Variant = JavaScriptBridge.eval(
|
||||
"'sec=' + (window.isSecureContext ? 1 : 0) + ' iso=' + (window.crossOriginIsolated ? 1 : 0)"
|
||||
+ " + ' fs=' + (window.__bull_fs || '?')"
|
||||
+ " + ' cur=' + ((document.fullscreenElement || document.webkitFullscreenElement) ? 1 : 0)",
|
||||
true)
|
||||
return str(r) if r != null else "?"
|
||||
|
||||
|
||||
## Whether to drive the game with the on-screen touch UI (joystick + buttons)
|
||||
@@ -117,6 +196,32 @@ func debug_overlay() -> bool:
|
||||
return _url_debug == 1
|
||||
|
||||
|
||||
## Whether to apply the rigid-skin workaround (rigid_skin.gd) instead of native GPU skinning.
|
||||
## Defaults to the DP "use_rigid_skin" flag (on for web), but a page URL param overrides it so
|
||||
## native skinning can be A/B'd on the actual phone with no console reachable: append `?noskin=1`
|
||||
## to force it OFF (does the device render skinned meshes natively now — e.g. after a Godot web
|
||||
## template update? — and do the bear's rigid-skin seam holes go away), or `?skin=1` to force ON.
|
||||
## -1 = not read yet, 0 = url forces off, 1 = url forces on, 2 = no url override (use DP flag).
|
||||
var _url_skin: int = -1
|
||||
|
||||
|
||||
func rigid_skin_enabled() -> bool:
|
||||
if _url_skin == -1:
|
||||
_url_skin = 2
|
||||
if OS.has_feature("web"):
|
||||
var q: Variant = JavaScriptBridge.eval("String(window.location.search)", true)
|
||||
var s: String = str(q) if q != null else ""
|
||||
if s.find("noskin") >= 0:
|
||||
_url_skin = 0
|
||||
elif s.find("skin") >= 0:
|
||||
_url_skin = 1
|
||||
if _url_skin == 0:
|
||||
return false
|
||||
if _url_skin == 1:
|
||||
return true
|
||||
return DP.b("use_rigid_skin")
|
||||
|
||||
|
||||
## Returns the first keyboard event bound to an action, or null.
|
||||
func get_key_event(action: StringName) -> InputEventKey:
|
||||
for event: InputEvent in InputMap.action_get_events(action):
|
||||
|
||||
+60
-36
@@ -9,8 +9,11 @@ extends Node
|
||||
## bodies get picked up within one interval.
|
||||
##
|
||||
## Toggle from the console:
|
||||
## show_collisions · show_hitboxes · show_bones · show_raycasts (true / false)
|
||||
## show_hitboxes also surfaces the bull's and bear's body capsules, not just Area3Ds
|
||||
## show_hitboxes · show_attacks · show_bones · show_raycasts (true / false)
|
||||
## show_hitboxes — the combatants' hurt volumes: each HitArea + the player/enemy body
|
||||
## capsules, drawn as calm translucent-blue volumes (what abilities/blades hit)
|
||||
## show_attacks — the attack hitboxes (bear claw/smash/leap, matador blade, thrown
|
||||
## spear), filled translucent red and shown ONLY while the swing is actually live
|
||||
## show_states — floating AI-state tags + velocity vectors over each matador
|
||||
## show_animation_name — floating current-clip tag over every AnimationPlayer host
|
||||
## show_stats — 2D corner readout: fps / frame ms / draw calls / matador tally
|
||||
@@ -21,13 +24,14 @@ extends Node
|
||||
const REBUILD_INTERVAL := 0.5
|
||||
const STATS_INTERVAL := 0.2 # stats text is re-composed 5×/sec, not every frame
|
||||
|
||||
const COLOR_BODY := Color(0.30, 1.0, 0.45) # collision wireframes (green)
|
||||
const COLOR_AREA := Color(0.0, 0.9, 1.0) # hit-area volumes (cyan, translucent)
|
||||
const COLOR_AREA := Color(0.0, 0.9, 1.0) # combatant hurt volumes (cyan, translucent)
|
||||
const COLOR_ATTACK := Color(1.0, 0.30, 0.15) # attack hitboxes (red, translucent, overlaid)
|
||||
const COLOR_BONE := Color(1.0, 0.35, 0.9) # skeleton bones (magenta)
|
||||
const COLOR_VEL := Color(1.0, 0.85, 0.2) # matador velocity vectors (amber)
|
||||
const COLOR_ANIM := Color(0.55, 0.85, 1.0) # animation-name tags (sky blue)
|
||||
const COLOR_GRID := Color(0.45, 0.45, 0.45, 0.5)
|
||||
const AREA_ALPHA := 0.25
|
||||
const ATTACK_ALPHA := 0.32
|
||||
|
||||
const GRID_HALF := 20 # grid extends ±GRID_HALF cells from the origin
|
||||
const GRID_STEP := 1.0 # metres between grid lines
|
||||
@@ -81,6 +85,7 @@ func ray(from: Vector3, to: Vector3, color: Color = Color.YELLOW) -> void:
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_reconcile(delta)
|
||||
_pulse_attacks()
|
||||
if DP.b("show_bones"):
|
||||
_draw_bones()
|
||||
if DP.b("show_states"):
|
||||
@@ -360,11 +365,11 @@ func _si(n: int) -> String:
|
||||
# ── Collision / hit-area overlays (incremental) ────────────────────────────────
|
||||
|
||||
func _reconcile(delta: float) -> void:
|
||||
var col := DP.b("show_collisions")
|
||||
var hit := DP.b("show_hitboxes")
|
||||
var atk := DP.b("show_attacks")
|
||||
var bone := DP.b("show_bones")
|
||||
var anim := DP.b("show_animation_name")
|
||||
if not (col or hit or bone or anim):
|
||||
if not (hit or atk or bone or anim):
|
||||
if not _overlays.is_empty():
|
||||
_clear_overlays()
|
||||
_skeletons.clear()
|
||||
@@ -372,7 +377,7 @@ func _reconcile(delta: float) -> void:
|
||||
_prev_flags = ""
|
||||
return
|
||||
|
||||
var flags := "%d%d%d%d" % [int(col), int(hit), int(bone), int(anim)]
|
||||
var flags := "%d%d%d%d" % [int(hit), int(atk), int(bone), int(anim)]
|
||||
_reconcile_t -= delta
|
||||
if flags != _prev_flags: # a toggle just changed — refresh immediately
|
||||
_prev_flags = flags
|
||||
@@ -386,7 +391,7 @@ func _reconcile(delta: float) -> void:
|
||||
var wanted: Dictionary = {}
|
||||
var scene := get_tree().current_scene
|
||||
if scene != null:
|
||||
_collect(scene, col, hit, bone, anim, wanted)
|
||||
_collect(scene, hit, atk, bone, anim, wanted)
|
||||
|
||||
# Drop overlays whose shape is gone or no longer wanted. The overlay is a child of
|
||||
# the collision shape, so it's freed with it — hold it as Variant, since assigning a
|
||||
@@ -402,10 +407,11 @@ func _reconcile(delta: float) -> void:
|
||||
for id: int in wanted:
|
||||
if not _overlays.has(id):
|
||||
var entry: Array = wanted[id]
|
||||
_overlays[id] = _attach(entry[0] as CollisionShape3D, entry[1] as bool)
|
||||
_overlays[id] = _attach(entry[0] as CollisionShape3D, entry[1] as String)
|
||||
|
||||
|
||||
func _collect(node: Node, col: bool, hit: bool, bone: bool, anim: bool, wanted: Dictionary) -> void:
|
||||
func _collect(node: Node, hit: bool, atk: bool, bone: bool, anim: bool,
|
||||
wanted: Dictionary) -> void:
|
||||
# The audience ("public") is ambient decoration, not a debug target — skip the whole
|
||||
# crowd subtree so its clapping AnimationPlayers/skeletons don't flood the overlays.
|
||||
if node.is_in_group(&"public"):
|
||||
@@ -417,18 +423,28 @@ func _collect(node: Node, col: bool, hit: bool, bone: bool, anim: bool, wanted:
|
||||
if node is CollisionShape3D:
|
||||
var cs := node as CollisionShape3D
|
||||
if cs.shape != null and not cs.disabled and _drawable(cs.shape):
|
||||
var parent := cs.get_parent()
|
||||
var is_area := parent is Area3D
|
||||
# Ragdoll bone colliders (PhysicalBone3D) are excluded — use show_bones for
|
||||
# the skeleton; otherwise every corpse floods the view with capsules.
|
||||
var is_body := parent is PhysicsBody3D and not (parent is PhysicalBone3D)
|
||||
# The bull's and bear's body capsules are combat volumes too, so they also
|
||||
# surface under show_hitboxes (not just show_collisions).
|
||||
var is_combatant := is_body and (parent.is_in_group(&"player") or parent.is_in_group(&"bear"))
|
||||
if (is_area and hit) or (is_body and col) or (is_combatant and hit):
|
||||
wanted[cs.get_instance_id()] = [cs, is_area]
|
||||
var kind := _classify(cs.get_parent())
|
||||
var show := (kind == "attack" and atk) or (kind == "hitbox" and hit)
|
||||
if show:
|
||||
wanted[cs.get_instance_id()] = [cs, kind]
|
||||
for child in node.get_children():
|
||||
_collect(child, col, hit, bone, anim, wanted)
|
||||
_collect(child, hit, atk, bone, anim, wanted)
|
||||
|
||||
|
||||
# Sort a shape's owning body/area into an overlay bucket, or "" to skip.
|
||||
# attack — a swing volume (a Hitbox area, or a thrown-spear projectile body)
|
||||
# hitbox — a combatant's hurt volume: its HitArea, or its own body capsule
|
||||
func _classify(parent: Node) -> String:
|
||||
if parent is Hitbox or parent is SpearProjectile:
|
||||
return "attack"
|
||||
if parent is Area3D:
|
||||
return "hitbox"
|
||||
# Ragdoll bone colliders (PhysicalBone3D) are excluded — use show_bones for the
|
||||
# skeleton; otherwise every corpse floods the view with capsules.
|
||||
if parent is PhysicsBody3D and not (parent is PhysicalBone3D):
|
||||
if parent.is_in_group(&"player") or parent.is_in_group(&"matador"):
|
||||
return "hitbox"
|
||||
return ""
|
||||
|
||||
|
||||
# Skip only the unbounded shapes whose debug mesh is meaningless/huge; concave arena
|
||||
@@ -437,20 +453,35 @@ func _drawable(shape: Shape3D) -> bool:
|
||||
return not (shape is WorldBoundaryShape3D or shape is HeightMapShape3D)
|
||||
|
||||
|
||||
func _attach(cs: CollisionShape3D, is_area: bool) -> MeshInstance3D:
|
||||
func _attach(cs: CollisionShape3D, kind: String) -> MeshInstance3D:
|
||||
var mi := MeshInstance3D.new()
|
||||
if is_area:
|
||||
var solid := _solid_mesh(cs.shape)
|
||||
mi.mesh = solid if solid != null else cs.shape.get_debug_mesh()
|
||||
mi.material_override = _translucent_material(COLOR_AREA)
|
||||
if kind == "attack":
|
||||
# Overlaid so a brief swing volume reads clearly on top of the action; its
|
||||
# visibility is pulsed per-frame in _pulse_attacks so it only shows while live.
|
||||
mi.material_override = _translucent_material(COLOR_ATTACK, ATTACK_ALPHA, true)
|
||||
else:
|
||||
mi.mesh = cs.shape.get_debug_mesh()
|
||||
mi.material_override = _wire_material(COLOR_BODY)
|
||||
# The calm translucent-blue volume — depth-tested so it sits in the world.
|
||||
mi.material_override = _translucent_material(COLOR_AREA, AREA_ALPHA, false)
|
||||
mi.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
cs.add_child(mi)
|
||||
return mi
|
||||
|
||||
|
||||
# Attack overlays exist for as long as show_attacks is on, but a swing hitbox is only a
|
||||
# hazard while its Hitbox is monitoring — so show each attack volume only when it's live.
|
||||
# (A thrown spear has no monitoring gate; it stays visible for its whole flight.)
|
||||
func _pulse_attacks() -> void:
|
||||
for id: int in _overlays:
|
||||
var mi: Variant = _overlays[id]
|
||||
if not is_instance_valid(mi):
|
||||
continue
|
||||
var owner := (mi as Node).get_parent().get_parent()
|
||||
if owner is Hitbox:
|
||||
(mi as MeshInstance3D).visible = (owner as Area3D).monitoring
|
||||
|
||||
|
||||
func _clear_overlays() -> void:
|
||||
for id: int in _overlays:
|
||||
var mi: Variant = _overlays[id]
|
||||
@@ -495,19 +526,12 @@ func _line_material() -> StandardMaterial3D:
|
||||
return mat
|
||||
|
||||
|
||||
func _wire_material(color: Color) -> StandardMaterial3D:
|
||||
var mat := StandardMaterial3D.new()
|
||||
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||
mat.albedo_color = color
|
||||
mat.no_depth_test = true
|
||||
return mat
|
||||
|
||||
|
||||
func _translucent_material(color: Color) -> StandardMaterial3D:
|
||||
func _translucent_material(color: Color, alpha: float, overlay: bool) -> StandardMaterial3D:
|
||||
var mat := StandardMaterial3D.new()
|
||||
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||
mat.albedo_color = Color(color.r, color.g, color.b, AREA_ALPHA)
|
||||
mat.albedo_color = Color(color.r, color.g, color.b, alpha)
|
||||
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||
mat.depth_draw_mode = BaseMaterial3D.DEPTH_DRAW_DISABLED
|
||||
mat.no_depth_test = overlay
|
||||
return mat
|
||||
|
||||
+84
-13
@@ -20,6 +20,10 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _register_all() -> void:
|
||||
#Gamepad vibration
|
||||
_reg_b("Gamepad", "gamepad_vibration", true)
|
||||
#Level Unlocking
|
||||
_reg_b("Gate", "gate_unlocked_bear", false)
|
||||
# ── Movement ──────────────────────────────────────────────────────────────
|
||||
# WASD/arrows drive the bull: move_accel ramps flat velocity toward max_speed in
|
||||
# the input direction; move_friction bleeds it off when no direction is held.
|
||||
@@ -37,6 +41,10 @@ func _register_all() -> void:
|
||||
# bull_hit_iframes seconds of invulnerability so a single pass can't drain it.
|
||||
_reg_f("Bull", "bull_max_hp", 10.0, 1.0, 100.0, 1.0)
|
||||
_reg_f("Bull", "bull_hit_iframes", 0.8, 0.0, 3.0, 0.1)
|
||||
# Half-angle (deg) of the bull's horns-first cone: running into an enemy only wounds it when the
|
||||
# bull's velocity points within this of the enemy (not a sideways brush). 90 = any contact at speed.
|
||||
# (The dash ability bypasses this.)
|
||||
_reg_f("Bull", "bull_gore_arc", 75.0, 10.0, 180.0, 5.0)
|
||||
# ── Dust speed thresholds ─────────────────────────────────────────────────
|
||||
_reg_f("Dust", "dust_walk_spd", 1.5, 0.1, 10.0)
|
||||
_reg_f("Dust", "dust_charge_spd", 7.0, 1.0, 20.0)
|
||||
@@ -112,6 +120,9 @@ func _register_all() -> void:
|
||||
_reg_f("Matador", "mat_idle_min", 1.2, 0.0, 5.0, 0.1)
|
||||
_reg_f("Matador", "mat_idle_max", 4.0, 0.5, 10.0, 0.1)
|
||||
_reg_f("Matador", "mat_hit_threshold", 4.0, 1.0, 30.0)
|
||||
# Planar reach at which the bull's swept charge path gores a matador (~bull + HitArea radii).
|
||||
# Raise for a more forgiving charge, lower for a more precise one.
|
||||
_reg_f("Matador", "mat_charge_gore_radius", 1.2, 0.5, 3.0, 0.05)
|
||||
_reg_f("Matador", "mat_ragdoll_impulse", 6.0, 0.5, 20.0)
|
||||
# Ragdoll joint limits — lower swing/twist = stiffer corpse that keeps its
|
||||
# shape; higher angular damp settles the flail instead of flopping flat.
|
||||
@@ -134,21 +145,42 @@ func _register_all() -> void:
|
||||
_reg_f("Matador", "mat_attack_range", 8.0, 2.0, 20.0)
|
||||
_reg_f("Matador", "mat_attack_speed", 7.5, 1.0, 12.0)
|
||||
_reg_f("Matador", "mat_attack_duration", 1.8, 0.5, 5.0, 0.1)
|
||||
_reg_f("Matador", "mat_attack_min_dist", 4.2, 0.5, 6.0, 0.1)
|
||||
# Forward drive during the opening of a melee swing — turns the stationary stab
|
||||
# into an estocada lunge so the blade covers ground toward the bull.
|
||||
_reg_f("Matador", "mat_lunge_speed", 13.0, 0.0, 20.0)
|
||||
_reg_f("Matador", "mat_lunge_time", 0.22, 0.0, 0.6, 0.01)
|
||||
# Reach of the reach-based stab (the reliable melee hit) and its re-strike gap.
|
||||
# The bull dies if it comes inside mat_stab_reach of a matador that's attacking,
|
||||
# bracing, or passing with a drawn blade — closing in is genuinely deadly.
|
||||
_reg_f("Matador", "mat_stab_reach", 1.7, 0.5, 4.0, 0.1)
|
||||
# Reach of the reach-based melee hit and its re-strike gap. This now governs ONLY the sidestep
|
||||
# PASS (mat charges the bull past with the blade out): a fast lateral sweep where the thin blade
|
||||
# Area would tunnel, so a center-to-center distance check is the reliable gore. The stationary
|
||||
# ATTACK stab no longer uses this — it drives off the sword's BladeHitbox collider (see below).
|
||||
_reg_f("Matador", "mat_stab_reach", 2.0, 0.5, 4.0, 0.1)
|
||||
# Distance the matador plants at to swing. The ATTACK stab damages off the animated BladeHitbox,
|
||||
# whose thrust reaches ~3.75 m at full extension — so this MUST stay under that or the blade never
|
||||
# touches the bull and the stab whiffs. 3.5 m keeps the matador clear of the bull's ~1.8 m-long
|
||||
# body while the thrust still lands. Raise toward 3.75 for more gap, lower to stab from closer.
|
||||
_reg_f("Matador", "mat_stab_standoff", 3.5, 0.5, 4.0, 0.1)
|
||||
# Fraction through the Attack clip at which the blade's collider is armed. The clip is guard →
|
||||
# wind-up (blade pulled back, phase ~0.3-0.5) → thrust (blade drives out to ~3.5 m, phase ~0.55+).
|
||||
# Arming at the thrust keeps the bull from being gored during the wind-up (blade not yet extended)
|
||||
# or the guard pose. The BladeHitbox overlap still decides the exact hit; this just gates timing.
|
||||
_reg_f("Matador", "mat_stab_strike_at", 0.5, 0.0, 1.0, 0.05)
|
||||
# Chance, each time a stab finishes, that the matador breaks off into something else (give ground,
|
||||
# circle, or throw) instead of immediately stabbing again — keeps it from drilling the same thrust
|
||||
# on repeat. 0 = always re-stab if in range, 1 = always break off after every stab.
|
||||
_reg_f("Matador", "mat_stab_followup_chance", 0.6, 0.0, 1.0, 0.05)
|
||||
# Beat after every stab where the brain won't re-commit to ATTACK, so it can't machine-gun the
|
||||
# bull — it circles/gives ground instead. 0 = stab as fast as range allows.
|
||||
_reg_f("Matador", "mat_stab_recovery", 0.9, 0.0, 3.0, 0.1)
|
||||
# Chance, when a stab actually CONNECTS, that the matador breaks into a crowd-pleasing taunt and
|
||||
# gives ground instead of pressing — milking the hit rather than spamming. High by design.
|
||||
_reg_f("Matador", "mat_taunt_after_hit", 0.85, 0.0, 1.0, 0.05)
|
||||
_reg_f("Matador", "mat_stab_cooldown", 0.6, 0.1, 3.0, 0.1)
|
||||
# Half-angle (deg) the matador must be facing the bull within for a stab to land.
|
||||
# Stops "sword's off to the side but I still died" — you're only gored when the
|
||||
# blade is actually presented at you.
|
||||
_reg_f("Matador", "mat_stab_arc", 55.0, 5.0, 180.0, 5.0)
|
||||
# Chance a matador rolls clear (survives) instead of ragdolling when the bull's charge connects.
|
||||
_reg_f("Matador", "mat_roll_chance", 0.8, 0.0, 1.0, 0.05)
|
||||
# How much a committed charge pierces the survival roll: roll chance fades toward
|
||||
# mat_roll_chance*(1-this) as bull speed climbs to mat_charge_speed. 1 = full-speed charge always
|
||||
# gores. (A dash connect ignores the roll entirely.)
|
||||
_reg_f("Matador", "mat_charge_pierce", 0.8, 0.0, 1.0, 0.05)
|
||||
_reg_f("Matador", "mat_roll_duration", 0.45, 0.1, 1.5, 0.05)
|
||||
# Playback rate of the Draw_weapon clip used for both drawing and sheathing —
|
||||
# higher = snappier unholster/holster.
|
||||
@@ -202,7 +234,8 @@ func _register_all() -> void:
|
||||
# close is deliberately generous — the bear commits to melee "from a bit further" and
|
||||
# steps in during the swing (see bear_lunge_speed) rather than needing to be on top.
|
||||
_reg_f("Bear", "bear_close_range", 5.0, 1.0, 12.0, 0.1)
|
||||
_reg_f("Bear", "bear_mid_range", 9.0, 3.0, 20.0, 0.5)
|
||||
_reg_f("Bear", "bear_mid_range", 10.0, 3.0, 20.0, 0.5)
|
||||
_reg_f("Bear", "bear_long_range", 15.0, 3.0, 100.0, 0.5)
|
||||
# Beat spent in NEUTRAL sizing up the bull between routines — kept short so the bear
|
||||
# flows straight from one action into the next instead of pausing (raise for a more
|
||||
# hesitant, readable boss; near-0 for relentless pressure). Shrinks again in phase 2.
|
||||
@@ -226,10 +259,22 @@ func _register_all() -> void:
|
||||
_reg_f("Bear", "bear_swipe_windup", 0.3, 0.05, 2.0, 0.05)
|
||||
_reg_f("Bear", "bear_swipe_recover", 0.35, 0.05, 3.0, 0.05)
|
||||
_reg_f("Bear", "bear_swipe_reach", 4.2, 1.0, 8.0, 0.1)
|
||||
# Which claw-slash FX plays on the first vs second swipe hit — the L/R clips are easy to
|
||||
# mix up, so 0 = first hit L then R, 1 = swap them. Purely cosmetic (no gameplay effect).
|
||||
_reg_f("Bear", "bear_fx_claw_swap", 0.0, 0.0, 1.0, 1.0)
|
||||
# Live yaw (deg) applied to the whole Bear_FX node before each effect fires, so the claw
|
||||
# rake / debris can be spun to line up with the bear's facing by eye. Bake the good value.
|
||||
_reg_f("Bear", "bear_fx_yaw", 0.0, -180.0, 180.0, 5.0)
|
||||
# The baked crater clip only pops up (no shrink), so hold it on the ground this long after a
|
||||
# leap slam before hiding it — otherwise it flashes for a single frame and reads as invisible.
|
||||
_reg_f("Bear", "bear_fx_crater_linger", 0.8, 0.0, 3.0, 0.1)
|
||||
# Overhead Smash (SMASH_HIT) — slower tell, biggest punish window, AoE on impact.
|
||||
_reg_f("Bear", "bear_smash_windup", 0.6, 0.1, 3.0, 0.05)
|
||||
_reg_f("Bear", "bear_smash_recover", 0.75, 0.1, 4.0, 0.05)
|
||||
_reg_f("Bear", "bear_smash_radius", 4.2, 1.0, 8.0, 0.1)
|
||||
# The overhead smash's hitbox is a forward box lane whose size + travel are authored in
|
||||
# BearAttackHitboxes.tscn's AnimationPlayer ("smash_travel"). Here we only set the upward
|
||||
# pop the bull takes off its feet at the far end (it ramps 0→this with hit distance).
|
||||
_reg_f("Bear", "bear_smash_knockup", 6.0, 0.0, 16.0, 0.5)
|
||||
# Leap Slam (JUMP_SMASH, 47 frames @30fps) — timed to the clip by FRAME: it plays the
|
||||
# crouch grounded, springs at the takeoff frame, and the arc is solved so the paws hit
|
||||
# ground exactly on the impact frame (25), leaving the tail frames to settle on the
|
||||
@@ -240,7 +285,10 @@ func _register_all() -> void:
|
||||
_reg_f("Bear", "bear_leap_height", 2.6, 0.5, 8.0, 0.1)
|
||||
_reg_f("Bear", "bear_leap_recover", 0.35, 0.0, 4.0, 0.05)
|
||||
_reg_f("Bear", "bear_leap_speed", 14.0, 4.0, 30.0, 0.5)
|
||||
_reg_f("Bear", "bear_slam_radius", 4.0, 1.0, 8.0, 0.1)
|
||||
# Where the leap-slam launch zone starts, as a fraction of the circle radius. 0 = launch anywhere
|
||||
# inside; raise to carve a grounded inner zone that only mauls (0.75 = only the outer quarter ring).
|
||||
_reg_f("Bear", "bear_leap_ring_frac", 0.0, 0.0, 1.0, 0.05)
|
||||
_reg_f("Bear", "bear_leap_knockup", 7.0, 0.0, 16.0, 0.5)
|
||||
# Stalk (WALK_ON2LEGS) — how long it will keep walking the bull down before re-deciding.
|
||||
_reg_f("Bear", "bear_stalk_time", 2.5, 0.0, 6.0, 0.1)
|
||||
# Odds a close combo chains a follow-up smash after the swipe (phase 2 always chains).
|
||||
@@ -249,12 +297,27 @@ func _register_all() -> void:
|
||||
# shrugged off, only a real charge or an ability wounds it. (The bear itself never
|
||||
# damages the bull by colliding — only its swings and slams hurt.)
|
||||
_reg_f("Bear", "bear_hit_threshold", 6.0, 1.0, 30.0, 0.5)
|
||||
# Planar reach at which a horns-first bull charge wounds the bear (~bear body radius + bull reach).
|
||||
# The bull's swept path is tested against this, so a tunnelling or point-blank charge still lands.
|
||||
_reg_f("Bear", "bear_ram_reach", 2.1, 0.5, 5.0, 0.1)
|
||||
# How long (s) the bear is rocked back and can't act after taking a hit.
|
||||
_reg_f("Bear", "bear_stagger_time", 0.5, 0.0, 2.0, 0.05)
|
||||
# Poise: after a stagger the bear shrugs off staggers for this long (hits still wound
|
||||
# it), so it can't be perma-stunlocked — it gets a window to commit an attack that then
|
||||
# rides its hyper-armour. 0 = no poise (stun-locks under sustained fire).
|
||||
_reg_f("Bear", "bear_stagger_cd", 1.0, 0.0, 4.0, 0.05)
|
||||
# ── Blood ─────────────────────────────────────────────────────────────────
|
||||
# Persistent floor/wall splats (blood_decals.gd), fired via the Gore autoload and
|
||||
# gated by the player's Settings.gore. blood_cap is the ring-buffer size: past it,
|
||||
# new splats overwrite the oldest so fill/memory stay bounded. blood_scale is a
|
||||
# global size multiplier over each hit's own size; satellites are extra droplets
|
||||
# scattered per floor cluster; the wall fan casts blood_wall_rays outward and stains
|
||||
# any wall within blood_wall_reach metres of the hit.
|
||||
_reg_f("Blood", "blood_cap", 192.0, 0.0, 512.0, 16.0)
|
||||
_reg_f("Blood", "blood_scale", 1.0, 0.1, 4.0, 0.05)
|
||||
_reg_f("Blood", "blood_satellites", 3.0, 0.0, 8.0, 1.0)
|
||||
_reg_f("Blood", "blood_wall_reach", 2.5, 0.0, 6.0, 0.1)
|
||||
_reg_f("Blood", "blood_wall_rays", 8.0, 0.0, 16.0, 1.0)
|
||||
# ── Sword ─────────────────────────────────────────────────────────────────
|
||||
# Local seating of the sword in the right hand (drawn / fighting).
|
||||
# The blade model runs along its local +Z, but weapon_bone (like every rig bone)
|
||||
@@ -342,7 +405,6 @@ func _register_all() -> void:
|
||||
_reg_f("Roll", "roll_hit_strength", 22.0, 1.0, 40.0) # horizontal launch on the pop
|
||||
_reg_f("Roll", "roll_knockup", 11.0, 0.0, 25.0) # vertical knock-up on the pop
|
||||
# ── Debug overlays (see debug_draw.gd) ───────────────────────────────────
|
||||
_reg_b("Debug", "show_collisions", false)
|
||||
# PS1 post-process filter (see ps1_filter.gd on the fullscreen ColorRect):
|
||||
# screen-covering CRT/PS1 shader — pixelation, colour-banding + dither, and a
|
||||
# rolling scanline. Keys map 1:1 onto the shader uniforms; show_ps1 toggles the
|
||||
@@ -356,6 +418,7 @@ func _register_all() -> void:
|
||||
_reg_f("PS1", "ps1_roll_speed", 3.0, 0.0, 10.0, 0.1)
|
||||
_reg_f("PS1", "ps1_roll_strength", 1.0, 0.0, 1.0, 0.05)
|
||||
_reg_b("Debug", "show_hitboxes", false)
|
||||
_reg_b("Debug", "show_attacks", false)
|
||||
_reg_b("Debug", "show_bones", false)
|
||||
_reg_b("Debug", "show_raycasts", false)
|
||||
_reg_b("Debug", "show_tail", false)
|
||||
@@ -371,6 +434,14 @@ func _register_all() -> void:
|
||||
# On-screen readout of live touch state (event count, last position, active zone) so
|
||||
# touch problems can be diagnosed on the actual device, where no console is reachable.
|
||||
_reg_b("Touch", "touch_debug", false)
|
||||
# Rebuild skinned characters as rigid, bone-attached mesh pieces instead of GPU vertex
|
||||
# skinning. This was a workaround for older Mali/ANGLE web GPUs where Compatibility skinning
|
||||
# rendered characters invisible — but the Godot 4.7 web templates fixed that (confirmed
|
||||
# on-device), so native skinning is now the default everywhere: it renders the bear's dense
|
||||
# mesh without the rigid-seam holes AND drops the per-spawn SurfaceTool rebuild that was
|
||||
# spiking the arena on matador spawn. Kept as an opt-in fallback (DP toggle, or ?skin=1 in
|
||||
# the URL) in case a device is found where Compatibility skinning still fails.
|
||||
_reg_b("Render", "use_rigid_skin", false)
|
||||
|
||||
|
||||
func _reg_f(section: String, key: String, default: float,
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
extends Node
|
||||
## Stateless façade (autoload `Gore`) for spawning persistent blood splats. Callers just say
|
||||
## Gore.splat(pos, dir, size) at each wound; this routes to the level's BloodDecals pool
|
||||
## (group &"blood_decals"), which the game shell rebuilds into LevelRoot on every load so the
|
||||
## stains die with the level. No-ops when there's no pool (menus, headless tests without a
|
||||
## level) or when the player has turned gore off — so the gate lives in one place.
|
||||
|
||||
|
||||
func splat(world_pos: Vector3, dir: Vector3 = Vector3.ZERO, size: float = 0.6) -> void:
|
||||
if not Settings.gore:
|
||||
return
|
||||
var pool := get_tree().get_first_node_in_group(&"blood_decals")
|
||||
if pool == null:
|
||||
return
|
||||
pool.call(&"splat", world_pos, dir, size * DP.f("blood_scale"))
|
||||
@@ -0,0 +1 @@
|
||||
uid://b3dobof8qule3
|
||||
@@ -0,0 +1,101 @@
|
||||
@tool
|
||||
extends Area3D
|
||||
class_name Hitbox
|
||||
## A designer-placeable attack hitbox: drop this into a scene, give it a CollisionShape3D
|
||||
## child, and drag the shape to size/position the attack's reach in the editor. The shape
|
||||
## itself decides what got hit — no distance/facing math in code.
|
||||
##
|
||||
## Inactive by default; the owning script calls activate() for the swing's active window and
|
||||
## deactivate() when it ends. Each activation only hits a given body once (the bull's own
|
||||
## i-frames also collapse a flurry, but this keeps a single swing from re-triggering).
|
||||
|
||||
const PhysicsLayers = preload("res://physics_layers.gd")
|
||||
|
||||
## How the hit is tagged on the bull's take_sword_hit ("mauled" / "gored" / …).
|
||||
@export var damage_cause: String = "mauled"
|
||||
## Upward launch (m/s) applied to the bull on hit — e.g. an overhead smash that pops it up.
|
||||
@export var knock_up: float = 0.0
|
||||
## Knock-up distance shaping, measured planar (XZ) from this hitbox's own origin to the body:
|
||||
## below `knock_up_min_dist` no pop is applied (leap slam: only the outer ring launches). If
|
||||
## `knock_up_max_dist` > min, the pop ramps 0→`knock_up` from min to max (overhead smash: the
|
||||
## further out the hit lands, the higher the bull flies); at/again 0 it's full past the min.
|
||||
@export var knock_up_min_dist: float = 0.0
|
||||
@export var knock_up_max_dist: float = 0.0
|
||||
|
||||
var _active: bool = false
|
||||
var _hit_this_swing: Dictionary = {}
|
||||
# Whether the most recent active window connected. Cleared on activate(), NOT deactivate(), so the
|
||||
# owner can read it after the window closes (e.g. a landed stab breaks off to taunt).
|
||||
var _did_hit: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# Detect the bull's body (layer BULL) only; never collide or push physics.
|
||||
collision_layer = 0
|
||||
collision_mask = PhysicsLayers.BULL
|
||||
monitorable = false
|
||||
monitoring = false
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
body_entered.connect(_on_body_entered)
|
||||
|
||||
|
||||
func activate() -> void:
|
||||
if _active:
|
||||
return
|
||||
_active = true
|
||||
_hit_this_swing.clear()
|
||||
_did_hit = false
|
||||
monitoring = true
|
||||
|
||||
|
||||
func deactivate() -> void:
|
||||
_active = false
|
||||
monitoring = false
|
||||
|
||||
|
||||
# Did the window that just closed connect? Valid until the next activate() clears it.
|
||||
func did_hit() -> bool:
|
||||
return _did_hit
|
||||
|
||||
|
||||
func _on_body_entered(body: Node3D) -> void:
|
||||
_apply_hit(body)
|
||||
|
||||
|
||||
# For AoE slams the bull is usually already standing inside the shape when it activates, so
|
||||
# body_entered never fires. The owner calls sweep() each active frame to catch current overlaps
|
||||
# (still deduped per activation, so the bull is only hit once per slam).
|
||||
func sweep() -> void:
|
||||
if not _active:
|
||||
return
|
||||
for body in get_overlapping_bodies():
|
||||
_apply_hit(body)
|
||||
|
||||
|
||||
func _apply_hit(body: Node3D) -> void:
|
||||
if not _active or not body.is_in_group(&"player"):
|
||||
return
|
||||
if _hit_this_swing.has(body):
|
||||
return
|
||||
_hit_this_swing[body] = true
|
||||
_did_hit = true
|
||||
body.call(&"take_sword_hit", damage_cause)
|
||||
if knock_up > 0.0:
|
||||
var v := _knock_up_for(body)
|
||||
if v > 0.0:
|
||||
body.call(&"apply_knock_up", v)
|
||||
|
||||
|
||||
# Scale the pop by how far the body is from this hitbox's origin (planar). See the export docs.
|
||||
func _knock_up_for(body: Node3D) -> float:
|
||||
if knock_up_min_dist <= 0.0 and knock_up_max_dist <= 0.0:
|
||||
return knock_up
|
||||
var to := body.global_position - global_position
|
||||
var d := Vector2(to.x, to.z).length()
|
||||
if d < knock_up_min_dist:
|
||||
return 0.0
|
||||
if knock_up_max_dist > knock_up_min_dist:
|
||||
var t := clampf((d - knock_up_min_dist) / (knock_up_max_dist - knock_up_min_dist), 0.0, 1.0)
|
||||
return knock_up * t
|
||||
return knock_up
|
||||
@@ -0,0 +1 @@
|
||||
uid://dlwjiw42q6b5f
|
||||
@@ -42,6 +42,13 @@ var _ability_bar: HBoxContainer
|
||||
var _ability_panels: Array[PanelContainer] = []
|
||||
var _bull_bg: TextureRect
|
||||
|
||||
# Lobby barrel-smash reward — tally the barrels present on load; when the last one bursts,
|
||||
# throw confetti + a "WOooOoW!" and grant the bull two yellow bonus pips. Latched so it
|
||||
# fires once per lobby visit.
|
||||
var _barrels_remaining: int = 0
|
||||
var _barrel_reward_given: bool = false
|
||||
const _BARREL_BONUS_HP: int = 2
|
||||
|
||||
# Red damage vignette — a full-screen shader ColorRect flashed on every hit.
|
||||
const _VIGNETTE_SHADER := "res://damage_vignette.gdshader"
|
||||
var _vignette: ColorRect
|
||||
@@ -88,8 +95,10 @@ func _ready() -> void:
|
||||
_build_damage_vignette()
|
||||
_build_game_over()
|
||||
_build_touch_controls()
|
||||
_build_mobile_hud()
|
||||
_update_control_hints()
|
||||
_find_spawner.call_deferred()
|
||||
_watch_barrels.call_deferred()
|
||||
|
||||
|
||||
# On-screen joystick + ability buttons for touch devices. Self-gating: the overlay
|
||||
@@ -99,6 +108,14 @@ func _build_touch_controls() -> void:
|
||||
add_child((load("res://touch_controls.gd") as Script).new())
|
||||
|
||||
|
||||
# Mobile-only health readouts (bull pips top-left + bear boss bar top-centre). On touch the
|
||||
# bottom pip cluster is hidden (see _build_health), so this is the only health display there;
|
||||
# on desktop it's never created.
|
||||
func _build_mobile_hud() -> void:
|
||||
if Controls.use_touch_ui():
|
||||
add_child((load("res://mobile_hud.gd") as Script).new())
|
||||
|
||||
|
||||
# Bottom-centre column that groups the gameplay HUD (abilities on top, bull health
|
||||
# directly beneath) so both read as one cluster instead of scattered corners.
|
||||
func _build_bottom_hud() -> void:
|
||||
@@ -163,18 +180,29 @@ func _position_bull_bg() -> void:
|
||||
vp_h - bh)
|
||||
|
||||
|
||||
# Unobtrusive early-build tag in the bottom-right corner.
|
||||
# Early-build tag. Bottom-right on desktop; on touch it moves to the bottom centre, clear of
|
||||
# the ability cluster + joystick that own the bottom corners, and reads with an outline.
|
||||
func _build_version_label() -> void:
|
||||
var lbl := Label.new()
|
||||
lbl.text = GameVersion.full()
|
||||
lbl.add_theme_color_override("font_color", _MUTED)
|
||||
lbl.add_theme_font_size_override("font_size", 12)
|
||||
lbl.set_anchors_preset(Control.PRESET_BOTTOM_RIGHT)
|
||||
lbl.grow_horizontal = Control.GROW_DIRECTION_BEGIN
|
||||
lbl.add_theme_color_override("font_color", Color(0.90, 0.86, 0.72))
|
||||
lbl.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.85))
|
||||
lbl.add_theme_constant_override("outline_size", 4)
|
||||
lbl.add_theme_font_size_override("font_size", 16)
|
||||
lbl.grow_vertical = Control.GROW_DIRECTION_BEGIN
|
||||
lbl.offset_right = -14.0
|
||||
lbl.offset_bottom = -10.0
|
||||
lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
if Controls.use_touch_ui():
|
||||
lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
lbl.anchor_left = 0.5
|
||||
lbl.anchor_right = 0.5
|
||||
lbl.anchor_top = 1.0
|
||||
lbl.anchor_bottom = 1.0
|
||||
lbl.grow_horizontal = Control.GROW_DIRECTION_BOTH
|
||||
else:
|
||||
lbl.set_anchors_preset(Control.PRESET_BOTTOM_RIGHT)
|
||||
lbl.grow_horizontal = Control.GROW_DIRECTION_BEGIN
|
||||
lbl.offset_right = -20.0
|
||||
add_child(lbl)
|
||||
|
||||
|
||||
@@ -213,6 +241,104 @@ func _find_spawner() -> void:
|
||||
_spawner.all_defeated.connect(_on_all_defeated)
|
||||
|
||||
|
||||
# ── Lobby barrel-smash reward ───────────────────────────────────────────────────
|
||||
|
||||
# Tally the barrels the current level loaded with and listen for each one bursting. Only
|
||||
# the lobby has barrels, so on every other level this simply finds none and stands down.
|
||||
func _watch_barrels() -> void:
|
||||
var barrels := get_tree().get_nodes_in_group(&"barrel")
|
||||
_barrels_remaining = barrels.size()
|
||||
if _barrels_remaining == 0:
|
||||
return
|
||||
for barrel: Node in barrels:
|
||||
barrel.destroyed.connect(_on_barrel_destroyed)
|
||||
|
||||
|
||||
func _on_barrel_destroyed() -> void:
|
||||
_barrels_remaining -= 1
|
||||
if _barrels_remaining > 0 or _barrel_reward_given:
|
||||
return
|
||||
_barrel_reward_given = true
|
||||
# Bank the reward run-wide (capped at +2). Only heal the bull for the pips that were
|
||||
# actually added — if it already carried the cap over from an earlier lobby, it keeps
|
||||
# the cheer but no new health.
|
||||
var granted := Run.add_bonus_hp(_BARREL_BONUS_HP)
|
||||
if granted > 0 and _player != null and _player.has_method(&"grant_bonus_hp"):
|
||||
_player.call(&"grant_bonus_hp", granted)
|
||||
_celebrate()
|
||||
|
||||
|
||||
# The "cleared the lobby" flourish: a burst of confetti and a big springy "WOooOoW!".
|
||||
func _celebrate() -> void:
|
||||
_spawn_confetti()
|
||||
_show_wow()
|
||||
|
||||
|
||||
func _show_wow() -> void:
|
||||
var wow := Label.new()
|
||||
wow.text = "WOooOoW!"
|
||||
wow.set_anchors_preset(Control.PRESET_CENTER)
|
||||
wow.grow_horizontal = Control.GROW_DIRECTION_BOTH
|
||||
wow.grow_vertical = Control.GROW_DIRECTION_BOTH
|
||||
wow.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
wow.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
wow.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
wow.add_theme_font_override("font", UiFonts.title())
|
||||
wow.add_theme_font_size_override("font_size", 96)
|
||||
wow.add_theme_color_override("font_color", _HP_BONUS)
|
||||
wow.add_theme_color_override("font_outline_color", Color(0.0, 0.0, 0.0, 0.9))
|
||||
wow.add_theme_constant_override("outline_size", 8)
|
||||
wow.pivot_offset = Vector2.ZERO
|
||||
wow.scale = Vector2(0.2, 0.2)
|
||||
add_child(wow)
|
||||
# Keep the pop growing from the label's centre once it has a real size.
|
||||
await get_tree().process_frame
|
||||
wow.pivot_offset = wow.size * 0.5
|
||||
|
||||
var tw := create_tween()
|
||||
tw.tween_property(wow, "scale", Vector2.ONE, 0.35).set_trans(Tween.TRANS_BACK).set_ease(
|
||||
Tween.EASE_OUT)
|
||||
tw.tween_interval(1.1)
|
||||
tw.parallel().tween_property(wow, "modulate:a", 0.0, 0.6)
|
||||
tw.parallel().tween_property(wow, "position:y", wow.position.y - 40.0, 0.6)
|
||||
tw.tween_callback(wow.queue_free)
|
||||
|
||||
|
||||
func _spawn_confetti() -> void:
|
||||
const _CONFETTI_COLORS: Array[Color] = [
|
||||
Color(0.98, 0.24, 0.28), # red
|
||||
Color(1.00, 0.78, 0.20), # gold
|
||||
Color(0.30, 0.80, 0.40), # green
|
||||
Color(0.30, 0.62, 1.00), # blue
|
||||
Color(0.85, 0.40, 0.95), # violet
|
||||
Color(1.00, 1.00, 1.00), # white
|
||||
]
|
||||
var vp := get_viewport().get_visible_rect().size
|
||||
# One emitter per colour, raining down across the top of the screen.
|
||||
for col: Color in _CONFETTI_COLORS:
|
||||
var p := CPUParticles2D.new()
|
||||
p.position = Vector2(vp.x * 0.5, -20.0)
|
||||
p.emission_shape = CPUParticles2D.EMISSION_SHAPE_RECTANGLE
|
||||
p.emission_rect_extents = Vector2(vp.x * 0.5, 6.0)
|
||||
p.amount = 40
|
||||
p.lifetime = 2.6
|
||||
p.one_shot = true
|
||||
p.explosiveness = 0.35
|
||||
p.direction = Vector2(0.0, 1.0)
|
||||
p.spread = 25.0
|
||||
p.gravity = Vector2(0.0, 420.0)
|
||||
p.initial_velocity_min = 120.0
|
||||
p.initial_velocity_max = 260.0
|
||||
p.angular_velocity_min = -360.0
|
||||
p.angular_velocity_max = 360.0
|
||||
p.scale_amount_min = 4.0
|
||||
p.scale_amount_max = 8.0
|
||||
p.color = col
|
||||
add_child(p)
|
||||
# Self-clean once the burst has fully fallen.
|
||||
get_tree().create_timer(p.lifetime + 0.5).timeout.connect(p.queue_free)
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventKey and event.pressed and not event.echo:
|
||||
if _game_over and event.physical_keycode in [KEY_ENTER, KEY_KP_ENTER]:
|
||||
@@ -238,14 +364,12 @@ func _restart() -> void:
|
||||
get_tree().reload_current_scene()
|
||||
|
||||
|
||||
# A cleared level advances the run and drops the player into the lobby hub: commit the
|
||||
# win, flag the lobby as the active level, then reload the shell so it builds the lobby.
|
||||
# (Choosing the next map node happens from the lobby via trigger areas, added later.)
|
||||
# A cleared level drops the player back into the lobby hub: bank the win (which opens the
|
||||
# gates it unlocks) and reload the shell so it rebuilds the lobby.
|
||||
func _continue_to_lobby() -> void:
|
||||
get_tree().paused = false
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
Run.complete_current_level()
|
||||
Run.go_to_lobby()
|
||||
Run.return_to_lobby()
|
||||
get_tree().change_scene_to_file(Run.active_level().scene_path)
|
||||
|
||||
|
||||
@@ -390,7 +514,7 @@ func _build_game_over() -> void:
|
||||
# Buttons overlaid at the bottom of the clip.
|
||||
var row := HBoxContainer.new()
|
||||
row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
row.add_theme_constant_override("separation", 16)
|
||||
row.add_theme_constant_override("separation", 32 if Controls.use_touch_ui() else 16)
|
||||
row.anchor_left = 0.5
|
||||
row.anchor_right = 0.5
|
||||
row.anchor_top = 1.0
|
||||
@@ -400,13 +524,13 @@ func _build_game_over() -> void:
|
||||
row.offset_bottom = -48.0
|
||||
_over_root.add_child(row)
|
||||
|
||||
# Win → Continue to the run map; loss → Go Again from the top. Shown per-result in
|
||||
# _show_game_over; both share the Enter shortcut.
|
||||
# Win → continue to the run map; loss → restart from the top. Shown per-result in
|
||||
# _show_game_over; both share the Enter shortcut and label.
|
||||
_over_continue = _make_button("Continue (Enter)")
|
||||
_over_continue.pressed.connect(_continue_to_lobby)
|
||||
row.add_child(_over_continue)
|
||||
|
||||
_over_again = _make_button("Go Again (Enter)")
|
||||
_over_again = _make_button("Continue (Enter)")
|
||||
_over_again.pressed.connect(_restart)
|
||||
row.add_child(_over_again)
|
||||
|
||||
@@ -414,6 +538,11 @@ func _build_game_over() -> void:
|
||||
menu.pressed.connect(_return_to_menu)
|
||||
row.add_child(menu)
|
||||
|
||||
# Thumbs need a far bigger target than a mouse pointer, and the outcome clip has room
|
||||
# for it — grow the whole row on touch only.
|
||||
for btn: Button in [_over_continue, _over_again, menu]:
|
||||
_grow_for_touch(btn)
|
||||
|
||||
# ── Bull health ───────────────────────────────────────────────────────────────
|
||||
# A row of gold-socketed pips beneath the ability bar — one pip per HP, so raising or
|
||||
# lowering max HP visibly grows or shrinks the row. Lit pips run red and shade toward
|
||||
@@ -422,6 +551,9 @@ func _build_game_over() -> void:
|
||||
const _HP_FULL: Color = Color(0.82, 0.16, 0.12)
|
||||
const _HP_EMPTY: Color = Color(0.35, 0.05, 0.05)
|
||||
const _HP_SOCKET: Color = Color(0.05, 0.02, 0.02, 0.92)
|
||||
# Bonus pips (barrel-smash reward) read as bright gold-yellow so they stand apart from the
|
||||
# red life bar.
|
||||
const _HP_BONUS: Color = Color(1.00, 0.84, 0.18)
|
||||
|
||||
const _HP_PIP_W: float = 22.0
|
||||
const _HP_PIP_H: float = 14.0
|
||||
@@ -433,6 +565,9 @@ func _build_health() -> void:
|
||||
"panel", UiTheme.plaque(UiTheme.LEATHER, UiTheme.BORDER, 4, 12.0, 6.0))
|
||||
panel.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
# On touch the bottom edge is crowded by the joystick + ability cluster and mobile_hud.gd
|
||||
# paints health up top instead, so drop this bottom pip cluster there.
|
||||
panel.visible = not Controls.use_touch_ui()
|
||||
_bottom_col.add_child(panel)
|
||||
|
||||
var row := HBoxContainer.new()
|
||||
@@ -500,10 +635,15 @@ func _on_health_changed(current: int, max_hp: int) -> void:
|
||||
var cur := maxi(current, 0)
|
||||
var frac := 0.0 if max_hp <= 0 else clampf(float(cur) / float(max_hp), 0.0, 1.0)
|
||||
var lit := _HP_FULL.lerp(_HP_EMPTY, 1.0 - frac)
|
||||
# Bonus pips sit at the high end of the bar; paint those top pips yellow when lit.
|
||||
var bonus := 0
|
||||
if _player != null and _player.has_method(&"get_bonus_hp"):
|
||||
bonus = _player.call(&"get_bonus_hp")
|
||||
var base_max := max_hp - bonus
|
||||
for i: int in _hp_seg_fills.size():
|
||||
var fill := _hp_seg_fills[i]
|
||||
fill.visible = i < cur
|
||||
fill.color = lit
|
||||
fill.color = _HP_BONUS if i >= base_max else lit
|
||||
|
||||
|
||||
const _SLOT_SEPARATION: int = 10
|
||||
@@ -687,6 +827,10 @@ func _build_controls_panel() -> void:
|
||||
vbox.add_child(_toggle_btn)
|
||||
|
||||
|
||||
const _TOUCH_BTN_FONT: int = 34
|
||||
const _TOUCH_BTN_MIN: Vector2 = Vector2(320.0, 110.0)
|
||||
|
||||
|
||||
func _make_button(label_text: String) -> Button:
|
||||
var btn := Button.new()
|
||||
btn.text = label_text
|
||||
@@ -707,6 +851,15 @@ func _make_button(label_text: String) -> Button:
|
||||
return btn
|
||||
|
||||
|
||||
# Scales a game-over button up to a comfortable thumb target on touch devices; a no-op
|
||||
# with mouse/gamepad, where the desktop sizing already reads fine.
|
||||
func _grow_for_touch(btn: Button) -> void:
|
||||
if not Controls.use_touch_ui():
|
||||
return
|
||||
btn.add_theme_font_size_override("font_size", _TOUCH_BTN_FONT)
|
||||
btn.custom_minimum_size = _TOUCH_BTN_MIN
|
||||
|
||||
|
||||
func _row(parent: VBoxContainer, key: String, desc: String, desc_color: Color) -> void:
|
||||
var row := HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 10)
|
||||
|
||||
@@ -79,6 +79,11 @@ light_energy = 0.106
|
||||
shadow_enabled = true
|
||||
shadow_blur = 10.0
|
||||
|
||||
[node name="DirectionalLight3D2" type="DirectionalLight3D" parent="Lights" unique_id=1111896461]
|
||||
transform = Transform3D(0.6177694, 0, 0.7863593, 0, 1, 0, -0.7863593, 0, 0.6177694, 0, 26.991016, 0)
|
||||
light_color = Color(0.80501384, 0.8787135, 1, 1)
|
||||
light_energy = 0.157
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1750284504]
|
||||
environment = SubResource("Environment_73fnb")
|
||||
|
||||
|
||||
+18
-1
@@ -4,6 +4,8 @@ extends Node3D
|
||||
## spawners, lighting, colliders) into LevelRoot. Switching levels frees the whole
|
||||
## previous module first, so no old mesh or collider can survive into the next fight.
|
||||
|
||||
const PhysicsLayers = preload("res://physics_layers.gd")
|
||||
|
||||
@onready var _level_root: Node3D = $LevelRoot
|
||||
@onready var _camera: IsoCamera = $Player/Camera3D
|
||||
|
||||
@@ -25,4 +27,19 @@ func load_active_level() -> void:
|
||||
push_warning("game_shell: active level has no level_scene")
|
||||
return
|
||||
_camera.set_framing_scale(level.camera_zoom)
|
||||
_level_root.add_child(level.level_scene.instantiate())
|
||||
var module := level.level_scene.instantiate()
|
||||
_tag_environment_for_corpses(module)
|
||||
_level_root.add_child(module)
|
||||
# A fresh blood-splat pool for this level, alongside the module under LevelRoot so it's
|
||||
# torn down with everything else on the next load — stains never leak into the next fight.
|
||||
_level_root.add_child(preload("res://blood_decals.gd").new())
|
||||
|
||||
|
||||
## Ground and walls stay on WORLD so the bull and live matadors collide with them; here
|
||||
## we add CORPSE too. A killed matador's ragdoll is masked to CORPSE alone, so it rests
|
||||
## on the arena while the bull — which only collides with WORLD — passes through the body
|
||||
## instead of spazzing out on it. Done at load so it also reaches colliders baked into
|
||||
## the instanced GLB arenas, not just the level module's own floor box.
|
||||
func _tag_environment_for_corpses(module: Node) -> void:
|
||||
for body: StaticBody3D in module.find_children("*", "StaticBody3D", true, false):
|
||||
body.collision_layer |= PhysicsLayers.CORPSE
|
||||
|
||||
+253
-11
@@ -1,25 +1,267 @@
|
||||
[gd_scene format=3 uid="uid://32nyipcwrab5"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cwmo5vh738x6w" path="res://Assets/Lobby_level.glb" id="1_lobby"]
|
||||
[ext_resource type="PackedScene" uid="uid://bbfvwolhomilp" path="res://tscn_s/torch.tscn" id="1_w7uyf"]
|
||||
[ext_resource type="PackedScene" uid="uid://bd56iuttyiypv" path="res://tscn_s/BarrelSimple.tscn" id="2_3o0md"]
|
||||
[ext_resource type="PackedScene" uid="uid://dctmlh4hnuux1" path="res://Assets/Lobby_underground.glb" id="2_w7uyf"]
|
||||
[ext_resource type="Script" uid="uid://cwbf7jfkr8j10" path="res://Assets/lobby_underground.gd" id="4_73452"]
|
||||
[ext_resource type="Script" uid="uid://dn77mjyxllgl6" path="res://levels/to_the_bear_level.gd" id="5_6j2sa"]
|
||||
[ext_resource type="Script" uid="uid://cgwliuslwfmbk" path="res://levels/to_the_arena_level.gd" id="6_jmi3x"]
|
||||
|
||||
[sub_resource type="Environment" id="Environment_lobby"]
|
||||
|
||||
[node name="lobby_level" type="Node3D" unique_id=1511255302]
|
||||
[sub_resource type="Animation" id="Animation_w7uyf"]
|
||||
resource_name = "Gate_opening"
|
||||
length = 7.5
|
||||
tracks/0/type = "position_3d"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Lobby_underground/Locked_grid")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = PackedFloat32Array(0, 1, 0, 0, 0, 0.033333335, 1, 0.032444477, 0, 0, 0.06666667, 1, -0.033060133, 0, 0, 0.10934577, 1, 0.032444477, 0, 0, 0.14267911, 1, -0.033060133, 0, 0, 0.17731747, 1, 0.032444477, 0, 0, 0.2106508, 1, -0.033060133, 0, 0, 0.24085623, 1, 0.032444477, 0, 0, 0.27418956, 1, -0.033060133, 0, 0, 0.29700676, 1, 0.032444477, 0, 0, 0.3303401, 1, -0.033060133, 0, 0, 0.36350083, 1, 0.032444477, 0, 0, 0.39683416, 1, -0.033060133, 0, 0, 0.42408428, 1, 0.032444477, 0, 0, 0.4574176, 1, -0.033060133, 0, 0, 0.48153976, 1, 0, 0, 0, 0.5148731, 1, 0.032444477, 0, 0, 0.54402214, 1, 0.032444477, 0, 0, 0.54820645, 1, -0.033060133, 0, 0, 0.57735544, 1, -0.033060133, 0, 0, 0.5908855, 1, 0.032444477, 0, 0, 0.60017264, 1, 0.032444477, 0, 0, 0.6242189, 1, -0.033060133, 0, 0, 0.633506, 1, -0.033060133, 0, 0, 0.6588572, 1, 0.032444477, 0, 0, 0.6666667, 1, 0.032444477, 0, 0, 0.6921905, 1, -0.033060133, 0, 0, 0.70000005, 1, -0.033060133, 0, 0, 0.72725016, 1, 0.032444477, 0, 0, 0.75179356, 1, 0, 0, 0, 0.76058346, 1, -0.033060133, 0, 0, 0.7851269, 1, 0.032444477, 0, 0, 0.8184602, 1, -0.033060133, 0, 0, 0.86113936, 1, 0.032444477, 0, 0, 0.8944727, 1, -0.033060133, 0, 0, 0.929111, 1, 0.032444477, 0, 0, 0.9624443, 1, -0.033060133, 0, 0, 0.9926498, 1, 0.032444477, 0, 0, 1.0259831, 1, -0.033060133, 0, 0, 1.0488003, 1, 0.032444477, 0, 0, 1.0821337, 1, -0.033060133, 0, 0, 1.1152945, 1, 0.032444477, 0, 0, 1.1486278, 1, -0.033060133, 0, 0, 1.1758778, 1, 0.032444477, 0, 0, 1.2092111, 1, -0.033060133, 0, 0, 1.2333333, 1, 0, 0, 0, 1.2666667, 1, 0.032444477, 0, 0, 1.2958157, 1, 0.032444477, 0, 0, 1.3, 1, -0.033060133, 0, 0, 1.329149, 1, -0.033060133, 0, 0, 1.342679, 1, 0.032444477, 0, 0, 1.3519661, 1, 0.032444477, 0, 0, 1.3760124, 1, -0.033060133, 0, 0, 1.3852996, 1, -0.033060133, 0, 0, 1.4106507, 1, 0.032444477, 0, 0, 1.4184602, 1, 0.032444477, 0, 0, 1.443984, 1, -0.033060133, 0, 0, 1.4517937, 1, -0.033060133, 0, 0, 1.4790437, 1, 0.032444477, 0, 0, 1.512377, 1, -0.033060133, 0, 0, 1.6, 1, 0, 0, 0, 7.4666667, 1, 0, 6.938447, 0)
|
||||
|
||||
[node name="Lobby_level" parent="." unique_id=1119577247 instance=ExtResource("1_lobby")]
|
||||
[sub_resource type="Animation" id="Animation_73452"]
|
||||
length = 0.001
|
||||
tracks/0/type = "position_3d"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Lobby_underground/Locked_grid")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = PackedFloat32Array(0, 1, 0, 0, 0)
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_6j2sa"]
|
||||
_data = {
|
||||
&"Gate_opening": SubResource("Animation_w7uyf"),
|
||||
&"RESET": SubResource("Animation_73452")
|
||||
}
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_73452"]
|
||||
size = Vector3(4.1274414, 8.299622, 6.9958496)
|
||||
|
||||
[node name="lobby_level" type="Node3D" unique_id=1511255302]
|
||||
|
||||
[node name="Lights" type="Node3D" parent="." unique_id=562527333]
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Lights" unique_id=837461706]
|
||||
transform = Transform3D(1, 0, 0, 0, 0.7071067, 0.70710677, 0, -0.70710677, 0.7071067, 0, 36.945946, 70)
|
||||
light_color = Color(1, 0.9137255, 0.827451, 1)
|
||||
light_energy = 1.6
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Lights" unique_id=955995990]
|
||||
transform = Transform3D(-0.502238, -0.82287306, 0.26577574, 0.36594617, 0.07621761, 0.9275096, -0.78347975, 0.5630903, 0.26284787, 0, 0, 0)
|
||||
light_color = Color(0.78431374, 0.8117647, 1, 1)
|
||||
light_energy = 0.228
|
||||
shadow_enabled = true
|
||||
|
||||
[node name="DirectionalLight3D2" type="DirectionalLight3D" parent="Lights" unique_id=513226199]
|
||||
transform = Transform3D(1, 0, 0, 0, -0.8660254, 0.49999994, 0, -0.49999994, -0.8660254, 0, 112.56815, 93.37274)
|
||||
light_color = Color(0.4784314, 0.6156863, 0.8, 1)
|
||||
light_energy = 0.45
|
||||
[node name="SpotLight3D" type="SpotLight3D" parent="Lights" unique_id=1783040386]
|
||||
transform = Transform3D(-0.9926004, -0.101570696, 0.06654498, -0.08617279, 0.9753173, 0.20329961, -0.08555172, 0.19606102, -0.9768528, -2.86597, 1.7488484, -31.233114)
|
||||
light_color = Color(0.51629305, 0.20273978, 0.034483083, 1)
|
||||
light_energy = 1000.0
|
||||
shadow_enabled = true
|
||||
shadow_reverse_cull_face = true
|
||||
spot_range = 22.312231
|
||||
|
||||
[node name="SpotLight3D3" type="SpotLight3D" parent="Lights" unique_id=30670834]
|
||||
transform = Transform3D(-0.94000536, -0.14085309, 0.31072634, 0.3218794, -0.064308055, 0.94459444, -0.11306689, 0.9879399, 0.105787426, 11.072751, 38.325985, 6.519638)
|
||||
light_color = Color(0.31635508, 0.2876817, 0.44758296, 1)
|
||||
light_energy = 17.27
|
||||
shadow_enabled = true
|
||||
shadow_reverse_cull_face = true
|
||||
spot_range = 4095.795
|
||||
|
||||
[node name="SpotLight3D2" type="SpotLight3D" parent="Lights" unique_id=748351326]
|
||||
transform = Transform3D(-0.0064023333, 0.48097554, -0.8767107, 0.0041269795, 0.87673384, 0.48095813, 0.99997103, -0.00053891214, -0.0075981184, -30.750355, 6.77676, -0.61776364)
|
||||
light_color = Color(0.1254902, 0.37254903, 0.16078432, 1)
|
||||
light_energy = 1000.0
|
||||
shadow_enabled = true
|
||||
shadow_reverse_cull_face = true
|
||||
spot_range = 22.312231
|
||||
|
||||
[node name="Torches" type="Node3D" parent="Lights" unique_id=1105190110]
|
||||
|
||||
[node name="Torch" parent="Lights/Torches" unique_id=1280811583 instance=ExtResource("1_w7uyf")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.966858, -0.26246262, 0)
|
||||
|
||||
[node name="Torch2" parent="Lights/Torches" unique_id=472577842 instance=ExtResource("1_w7uyf")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.3695145, 0, 0)
|
||||
|
||||
[node name="Torch3" parent="Lights/Torches" unique_id=207127049 instance=ExtResource("1_w7uyf")]
|
||||
transform = Transform3D(0.0026565322, 0, 0.9999965, 0, 1, 0, -0.9999965, 0, 0.0026565322, -0.38332775, 1.9073486e-06, 16.218426)
|
||||
|
||||
[node name="Torch4" parent="Lights/Torches" unique_id=601493997 instance=ExtResource("1_w7uyf")]
|
||||
transform = Transform3D(0.0026565322, 0, 0.9999965, 0, 1, 0, -0.9999965, 0, 0.0026565322, -0.3482311, 1.9073486e-06, 3.0070276)
|
||||
|
||||
[node name="Torch5" parent="Lights/Torches" unique_id=1952598831 instance=ExtResource("1_w7uyf")]
|
||||
transform = Transform3D(-1, 0, 8.742278e-08, 0, 1, 0, -8.742278e-08, 0, -1, 0.09400132, 1.9073486e-06, -0.31505296)
|
||||
|
||||
[node name="Torch6" parent="Lights/Torches" unique_id=830103133 instance=ExtResource("1_w7uyf")]
|
||||
transform = Transform3D(-1, 0, 8.742278e-08, 0, 1, 0, -8.742278e-08, 0, -1, 16.002838, 1.9073486e-06, -0.31505156)
|
||||
|
||||
[node name="Torch7" parent="Lights/Torches" unique_id=1842073656 instance=ExtResource("1_w7uyf")]
|
||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -0.349617, 1.9073486e-06, -0.31505227)
|
||||
|
||||
[node name="Torch8" parent="Lights/Torches" unique_id=987701581 instance=ExtResource("1_w7uyf")]
|
||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -0.349617, 1.9073486e-06, -0.31505227)
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=939963056]
|
||||
environment = SubResource("Environment_lobby")
|
||||
|
||||
[node name="Barrels" type="Node3D" parent="." unique_id=1740830546]
|
||||
|
||||
[node name="BarrelSimple" parent="Barrels" unique_id=771860903 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.276957, 0.056278944, -13.151918)
|
||||
|
||||
[node name="BarrelSimple2" parent="Barrels" unique_id=609563864 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.8753104, 0.11255789, -14.810173)
|
||||
|
||||
[node name="BarrelSimple3" parent="Barrels" unique_id=2089803156 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.758999, 0.11255789, -14.810173)
|
||||
|
||||
[node name="BarrelSimple4" parent="Barrels" unique_id=223671996 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14.40292, 0.11255789, -14.810173)
|
||||
|
||||
[node name="BarrelSimple5" parent="Barrels" unique_id=1643056602 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.8811536, 0.11255789, -10.928238)
|
||||
|
||||
[node name="BarrelSimple6" parent="Barrels" unique_id=1861324204 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.764843, 0.11255789, -10.928238)
|
||||
|
||||
[node name="BarrelSimple7" parent="Barrels" unique_id=1662505485 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14.597986, 0.11255789, -11.120108)
|
||||
|
||||
[node name="BarrelSimple8" parent="Barrels" unique_id=711949884 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.686088, 0.11255789, -6.599861)
|
||||
|
||||
[node name="BarrelSimple9" parent="Barrels" unique_id=633001295 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.569777, 0.11255789, -6.599861)
|
||||
|
||||
[node name="BarrelSimple10" parent="Barrels" unique_id=1460426434 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14.40292, 0.11255789, -6.791731)
|
||||
|
||||
[node name="BarrelSimple11" parent="Barrels" unique_id=1660531493 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.210243, 0.056278944, 12.913824)
|
||||
|
||||
[node name="BarrelSimple12" parent="Barrels" unique_id=1652485637 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.8753104, 0.11255789, 6.3396435)
|
||||
|
||||
[node name="BarrelSimple13" parent="Barrels" unique_id=590613985 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.758999, 0.11255789, 6.3396435)
|
||||
|
||||
[node name="BarrelSimple14" parent="Barrels" unique_id=176616372 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14.40292, 0.11255789, 6.3396435)
|
||||
|
||||
[node name="BarrelSimple15" parent="Barrels" unique_id=465036756 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.070376, 0.11255789, 10.029709)
|
||||
|
||||
[node name="BarrelSimple16" parent="Barrels" unique_id=224566162 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.954065, 0.11255789, 10.029709)
|
||||
|
||||
[node name="BarrelSimple17" parent="Barrels" unique_id=1512161234 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14.597986, 0.11255789, 10.029709)
|
||||
|
||||
[node name="BarrelSimple18" parent="Barrels" unique_id=1113697629 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.8753104, 0.11255789, 14.358086)
|
||||
|
||||
[node name="BarrelSimple19" parent="Barrels" unique_id=1224035347 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.758999, 0.11255789, 14.358086)
|
||||
|
||||
[node name="BarrelSimple20" parent="Barrels" unique_id=249931770 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14.40292, 0.11255789, 14.358086)
|
||||
|
||||
[node name="BarrelSimple21" parent="Barrels" unique_id=1893459330 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.3384705, 0.056278944, 15.129177)
|
||||
|
||||
[node name="BarrelSimple22" parent="Barrels" unique_id=1386374345 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -14.883017, 0.11255789, 6.7661877)
|
||||
|
||||
[node name="BarrelSimple23" parent="Barrels" unique_id=1508934681 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.999329, 0.11255789, 6.7661877)
|
||||
|
||||
[node name="BarrelSimple24" parent="Barrels" unique_id=1567182843 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.3554077, 0.11255789, 6.7661877)
|
||||
|
||||
[node name="BarrelSimple25" parent="Barrels" unique_id=2023488949 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -14.687952, 0.11255789, 10.456253)
|
||||
|
||||
[node name="BarrelSimple26" parent="Barrels" unique_id=918952214 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.804262, 0.11255789, 10.456253)
|
||||
|
||||
[node name="BarrelSimple27" parent="Barrels" unique_id=1651601809 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.1603413, 0.11255789, 10.456253)
|
||||
|
||||
[node name="BarrelSimple28" parent="Barrels" unique_id=1526224674 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -14.883017, 0.11255789, 14.78463)
|
||||
|
||||
[node name="BarrelSimple29" parent="Barrels" unique_id=212191494 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.999329, 0.11255789, 14.78463)
|
||||
|
||||
[node name="BarrelSimple30" parent="Barrels" unique_id=625425940 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.3554077, 0.11255789, 14.78463)
|
||||
|
||||
[node name="BarrelSimple31" parent="Barrels" unique_id=1216255698 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.165121, 0.056277037, -13.43729)
|
||||
|
||||
[node name="BarrelSimple32" parent="Barrels" unique_id=1511816190 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15.938013, 0.11255789, -14.810173)
|
||||
|
||||
[node name="BarrelSimple33" parent="Barrels" unique_id=592677866 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.054325, 0.11255789, -14.810173)
|
||||
|
||||
[node name="BarrelSimple34" parent="Barrels" unique_id=855289598 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.410404, 0.11255789, -14.810173)
|
||||
|
||||
[node name="BarrelSimple35" parent="Barrels" unique_id=521586989 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15.742949, 0.11255789, -11.120108)
|
||||
|
||||
[node name="BarrelSimple36" parent="Barrels" unique_id=841067379 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -11.859259, 0.11255789, -11.120108)
|
||||
|
||||
[node name="BarrelSimple37" parent="Barrels" unique_id=1167528508 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.215338, 0.11255789, -11.120108)
|
||||
|
||||
[node name="BarrelSimple38" parent="Barrels" unique_id=2081881340 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15.938013, 0.11255789, -6.791731)
|
||||
|
||||
[node name="BarrelSimple39" parent="Barrels" unique_id=716196812 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.054325, 0.11255789, -6.791731)
|
||||
|
||||
[node name="BarrelSimple40" parent="Barrels" unique_id=1689907554 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.410404, 0.11255789, -6.791731)
|
||||
|
||||
[node name="BarrelSimple41" parent="Barrels" unique_id=1885522518 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.4957442, 0.11255789, -1.522007)
|
||||
|
||||
[node name="BarrelSimple42" parent="Barrels" unique_id=138543996 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.3879452, 0.11255789, -1.522007)
|
||||
|
||||
[node name="BarrelSimple43" parent="Barrels" unique_id=1456059567 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.6908097, 0.11255789, 2.8063698)
|
||||
|
||||
[node name="BarrelSimple44" parent="Barrels" unique_id=1888973294 instance=ExtResource("2_3o0md")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.1928787, 0.11255789, 2.8063698)
|
||||
|
||||
[node name="Lobby_underground" parent="." unique_id=1313381882 instance=ExtResource("2_w7uyf")]
|
||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 0, 0)
|
||||
script = ExtResource("4_73452")
|
||||
|
||||
[node name="Plane" parent="Lobby_underground" index="1" unique_id=1962555538]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2352347, 0)
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="Lobby_underground" unique_id=2070502042]
|
||||
root_node = NodePath("../..")
|
||||
libraries/ = SubResource("AnimationLibrary_6j2sa")
|
||||
|
||||
[node name="to_the_bear_level" type="Area3D" parent="." unique_id=267572930]
|
||||
collision_mask = 3
|
||||
script = ExtResource("5_6j2sa")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="to_the_bear_level" unique_id=2080871641]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -24.975298, 3.6498108, 0.59606934)
|
||||
shape = SubResource("BoxShape3D_73452")
|
||||
|
||||
[node name="to_the_arena_level" type="Area3D" parent="." unique_id=293174522]
|
||||
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -2.7537346, 0, -1.2036956e-07)
|
||||
collision_mask = 3
|
||||
script = ExtResource("6_jmi3x")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="to_the_arena_level" unique_id=409491377]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -23.561888, 2.767395, 0.59606934)
|
||||
shape = SubResource("BoxShape3D_73452")
|
||||
|
||||
[editable path="Lobby_underground"]
|
||||
|
||||
@@ -83,6 +83,7 @@ func _on_matador_killed() -> void:
|
||||
if _alive > 0 or _resolved:
|
||||
return
|
||||
if _wave >= DP.f("mat_wave_size"):
|
||||
DP.set_value("gate_unlocked_bear", true)
|
||||
_resolved = true
|
||||
all_defeated.emit()
|
||||
else:
|
||||
|
||||
+54
-7
@@ -34,11 +34,20 @@ var pending_col: int = -1
|
||||
## Debug override — when set, active_level() returns this regardless of map state.
|
||||
## Set via the console `level` command; cleared on start_new_run().
|
||||
var debug_level_override: LevelDef = null
|
||||
## The lobby is an interstitial hub between fights, not a map node: the player is sent
|
||||
## here after clearing a level (go_to_lobby()) to move around freely before choosing the
|
||||
## next node. While set, active_level() serves the lobby; cleared once a node is picked
|
||||
## (select_node) or a fresh run begins.
|
||||
## The lobby is the hub the run starts and returns to: a walk-around room whose gates lead
|
||||
## into the fights. While set, active_level() serves the lobby; cleared once a gate is
|
||||
## entered (choose_level) and set again on a win (return_to_lobby).
|
||||
var enter_lobby: bool = false
|
||||
## Level picked at a lobby gate and being fought now — active_level() serves it while
|
||||
## enter_lobby is false. Null in the lobby itself.
|
||||
var lobby_choice: LevelDef = null
|
||||
## Ids of levels the player has cleared this run (StringName -> true). Drives which lobby
|
||||
## gates are open: the bear gate stays shut until the arena is beaten.
|
||||
var cleared: Dictionary = {}
|
||||
## Run-long bonus health (yellow pips) earned from lobby rewards. Persists across level
|
||||
## loads — the player reads it on spawn — and is capped so it can't stack past BONUS_HP_CAP.
|
||||
var bonus_hp: int = 0
|
||||
const BONUS_HP_CAP: int = 2
|
||||
|
||||
# Level catalog. Every level shares the shell scene; what changes is the level module
|
||||
# (its geometry + spawners) and the opponent. The arena (matador wave, normal + boss
|
||||
@@ -85,6 +94,8 @@ func active_level() -> LevelDef:
|
||||
return debug_level_override
|
||||
if enter_lobby:
|
||||
return _lobby
|
||||
if lobby_choice != null:
|
||||
return lobby_choice
|
||||
var n := node_at(pending_row, pending_col)
|
||||
if n == null:
|
||||
n = current_node()
|
||||
@@ -115,7 +126,11 @@ func start_new_run() -> void:
|
||||
pending_row = -1
|
||||
pending_col = -1
|
||||
debug_level_override = null
|
||||
enter_lobby = false
|
||||
# The run opens in the lobby hub; its gates lead into the fights.
|
||||
enter_lobby = true
|
||||
lobby_choice = null
|
||||
cleared = {}
|
||||
bonus_hp = 0
|
||||
run_started.emit()
|
||||
|
||||
|
||||
@@ -177,10 +192,42 @@ func select_node(node: MapNode) -> void:
|
||||
|
||||
|
||||
## Send the player to the lobby hub instead of a fight — active_level() serves the lobby
|
||||
## until a node is picked. Called after clearing a level so the player lands in the lobby
|
||||
## rather than jumping straight to the next fight.
|
||||
## until a gate is entered.
|
||||
func go_to_lobby() -> void:
|
||||
enter_lobby = true
|
||||
lobby_choice = null
|
||||
|
||||
|
||||
## Enter the fight behind a lobby gate: active_level() serves it until the player wins and
|
||||
## returns to the lobby. Ignored for an unknown id.
|
||||
func choose_level(id: StringName) -> void:
|
||||
var l := get_level(id)
|
||||
if l == null:
|
||||
return
|
||||
enter_lobby = false
|
||||
lobby_choice = l
|
||||
|
||||
|
||||
## Land back in the lobby after a win, banking the cleared level so its follow-on gates
|
||||
## open (clearing the arena unlocks the bear gate).
|
||||
func return_to_lobby() -> void:
|
||||
if lobby_choice != null:
|
||||
cleared[lobby_choice.id] = true
|
||||
go_to_lobby()
|
||||
|
||||
|
||||
## Whether the bear gate should be open — the arena must be cleared first.
|
||||
func bear_gate_open() -> bool:
|
||||
return cleared.has(&"arena")
|
||||
|
||||
|
||||
## Bank bonus health for the rest of the run, clamped to BONUS_HP_CAP. Returns how many
|
||||
## pips were actually added (0 once the cap is reached) so the HUD only heals the bull when
|
||||
## there's headroom — a repeat barrel clear still cheers but grants nothing.
|
||||
func add_bonus_hp(amount: int) -> int:
|
||||
var before := bonus_hp
|
||||
bonus_hp = clampi(bonus_hp + amount, 0, BONUS_HP_CAP)
|
||||
return bonus_hp - before
|
||||
|
||||
|
||||
## Commit the level just won: move the player onto the pending node (or leave them at the
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
extends Area3D
|
||||
## Lobby gate into the arena fight. Always open — the arena is the run's first door.
|
||||
|
||||
func _ready() -> void:
|
||||
body_entered.connect(_on_body_entered)
|
||||
|
||||
|
||||
func _on_body_entered(body: Node3D) -> void:
|
||||
if not body.is_in_group("player"):
|
||||
return
|
||||
Run.choose_level(&"arena")
|
||||
get_tree().change_scene_to_file(Run.active_level().scene_path)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cgwliuslwfmbk
|
||||
@@ -0,0 +1,16 @@
|
||||
extends Area3D
|
||||
## Lobby gate into the Bear's Den. Shut until the arena is cleared (Run.bear_gate_open()),
|
||||
## which is also what plays the grid-opening animation — so the trigger only fires once the
|
||||
## gate has actually risen.
|
||||
|
||||
func _ready() -> void:
|
||||
body_entered.connect(_on_body_entered)
|
||||
|
||||
|
||||
func _on_body_entered(body: Node3D) -> void:
|
||||
if not body.is_in_group("player"):
|
||||
return
|
||||
#if not Run.bear_gate_open():
|
||||
# return
|
||||
Run.choose_level(&"bear")
|
||||
get_tree().change_scene_to_file(Run.active_level().scene_path)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dn77mjyxllgl6
|
||||
@@ -100,6 +100,12 @@ func _ready() -> void:
|
||||
exit_button.pressed.connect(_on_exit_pressed)
|
||||
options_back.pressed.connect(_close_subpanels)
|
||||
credits_back.pressed.connect(_close_subpanels)
|
||||
# The Options panel is keyboard rebinds + desktop-shaped audio rows — meaningless on a
|
||||
# phone, so drop the entry point on touch devices.
|
||||
options_button.visible = not Controls.use_touch_ui()
|
||||
# On the web build get_tree().quit() just freezes the canvas (you can't close a browser
|
||||
# tab from script), so Exit has nowhere to go — hide it. Native desktop keeps it.
|
||||
exit_button.visible = not OS.has_feature("web")
|
||||
_apply_theme()
|
||||
_build_version_label()
|
||||
_build_options_toggles()
|
||||
|
||||
+221
-87
@@ -1,13 +1,9 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
# WANDER → bull outside flee range, roaming freely
|
||||
# FLEE → bull within range, matador backs away (raycast-steered around walls)
|
||||
# BRACE → charge detected: plant feet, face the bull (cite phase)
|
||||
# SIDESTEP→ bull commits: sharp lateral step to let it pass (pase phase)
|
||||
# ATTACK → post-dodge or mid-range: chase and strike
|
||||
# ROLL → hit by bull but roll chance fires: survive and recover
|
||||
# THROW → planted, winding up an overhand throw, then releasing the sword
|
||||
# RAGDOLL → hit by bull, no roll chance
|
||||
# WANDER → roam/taunt outside flee range. FLEE → bull close: back away (raycast-steered).
|
||||
# BRACE → charge detected: plant + face (cite). SIDESTEP → bull commits: lateral pass (pase).
|
||||
# ATTACK → chase and strike. ROLL → hit but rolled: survive. THROW → wind up + hurl the spear.
|
||||
# RAGDOLL → hit, no roll.
|
||||
enum State { WANDER, FLEE, BRACE, SIDESTEP, ATTACK, ROLL, THROW, RAGDOLL }
|
||||
|
||||
# The matador's high-level *want*, chosen by a weighted utility vote (see
|
||||
@@ -32,7 +28,9 @@ var _dodge_cd: float = 0.0
|
||||
var _will_dodge: bool = true
|
||||
var _attack_timer: float = 0.0
|
||||
var _swing_timer: float = 0.0
|
||||
var _lunge_timer: float = 0.0
|
||||
var _attack_cd: float = 0.0
|
||||
var _bull_prev_pos: Vector3 = Vector3.ZERO
|
||||
var _bull_prev_seen: bool = false
|
||||
var _roll_timer: float = 0.0
|
||||
var _roll_dir: Vector3 = Vector3.ZERO
|
||||
var _is_spawning: bool = false
|
||||
@@ -52,7 +50,7 @@ var _drawing: bool = false
|
||||
var _sheathing: bool = false
|
||||
var _draw_timer: float = 0.0
|
||||
var _draw_len: float = 0.0
|
||||
var _sword_blade_area: Area3D = null
|
||||
var _sword_blade_area: Hitbox = null
|
||||
var _spear_node: Node3D = null
|
||||
var _blade_hit_cd: float = 0.0
|
||||
var _death_player: AudioStreamPlayer = null
|
||||
@@ -76,8 +74,9 @@ const _ANIM_TAUNTS: Array[StringName] = [&"Taunt", &"Taunt_B", &"Taunt_C"]
|
||||
# reparents from holster to hand at this point in the animation.
|
||||
const _DRAW_GRAB_AT: float = 0.55
|
||||
|
||||
const _SWORD_SCENE: PackedScene = preload("res://Assets/sword.glb")
|
||||
const _SPEAR_SCENE: PackedScene = preload("res://Assets/spear.glb")
|
||||
# Wrapper scenes (glb + an editor-tweakable hitbox / collider) — see Sword.tscn / Spear.tscn.
|
||||
const _SWORD_SCENE: PackedScene = preload("res://Sword.tscn")
|
||||
const _SPEAR_SCENE: PackedScene = preload("res://Spear.tscn")
|
||||
|
||||
const _GRAVITY: float = 9.8 # arena gravity, for the spear's ballistic arc
|
||||
|
||||
@@ -103,9 +102,10 @@ func _ready() -> void:
|
||||
_anim_player = _find_anim_player(_mesh)
|
||||
if _skeleton:
|
||||
_sim = MatadorRagdoll.build(_skeleton)
|
||||
# Web (Mali/ANGLE) can't run Compatibility vertex-skinning; rebuild as non-skinned
|
||||
# bone-attached pieces. Runs after the ragdoll sim is built (both drive the same bones).
|
||||
if OS.has_feature("web"):
|
||||
# Native GPU skinning by default; rigid_skin is an opt-in fallback now (the Mali/ANGLE
|
||||
# invisible-skinning bug is fixed in the 4.7 web templates). See Controls.rigid_skin_enabled().
|
||||
# When on, it runs after the ragdoll sim is built (both drive the same bones).
|
||||
if Controls.rigid_skin_enabled():
|
||||
RigidSkin.convert_tree(self)
|
||||
if _anim_player:
|
||||
for anim in [_ANIM_RUN, _ANIM_ATTACK] + _ANIM_TAUNTS:
|
||||
@@ -168,6 +168,9 @@ func _physics_process(delta: float) -> void:
|
||||
_dodge_cd = maxf(0.0, _dodge_cd - delta)
|
||||
_blade_hit_cd = maxf(0.0, _blade_hit_cd - delta)
|
||||
_throw_aim_cd = maxf(0.0, _throw_aim_cd - delta)
|
||||
_attack_cd = maxf(0.0, _attack_cd - delta)
|
||||
if _bull != null:
|
||||
_sweep_bull_gore()
|
||||
if _state != State.RAGDOLL and _bull != null:
|
||||
_update_ai_state(delta)
|
||||
|
||||
@@ -185,9 +188,8 @@ func _physics_process(delta: float) -> void:
|
||||
_advance_draw(delta)
|
||||
|
||||
|
||||
# Utility-driven brain. The physically committed states (a brace, a pass, a roll, a
|
||||
# throw wind-up) run to completion on their own timers; from the free states the
|
||||
# matador re-scores its options every mat_decide_interval and acts on the winner.
|
||||
# Utility-driven brain. Committed states (brace / pass / roll / throw wind-up) run to completion on
|
||||
# their own timers; from the free states the matador re-scores every mat_decide_interval.
|
||||
func _update_ai_state(delta: float) -> void:
|
||||
if _state == State.BRACE or _state == State.SIDESTEP \
|
||||
or _state == State.ROLL or _state == State.THROW:
|
||||
@@ -204,9 +206,8 @@ func _update_ai_state(delta: float) -> void:
|
||||
_enter_intent(intent)
|
||||
|
||||
|
||||
# Score each intent from weighted heuristics and return the winner. Weights (the
|
||||
# mat_w_* params) shape the personality; a small commit bonus on the current intent
|
||||
# stops it flip-flopping between two near-tied options.
|
||||
# Score each intent from weighted mat_w_* heuristics and return the winner; a small commit bonus on
|
||||
# the current intent stops it flip-flopping between two near-tied options.
|
||||
func _choose_intent() -> Intent:
|
||||
var dist := global_position.distance_to(_bull.global_position)
|
||||
var bull_flat := Vector3(_bull.velocity.x, 0.0, _bull.velocity.z)
|
||||
@@ -227,6 +228,9 @@ func _choose_intent() -> Intent:
|
||||
# A matador won't commit to a strike it can't bail out of, so a spent dodge
|
||||
# cooldown makes attacking (and dodging outright) less attractive.
|
||||
var dodge_ready := 1.0 if _dodge_cd <= 0.0 else 0.35
|
||||
# The post-stab recovery beat (mat_stab_recovery) kills ATTACK outright — the matador circles
|
||||
# or gives ground between thrusts rather than machine-gunning the bull; DODGE/FLEE stay live.
|
||||
var attack_ready := 0.0 if _attack_cd > 0.0 else 1.0
|
||||
var throw_ok := _throw_aim_cd <= 0.0 and is_instance_valid(_sword_node) \
|
||||
and dist >= DP.f("mat_throw_min_dist") and dist <= DP.f("mat_throw_range")
|
||||
|
||||
@@ -247,7 +251,7 @@ func _choose_intent() -> Intent:
|
||||
# Press the attack; ease off a touch when a charge is barrelling in. Supporting
|
||||
# matadors barely press — they yield the pass to whoever's engaging.
|
||||
Intent.ATTACK: DP.f("mat_w_aggression") * (0.45 + 0.55 * close) \
|
||||
* (1.0 - 0.55 * danger) * dodge_ready * engage_mult,
|
||||
* (1.0 - 0.55 * danger) * dodge_ready * engage_mult * attack_ready,
|
||||
# Sidestep / plant against an incoming charge.
|
||||
Intent.DODGE: DP.f("mat_w_caution") * danger * (1.0 if _dodge_cd <= 0.0 else 0.0),
|
||||
# Hurl the blade — an occasional ranged flourish from an engaging matador when
|
||||
@@ -255,6 +259,9 @@ func _choose_intent() -> Intent:
|
||||
Intent.THROW: (DP.f("mat_w_throw") * (0.35 + 0.65 * (1.0 - close))) \
|
||||
if (throw_ok and is_engager) else -1.0,
|
||||
}
|
||||
# Commit bonus keeps a near-tied choice from flip-flopping — but don't re-reinforce a
|
||||
# just-swung ATTACK we're recovering from, or the matador clings to it and spams the bull.
|
||||
if not (_intent == Intent.ATTACK and _attack_cd > 0.0):
|
||||
score[_intent] = float(score[_intent]) + DP.f("mat_w_commit")
|
||||
|
||||
var best: Intent = Intent.WANDER
|
||||
@@ -301,9 +308,8 @@ func _enter_intent(intent: Intent) -> void:
|
||||
_start_throw()
|
||||
|
||||
|
||||
# How many other live matadors are closer to the bull than this one. 0 = the
|
||||
# closest (the natural lead engager); the utility brain gives the nearest
|
||||
# mat_engage_slots the go-ahead to press while the rest spread out and taunt.
|
||||
# How many other live matadors are closer to the bull than this one (0 = the lead engager); the
|
||||
# brain lets the nearest mat_engage_slots press while the rest spread out and taunt.
|
||||
func _engagement_rank() -> int:
|
||||
if _bull == null:
|
||||
return 0
|
||||
@@ -347,6 +353,19 @@ func _is_charge_incoming() -> bool:
|
||||
return bull_flat.normalized().dot(to_me.normalized()) > 0.85
|
||||
|
||||
|
||||
# Bull charging fast and aimed straight at the matador, at ANY range (unlike _is_charge_incoming,
|
||||
# which is capped to brace range) — so a taunting matador can answer a charge from across the arena.
|
||||
func _charge_aimed_at_me() -> bool:
|
||||
var bull_flat := Vector3(_bull.velocity.x, 0.0, _bull.velocity.z)
|
||||
if bull_flat.length() < DP.f("mat_charge_speed"):
|
||||
return false
|
||||
var to_me := global_position - _bull.global_position
|
||||
to_me.y = 0.0
|
||||
if to_me.length() < 0.1:
|
||||
return true
|
||||
return bull_flat.normalized().dot(to_me.normalized()) > 0.9
|
||||
|
||||
|
||||
# Returns a wall-clear direction, recomputed at most every _STEER_INTERVAL seconds.
|
||||
# Randomises among available clear angles so juke direction is unpredictable.
|
||||
func _steer_clear(desired_dir: Vector3, delta: float) -> Vector3:
|
||||
@@ -407,6 +426,19 @@ func _face_point(point: Vector3, delta: float, rate: float) -> void:
|
||||
func _tick_wander(delta: float) -> void:
|
||||
# Plant the feet while drawing / sheathing instead of sliding through the clip.
|
||||
if _drawing or _sheathing or _idle_timer > 0.0:
|
||||
# A charge aimed at a taunting matador snaps it out of the pose: hurl a spear at a bull
|
||||
# barrelling in from range, or switch to the sword (brace/cite) to meet a closer rush.
|
||||
if _idle_timer > 0.0 and not _drawing and not _sheathing \
|
||||
and _bull != null and _charge_aimed_at_me():
|
||||
var dist := global_position.distance_to(_bull.global_position)
|
||||
var throw_ok := _throw_aim_cd <= 0.0 and is_instance_valid(_sword_node) \
|
||||
and dist >= DP.f("mat_throw_min_dist") and dist <= DP.f("mat_throw_range")
|
||||
if dist > DP.f("mat_brace_range") and throw_ok:
|
||||
_start_throw() # far charge — get the spear off before it arrives
|
||||
return
|
||||
if dist <= DP.f("mat_brace_range"):
|
||||
_start_brace() # closer rush — draw the sword and cite the charge
|
||||
return
|
||||
_idle_timer = maxf(0.0, _idle_timer - delta)
|
||||
_decelerate(10.0, delta)
|
||||
# Taunt toward the bull so the posturing plays to it, not off into space.
|
||||
@@ -531,6 +563,7 @@ func _start_attack() -> void:
|
||||
|
||||
func _tick_attack(delta: float) -> void:
|
||||
_attack_timer -= delta
|
||||
var was_swinging := _swing_timer > 0.0
|
||||
_swing_timer = maxf(0.0, _swing_timer - delta)
|
||||
# Plant the feet while drawing instead of sliding toward the bull mid-clip.
|
||||
if _drawing or _sheathing:
|
||||
@@ -543,22 +576,41 @@ func _tick_attack(delta: float) -> void:
|
||||
to_bull.y = 0.0
|
||||
var dist := to_bull.length()
|
||||
|
||||
# Commit to a full swing once in range instead of flipping Run/Attack at the
|
||||
# distance boundary every frame (the old foot-slide jitter). When the swing
|
||||
# ends the matador re-closes if the bull slipped away, or stabs again if not.
|
||||
if _swing_timer <= 0.0 and dist <= DP.f("mat_attack_min_dist") and _sword_in_hand:
|
||||
# A finished stab enforces a recovery beat (no re-commit for mat_stab_recovery), then decides
|
||||
# what's next: a landed hit very likely breaks into a taunt/retreat, otherwise the usual roll
|
||||
# to give ground / circle / throw — anything but instantly drilling the same thrust again.
|
||||
if was_swinging and _swing_timer <= 0.0:
|
||||
_attack_cd = DP.f("mat_stab_recovery")
|
||||
var landed := _sword_blade_area != null and _sword_blade_area.did_hit()
|
||||
if landed and randf() < DP.f("mat_taunt_after_hit"):
|
||||
_do_taunt_retreat()
|
||||
return
|
||||
if randf() < DP.f("mat_stab_followup_chance"):
|
||||
_do_stab_followup()
|
||||
return
|
||||
|
||||
# Run in (Run clip) to mat_stab_standoff, then plant and swing on the spot — the standoff sits
|
||||
# inside the sword's ~3.75 m thrust reach; killing velocity on commit stops the feet sliding.
|
||||
# The recovery beat gates the next commit so back-to-back stabs can't machine-gun the bull.
|
||||
if _swing_timer <= 0.0 and _attack_cd <= 0.0 and dist <= DP.f("mat_stab_standoff") and _sword_in_hand:
|
||||
_swing_timer = _anim_length(_ANIM_ATTACK, 0.9)
|
||||
_lunge_timer = DP.f("mat_lunge_time")
|
||||
velocity.x = 0.0
|
||||
velocity.z = 0.0
|
||||
# Re-arm fresh each swing — back-to-back stabs commit before the else-branch deactivate runs.
|
||||
if _sword_blade_area != null:
|
||||
_sword_blade_area.deactivate()
|
||||
|
||||
if _swing_timer > 0.0:
|
||||
_lunge_timer = maxf(0.0, _lunge_timer - delta)
|
||||
if _lunge_timer > 0.0 and dist > DP.f("mat_attack_min_dist"):
|
||||
_accelerate(to_bull.normalized(), DP.f("mat_lunge_speed"), delta)
|
||||
else:
|
||||
_decelerate(22.0, delta)
|
||||
_play_anim(_ANIM_ATTACK)
|
||||
_try_melee_hit(DP.f("mat_stab_reach"))
|
||||
# Damage off the sword's own BladeHitbox (Sword.tscn), riding the animated blade — gored only
|
||||
# when the thrust reaches it. Arm at the thrust (mat_stab_strike_at) and sweep for the overlap.
|
||||
if _sword_blade_area != null and _swing_phase() >= DP.f("mat_stab_strike_at"):
|
||||
_sword_blade_area.activate()
|
||||
_sword_blade_area.sweep()
|
||||
else:
|
||||
if _sword_blade_area != null:
|
||||
_sword_blade_area.deactivate()
|
||||
var dir := _steer_clear(to_bull.normalized(), delta)
|
||||
_accelerate(dir, DP.f("mat_attack_speed"), delta)
|
||||
_play_anim(_ANIM_RUN)
|
||||
@@ -566,6 +618,50 @@ func _tick_attack(delta: float) -> void:
|
||||
move_and_slide()
|
||||
|
||||
|
||||
# How far through the attack swing: 0 (just committed) → 1 (finished), tracking the clip's progress.
|
||||
func _swing_phase() -> float:
|
||||
var length := _anim_length(_ANIM_ATTACK, 0.9)
|
||||
if length <= 0.0:
|
||||
return 1.0
|
||||
return clampf(1.0 - _swing_timer / length, 0.0, 1.0)
|
||||
|
||||
|
||||
# Break off after a stab instead of drilling the same thrust: give ground, hurl a spear, or circle.
|
||||
# The brain re-engages after; _decide_cd is reset so the pick plays out before it re-scores.
|
||||
func _do_stab_followup() -> void:
|
||||
_decide_cd = DP.f("mat_decide_interval")
|
||||
_dodge_cd = DP.f("mat_dodge_cooldown")
|
||||
_steer_cd = 0.0
|
||||
var roll := randf()
|
||||
if roll < 0.2 and _throw_aim_cd <= 0.0 and is_instance_valid(_sword_node):
|
||||
_start_throw() # ranged flourish
|
||||
elif roll < 0.6:
|
||||
_state = State.FLEE # give ground after the thrust
|
||||
_intent = Intent.FLEE
|
||||
else:
|
||||
_state = State.WANDER # circle to a fresh angle before pressing again
|
||||
_intent = Intent.WANDER
|
||||
_pick_wander_target()
|
||||
|
||||
|
||||
# A stab that LANDED: milk it. Break into a long taunt held toward the bull, then drift out to the
|
||||
# showmanship ring — and lock ATTACK out for the whole hold (_attack_cd) so the brain can't drag the
|
||||
# matador straight back into another thrust. DODGE/FLEE stay live, so a charging bull is still
|
||||
# answered. This is what stops the "stab, stab, stab" spam after the matador connects.
|
||||
func _do_taunt_retreat() -> void:
|
||||
_state = State.WANDER
|
||||
_intent = Intent.WANDER
|
||||
_idle_timer = randf_range(DP.f("mat_taunt_hold") * 0.7, DP.f("mat_taunt_hold") * 1.3)
|
||||
_idle_anim = _pick_taunt()
|
||||
_taunt_swap = randf_range(1.5, 3.0)
|
||||
_attack_cd = maxf(_attack_cd, _idle_timer)
|
||||
_dodge_cd = DP.f("mat_dodge_cooldown")
|
||||
_steer_cd = 0.0
|
||||
_pick_wander_target()
|
||||
if _sword_blade_area != null:
|
||||
_sword_blade_area.deactivate()
|
||||
|
||||
|
||||
func _enter_roll(hit_dir: Vector3) -> void:
|
||||
_state = State.ROLL
|
||||
# Match the state to the actual clip so the roll plays through once instead of
|
||||
@@ -579,9 +675,8 @@ func _enter_roll(hit_dir: Vector3) -> void:
|
||||
_anim_player.seek(0.0, true)
|
||||
|
||||
|
||||
# Called by the spawner (deferred) to make the matador leap-roll toward a target
|
||||
# point on entry — the cinematic arena entrance. After the roll it transitions to
|
||||
# normal AI via the standard ROLL → FLEE path.
|
||||
# Called (deferred) by the spawner to make the matador leap-roll toward a target on entry — the
|
||||
# cinematic arena entrance. After the roll it transitions to normal AI via the ROLL → FLEE path.
|
||||
func enter_spawn_roll(toward: Vector3) -> void:
|
||||
var dir := toward - global_position
|
||||
dir.y = 0.0
|
||||
@@ -770,34 +865,84 @@ func _on_body_entered(body: Node3D) -> void:
|
||||
if not body.is_in_group(&"player"):
|
||||
return
|
||||
var player := body as CharacterBody3D
|
||||
if player.velocity.length() < DP.f("mat_hit_threshold"):
|
||||
var bull_speed := player.velocity.length()
|
||||
if bull_speed < DP.f("mat_hit_threshold"):
|
||||
return
|
||||
if not _horns_first(player.global_position):
|
||||
return
|
||||
var flat_vel := Vector3(player.velocity.x, 0.0, player.velocity.z)
|
||||
var hit_dir := flat_vel.normalized() if flat_vel.length() > 0.5 else \
|
||||
(global_position - player.global_position).normalized()
|
||||
_take_bull_charge(bull_speed, hit_dir)
|
||||
|
||||
if randf() < DP.f("mat_roll_chance"):
|
||||
|
||||
# Tunnel-proof charge detection: at dash speed the bull skips clean over the thin HitArea between
|
||||
# ticks, so body_entered never fires. Sweep its actual travel (prev → now) and gore on any pass within
|
||||
# mat_charge_gore_radius. Runs every frame (even ragdolled) to keep the segment fresh.
|
||||
func _sweep_bull_gore() -> void:
|
||||
var now := _bull.global_position
|
||||
var seg_from := _bull_prev_pos if _bull_prev_seen else now
|
||||
_bull_prev_pos = now
|
||||
_bull_prev_seen = true
|
||||
if _state == State.RAGDOLL or _state == State.ROLL:
|
||||
return
|
||||
var flat_vel := Vector3(_bull.velocity.x, 0.0, _bull.velocity.z)
|
||||
var bull_speed := flat_vel.length()
|
||||
if bull_speed < DP.f("mat_hit_threshold"):
|
||||
return
|
||||
var a := Vector3(seg_from.x, 0.0, seg_from.z)
|
||||
var b := Vector3(now.x, 0.0, now.z)
|
||||
var p := Vector3(global_position.x, 0.0, global_position.z)
|
||||
var closest := Geometry3D.get_closest_point_to_segment(p, a, b)
|
||||
if p.distance_to(closest) > DP.f("mat_charge_gore_radius"):
|
||||
return
|
||||
if not _horns_first(seg_from):
|
||||
return
|
||||
var hit_dir := flat_vel.normalized() if bull_speed > 0.5 \
|
||||
else (global_position - now).normalized()
|
||||
_take_bull_charge(bull_speed, hit_dir)
|
||||
|
||||
|
||||
# Horns-first gate: gore only when the bull's velocity points within bull_gore_arc of the direction
|
||||
# from `from` to the matador — not a sideways brush or backing in. The dash ability skips the gate.
|
||||
func _horns_first(from: Vector3) -> bool:
|
||||
if _bull == null:
|
||||
return false
|
||||
if _bull.has_method(&"is_dashing") and _bull.call(&"is_dashing"):
|
||||
return true # the dash ability is a committed lunge — it gores on contact, no angle gate
|
||||
var vel := Vector3(_bull.velocity.x, 0.0, _bull.velocity.z)
|
||||
if vel.length() < 0.5:
|
||||
return false
|
||||
var to_me := global_position - from
|
||||
to_me.y = 0.0
|
||||
if to_me.length() < 0.01:
|
||||
return true
|
||||
return vel.normalized().dot(to_me.normalized()) > cos(deg_to_rad(DP.f("bull_gore_arc")))
|
||||
|
||||
|
||||
# Resolve a connected charge: the survival roll fades as bull speed climbs (mat_charge_pierce), so a
|
||||
# committed charge gores rather than getting shrugged off.
|
||||
func _take_bull_charge(bull_speed: float, hit_dir: Vector3) -> void:
|
||||
# The boulder roll bowls matadors over with its own launch + chain (player._roll_try_pop); don't
|
||||
# pre-empt that with a quiet gore, or the ball rolls straight through without popping.
|
||||
if _bull.has_method(&"is_rolling") and _bull.call(&"is_rolling"):
|
||||
return
|
||||
# The dash is a committed lunge — a connect is a guaranteed kill, no survival roll (it already
|
||||
# bypasses the horns cone). A passive cruise-charge still leaves a roll chance that fades with speed.
|
||||
var roll_chance := 0.0
|
||||
if not (_bull.has_method(&"is_dashing") and _bull.call(&"is_dashing")):
|
||||
var floor_spd := DP.f("mat_hit_threshold")
|
||||
var full_spd := maxf(DP.f("mat_charge_speed"), floor_spd + 0.1)
|
||||
var commit := clampf((bull_speed - floor_spd) / (full_spd - floor_spd), 0.0, 1.0)
|
||||
roll_chance = DP.f("mat_roll_chance") * (1.0 - commit * DP.f("mat_charge_pierce"))
|
||||
if randf() < roll_chance:
|
||||
_enter_roll(hit_dir)
|
||||
else:
|
||||
_enter_ragdoll(hit_dir, player.velocity.length())
|
||||
_enter_ragdoll(hit_dir, bull_speed)
|
||||
|
||||
|
||||
func _on_blade_hit(body: Node3D) -> void:
|
||||
if _state != State.ATTACK and _state != State.SIDESTEP and _state != State.BRACE:
|
||||
return
|
||||
if not body.is_in_group(&"player"):
|
||||
return
|
||||
if _blade_hit_cd > 0.0:
|
||||
return
|
||||
_blade_hit_cd = DP.f("mat_stab_cooldown")
|
||||
body.call(&"take_sword_hit", "gored")
|
||||
|
||||
|
||||
# Reach-based stab. A charging bull crosses metres per physics frame, so it easily
|
||||
# tunnels through the thin blade Area between frames — this distance check is the
|
||||
# reliable hit. Called from the offensive ticks (active swing / pass) whenever the
|
||||
# blade is drawn: if the bull is inside reach AND the matador is facing it — the
|
||||
# blade actually presented, not held off to the side — it's gored.
|
||||
# Reach-based hit for the sidestep PASS (fast lateral sweep — the thin blade Area tunnels, so a
|
||||
# distance+facing check is the reliable gore; the ATTACK stab uses the blade collider instead).
|
||||
func _try_melee_hit(reach: float) -> void:
|
||||
if _blade_hit_cd > 0.0 or not _sword_in_hand or _bull == null:
|
||||
return
|
||||
@@ -806,8 +951,6 @@ func _try_melee_hit(reach: float) -> void:
|
||||
var dist := to_bull.length()
|
||||
if dist > reach or dist < 0.01:
|
||||
return
|
||||
# Only lands within the frontal arc — you're gored on a presented blade, not by
|
||||
# brushing a matador whose sword is pointing elsewhere.
|
||||
var facing := Vector3(sin(_mesh.rotation.y), 0.0, cos(_mesh.rotation.y))
|
||||
if facing.dot(to_bull / dist) < cos(deg_to_rad(DP.f("mat_stab_arc"))):
|
||||
return
|
||||
@@ -817,8 +960,8 @@ func _try_melee_hit(reach: float) -> void:
|
||||
|
||||
func _enter_ragdoll(hit_dir: Vector3, bull_speed: float, up_boost: float = 0.0) -> void:
|
||||
_state = State.RAGDOLL
|
||||
if _sword_blade_area:
|
||||
_sword_blade_area.monitoring = false
|
||||
if _sword_blade_area != null:
|
||||
_sword_blade_area.deactivate()
|
||||
_clear_spear() # a spear mid-wind-up dies with the matador, not in the air
|
||||
killed.emit()
|
||||
var cleanup_timer := get_tree().create_timer(4.0)
|
||||
@@ -831,6 +974,7 @@ func _enter_ragdoll(hit_dir: Vector3, bull_speed: float, up_boost: float = 0.0)
|
||||
var throw_dir := (hit_dir + Vector3(0.0, 0.5, 0.0)).normalized()
|
||||
|
||||
_blood_burst.burst(global_position + Vector3(0.0, 0.9, 0.0), hit_dir)
|
||||
Gore.splat(global_position, hit_dir, 0.55)
|
||||
if _death_player:
|
||||
_death_player.pitch_scale = randf_range(0.9, 1.1)
|
||||
_death_player.play()
|
||||
@@ -1011,10 +1155,9 @@ func _pick_wander_target() -> void:
|
||||
|
||||
# ── Sword attachment ──────────────────────────────────────────────────────────
|
||||
|
||||
# The rig (matador_v03) carries two purpose-built bones: weapon_bone (right-hand
|
||||
# grip) and weapon_rest_bone (hip holster). The sword rides in the holster and is
|
||||
# carried to the hand in combat (see _carry_sword); each bone has its own DP-tunable
|
||||
# local offset/rotation (sword_* / sword_rest_*) so the poses seat independently.
|
||||
# The rig (matador_v03) carries two bones: weapon_bone (right-hand grip) and weapon_rest_bone (hip
|
||||
# holster). The sword rides in the holster, carried to the hand in combat (_carry_sword); each bone
|
||||
# has its own DP-tunable offset/rotation (sword_* / sword_rest_*) so the poses seat independently.
|
||||
func _setup_sword() -> void:
|
||||
if not _skeleton:
|
||||
return
|
||||
@@ -1047,28 +1190,15 @@ func _spawn_sword() -> void:
|
||||
_drawing = false
|
||||
_apply_sword_grip()
|
||||
|
||||
# Blade collider along +Z (hilt at origin), tipped from the capsule's default Y.
|
||||
# Only monitors while the sword is in hand (see _carry_sword).
|
||||
var blade_cap := CapsuleShape3D.new()
|
||||
blade_cap.radius = 0.18
|
||||
blade_cap.height = 1.30
|
||||
var blade_cs := CollisionShape3D.new()
|
||||
blade_cs.shape = blade_cap
|
||||
blade_cs.position = Vector3(0.0, 0.0, 0.8)
|
||||
blade_cs.rotation_degrees = Vector3(90.0, 0.0, 0.0)
|
||||
|
||||
_sword_blade_area = Area3D.new()
|
||||
_sword_blade_area.collision_layer = 0
|
||||
_sword_blade_area.collision_mask = 1
|
||||
_sword_blade_area.monitoring = _sword_in_hand
|
||||
_sword_blade_area.add_child(blade_cs)
|
||||
_sword_node.add_child(_sword_blade_area)
|
||||
_sword_blade_area.body_entered.connect(_on_blade_hit)
|
||||
# The blade hitbox (Sword.tscn, hitbox.gd) is armed only during the ATTACK thrust (see
|
||||
# _tick_attack); off while merely carried, so brushing a drawn matador never gores the bull.
|
||||
_sword_blade_area = _sword_node.get_node_or_null("BladeHitbox") as Hitbox
|
||||
if _sword_blade_area != null:
|
||||
_sword_blade_area.deactivate()
|
||||
|
||||
|
||||
# The sword is MELEE-only: drawn while fighting up close (ATTACK) or guarding
|
||||
# (BRACE / SIDESTEP), holstered otherwise. Ranged throws use a spear instead
|
||||
# (see _spawn_spear_in_hand), so THROW keeps the sword holstered.
|
||||
# The sword is MELEE-only: drawn for ATTACK / BRACE / SIDESTEP, holstered otherwise. Ranged throws
|
||||
# use a spear (_spawn_spear_in_hand), so THROW keeps the sword holstered.
|
||||
func _wants_sword_drawn() -> bool:
|
||||
return _state == State.ATTACK \
|
||||
or _state == State.BRACE or _state == State.SIDESTEP
|
||||
@@ -1077,6 +1207,9 @@ func _wants_sword_drawn() -> bool:
|
||||
func _update_sword_carry() -> void:
|
||||
if not is_instance_valid(_sword_node) or _state == State.RAGDOLL:
|
||||
return
|
||||
# The blade collider lives only during the ATTACK thrust; leaving ATTACK disarms it.
|
||||
if _state != State.ATTACK and _sword_blade_area != null:
|
||||
_sword_blade_area.deactivate()
|
||||
if _wants_sword_drawn():
|
||||
if not _sword_in_hand and not _drawing:
|
||||
_begin_draw()
|
||||
@@ -1156,8 +1289,9 @@ func _carry_sword(in_hand: bool) -> void:
|
||||
_sword_in_hand = in_hand
|
||||
_sword_node.reparent(target, false)
|
||||
_apply_sword_grip()
|
||||
if _sword_blade_area:
|
||||
_sword_blade_area.monitoring = in_hand
|
||||
# Carrying never arms the blade — only the ATTACK thrust does (see _tick_attack).
|
||||
if _sword_blade_area != null:
|
||||
_sword_blade_area.deactivate()
|
||||
|
||||
|
||||
func _apply_sword_grip() -> void:
|
||||
|
||||
+10
-3
@@ -4,6 +4,8 @@ extends RefCounted
|
||||
## limited swing/twist (DP-tunable) so the corpse keeps its silhouette instead of
|
||||
## folding into a flat "deflated" pile; the cape stays free (PIN) so it drapes.
|
||||
|
||||
const PhysicsLayers = preload("res://physics_layers.gd")
|
||||
|
||||
# [bone, radius] → sphere collider; [bone, radius, height] → capsule.
|
||||
const _BONES: Array = [
|
||||
["matador", 0.18],
|
||||
@@ -53,10 +55,15 @@ static func build(skeleton: Skeleton3D) -> PhysicalBoneSimulator3D:
|
||||
pb.bone_name = bname
|
||||
pb.mass = 0.4
|
||||
pb.linear_damp = 0.1
|
||||
pb.collision_layer = 1
|
||||
pb.collision_mask = 1
|
||||
# The ragdoll only simulates once the matador is dead, so it lives on the CORPSE
|
||||
# layer and masks to CORPSE alone: it rests on the ground/walls (which also carry
|
||||
# CORPSE) but the bull — which collides only with WORLD — passes straight through
|
||||
# the bodies instead of tripping over them.
|
||||
pb.collision_layer = PhysicsLayers.CORPSE
|
||||
pb.collision_mask = PhysicsLayers.CORPSE
|
||||
if bname.begins_with("Bone"):
|
||||
# Cape: floppy cloth — free swing, light, draggy, one-way collision.
|
||||
# Cape: floppy cloth — free swing, light, draggy, one-way collision (layer 0
|
||||
# so nothing collides with it; it still drapes on the CORPSE-masked ground).
|
||||
pb.joint_type = PhysicalBone3D.JOINT_TYPE_PIN
|
||||
pb.mass = 0.15
|
||||
pb.linear_damp = 0.5
|
||||
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
extends CanvasLayer
|
||||
## Mobile-only health readouts (instanced by hud.gd only when Controls.use_touch_ui()).
|
||||
## The desktop HUD's bull pips are tiny and, on a phone, the on-screen thumb cluster crowds
|
||||
## the bottom edge — so on touch we hide that cluster (hud.gd) and paint health up top where
|
||||
## it's clear of the joystick and abilities:
|
||||
## • bull health — a big pip row, top-left
|
||||
## • boss health — a wide Souls-style bar, top-centre, shown only while a bear is alive
|
||||
##
|
||||
## Everything is drawn in one IGNORE-filtered Control (never eats a touch), same immediate-mode
|
||||
## approach as touch_controls.gd. Cached values are refreshed from each character's
|
||||
## health_changed signal; the bear is discovered by group (&"bear") because it spawns after the
|
||||
## HUD, and a level swap frees it so we re-acquire the next one.
|
||||
|
||||
const _HP_FULL: Color = Color(0.82, 0.16, 0.12)
|
||||
const _HP_BONUS: Color = Color(1.00, 0.84, 0.18)
|
||||
const _SOCKET: Color = Color(0.05, 0.02, 0.02, 0.92)
|
||||
const _PANEL_BG: Color = Color(0.06, 0.04, 0.02, 0.82)
|
||||
|
||||
const _PIP_W: float = 42.0
|
||||
const _PIP_H: float = 28.0
|
||||
const _PIP_GAP: float = 7.0
|
||||
|
||||
var _surface: Control
|
||||
|
||||
var _player: Node = null
|
||||
var _bull_cur: int = 0
|
||||
var _bull_max: int = 0
|
||||
var _bull_bonus: int = 0
|
||||
|
||||
var _boss: Node = null
|
||||
var _boss_alive: bool = false
|
||||
var _boss_cur: int = 0
|
||||
var _boss_max: int = 1
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
layer = 9 # below touch UI (10) and the HUD/game-over (11) so the outcome screen covers it
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
|
||||
_surface = Control.new()
|
||||
_surface.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
_surface.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_surface.draw.connect(_draw_surface)
|
||||
add_child(_surface)
|
||||
|
||||
get_viewport().size_changed.connect(_surface.queue_redraw)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if not Controls.use_touch_ui():
|
||||
return
|
||||
|
||||
if _player == null:
|
||||
var players := get_tree().get_nodes_in_group(&"player")
|
||||
if not players.is_empty():
|
||||
_player = players[0]
|
||||
_player.health_changed.connect(_on_bull_health)
|
||||
_on_bull_health(_player.call(&"get_hp"), _player.call(&"get_max_hp"))
|
||||
|
||||
# A level swap frees the old bear; drop the stale ref so the next level's bear is picked up.
|
||||
if _boss != null and not is_instance_valid(_boss):
|
||||
_boss = null
|
||||
_boss_alive = false
|
||||
_surface.queue_redraw()
|
||||
if _boss == null:
|
||||
var bears := get_tree().get_nodes_in_group(&"bear")
|
||||
if not bears.is_empty():
|
||||
_boss = bears[0]
|
||||
_boss_alive = true
|
||||
_boss.health_changed.connect(_on_boss_health)
|
||||
if _boss.has_signal(&"killed"):
|
||||
_boss.killed.connect(_on_boss_killed)
|
||||
_boss_cur = int(_boss.call(&"get_hp"))
|
||||
_boss_max = maxi(_boss_cur, int(DP.f("bear_max_hp")))
|
||||
_surface.queue_redraw()
|
||||
|
||||
|
||||
func _on_bull_health(current: int, max_hp: int) -> void:
|
||||
_bull_cur = maxi(current, 0)
|
||||
_bull_max = maxi(max_hp, 0)
|
||||
_bull_bonus = 0
|
||||
if _player != null and _player.has_method(&"get_bonus_hp"):
|
||||
_bull_bonus = int(_player.call(&"get_bonus_hp"))
|
||||
_surface.queue_redraw()
|
||||
|
||||
|
||||
func _on_boss_health(current: int, max_hp: int) -> void:
|
||||
_boss_cur = maxi(current, 0)
|
||||
_boss_max = maxi(max_hp, maxi(_boss_cur, 1))
|
||||
if _boss_cur <= 0:
|
||||
_boss_alive = false
|
||||
_surface.queue_redraw()
|
||||
|
||||
|
||||
func _on_boss_killed() -> void:
|
||||
_boss_alive = false
|
||||
_surface.queue_redraw()
|
||||
|
||||
|
||||
# ── Drawing ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
func _draw_surface() -> void:
|
||||
if not Controls.use_touch_ui():
|
||||
return
|
||||
var boss_showing := _boss != null and is_instance_valid(_boss) and _boss_alive and _boss_cur > 0
|
||||
# The boss bar is centred at the very top; the bull pip row is top-left. On a narrow landscape
|
||||
# phone a long pip row reaches the centre and collides with the boss bar, so when the bar is up
|
||||
# the bull row drops to a second line just beneath it (guaranteed clear, whatever the HP count).
|
||||
var bull_top := 22.0
|
||||
if boss_showing:
|
||||
bull_top = _draw_boss_bar() + 12.0
|
||||
_draw_bull_health(bull_top)
|
||||
|
||||
|
||||
# Big pip row in the top-left. Bonus pips (barrel reward) sit at the high end and light gold,
|
||||
# matching the desktop HUD; base pips light red; spent pips read as dark sockets.
|
||||
func _draw_bull_health(top: float) -> void:
|
||||
var font := UiFonts.body()
|
||||
var x := 24.0
|
||||
var y := top
|
||||
if font != null:
|
||||
var label := "BULL"
|
||||
var fs := 20
|
||||
_surface.draw_string(
|
||||
font, Vector2(x, y + _PIP_H * 0.85), label, HORIZONTAL_ALIGNMENT_LEFT, -1, fs,
|
||||
UiTheme.GOLD)
|
||||
x += font.get_string_size(label, HORIZONTAL_ALIGNMENT_LEFT, -1, fs).x + 12.0
|
||||
|
||||
var base_max := _bull_max - _bull_bonus
|
||||
for i: int in _bull_max:
|
||||
var r := Rect2(x + i * (_PIP_W + _PIP_GAP), y, _PIP_W, _PIP_H)
|
||||
_surface.draw_rect(r, _SOCKET)
|
||||
if i < _bull_cur:
|
||||
var c := _HP_BONUS if i >= base_max else _HP_FULL
|
||||
_surface.draw_rect(r.grow(-2.0), c)
|
||||
_surface.draw_rect(r, Color(UiTheme.GOLD.r, UiTheme.GOLD.g, UiTheme.GOLD.b, 0.45), false, 2.0)
|
||||
|
||||
|
||||
# Wide boss bar centred at the top: dark trough, red fill scaled to remaining HP, gold trim,
|
||||
# name centred above it. Returns the bar's bottom Y so the bull pip row can sit clear beneath it.
|
||||
func _draw_boss_bar() -> float:
|
||||
var vp := get_viewport().get_visible_rect().size
|
||||
var bw := clampf(vp.x * 0.55, 280.0, 620.0)
|
||||
var bh := 30.0
|
||||
var bx := (vp.x - bw) * 0.5
|
||||
var by := 20.0
|
||||
var bar := Rect2(bx, by, bw, bh)
|
||||
|
||||
_surface.draw_rect(bar, _PANEL_BG)
|
||||
var frac := clampf(float(_boss_cur) / float(_boss_max), 0.0, 1.0)
|
||||
var fill := bar.grow(-3.0)
|
||||
fill.size.x *= frac
|
||||
_surface.draw_rect(fill, _HP_FULL)
|
||||
_surface.draw_rect(bar, UiTheme.BORDER, false, 2.0)
|
||||
|
||||
var font := UiFonts.body()
|
||||
if font != null:
|
||||
var boss_name := "BEAR"
|
||||
var fs := 20
|
||||
var tw := font.get_string_size(boss_name, HORIZONTAL_ALIGNMENT_LEFT, -1, fs)
|
||||
_surface.draw_string(
|
||||
font, Vector2(bx + (bw - tw.x) * 0.5, by - 6.0), boss_name,
|
||||
HORIZONTAL_ALIGNMENT_LEFT, -1, fs, UiTheme.GOLD)
|
||||
return by + bh
|
||||
@@ -0,0 +1 @@
|
||||
uid://p8cqggisskor
|
||||
@@ -0,0 +1,11 @@
|
||||
## Central registry of the 3D physics collision-layer bits. These mirror the
|
||||
## layer_names in project.godot so the editor's layer picker reads the same words.
|
||||
##
|
||||
## The bull only collides with WORLD, so a killed matador is lifted off WORLD onto
|
||||
## CORPSE alone (see matador_ragdoll.gd). The ground and walls carry WORLD | CORPSE
|
||||
## (tagged at level load in game_shell.gd), so the ragdoll still rests on the arena
|
||||
## while the bull passes through the bodies instead of tripping over them.
|
||||
|
||||
const WORLD: int = 1 # layer 1 — environment + live actors (bull, matadors, spears)
|
||||
const BULL: int = 2 # layer 2 — the bull's own body
|
||||
const CORPSE: int = 4 # layer 3 — ragdolled matadors; ground/walls also carry this
|
||||
@@ -0,0 +1 @@
|
||||
uid://d01o2ul83waw5
|
||||
@@ -28,6 +28,11 @@ var _was_on_floor: bool = false
|
||||
var _pre_slide_vel_y: float = 0.0
|
||||
|
||||
var _slam_ring_mesh: ArrayMesh = null
|
||||
# Attack-FX resources are identical every swing, so build them once and reuse. Recreating a fresh
|
||||
# StandardMaterial3D / SphereMesh per attack makes a mobile WebGL driver recompile the shader and
|
||||
# re-upload the mesh each time — a main-thread hitch "when attacking" that never shows on desktop.
|
||||
var _unshaded_mat: StandardMaterial3D = null
|
||||
var _particle_sphere_cache: Dictionary = {} # "radius:seg:ring" -> SphereMesh (shared)
|
||||
|
||||
# Ability system — kick=0, dash=1, slam=2, roll=3
|
||||
var ability_cd: Array[float] = [0.0, 0.0, 0.0, 0.0]
|
||||
@@ -67,6 +72,9 @@ signal health_changed(current: int, max_hp: int)
|
||||
signal hit_taken(cause: String)
|
||||
var _max_hp: int = 10
|
||||
var _hp: int = 10
|
||||
# Bonus pips granted by lobby rewards (e.g. smashing every barrel). Tacked on top of the
|
||||
# base bar; the HUD paints these top pips yellow instead of red.
|
||||
var _bonus_hp: int = 0
|
||||
var _hit_iframes: float = 0.0
|
||||
|
||||
var _huff_player: AudioStreamPlayer = null
|
||||
@@ -86,13 +94,17 @@ var _hit_flash_tween: Tween
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group(&"player")
|
||||
# Mali/ANGLE mobile GPUs can't run Godot's Compatibility vertex-skinning (transform
|
||||
# feedback) — skinned meshes render invisible on the web build. Rebuild the bull as
|
||||
# non-skinned bone-attached pieces there; desktop keeps smooth GPU skinning.
|
||||
if OS.has_feature("web"):
|
||||
# Native GPU skinning by default (the old Mali/ANGLE invisible-skinning bug is fixed in the
|
||||
# 4.7 web templates). rigid_skin is now an opt-in fallback — see Controls.rigid_skin_enabled().
|
||||
if Controls.rigid_skin_enabled():
|
||||
RigidSkin.convert_tree(self)
|
||||
_max_hp = maxi(1, int(DP.f("bull_max_hp")))
|
||||
_hp = _max_hp
|
||||
# Carry any run-long bonus pips (barrel reward) into this level so they survive the
|
||||
# scene reload between fights; the HUD paints these top pips yellow.
|
||||
_bonus_hp = Run.bonus_hp
|
||||
_max_hp += _bonus_hp
|
||||
_hp += _bonus_hp
|
||||
_cube_scale = cube_guy.scale
|
||||
_setup_hoof_dust()
|
||||
_setup_legs()
|
||||
@@ -511,6 +523,7 @@ func _tick_roll(delta: float, _steer: Vector3) -> void:
|
||||
|
||||
move_and_slide()
|
||||
_was_on_floor = is_on_floor()
|
||||
_smash_barrels_in_radius(DP.f("roll_hit_radius"))
|
||||
_roll_try_pop(speed)
|
||||
|
||||
|
||||
@@ -549,22 +562,37 @@ func _roll_try_pop(speed: float) -> bool:
|
||||
return false
|
||||
|
||||
|
||||
# Closest active matador we haven't already popped this roll, or null if none left.
|
||||
# Closest thing the roll should home on — an active matador (arena) or an intact barrel
|
||||
# (lobby) we haven't already smashed this roll. Null if nothing is left to hit.
|
||||
func _roll_pick_target() -> Node3D:
|
||||
var best: Node3D = null
|
||||
var best_d := INF
|
||||
for mat: Node in get_tree().get_nodes_in_group(&"matador"):
|
||||
if _roll_hit.has(mat) or not _mat_active(mat):
|
||||
continue
|
||||
var d: float = (mat as Node3D).global_position.distance_squared_to(global_position)
|
||||
for cand: Node3D in _roll_targets():
|
||||
var d: float = cand.global_position.distance_squared_to(global_position)
|
||||
if d < best_d:
|
||||
best_d = d
|
||||
best = mat as Node3D
|
||||
best = cand
|
||||
return best
|
||||
|
||||
|
||||
# Live roll targets: active matadors plus standing barrels, minus anything already popped.
|
||||
func _roll_targets() -> Array[Node3D]:
|
||||
var out: Array[Node3D] = []
|
||||
for mat: Node in get_tree().get_nodes_in_group(&"matador"):
|
||||
if not _roll_hit.has(mat) and _mat_active(mat):
|
||||
out.append(mat as Node3D)
|
||||
for barrel: Node in get_tree().get_nodes_in_group(&"barrel"):
|
||||
if _barrel_alive(barrel):
|
||||
out.append(barrel as Node3D)
|
||||
return out
|
||||
|
||||
|
||||
func _roll_target_valid() -> bool:
|
||||
return is_instance_valid(_roll_target) and _mat_active(_roll_target)
|
||||
if not is_instance_valid(_roll_target):
|
||||
return false
|
||||
if _roll_target.is_in_group(&"barrel"):
|
||||
return _barrel_alive(_roll_target)
|
||||
return _mat_active(_roll_target)
|
||||
|
||||
|
||||
# A matador still in play — valid, not ragdolled/consumed. Ragdolled bodies report
|
||||
@@ -573,8 +601,39 @@ func _mat_active(mat: Node) -> bool:
|
||||
return is_instance_valid(mat) and mat.has_method(&"is_active") and mat.call(&"is_active")
|
||||
|
||||
|
||||
# End the Powerball early: brake hard (the ball "pops" and unrolls) and drop back to
|
||||
# the normal locomotion path next frame.
|
||||
# A lobby barrel still standing — valid and not already queued for removal by an earlier hit.
|
||||
func _barrel_alive(barrel: Node) -> bool:
|
||||
return is_instance_valid(barrel) and not barrel.is_queued_for_deletion()
|
||||
|
||||
|
||||
# Burst every barrel whose centre sits within range_m on the ground plane. Shared by the
|
||||
# boulder roll (which ploughs straight through them) and the slam shockwave. Each barrel
|
||||
# self-removes and leaves the &"barrel" group, so the HUD's clear-the-lobby tally counts it
|
||||
# exactly once.
|
||||
func _smash_barrels_in_radius(range_m: float) -> void:
|
||||
for barrel: Node in get_tree().get_nodes_in_group(&"barrel"):
|
||||
if not _barrel_alive(barrel):
|
||||
continue
|
||||
var to_b: Vector3 = (barrel as Node3D).global_position - global_position
|
||||
to_b.y = 0.0
|
||||
if to_b.length() <= range_m:
|
||||
barrel.call(&"destroy_barrel")
|
||||
|
||||
|
||||
# True while the boulder roll is live — matadors defer their charge-gore to the roll's own pop
|
||||
# (is_rolling guard in matador._take_bull_charge) so the ball pops instead of quietly goring.
|
||||
func is_rolling() -> bool:
|
||||
return _active_ability == 3 and _ability_active
|
||||
|
||||
|
||||
# True while the dash ability is live. A dash is a committed lunge — it gores/rams on contact
|
||||
# regardless of angle (enemies bypass their horns-first cone while it's set).
|
||||
func is_dashing() -> bool:
|
||||
return _active_ability == 1 and _ability_active
|
||||
|
||||
|
||||
# End the Powerball early: brake hard (the ball "pops" and unrolls) and drop back to the normal
|
||||
# locomotion path next frame.
|
||||
func _end_roll() -> void:
|
||||
_ability_active = false
|
||||
_active_ability = -1
|
||||
@@ -626,23 +685,33 @@ func _hit_matadors_radius(range_m: float, strength: float, up_boost: float = 0.0
|
||||
# All FX in this script use unshaded, vertex-coloured, alpha-blended particles;
|
||||
# these three helpers remove the boilerplate each spawn function used to repeat.
|
||||
|
||||
# One shared unshaded material for every particle FX (per-particle colour comes from the
|
||||
# CPUParticles3D colour_ramp via vertex colour, not the material) — built once so the mobile
|
||||
# driver compiles this shader a single time instead of on every attack.
|
||||
func _unshaded_material() -> StandardMaterial3D:
|
||||
var mat := StandardMaterial3D.new()
|
||||
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||
mat.vertex_color_use_as_albedo = true
|
||||
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||
return mat
|
||||
if _unshaded_mat == null:
|
||||
_unshaded_mat = StandardMaterial3D.new()
|
||||
_unshaded_mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||
_unshaded_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||
_unshaded_mat.vertex_color_use_as_albedo = true
|
||||
_unshaded_mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||
return _unshaded_mat
|
||||
|
||||
|
||||
# Low-poly sphere sized for a particle mesh (height is always the diameter).
|
||||
# Low-poly sphere sized for a particle mesh (height is always the diameter). Cached per size so
|
||||
# repeat attacks reuse the same mesh (one GPU upload) instead of generating + uploading a new one.
|
||||
func _particle_sphere(radius: float, segments: int, rings: int, mat: Material) -> SphereMesh:
|
||||
var key := "%.4f:%d:%d" % [radius, segments, rings]
|
||||
var cached: SphereMesh = _particle_sphere_cache.get(key)
|
||||
if cached != null:
|
||||
return cached
|
||||
var sphere := SphereMesh.new()
|
||||
sphere.radius = radius
|
||||
sphere.height = radius * 2.0
|
||||
sphere.radial_segments = segments
|
||||
sphere.rings = rings
|
||||
sphere.material = mat
|
||||
_particle_sphere_cache[key] = sphere
|
||||
return sphere
|
||||
|
||||
|
||||
@@ -1019,13 +1088,15 @@ func _physics_process(delta: float) -> void:
|
||||
cube_guy.rotation.y = lerp_angle(
|
||||
cube_guy.rotation.y, target_angle, delta * DP.f("visual_turn_speed"))
|
||||
|
||||
# Looping DASH clip while genuinely moving on the ground, idle otherwise.
|
||||
# Looping WALK clip while genuinely moving on the ground, idle otherwise.
|
||||
_update_locomotion_anim(on_floor and flat_speed > 1.0)
|
||||
|
||||
_pre_slide_vel_y = velocity.y
|
||||
var pre_wall_vel := Vector3(velocity.x, 0.0, velocity.z)
|
||||
move_and_slide()
|
||||
|
||||
|
||||
|
||||
# ── Wall bounce — no sliding, guaranteed exit ────────────────────────────
|
||||
# pre_wall_vel is captured before move_and_slide strips the into-wall component,
|
||||
# so into_spd correctly reflects how hard the bull hit the wall even when stationary.
|
||||
@@ -1041,6 +1112,16 @@ func _physics_process(delta: float) -> void:
|
||||
velocity.z = flat_n.z * exit_spd
|
||||
pre_wall_vel = Vector3(velocity.x, 0.0, velocity.z)
|
||||
|
||||
# --- ADD THIS BREAKABLE BARREL DETECTION CODE ---
|
||||
var collision = get_slide_collision(i)
|
||||
var collider = collision.get_collider()
|
||||
|
||||
# Check if the object we hit has the "destroy_barrel" function
|
||||
if collider and collider.has_method("destroy_barrel"):
|
||||
# Optional: Only break if moving fast (e.g., sprinting or dashing)
|
||||
# if velocity.length() > 5.0:
|
||||
collider.destroy_barrel()
|
||||
|
||||
# ── Landing. Don't bounce ─────────────────────────────────────────────────────
|
||||
if is_on_floor() and not _was_on_floor:
|
||||
velocity.y = 0.0
|
||||
@@ -1060,6 +1141,7 @@ func _physics_process(delta: float) -> void:
|
||||
_play_idle()
|
||||
_spawn_slam_fx()
|
||||
_hit_matadors_radius(DP.f("slam_range"), DP.f("slam_strength"), DP.f("slam_launch_up"))
|
||||
_smash_barrels_in_radius(DP.f("slam_range"))
|
||||
|
||||
# ── Dust ──────────────────────────────────────────────────────────────────
|
||||
if flat_speed > DP.f("dust_charge_spd") and on_floor:
|
||||
@@ -1086,6 +1168,22 @@ func get_max_hp() -> int:
|
||||
return _max_hp
|
||||
|
||||
|
||||
# Bonus pips currently on the bar — the HUD colours this many top pips yellow.
|
||||
func get_bonus_hp() -> int:
|
||||
return _bonus_hp
|
||||
|
||||
|
||||
# Award extra health (from a lobby reward): grows both the cap and the current bar so the
|
||||
# new pips arrive full, and marks them as bonus so the HUD paints them yellow.
|
||||
func grant_bonus_hp(amount: int) -> void:
|
||||
if amount <= 0:
|
||||
return
|
||||
_bonus_hp += amount
|
||||
_max_hp += amount
|
||||
_hp += amount
|
||||
health_changed.emit(_hp, _max_hp)
|
||||
|
||||
|
||||
# A clean hit — thrown or swung blade — costs the bull one HP pip; the run ends only
|
||||
# when the last pip is gone. `cause` ("gored" / "thrown") tags how it happened for the
|
||||
# death notice. I-frames absorb a flurry so several blades in one pass drop one pip,
|
||||
@@ -1099,10 +1197,17 @@ func take_sword_hit(cause: String = "", hit_pos: Vector3 = Vector3.ZERO) -> void
|
||||
health_changed.emit(_hp, _max_hp)
|
||||
hit_taken.emit(cause)
|
||||
camera_pivot.call(&"trigger_hit", 0.7)
|
||||
# Vibrate controller 0 with half weak strength, full strong strength, for 0.5 seconds
|
||||
if DP.b("gamepad_vibration"):
|
||||
Input.start_joy_vibration(0, 0.5, 1, 0.2)
|
||||
|
||||
# A spear gores a spot — blood spurts from the entry wound (where it struck the
|
||||
# bull). Melee gores pass no position and skip the spurt; gore can be turned off.
|
||||
if cause == "thrown" and Settings.gore:
|
||||
_spawn_blood(hit_pos if hit_pos != Vector3.ZERO else global_position)
|
||||
# Any hit — melee or thrown — leaves a lasting stain on the ground the bull bled on.
|
||||
var splat_dir := global_position - hit_pos if hit_pos != Vector3.ZERO else Vector3.ZERO
|
||||
Gore.splat(global_position, splat_dir, 0.5)
|
||||
if _huff_player:
|
||||
_huff_player.pitch_scale = randf_range(0.7, 0.9)
|
||||
_huff_player.play()
|
||||
@@ -1114,6 +1219,12 @@ func take_sword_hit(cause: String = "", hit_pos: Vector3 = Vector3.ZERO) -> void
|
||||
died.emit(cause)
|
||||
|
||||
|
||||
# Pop the bull upward — a smash hitbox knocks it off its feet. Only ever raises the
|
||||
# vertical speed so a downward-moving bull still gets launched.
|
||||
func apply_knock_up(v: float) -> void:
|
||||
velocity.y = maxf(velocity.y, v)
|
||||
|
||||
|
||||
# Blood spurt from a spear wound: a short-lived spray of dark-red gobs flung out of the
|
||||
# entry point, biased outward from the bull's centre (so it reads as bursting from the
|
||||
# hide) with a touch of lift before gravity drags it down.
|
||||
|
||||
+12
-2
@@ -11,8 +11,8 @@ config_version=5
|
||||
[application]
|
||||
|
||||
config/name="Bullosseum"
|
||||
config/version="0.2.0"
|
||||
run/main_scene="res://MainMenu.tscn"
|
||||
config/version="0.4.0"
|
||||
run/main_scene="uid://bmnmenu0intr1"
|
||||
config/features=PackedStringArray("4.7", "GL Compatibility")
|
||||
boot_splash/bg_color=Color(0, 0, 0, 1)
|
||||
boot_splash/image="res://Assets/loading_screen.png"
|
||||
@@ -28,6 +28,8 @@ DebugDraw="*res://debug_draw.gd"
|
||||
Settings="*res://settings.gd"
|
||||
Run="*res://levels/run_state.gd"
|
||||
OrientationGuard="*res://orientation_guard.gd"
|
||||
WebStartGate="*res://web_start_gate.gd"
|
||||
Gore="*res://gore.gd"
|
||||
|
||||
[display]
|
||||
|
||||
@@ -118,6 +120,13 @@ ability_roll={
|
||||
|
||||
pointing/emulate_touch_from_mouse=true
|
||||
|
||||
[layer_names]
|
||||
|
||||
3d_physics/layer_1="world"
|
||||
3d_physics/layer_2="bull"
|
||||
3d_physics/layer_3="corpse"
|
||||
3d_physics/layer_4="bear_FX"
|
||||
|
||||
[physics]
|
||||
|
||||
3d/physics_engine="Jolt Physics"
|
||||
@@ -128,3 +137,4 @@ rendering_device/driver.windows="opengl3"
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
textures/vram_compression/import_s3tc_bptc=true
|
||||
textures/vram_compression/import_etc2_astc=true
|
||||
environment/defaults/default_clear_color=Color(0, 0, 0, 1)
|
||||
|
||||
+40
-17
@@ -43,9 +43,11 @@ static func _convert(skel: Skeleton3D, mi: MeshInstance3D) -> bool:
|
||||
bind_bone.append(bone)
|
||||
bind_pose.append(skin.get_bind_pose(b))
|
||||
|
||||
# Accumulate SurfaceTool geometry per destination bone.
|
||||
var st_by_bone: Dictionary = {} # bone index -> SurfaceTool
|
||||
var mat_by_bone: Dictionary = {} # bone index -> Material (first seen)
|
||||
# Accumulate SurfaceTool geometry per (destination bone, source surface). Keying on the
|
||||
# surface too — not just the bone — is what preserves materials: a head bone that carries
|
||||
# both the skin and hair surfaces must stay two pieces with two materials, otherwise every
|
||||
# surface funnelled to a bone collapses onto one material (bald matadors, wrong uniforms).
|
||||
var groups: Dictionary = {} # "bone:surface" -> {"st": SurfaceTool, "mat": Material, "bone": int}
|
||||
|
||||
for s: int in mesh.get_surface_count():
|
||||
var arr := mesh.surface_get_arrays(s)
|
||||
@@ -56,7 +58,13 @@ static func _convert(skel: Skeleton3D, mi: MeshInstance3D) -> bool:
|
||||
var bones: PackedInt32Array = arr[Mesh.ARRAY_BONES]
|
||||
var weights: PackedFloat32Array = arr[Mesh.ARRAY_WEIGHTS]
|
||||
var idx: PackedInt32Array = arr[Mesh.ARRAY_INDEX]
|
||||
var mat := mesh.surface_get_material(s)
|
||||
# Honour a per-instance override (whole mesh) or per-surface override the scene set,
|
||||
# falling back to the material baked into the mesh surface.
|
||||
var mat: Material = mi.material_override
|
||||
if mat == null:
|
||||
mat = mi.get_surface_override_material(s)
|
||||
if mat == null:
|
||||
mat = mesh.surface_get_material(s)
|
||||
var infl := 8 if (mesh.surface_get_format(s) & Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS) else 4
|
||||
|
||||
var tri := PackedInt32Array()
|
||||
@@ -74,12 +82,14 @@ static func _convert(skel: Skeleton3D, mi: MeshInstance3D) -> bool:
|
||||
var bind := _dominant_bind([a, b, c], bones, weights, infl)
|
||||
var bone := bind_bone[bind]
|
||||
var pose := bind_pose[bind]
|
||||
var st: SurfaceTool = st_by_bone.get(bone)
|
||||
if st == null:
|
||||
st = SurfaceTool.new()
|
||||
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
st_by_bone[bone] = st
|
||||
mat_by_bone[bone] = mat
|
||||
var key := "%d:%d" % [bone, s]
|
||||
var group: Dictionary = groups.get(key, {})
|
||||
if group.is_empty():
|
||||
var new_st := SurfaceTool.new()
|
||||
new_st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
group = {"st": new_st, "mat": mat, "bone": bone}
|
||||
groups[key] = group
|
||||
var st: SurfaceTool = group["st"]
|
||||
for v: int in [a, b, c]:
|
||||
if cols.size() > v:
|
||||
st.set_color(cols[v])
|
||||
@@ -89,19 +99,32 @@ static func _convert(skel: Skeleton3D, mi: MeshInstance3D) -> bool:
|
||||
st.set_normal((pose.basis * norms[v]).normalized())
|
||||
st.add_vertex(pose * verts[v])
|
||||
|
||||
if st_by_bone.is_empty():
|
||||
if groups.is_empty():
|
||||
return false
|
||||
|
||||
for bone: int in st_by_bone:
|
||||
# Combine all of a bone's surface-groups into ONE mesh under ONE BoneAttachment (each group
|
||||
# stays its own surface + material). Same draw calls as before, but roughly half the nodes to
|
||||
# transform/cull every frame — which is what a phone feels while ragdolls drive the skeleton.
|
||||
var by_bone: Dictionary = {} # bone:int -> Array[Dictionary]
|
||||
for key: String in groups:
|
||||
var group: Dictionary = groups[key]
|
||||
var bone: int = group["bone"]
|
||||
if not by_bone.has(bone):
|
||||
by_bone[bone] = []
|
||||
(by_bone[bone] as Array).append(group)
|
||||
|
||||
for bone: int in by_bone:
|
||||
var att := BoneAttachment3D.new()
|
||||
att.bone_name = skel.get_bone_name(bone)
|
||||
skel.add_child(att)
|
||||
var piece := MeshInstance3D.new()
|
||||
var st: SurfaceTool = st_by_bone[bone]
|
||||
var m := st.commit()
|
||||
if mat_by_bone[bone] != null:
|
||||
m.surface_set_material(0, mat_by_bone[bone])
|
||||
piece.mesh = m
|
||||
var combined := ArrayMesh.new()
|
||||
for group: Dictionary in by_bone[bone]:
|
||||
var st: SurfaceTool = group["st"]
|
||||
st.commit(combined)
|
||||
if group["mat"] != null:
|
||||
combined.surface_set_material(combined.get_surface_count() - 1, group["mat"])
|
||||
piece.mesh = combined
|
||||
att.add_child(piece)
|
||||
|
||||
# Hide (don't free) the original: keeps the node for any gameplay code that references
|
||||
|
||||
@@ -22,10 +22,26 @@ echo ""
|
||||
echo "=== Level switch tests (no cross-level geometry/collider leaks) ==="
|
||||
"$GODOT" --headless --script tests/level_switch_test.gd
|
||||
|
||||
echo ""
|
||||
echo "=== Touch control tests (joystick self-heals, never strands) ==="
|
||||
"$GODOT" --headless --script tests/touch_controls_test.gd
|
||||
|
||||
echo ""
|
||||
echo "=== Blood decal tests (floor+wall stamps, ring-buffer cap, gore gate) ==="
|
||||
"$GODOT" --headless --script tests/blood_decals_test.gd
|
||||
|
||||
echo ""
|
||||
echo "=== Rigid-skin tests (web mesh conversion keeps all materials) ==="
|
||||
"$GODOT" --headless --script tests/rigid_skin_test.gd
|
||||
|
||||
echo ""
|
||||
echo "=== Performance tests (frame-budget regression guard) ==="
|
||||
"$GODOT" --headless --script tests/performance_test.gd
|
||||
|
||||
echo ""
|
||||
echo "=== Ragdoll perf (on-hit spike breakdown: build / sim-start / burst / mass hit) ==="
|
||||
"$GODOT" --headless --script tests/ragdoll_perf_test.gd
|
||||
|
||||
if [[ "$SKIP_GAMEPLAY" -eq 0 ]]; then
|
||||
echo ""
|
||||
echo "=== Gameplay tests (headless — assertions only, screenshots may be blank) ==="
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ script = ExtResource("13_shell")
|
||||
[node name="Player" parent="." unique_id=332720469 instance=ExtResource("1_ulcgi")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.2416196, 5.1711025, -4.841382)
|
||||
|
||||
[node name="Camera3D" parent="Player" index="3" unique_id=1120161087]
|
||||
[node name="Camera3D" parent="Player" index="1" unique_id=1120161087]
|
||||
attributes = SubResource("CameraAttributesPractical_73fnb")
|
||||
fov = 50.0
|
||||
near = 2.636
|
||||
|
||||
+25
-2
@@ -10,6 +10,8 @@ extends RigidBody3D
|
||||
# (see shed_all, which the bull's slam calls to fling them all off); other hits pin
|
||||
# it in place until the despawn timer clears it.
|
||||
|
||||
const PhysicsLayers = preload("res://physics_layers.gd")
|
||||
|
||||
const _DESPAWN_SEC: float = 8.0
|
||||
const _STUCK_GROUP: StringName = &"stuck_spear"
|
||||
# Shaft geometry in spear.glb local space: tip at +Z, butt behind the origin.
|
||||
@@ -34,16 +36,25 @@ static func launch(parent: Node, mesh: Node3D, origin: Vector3, velocity: Vector
|
||||
var s := SpearProjectile.new()
|
||||
s.gravity_scale = gravity
|
||||
s.collision_layer = 0
|
||||
s.collision_mask = 1
|
||||
# Mask WORLD so a miss sticks in the arena, and BULL so it can actually hit the
|
||||
# bull — the bull's body is on layer BULL, not WORLD, so a WORLD-only mask flew
|
||||
# straight through it (every throw whiffed, even against a stationary bull).
|
||||
s.collision_mask = PhysicsLayers.WORLD | PhysicsLayers.BULL
|
||||
s.contact_monitor = true
|
||||
s.max_contacts_reported = 6
|
||||
parent.add_child(s)
|
||||
# Seat the body so its local +Z (the shaft, see spear.glb) points along the throw.
|
||||
s.global_transform = Transform3D(_aim_basis(velocity), origin)
|
||||
# Take the editor-tweakable collider from the spear wrapper (Spear.tscn's HitShape)
|
||||
# before reparenting, then drop the now-nested template.
|
||||
var collider := _collider_from(mesh)
|
||||
mesh.reparent(s, false)
|
||||
mesh.transform = Transform3D.IDENTITY
|
||||
s._mesh = mesh
|
||||
s.add_child(_shaft_collider())
|
||||
var tmpl := mesh.get_node_or_null("HitShape")
|
||||
if tmpl != null:
|
||||
tmpl.queue_free()
|
||||
s.add_child(collider)
|
||||
s.linear_velocity = velocity
|
||||
_despawn(s)
|
||||
return s
|
||||
@@ -84,6 +95,18 @@ static func shed_all(bull: Node) -> void:
|
||||
_despawn(rb)
|
||||
|
||||
|
||||
# Clone the wrapper's editor-tweakable HitShape (Spear.tscn) into a fresh CollisionShape3D
|
||||
# for the projectile body; falls back to the built-in shaft collider if it's missing.
|
||||
static func _collider_from(source: Node) -> CollisionShape3D:
|
||||
var tmpl := source.get_node_or_null("HitShape") as CollisionShape3D
|
||||
if tmpl != null and tmpl.shape != null:
|
||||
var cs := CollisionShape3D.new()
|
||||
cs.shape = tmpl.shape
|
||||
cs.transform = tmpl.transform
|
||||
return cs
|
||||
return _shaft_collider()
|
||||
|
||||
|
||||
static func _shaft_collider() -> CollisionShape3D:
|
||||
# Collider along local +Z (mesh runs z≈-0.34 … 1.92), fattened so a fast throw
|
||||
# can't tunnel past the bull's collision spheres.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
extends CharacterBody3D
|
||||
## Stand-in bull for the combat tests. As a TARGET it records hitbox callbacks (hits / knock-up);
|
||||
## as an ATTACKER it exposes the ability-state interface (is_dashing / is_rolling) the matador and
|
||||
## bear query. Ability flags default off = an ordinary charge.
|
||||
|
||||
var hits: int = 0
|
||||
var knocked_up: float = 0.0
|
||||
var dashing: bool = false
|
||||
var rolling: bool = false
|
||||
|
||||
|
||||
func take_sword_hit(_cause: String = "", _hit_pos: Vector3 = Vector3.ZERO) -> void:
|
||||
hits += 1
|
||||
|
||||
|
||||
func apply_knock_up(v: float) -> void:
|
||||
knocked_up = maxf(knocked_up, v)
|
||||
|
||||
|
||||
func is_dashing() -> bool:
|
||||
return dashing
|
||||
|
||||
|
||||
func is_rolling() -> bool:
|
||||
return rolling
|
||||
@@ -0,0 +1 @@
|
||||
uid://bamw0bnk3bfvs
|
||||
@@ -0,0 +1,98 @@
|
||||
extends SceneTree
|
||||
## Bear attack-FX test. The four attack effects (crater, smash debris, left/right claw slash)
|
||||
## live in Assets/fx/Bear_FX.glb as meshes that rest at scale 0 at Siim's baked positions. The
|
||||
## GLB carries its own AnimationPlayer whose clips scale one mesh up at its strike frame and
|
||||
## back to 0 (self-hiding) while pinning the others at 0. bear.gd fires the matching clip on
|
||||
## each strike (see _play_fx). This asserts each clip pops its own mesh, self-hides by the end,
|
||||
## and never leaves another effect on-screen — so a mis-wired trigger or a broken clip is caught
|
||||
## headlessly. Run: godot --headless --script res://tests/bear_fx_test.gd
|
||||
|
||||
var _pass := 0
|
||||
var _fail := 0
|
||||
var _fx_player: AnimationPlayer = null
|
||||
var _fx: Dictionary = {} # short name -> Node3D
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
|
||||
func _ok(c: bool, m: String) -> void:
|
||||
if c:
|
||||
_pass += 1
|
||||
print(" PASS: ", m)
|
||||
else:
|
||||
_fail += 1
|
||||
print(" FAIL: ", m)
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var bear := (load("res://Bear.tscn") as PackedScene).instantiate()
|
||||
root.add_child(bear)
|
||||
await physics_frame
|
||||
|
||||
var fx_root := bear.find_child("Bear_FX", true, false)
|
||||
_ok(fx_root != null, "Bear_FX instanced in the scene")
|
||||
if fx_root == null:
|
||||
_finish()
|
||||
return
|
||||
_fx_player = fx_root.get_node_or_null("AnimationPlayer") as AnimationPlayer
|
||||
_ok(_fx_player != null, "found the Bear_FX AnimationPlayer")
|
||||
if _fx_player == null:
|
||||
_finish()
|
||||
return
|
||||
|
||||
for n: String in ["jump_smash", "smash_hit", "claw_attack_R", "claw_attack_L"]:
|
||||
_fx[n] = bear.find_child("Bear_fx_" + n, true, false)
|
||||
_ok(_fx[n] != null, "found Bear_fx_" + n)
|
||||
if _fx.values().has(null):
|
||||
_finish()
|
||||
return
|
||||
|
||||
_ok(not _vis("jump_smash") and not _vis("smash_hit")
|
||||
and not _vis("claw_attack_R") and not _vis("claw_attack_L"),
|
||||
"all FX hidden at rest (scale 0)")
|
||||
|
||||
# Each clip pops only its own mesh at the strike, then self-hides, leaving nothing stale.
|
||||
await _check_clip("Bear_fx_claw_attack_L", "claw_attack_L")
|
||||
await _check_clip("Bear_fx_claw_attack_R", "claw_attack_R")
|
||||
await _check_clip("Bear_fx_smash_hit", "smash_hit")
|
||||
await _check_clip("Bear_fx_jump_smash", "jump_smash")
|
||||
|
||||
_finish()
|
||||
|
||||
|
||||
# Play a clip to completion in real process mode (so bear.gd's animation_finished hide runs):
|
||||
# the clip's own mesh scales up somewhere in the middle, every other mesh stays hidden, and the
|
||||
# mesh is back to scale 0 once the clip has finished.
|
||||
func _check_clip(clip: String, owner_key: String) -> void:
|
||||
_fx_player.play(clip)
|
||||
_fx_player.seek(0.0, true)
|
||||
var peak := 0.0
|
||||
var others_clean := true
|
||||
var frames := 0
|
||||
while _fx_player.is_playing() and frames < 600:
|
||||
await process_frame
|
||||
frames += 1
|
||||
peak = maxf(peak, (_fx[owner_key] as Node3D).scale.length())
|
||||
for k: String in _fx.keys():
|
||||
if k != owner_key and _vis(k):
|
||||
others_clean = false
|
||||
# Hide happens on animation_finished (immediately for most, after a linger for the crater),
|
||||
# so poll a bounded window rather than assume it's gone on the very next frame.
|
||||
var settle := 0
|
||||
while _vis(owner_key) and settle < 600:
|
||||
await process_frame
|
||||
settle += 1
|
||||
_ok(peak > 0.05, clip + ": its mesh pops during the clip")
|
||||
_ok(others_clean, clip + ": no other effect shows while it plays")
|
||||
_ok(not _vis(owner_key), clip + ": hidden again after the clip ends")
|
||||
|
||||
|
||||
func _vis(n: String) -> bool:
|
||||
return (_fx[n] as Node3D).scale.length() > 0.05
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
print("Results: %d passed, %d failed" % [_pass, _fail])
|
||||
quit(1 if _fail > 0 else 0)
|
||||
@@ -0,0 +1 @@
|
||||
uid://duyfxhca4np78
|
||||
@@ -0,0 +1,121 @@
|
||||
extends SceneTree
|
||||
## Bear attack-collider test. The colliders + their motion live in BearAttackHitboxes.tscn: the
|
||||
## leap slam is a ground circle (cylinder) whose "leap_slam" clip pops it open; the overhead smash
|
||||
## is a forward box lane whose "smash_travel" clip grows it out from the bear. bear.gd fires the
|
||||
## clip, arms the knock-up shaping, and sweeps while it runs. This asserts: a bull anywhere in the
|
||||
## leap circle is mauled AND launched by default (bear_leap_ring_frac 0), while raising ring_frac
|
||||
## carves a grounded inner zone; the smash lane catches bulls near AND far as the front travels,
|
||||
## throws the further one higher, and spares anything off the lane.
|
||||
## Run: godot --headless --script res://tests/bear_hitbox_test.gd
|
||||
|
||||
var _pass := 0
|
||||
var _fail := 0
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
|
||||
func _ok(c: bool, m: String) -> void:
|
||||
if c:
|
||||
_pass += 1
|
||||
print(" PASS: ", m)
|
||||
else:
|
||||
_fail += 1
|
||||
print(" FAIL: ", m)
|
||||
|
||||
|
||||
func _make_bull(pos: Vector3) -> CharacterBody3D:
|
||||
var b := CharacterBody3D.new()
|
||||
b.collision_layer = 2 # PhysicsLayers.BULL — what the hitboxes mask
|
||||
b.collision_mask = 0
|
||||
b.add_to_group(&"player")
|
||||
b.set_script(load("res://tests/_fake_bull.gd"))
|
||||
var cs := CollisionShape3D.new()
|
||||
var shape := SphereShape3D.new()
|
||||
shape.radius = 0.6
|
||||
cs.shape = shape
|
||||
b.add_child(cs)
|
||||
root.add_child(b)
|
||||
b.global_position = pos
|
||||
return b
|
||||
|
||||
|
||||
# Drive one attack collider clip to completion, sweeping each physics frame like _physics_process.
|
||||
func _drive(bear: Node, fire: String) -> void:
|
||||
bear.call(fire)
|
||||
for i in 60:
|
||||
bear.call("_tick_attack_hitbox")
|
||||
await physics_frame
|
||||
if bear.get("_active_hitbox") == null:
|
||||
break
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var bear := (load("res://Bear.tscn") as PackedScene).instantiate() as Node3D
|
||||
root.add_child(bear)
|
||||
bear.set_physics_process(false) # freeze the AI; we fire the colliders ourselves
|
||||
await physics_frame
|
||||
|
||||
var leap_hb := bear.find_child("LeapSlamHitbox", true, false) as Area3D
|
||||
var smash_hb := bear.find_child("SmashHitbox", true, false) as Area3D
|
||||
_ok(leap_hb != null, "leap slam cylinder hitbox exists (from BearAttackHitboxes.tscn)")
|
||||
_ok(smash_hb != null, "overhead smash lane hitbox exists (from BearAttackHitboxes.tscn)")
|
||||
if leap_hb == null or smash_hb == null:
|
||||
_finish()
|
||||
return
|
||||
|
||||
var dp := root.get_node("/root/DP")
|
||||
var slam_r: float = (leap_hb.get_node("CollisionShape3D").shape as CylinderShape3D).radius
|
||||
var lane: float = (smash_hb.get_node("CollisionShape3D").shape as BoxShape3D).size.z
|
||||
|
||||
# ── Leap slam: by default (bear_leap_ring_frac 0) the bull is launched from ANYWHERE in the
|
||||
# circle — no safe inner spot. Off the circle is still spared.
|
||||
dp.call("set_value", "bear_leap_ring_frac", 0.0)
|
||||
var center := _make_bull(Vector3(0.0, 0.5, 0.0))
|
||||
var midring := _make_bull(Vector3(slam_r * 0.5, 0.5, 0.0))
|
||||
var outside := _make_bull(Vector3(slam_r + 3.0, 0.5, 0.0))
|
||||
await physics_frame
|
||||
await _drive(bear, "_fire_leap_hitbox")
|
||||
_ok(center.hits >= 1 and center.knocked_up > 0.0, "bull at the circle center is mauled AND launched")
|
||||
_ok(midring.hits >= 1 and midring.knocked_up > 0.0, "bull mid-circle is mauled AND launched")
|
||||
_ok(outside.hits == 0, "bull outside the slam radius is spared")
|
||||
center.queue_free()
|
||||
midring.queue_free()
|
||||
outside.queue_free()
|
||||
await physics_frame
|
||||
|
||||
# Raising ring_frac restores a grounded inner zone that only mauls (the slider still works).
|
||||
dp.call("set_value", "bear_leap_ring_frac", 0.75)
|
||||
var frac: float = dp.f("bear_leap_ring_frac")
|
||||
var inner := _make_bull(Vector3(slam_r * (frac * 0.5), 0.5, 0.0))
|
||||
var ring := _make_bull(Vector3(slam_r * (frac + (1.0 - frac) * 0.5), 0.5, 0.0))
|
||||
await physics_frame
|
||||
await _drive(bear, "_fire_leap_hitbox")
|
||||
_ok(inner.hits >= 1 and inner.knocked_up == 0.0, "raised ring_frac keeps the inner circle grounded")
|
||||
_ok(ring.knocked_up > 0.0, "raised ring_frac still launches the outer ring")
|
||||
inner.queue_free()
|
||||
ring.queue_free()
|
||||
dp.call("set_value", "bear_leap_ring_frac", 0.0)
|
||||
await physics_frame
|
||||
|
||||
# ── Overhead smash: the lane's leading edge travels the whole way, so bulls near AND far are
|
||||
# both caught as the front passes; the further one is thrown higher. Off-lane is spared.
|
||||
var near := _make_bull(Vector3(0.0, 0.5, lane * 0.2))
|
||||
var far := _make_bull(Vector3(0.0, 0.5, lane * 0.8))
|
||||
var beside := _make_bull(Vector3(lane * 0.5, 0.5, lane * 0.5))
|
||||
var behind := _make_bull(Vector3(0.0, 0.5, -3.0))
|
||||
await physics_frame
|
||||
await _drive(bear, "_begin_smash_hitbox")
|
||||
_ok(near.hits >= 1, "bull near the bear is caught as the shockwave starts")
|
||||
_ok(far.hits >= 1, "bull far down the lane is caught when the front reaches it")
|
||||
_ok(far.knocked_up > near.knocked_up, "the further hit is thrown higher")
|
||||
_ok(beside.hits == 0, "bull beside the lane is spared (a lane, not a circle)")
|
||||
_ok(behind.hits == 0, "bull behind the bear is spared")
|
||||
|
||||
_finish()
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
print("Results: %d passed, %d failed" % [_pass, _fail])
|
||||
quit(1 if _fail > 0 else 0)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cvweb2dnv23s
|
||||
@@ -0,0 +1,112 @@
|
||||
extends SceneTree
|
||||
## Bear ram test. Running the bull HORNS-FIRST into the bear should wound it. The bear detects this by
|
||||
## sweeping the bull's actual travel (prev → now) against its body each frame (bear._sweep_bull_ram),
|
||||
## gated by speed (bear_hit_threshold), reach (bear_ram_reach) and a horns-first cone (bull_gore_arc),
|
||||
## and edge-triggered so one charge = one wound. This drives passes against a frozen bear and asserts:
|
||||
## a horns-first charge (even one that tunnels / starts close) wounds it once; a charge moving AWAY
|
||||
## (bear behind the horns), a pass out of reach, and a too-slow nudge all leave it unharmed.
|
||||
## Run: godot --headless --script res://tests/bear_ram_test.gd
|
||||
|
||||
var _pass := 0
|
||||
var _fail := 0
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
|
||||
func _ok(c: bool, m: String) -> void:
|
||||
if c:
|
||||
_pass += 1
|
||||
print(" PASS: ", m)
|
||||
else:
|
||||
_fail += 1
|
||||
print(" FAIL: ", m)
|
||||
|
||||
|
||||
func _make_bull() -> CharacterBody3D:
|
||||
var b := CharacterBody3D.new()
|
||||
b.set_script(load("res://tests/_fake_bull.gd")) # exposes is_dashing()/is_rolling()
|
||||
b.collision_layer = 2
|
||||
b.collision_mask = 0
|
||||
b.add_to_group(&"player")
|
||||
var cs := CollisionShape3D.new()
|
||||
var shape := CapsuleShape3D.new()
|
||||
shape.radius = 0.75
|
||||
shape.height = 1.845
|
||||
cs.shape = shape
|
||||
b.add_child(cs)
|
||||
root.add_child(b)
|
||||
return b
|
||||
|
||||
|
||||
# Sweep the bull from `from` to `to` at `speed` (velocity along the travel), reseting the bear's ram
|
||||
# edge-state first so each pass is isolated. The prev → now segment is what the bear tests against.
|
||||
func _ram_pass(bear: Node, bull: CharacterBody3D, speed: float, from: Vector3, to: Vector3) -> void:
|
||||
bear.set("_bull_prev_seen", false)
|
||||
bear.set("_bull_ramming", false)
|
||||
var dir := to - from
|
||||
dir.y = 0.0
|
||||
bull.velocity = dir.normalized() * speed if dir.length() > 0.01 else Vector3.ZERO
|
||||
bull.global_position = from
|
||||
bear.call("_sweep_bull_ram")
|
||||
bull.global_position = to
|
||||
bear.call("_sweep_bull_ram")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var bull := _make_bull()
|
||||
var bear := (load("res://Bear.tscn") as PackedScene).instantiate() as Node3D
|
||||
root.add_child(bear)
|
||||
bear.global_position = Vector3.ZERO
|
||||
bear.set_physics_process(false) # freeze the AI; we drive the ram sweep ourselves
|
||||
await physics_frame
|
||||
bear.call("_acquire_bull")
|
||||
|
||||
var dp := root.get_node("/root/DP")
|
||||
var reach: float = dp.f("bear_ram_reach")
|
||||
var thr: float = dp.f("bear_hit_threshold")
|
||||
_ok(bear.get("_bull") == bull, "bear acquired the bull")
|
||||
|
||||
# (a) Horns-first charge straight through the bear — endpoints (3 m) sit outside the reach, so
|
||||
# only the swept test catches the pass-through.
|
||||
var hp0: int = bear.get("_hp")
|
||||
_ok(3.0 > reach, "test pass tunnels: endpoints (3 m) exceed the ram reach (%.2f m)" % reach)
|
||||
_ram_pass(bear, bull, 66.0, Vector3(-3, 0, 0), Vector3(3, 0, 0))
|
||||
_ok(bear.get("_hp") == hp0 - 1, "a horns-first charge wounds the bear once")
|
||||
|
||||
# (b) One charge = one wound: sweeping the same charge again without disengaging doesn't re-hit
|
||||
# mid-contact (edge-triggered). Re-seed as if the bull never left the ram — no reset.
|
||||
var hp1: int = bear.get("_hp")
|
||||
bull.velocity = Vector3(66, 0, 0)
|
||||
bull.global_position = Vector3(0.2, 0, 0) # still on top of the bear, still charging
|
||||
bear.call("_sweep_bull_ram")
|
||||
_ok(bear.get("_hp") == hp1, "a sustained charge doesn't drain the bear frame-by-frame")
|
||||
|
||||
# (c) Charging AWAY (bear behind the horns) is not a horns-first ram, even up close.
|
||||
var hp2: int = bear.get("_hp")
|
||||
_ram_pass(bear, bull, 66.0, Vector3(0.5, 0, 0), Vector3(4, 0, 0))
|
||||
_ok(bear.get("_hp") == hp2, "a charge moving away from the bear leaves it unharmed")
|
||||
|
||||
# (d) A fast pass wide of the bear (out of reach) is spared.
|
||||
_ram_pass(bear, bull, 66.0, Vector3(-3, 0, 3), Vector3(3, 0, 3))
|
||||
_ok(bear.get("_hp") == hp2, "a charge that passes wide of the bear is spared")
|
||||
|
||||
# (e) A slow nudge below the hit threshold is shrugged off.
|
||||
_ram_pass(bear, bull, thr - 1.0, Vector3(-3, 0, 0), Vector3(3, 0, 0))
|
||||
_ok(bear.get("_hp") == hp2, "a nudge below the hit threshold doesn't wound the bear")
|
||||
|
||||
# (f) The DASH ability bypasses the horns-first cone: the same charge-away pass that (c) shrugged
|
||||
# off DOES wound the bear while dashing (a committed lunge rams on contact).
|
||||
var hp3: int = bear.get("_hp")
|
||||
bull.set("dashing", true)
|
||||
_ram_pass(bear, bull, 66.0, Vector3(0.5, 0, 0), Vector3(4, 0, 0))
|
||||
_ok(bear.get("_hp") == hp3 - 1, "the dash ability rams the bear on contact even when not horns-first")
|
||||
bull.set("dashing", false)
|
||||
|
||||
_finish()
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
print("Results: %d passed, %d failed" % [_pass, _fail])
|
||||
quit(1 if _fail > 0 else 0)
|
||||
@@ -0,0 +1 @@
|
||||
uid://o2cdiyq77u8k
|
||||
@@ -0,0 +1,97 @@
|
||||
extends SceneTree
|
||||
## Persistent blood splats (blood_decals.gd + the Gore autoload). Guards four contracts:
|
||||
## • a splat stamps quads onto the floor and onto a wall within reach of the hit;
|
||||
## • the ring buffer caps the instance count no matter how many hits land;
|
||||
## • Settings.gore = false spawns nothing;
|
||||
## • the pool is a plain node, so it frees with its parent (a level swap clears the stains).
|
||||
## blood_decals.gd references the DP autoload, so it's load()ed at runtime here (not a
|
||||
## top-level preload) — under --script a preload compiles before autoloads register.
|
||||
## Run: godot --headless --script tests/blood_decals_test.gd
|
||||
|
||||
var _pass := 0
|
||||
var _fail := 0
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
|
||||
func _ok(c: bool, m: String) -> void:
|
||||
if c:
|
||||
_pass += 1
|
||||
print(" PASS: ", m)
|
||||
else:
|
||||
_fail += 1
|
||||
print(" FAIL: ", m)
|
||||
|
||||
|
||||
# Count instances actually placed on the map. Only the first `visible_instance_count` slots of
|
||||
# the ring buffer are drawn, so that's the live count once the buffer has wrapped.
|
||||
func _live_instances(pool: Node) -> int:
|
||||
var mm: MultiMesh = pool.multimesh
|
||||
if mm == null:
|
||||
return 0
|
||||
return mm.visible_instance_count
|
||||
|
||||
|
||||
func _static_box(size: Vector3, pos: Vector3) -> StaticBody3D:
|
||||
var body := StaticBody3D.new()
|
||||
body.collision_layer = 1 # PhysicsLayers.WORLD
|
||||
body.position = pos
|
||||
var shape := CollisionShape3D.new()
|
||||
var box := BoxShape3D.new()
|
||||
box.size = size
|
||||
shape.shape = box
|
||||
body.add_child(shape)
|
||||
return body
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var dp: Node = root.get_node("DP")
|
||||
var settings: Node = root.get_node("Settings")
|
||||
var cap := int(dp.f("blood_cap"))
|
||||
|
||||
# A minimal world: a floor plane and one vertical wall, both on WORLD so the splat rays hit.
|
||||
var world := Node3D.new()
|
||||
root.add_child(world)
|
||||
world.add_child(_static_box(Vector3(40, 1, 40), Vector3(0, -0.5, 0))) # floor
|
||||
world.add_child(_static_box(Vector3(1, 6, 40), Vector3(1.4, 3, 0))) # wall at x≈1.4
|
||||
|
||||
var pool: Node = (load("res://blood_decals.gd") as GDScript).new()
|
||||
world.add_child(pool)
|
||||
await create_timer(0.4).timeout
|
||||
|
||||
# Baked atlas exists and is one row of 8 shapes.
|
||||
var atlas: Texture2D = pool.material_override.get_shader_parameter("atlas")
|
||||
_ok(atlas != null and atlas.get_width() == 8 * 64, "splat atlas baked (8 cells)")
|
||||
|
||||
# A hit next to the wall stains both the floor beneath it and the wall.
|
||||
settings.gore = true
|
||||
pool.splat(Vector3(0.8, 0.1, 0.0), Vector3(1, 0, 0), 0.6)
|
||||
var after_one := _live_instances(pool)
|
||||
_ok(after_one > 0, "a splat stamps the floor (got %d quads)" % after_one)
|
||||
# Floor cluster is 1 + satellites; anything beyond that came from the wall fan.
|
||||
var floor_max := 1 + int(dp.f("blood_satellites"))
|
||||
_ok(
|
||||
after_one > floor_max,
|
||||
"a nearby wall also catches blood (%d > floor-only %d)" % [after_one, floor_max]
|
||||
)
|
||||
|
||||
# Ring buffer: hammer far past the cap; live count never exceeds it.
|
||||
for i in cap * 2:
|
||||
pool.splat(Vector3(0.0, 0.1, 0.0), Vector3(1, 0, 0), 0.4)
|
||||
_ok(_live_instances(pool) <= cap, "ring buffer holds at the cap (%d)" % cap)
|
||||
|
||||
# Gore off: no new stains. Route through the Gore autoload to prove the gate lives there.
|
||||
var before_off := _live_instances(pool)
|
||||
settings.gore = false
|
||||
root.get_node("Gore").splat(Vector3(5, 0.1, 0.0), Vector3.ZERO, 0.6)
|
||||
_ok(_live_instances(pool) == before_off, "gore off spawns nothing")
|
||||
|
||||
# Lifetime: the pool is a plain node, so freeing its parent (a level swap) clears it.
|
||||
world.queue_free()
|
||||
await create_timer(0.2).timeout
|
||||
_ok(not is_instance_valid(pool), "pool frees with its parent (no leak into next level)")
|
||||
|
||||
print("Results: %d passed, %d failed" % [_pass, _fail])
|
||||
quit(1 if _fail > 0 else 0)
|
||||
@@ -0,0 +1 @@
|
||||
uid://b8em8poj26a57
|
||||
@@ -46,6 +46,13 @@ func _run() -> void:
|
||||
quit(1)
|
||||
return
|
||||
|
||||
# The run now opens in the fightless lobby; force the matador arena so the scene loads
|
||||
# with live matadors for the checks below.
|
||||
var run: Node = root.get_node_or_null("/root/Run")
|
||||
if run != null:
|
||||
run.ensure_run() # build the run first — the shell's own ensure_run would wipe the override
|
||||
run.debug_level_override = run.get_level(&"arena")
|
||||
|
||||
var scene: Node = scene_res.instantiate()
|
||||
root.add_child(scene)
|
||||
current_scene = scene # match runtime: game code (sword throw, overlays) uses current_scene
|
||||
@@ -283,7 +290,7 @@ func _check_overlays() -> void:
|
||||
_note("overlay check: DP / DebugDraw autoload missing")
|
||||
return
|
||||
var flags := [
|
||||
"show_states", "show_stats", "show_collisions", "show_hitboxes", "show_bones",
|
||||
"show_states", "show_stats", "show_attacks", "show_hitboxes", "show_bones",
|
||||
"show_animation_name", "show_wireframe", "show_grid", "show_axes",
|
||||
]
|
||||
for flag: String in flags:
|
||||
|
||||
@@ -53,7 +53,14 @@ func _run() -> void:
|
||||
# Shell survives and hosts exactly one level module.
|
||||
var level_root: Node = scene.get_node_or_null("LevelRoot")
|
||||
_ok(level_root != null, "shell has a LevelRoot")
|
||||
_ok(level_root != null and level_root.get_child_count() == 1, "exactly one level module loaded")
|
||||
# LevelRoot holds the module plus the level's blood-splat pool; exactly one of them
|
||||
# is the geometry module (the other is BloodDecals).
|
||||
var module_children := 0
|
||||
if level_root != null:
|
||||
for child: Node in level_root.get_children():
|
||||
if not child.is_in_group(&"blood_decals"):
|
||||
module_children += 1
|
||||
_ok(module_children == 1, "exactly one level module loaded")
|
||||
_ok(not get_nodes_in_group(&"player").is_empty(), "player (shell) present")
|
||||
|
||||
# The leak we are guarding against: no arena geometry may exist in the bear level.
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
extends SceneTree
|
||||
## Charge-reliability test. A fast bull (dash ≈ 66 m/s ≈ 1.1 m/frame) moves far enough per physics
|
||||
## frame to tunnel clean through the matador's thin HitArea, so the Area's body_entered never fires
|
||||
## — "my charge goes right through them." matador.gd now sweeps the bull's actual travel (prev → now)
|
||||
## each frame and gores any matador on the path (_sweep_bull_gore), and a committed charge pierces the
|
||||
## survival roll (mat_charge_pierce). This drives a tunnelling pass whose endpoints both sit OUTSIDE
|
||||
## the gore radius — so only the swept test can catch it — and asserts: (a) the charge still connects,
|
||||
## (b) a full-speed charge gores (kills) rather than being rolled off, and (c) a slow bump at the hit
|
||||
## threshold still lets the matador roll clear.
|
||||
## Run: godot --headless --script res://tests/matador_charge_test.gd
|
||||
|
||||
var _pass := 0
|
||||
var _fail := 0
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
|
||||
func _ok(c: bool, m: String) -> void:
|
||||
if c:
|
||||
_pass += 1
|
||||
print(" PASS: ", m)
|
||||
else:
|
||||
_fail += 1
|
||||
print(" FAIL: ", m)
|
||||
|
||||
|
||||
func _make_bull() -> CharacterBody3D:
|
||||
var bull := CharacterBody3D.new()
|
||||
bull.set_script(load("res://tests/_fake_bull.gd")) # exposes is_dashing()/is_rolling()
|
||||
bull.collision_layer = 2
|
||||
bull.collision_mask = 0
|
||||
bull.add_to_group(&"player")
|
||||
var cs := CollisionShape3D.new()
|
||||
var shape := CapsuleShape3D.new()
|
||||
shape.radius = 0.75
|
||||
shape.height = 1.845
|
||||
cs.shape = shape
|
||||
bull.add_child(cs)
|
||||
root.add_child(bull)
|
||||
return bull
|
||||
|
||||
|
||||
func _make_matador(_bull: CharacterBody3D) -> CharacterBody3D:
|
||||
var mat := (load("res://Matador.tscn") as PackedScene).instantiate() as CharacterBody3D
|
||||
root.add_child(mat)
|
||||
mat.global_position = Vector3.ZERO
|
||||
mat.set_physics_process(false) # we drive the swept gore ourselves, isolated from the AI
|
||||
await physics_frame
|
||||
mat.call("_acquire_bull")
|
||||
return mat
|
||||
|
||||
|
||||
# Sweep the bull straight across the matador at `speed`: seed the previous position at from_x (too
|
||||
# far to gore), then teleport to to_x so the prev → now segment passes through the matador at x=0.
|
||||
func _charge_pass(mat: CharacterBody3D, bull: CharacterBody3D, speed: float, from_x: float, to_x: float) -> void:
|
||||
bull.global_position = Vector3(from_x, 0.0, 0.0)
|
||||
bull.velocity = Vector3(speed, 0.0, 0.0)
|
||||
mat.call("_sweep_bull_gore")
|
||||
bull.global_position = Vector3(to_x, 0.0, 0.0)
|
||||
mat.call("_sweep_bull_gore")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var dp := root.get_node("/root/DP")
|
||||
var gore_r: float = dp.f("mat_charge_gore_radius")
|
||||
var thr: float = dp.f("mat_hit_threshold")
|
||||
_ok(2.0 > gore_r, "test pass tunnels: endpoints (2 m) sit outside the gore radius (%.2f m)" % gore_r)
|
||||
|
||||
# One shared bull — matadors acquire the sole node in the "player" group, so every scenario
|
||||
# sweeps the same body (a second bull would leave later matadors reading the wrong, stale one).
|
||||
var bull := _make_bull()
|
||||
|
||||
# (a) A dash-speed pass that leaps clean over the HitArea must still connect. Force the roll so
|
||||
# the reaction is a clean, ragdoll-free state change proving detection.
|
||||
dp.call("set_value", "mat_charge_pierce", 0.0)
|
||||
dp.call("set_value", "mat_roll_chance", 1.0)
|
||||
var mat_a: CharacterBody3D = await _make_matador(bull)
|
||||
_charge_pass(mat_a, bull, 66.0, -2.0, 2.0)
|
||||
_ok(mat_a.call("ai_state_name") == "ROLL", "a dash that tunnels the HitArea still connects (matador reacts)")
|
||||
|
||||
# (b) A full-speed charge pierces the survival roll and gores — even forced roll_chance can't save it.
|
||||
dp.call("set_value", "mat_charge_pierce", 1.0)
|
||||
dp.call("set_value", "mat_roll_chance", 1.0)
|
||||
var mat_b: CharacterBody3D = await _make_matador(bull)
|
||||
_charge_pass(mat_b, bull, 66.0, -2.0, 2.0)
|
||||
_ok(mat_b.call("ai_state_name") == "RAGDOLL", "a full-speed charge pierces the roll and gores the matador")
|
||||
|
||||
# (c) The pierce only bites at speed: a slow bump at the hit threshold still lets them roll clear.
|
||||
var mat_c: CharacterBody3D = await _make_matador(bull)
|
||||
_charge_pass(mat_c, bull, thr, -2.0, 2.0)
|
||||
_ok(mat_c.call("ai_state_name") == "ROLL", "a slow bump at the threshold still rolls clear")
|
||||
|
||||
# (d) Horns-first only: a fast pass with the matador BEHIND the bull's heading (it charges away,
|
||||
# 0.5 → 3, matador at 0) doesn't gore, even though the swept path passes within reach.
|
||||
dp.call("set_value", "mat_charge_pierce", 0.0)
|
||||
dp.call("set_value", "mat_roll_chance", 1.0)
|
||||
var mat_d: CharacterBody3D = await _make_matador(bull)
|
||||
_charge_pass(mat_d, bull, 66.0, 0.5, 3.0)
|
||||
_ok(mat_d.call("ai_state_name") == "WANDER", "a charge moving away from the matador doesn't gore (horns-first)")
|
||||
|
||||
# (e) The DASH ability is a committed lunge: even the not-horns-first pass connects (is_dashing
|
||||
# bypasses the cone) AND is a guaranteed kill — roll_chance forced to 1.0 still RAGDOLLS, not rolls.
|
||||
dp.call("set_value", "mat_roll_chance", 1.0)
|
||||
dp.call("set_value", "mat_charge_pierce", 0.0)
|
||||
bull.set("dashing", true)
|
||||
var mat_e: CharacterBody3D = await _make_matador(bull)
|
||||
_charge_pass(mat_e, bull, 66.0, 0.5, 3.0)
|
||||
_ok(mat_e.call("ai_state_name") == "RAGDOLL", "a dash connect is a guaranteed kill (no survival roll)")
|
||||
bull.set("dashing", false)
|
||||
|
||||
_finish()
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
print("Results: %d passed, %d failed" % [_pass, _fail])
|
||||
quit(1 if _fail > 0 else 0)
|
||||
@@ -0,0 +1 @@
|
||||
uid://wplxv71pxkrl
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user