Add pose-switching system with continuous hold and sprint reset
New PlayerPose ScriptableObject (AnimationClip + ceiling Y-offset) and PlayerPoseController that drives poses via a PlayableGraph, overriding the Animator controller. Poses are held continuously (idle, moving, on wall/ ceiling) so cycle and sprint changes show immediately. Sprinting in any state resets to pose 0. Non-keyed bones fall back to a captured rest pose so empty/partial clips apply fully. Ceiling Y-offset is folded into the controller's single mesh-offset writer. PlayerCharacterController gains IsIdle / IsSprinting / IsOnCeiling / AnimatorOverridden accessors and SetPoseLocalYOffset; SetAnimatorRunning is guarded while a pose owns the Animator. Removed obsolete Paintman.controller. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
d867c617df
commit
c41fb398e4
18 files changed
+649
-465
No files matched your search
@@ -586,21 +586,6 @@ MonoBehaviour:
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
- m_Index: 24
|
||||
m_Metrics:
|
||||
m_Width: 153.29688
|
||||
m_Height: 219.59375
|
||||
m_HorizontalBearingX: 9.296875
|
||||
m_HorizontalBearingY: 216
|
||||
m_HorizontalAdvance: 178.20312
|
||||
m_GlyphRect:
|
||||
m_X: 1609
|
||||
m_Y: 459
|
||||
m_Width: 154
|
||||
m_Height: 220
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
- m_Index: 76
|
||||
m_Metrics:
|
||||
m_Width: 228.90625
|
||||
@@ -609,43 +594,13 @@ MonoBehaviour:
|
||||
m_HorizontalBearingY: 159
|
||||
m_HorizontalAdvance: 265.5
|
||||
m_GlyphRect:
|
||||
m_X: 1792
|
||||
m_X: 1609
|
||||
m_Y: 459
|
||||
m_Width: 230
|
||||
m_Height: 163
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
- m_Index: 22
|
||||
m_Metrics:
|
||||
m_Width: 148.79688
|
||||
m_Height: 216.29688
|
||||
m_HorizontalBearingX: 22.203125
|
||||
m_HorizontalBearingY: 212.70312
|
||||
m_HorizontalAdvance: 178.20312
|
||||
m_GlyphRect:
|
||||
m_X: 1367
|
||||
m_Y: 515
|
||||
m_Width: 149
|
||||
m_Height: 217
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
- m_Index: 21
|
||||
m_Metrics:
|
||||
m_Width: 153.29688
|
||||
m_Height: 219.59375
|
||||
m_HorizontalBearingX: 13.796875
|
||||
m_HorizontalBearingY: 216
|
||||
m_HorizontalAdvance: 178.20312
|
||||
m_GlyphRect:
|
||||
m_X: 1792
|
||||
m_Y: 651
|
||||
m_Width: 155
|
||||
m_Height: 220
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
- m_Index: 74
|
||||
m_Metrics:
|
||||
m_Width: 138
|
||||
@@ -654,13 +609,43 @@ MonoBehaviour:
|
||||
m_HorizontalBearingY: 218.40625
|
||||
m_HorizontalAdvance: 171.90625
|
||||
m_GlyphRect:
|
||||
m_X: 1545
|
||||
m_Y: 708
|
||||
m_X: 1868
|
||||
m_Y: 459
|
||||
m_Width: 139
|
||||
m_Height: 223
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
- m_Index: 21
|
||||
m_Metrics:
|
||||
m_Width: 153.29688
|
||||
m_Height: 219.59375
|
||||
m_HorizontalBearingX: 13.796875
|
||||
m_HorizontalBearingY: 216
|
||||
m_HorizontalAdvance: 178.20312
|
||||
m_GlyphRect:
|
||||
m_X: 1367
|
||||
m_Y: 515
|
||||
m_Width: 155
|
||||
m_Height: 220
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
- m_Index: 22
|
||||
m_Metrics:
|
||||
m_Width: 148.79688
|
||||
m_Height: 216.29688
|
||||
m_HorizontalBearingX: 22.203125
|
||||
m_HorizontalBearingY: 212.70312
|
||||
m_HorizontalAdvance: 178.20312
|
||||
m_GlyphRect:
|
||||
m_X: 1551
|
||||
m_Y: 651
|
||||
m_Width: 149
|
||||
m_Height: 217
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
- m_Index: 47
|
||||
m_Metrics:
|
||||
m_Width: 163.5
|
||||
@@ -685,7 +670,7 @@ MonoBehaviour:
|
||||
m_HorizontalAdvance: 237.59375
|
||||
m_GlyphRect:
|
||||
m_X: 1229
|
||||
m_Y: 761
|
||||
m_Y: 764
|
||||
m_Width: 211
|
||||
m_Height: 223
|
||||
m_Scale: 1
|
||||
@@ -751,21 +736,6 @@ MonoBehaviour:
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
- m_Index: 18
|
||||
m_Metrics:
|
||||
m_Width: 149.39062
|
||||
m_Height: 219.59375
|
||||
m_HorizontalBearingX: 14.703125
|
||||
m_HorizontalBearingY: 216
|
||||
m_HorizontalAdvance: 178.20312
|
||||
m_GlyphRect:
|
||||
m_X: 244
|
||||
m_Y: 959
|
||||
m_Width: 151
|
||||
m_Height: 220
|
||||
m_Scale: 1
|
||||
m_AtlasIndex: 0
|
||||
m_ClassDefinitionType: 0
|
||||
m_CharacterTable:
|
||||
- m_ElementType: 1
|
||||
m_Unicode: 8230
|
||||
@@ -907,25 +877,21 @@ MonoBehaviour:
|
||||
m_Unicode: 99
|
||||
m_GlyphIndex: 66
|
||||
m_Scale: 1
|
||||
- m_ElementType: 1
|
||||
m_Unicode: 57
|
||||
m_GlyphIndex: 24
|
||||
m_Scale: 1
|
||||
- m_ElementType: 1
|
||||
m_Unicode: 109
|
||||
m_GlyphIndex: 76
|
||||
m_Scale: 1
|
||||
- m_ElementType: 1
|
||||
m_Unicode: 55
|
||||
m_GlyphIndex: 22
|
||||
m_Unicode: 107
|
||||
m_GlyphIndex: 74
|
||||
m_Scale: 1
|
||||
- m_ElementType: 1
|
||||
m_Unicode: 54
|
||||
m_GlyphIndex: 21
|
||||
m_Scale: 1
|
||||
- m_ElementType: 1
|
||||
m_Unicode: 107
|
||||
m_GlyphIndex: 74
|
||||
m_Unicode: 55
|
||||
m_GlyphIndex: 22
|
||||
m_Scale: 1
|
||||
- m_ElementType: 1
|
||||
m_Unicode: 80
|
||||
@@ -951,10 +917,6 @@ MonoBehaviour:
|
||||
m_Unicode: 73
|
||||
m_GlyphIndex: 40
|
||||
m_Scale: 1
|
||||
- m_ElementType: 1
|
||||
m_Unicode: 51
|
||||
m_GlyphIndex: 18
|
||||
m_Scale: 1
|
||||
m_AtlasTextures:
|
||||
- {fileID: 2664084111089754775}
|
||||
m_AtlasTextureIndex: 0
|
||||
@@ -1103,31 +1065,27 @@ MonoBehaviour:
|
||||
m_Width: 182
|
||||
m_Height: 192
|
||||
- m_X: 1594
|
||||
m_Y: 444
|
||||
m_Width: 183
|
||||
m_Height: 249
|
||||
- m_X: 1777
|
||||
m_Y: 444
|
||||
m_Width: 259
|
||||
m_Height: 192
|
||||
- m_X: 1352
|
||||
m_Y: 500
|
||||
m_Width: 178
|
||||
m_Height: 246
|
||||
- m_X: 1777
|
||||
m_Y: 636
|
||||
m_Width: 184
|
||||
m_Height: 249
|
||||
- m_X: 1530
|
||||
m_Y: 693
|
||||
- m_X: 1853
|
||||
m_Y: 444
|
||||
m_Width: 168
|
||||
m_Height: 252
|
||||
- m_X: 1352
|
||||
m_Y: 500
|
||||
m_Width: 184
|
||||
m_Height: 249
|
||||
- m_X: 1536
|
||||
m_Y: 636
|
||||
m_Width: 178
|
||||
m_Height: 246
|
||||
- m_X: 1020
|
||||
m_Y: 628
|
||||
m_Width: 194
|
||||
m_Height: 248
|
||||
- m_X: 1214
|
||||
m_Y: 746
|
||||
m_Y: 749
|
||||
m_Width: 240
|
||||
m_Height: 252
|
||||
- m_X: 822
|
||||
@@ -1146,10 +1104,6 @@ MonoBehaviour:
|
||||
m_Y: 192
|
||||
m_Width: 74
|
||||
m_Height: 252
|
||||
- m_X: 229
|
||||
m_Y: 944
|
||||
m_Width: 180
|
||||
m_Height: 249
|
||||
m_FreeGlyphRects:
|
||||
- m_X: 189
|
||||
m_Y: 74
|
||||
@@ -1191,10 +1145,18 @@ MonoBehaviour:
|
||||
m_Y: 694
|
||||
m_Width: 78
|
||||
m_Height: 193
|
||||
- m_X: 0
|
||||
m_Y: 1139
|
||||
m_Width: 2047
|
||||
m_Height: 908
|
||||
- m_X: 103
|
||||
m_Y: 864
|
||||
m_Width: 214
|
||||
m_Height: 23
|
||||
- m_X: 229
|
||||
m_Y: 864
|
||||
m_Width: 88
|
||||
m_Height: 1183
|
||||
- m_X: 1373
|
||||
m_Y: 192
|
||||
m_Width: 10
|
||||
@@ -1211,30 +1173,26 @@ MonoBehaviour:
|
||||
m_Y: 252
|
||||
m_Width: 17
|
||||
m_Height: 192
|
||||
- m_X: 2036
|
||||
- m_X: 2021
|
||||
m_Y: 0
|
||||
m_Width: 11
|
||||
m_Width: 26
|
||||
m_Height: 2047
|
||||
- m_X: 1352
|
||||
m_Y: 384
|
||||
m_Width: 21
|
||||
m_Height: 116
|
||||
- m_X: 1961
|
||||
m_Y: 636
|
||||
m_Width: 86
|
||||
m_Height: 1411
|
||||
- m_X: 1530
|
||||
- m_X: 1536
|
||||
m_Y: 500
|
||||
m_Width: 64
|
||||
m_Height: 193
|
||||
- m_X: 1698
|
||||
m_Y: 885
|
||||
m_Width: 349
|
||||
m_Height: 1162
|
||||
- m_X: 1698
|
||||
m_Y: 693
|
||||
m_Width: 79
|
||||
m_Height: 1354
|
||||
m_Width: 58
|
||||
m_Height: 136
|
||||
- m_X: 1714
|
||||
m_Y: 696
|
||||
m_Width: 333
|
||||
m_Height: 1351
|
||||
- m_X: 1714
|
||||
m_Y: 636
|
||||
m_Width: 139
|
||||
m_Height: 1411
|
||||
- m_X: 1020
|
||||
m_Y: 384
|
||||
m_Width: 20
|
||||
@@ -1244,17 +1202,17 @@ MonoBehaviour:
|
||||
m_Width: 123
|
||||
m_Height: 70
|
||||
- m_X: 1454
|
||||
m_Y: 945
|
||||
m_Y: 882
|
||||
m_Width: 593
|
||||
m_Height: 1102
|
||||
m_Height: 1165
|
||||
- m_X: 1214
|
||||
m_Y: 628
|
||||
m_Width: 138
|
||||
m_Height: 118
|
||||
m_Height: 121
|
||||
- m_X: 1454
|
||||
m_Y: 746
|
||||
m_Width: 76
|
||||
m_Height: 1301
|
||||
m_Y: 749
|
||||
m_Width: 82
|
||||
m_Height: 1298
|
||||
- m_X: 822
|
||||
m_Y: 490
|
||||
m_Width: 17
|
||||
@@ -1267,6 +1225,10 @@ MonoBehaviour:
|
||||
m_Y: 695
|
||||
m_Width: 73
|
||||
m_Height: 59
|
||||
- m_X: 229
|
||||
m_Y: 944
|
||||
m_Width: 269
|
||||
m_Height: 1103
|
||||
- m_X: 641
|
||||
m_Y: 736
|
||||
m_Width: 181
|
||||
@@ -1283,10 +1245,18 @@ MonoBehaviour:
|
||||
m_Y: 876
|
||||
m_Width: 7
|
||||
m_Height: 1171
|
||||
- m_X: 229
|
||||
m_Y: 1128
|
||||
m_Width: 1818
|
||||
m_Height: 919
|
||||
- m_X: 229
|
||||
m_Y: 1006
|
||||
m_Width: 789
|
||||
m_Height: 1041
|
||||
- m_X: 1207
|
||||
m_Y: 998
|
||||
m_Y: 1001
|
||||
m_Width: 840
|
||||
m_Height: 1049
|
||||
m_Height: 1046
|
||||
- m_X: 733
|
||||
m_Y: 877
|
||||
m_Width: 285
|
||||
@@ -1299,30 +1269,6 @@ MonoBehaviour:
|
||||
m_Y: 0
|
||||
m_Width: 34
|
||||
m_Height: 444
|
||||
- m_X: 0
|
||||
m_Y: 1193
|
||||
m_Width: 2047
|
||||
m_Height: 854
|
||||
- m_X: 0
|
||||
m_Y: 1139
|
||||
m_Width: 229
|
||||
m_Height: 908
|
||||
- m_X: 229
|
||||
m_Y: 864
|
||||
m_Width: 88
|
||||
m_Height: 80
|
||||
- m_X: 409
|
||||
m_Y: 944
|
||||
m_Width: 89
|
||||
m_Height: 1103
|
||||
- m_X: 409
|
||||
m_Y: 1128
|
||||
m_Width: 1638
|
||||
m_Height: 919
|
||||
- m_X: 409
|
||||
m_Y: 1006
|
||||
m_Width: 609
|
||||
m_Height: 1041
|
||||
m_FontFeatureTable:
|
||||
m_MultipleSubstitutionRecords: []
|
||||
m_LigatureSubstitutionRecords:
|
||||
@@ -13960,7 +13906,7 @@ Texture2D:
|
||||
m_ColorSpace: 1
|
||||
m_PlatformBlob:
|
||||
image data: 4194304
|
||||
_typelessdata: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204050506070809090807060505040301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103040505060708090908070605050402000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020405050607080909080706050504030100000000000000000000000000000000000000000000000000000000000000000000000000000003050607080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808Line truncated
|
||||
_typelessdata: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000204050506070809090807060505040301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103040505060708090908070605050402000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020405050607080909080706050504030100000000000000000000000000000000000000000000000000000000000000000000000000000003050607080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808Line truncated
|
||||
m_StreamData:
|
||||
serializedVersion: 2
|
||||
offset: 0
|
||||
|
||||
@@ -1,313 +0,0 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1101 &-6853059573835313590
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: TPose
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: -6819265730547739275}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0.25
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!1102 &-6819265730547739275
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Paintman-TPose
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: 04d9bfa04f5cc4b46891f0bd8f3b0e54, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1102 &-6714276574684263144
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Paintman-Idle
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: 18925b0fe0029224aa6d9f4d9ca9ab72, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1107 &-5185339043531200129
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -6714276574684263144}
|
||||
m_Position: {x: 330, y: 10, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -6819265730547739275}
|
||||
m_Position: {x: 320, y: 100, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -1498405215906516480}
|
||||
m_Position: {x: 150, y: -110, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -2107490064458262391}
|
||||
m_Position: {x: 380, y: -90, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions:
|
||||
- {fileID: -6853059573835313590}
|
||||
- {fileID: 4958962520971213014}
|
||||
- {fileID: 3402233433967624360}
|
||||
- {fileID: 4791190028147075683}
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 10, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 570, y: -10, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: -6714276574684263144}
|
||||
--- !u!1102 &-2107490064458262391
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Paintman-Run
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions:
|
||||
- {fileID: -292899167866801743}
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: 681e55cb51beb3b44958b7c4aca15a9f, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1102 &-1498405215906516480
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Paintman-Star
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 7400000, guid: 933a7fdefa4f6974b9ed61bd940da6ed, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1101 &-292899167866801743
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 2
|
||||
m_ConditionEvent: Running
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: 0}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 1
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0.1
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Paintman
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters:
|
||||
- m_Name: TPose
|
||||
m_Type: 9
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
- m_Name: Idle
|
||||
m_Type: 9
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
- m_Name: Star
|
||||
m_Type: 9
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
- m_Name: Running
|
||||
m_Type: 4
|
||||
m_DefaultFloat: 0
|
||||
m_DefaultInt: 0
|
||||
m_DefaultBool: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: -5185339043531200129}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
--- !u!1101 &3402233433967624360
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: Star
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: -1498405215906516480}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0.25
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!1101 &4791190028147075683
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: Running
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: -2107490064458262391}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0.1
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
--- !u!1101 &4958962520971213014
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name:
|
||||
m_Conditions:
|
||||
- m_ConditionMode: 1
|
||||
m_ConditionEvent: Idle
|
||||
m_EventTreshold: 0
|
||||
m_DstStateMachine: {fileID: 0}
|
||||
m_DstState: {fileID: -6714276574684263144}
|
||||
m_Solo: 0
|
||||
m_Mute: 0
|
||||
m_IsExit: 0
|
||||
serializedVersion: 3
|
||||
m_TransitionDuration: 0.25
|
||||
m_TransitionOffset: 0
|
||||
m_ExitTime: 0.75
|
||||
m_HasExitTime: 0
|
||||
m_HasFixedDuration: 1
|
||||
m_InterruptionSource: 0
|
||||
m_OrderedInterruption: 1
|
||||
m_CanTransitionToSelf: 1
|
||||
@@ -1356,7 +1356,7 @@ Animator:
|
||||
m_GameObject: {fileID: 341947179}
|
||||
m_Enabled: 1
|
||||
m_Avatar: {fileID: 0}
|
||||
m_Controller: {fileID: 9100000, guid: db81cb9b04dc81e4bbb493a273d47245, type: 2}
|
||||
m_Controller: {fileID: 0}
|
||||
m_CullingMode: 0
|
||||
m_UpdateMode: 0
|
||||
m_ApplyRootMotion: 0
|
||||
@@ -3240,6 +3240,7 @@ GameObject:
|
||||
- component: {fileID: 1141039639}
|
||||
- component: {fileID: 1141039641}
|
||||
- component: {fileID: 1141039642}
|
||||
- component: {fileID: 1141039643}
|
||||
m_Layer: 0
|
||||
m_Name: Player (Variant 1)
|
||||
m_TagString: Player
|
||||
@@ -3336,6 +3337,26 @@ MonoBehaviour:
|
||||
wallTopOutBoost: 0.3
|
||||
cameraOrbit: {fileID: 0}
|
||||
meshOffsetTarget: {fileID: 0}
|
||||
--- !u!114 &1141039643
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1141039638}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 324ce9a23e6a5144096a195460dd567f, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::PlayerPoseController
|
||||
persistPose: 1
|
||||
poseSaveId:
|
||||
poses:
|
||||
- {fileID: 11400000, guid: 3b59c882f27d0d04a82d2db251af1728, type: 2}
|
||||
- {fileID: 11400000, guid: 1545cfba9b5e06d41ae72c7ec766baaf, type: 2}
|
||||
- {fileID: 11400000, guid: 649ecccdabb7ef9438addcec6663b037, type: 2}
|
||||
defaultPoseIndex: 0
|
||||
cycleKey: 17
|
||||
--- !u!1 &1238479929
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54e7941c6d0121a43b23c184d6245569
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22e12daced5232d4795b1a2181319eee
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e3e6fee2893b9d848b8b1ccca743c14f, type: 3}
|
||||
m_Name: Pose_Idle
|
||||
m_EditorClassIdentifier: Assembly-CSharp::PlayerPose
|
||||
clip: {fileID: 7400000, guid: 18925b0fe0029224aa6d9f4d9ca9ab72, type: 2}
|
||||
ceilingYOffset: 0
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db81cb9b04dc81e4bbb493a273d47245
|
||||
guid: 3b59c882f27d0d04a82d2db251af1728
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e3e6fee2893b9d848b8b1ccca743c14f, type: 3}
|
||||
m_Name: Pose_Star
|
||||
m_EditorClassIdentifier: Assembly-CSharp::PlayerPose
|
||||
clip: {fileID: 7400000, guid: 933a7fdefa4f6974b9ed61bd940da6ed, type: 2}
|
||||
ceilingYOffset: 0
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1545cfba9b5e06d41ae72c7ec766baaf
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e3e6fee2893b9d848b8b1ccca743c14f, type: 3}
|
||||
m_Name: Pose_TPose
|
||||
m_EditorClassIdentifier: Assembly-CSharp::PlayerPose
|
||||
clip: {fileID: 7400000, guid: 04d9bfa04f5cc4b46891f0bd8f3b0e54, type: 2}
|
||||
ceilingYOffset: 0
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 649ecccdabb7ef9438addcec6663b037
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -147,6 +147,26 @@ public partial class PlayerCharacterController : MonoBehaviour
|
||||
/// <summary>True while in wall-climb mode.</summary>
|
||||
public bool IsWallClimbing => _isWallClimbing;
|
||||
|
||||
/// <summary>
|
||||
/// True while the player is idle (under control and essentially still): standing on the floor
|
||||
/// below the run threshold, or attached to a wall/ceiling with no climb input. Snapshotted at the
|
||||
/// end of Update so a sibling reads a stable, order-independent value.
|
||||
/// </summary>
|
||||
public bool IsIdle => _isIdle;
|
||||
|
||||
/// <summary>True while the sprint key is held, in any state (ground, air, wall, or ceiling).</summary>
|
||||
public bool IsSprinting => _sprinting;
|
||||
|
||||
/// <summary>True while stuck to a ceiling (wall-climb mode with a downward-facing surface normal).</summary>
|
||||
public bool IsOnCeiling => _isWallClimbing && _wallNormal.y < CeilingNormalThreshold;
|
||||
|
||||
/// <summary>
|
||||
/// Set by <see cref="PlayerPoseController"/> while a pose Playable graph owns the Animator output.
|
||||
/// While set, the run-bool is not poked: it would be moot (the graph overrides it) and Unity would
|
||||
/// log "Animator is not playing an AnimatorController" every frame.
|
||||
/// </summary>
|
||||
public bool AnimatorOverridden { get; set; }
|
||||
|
||||
// Below this horizontal speed (m/s, squared) the character counts as idle for the run animation.
|
||||
private const float RunningSpeedThresholdSqr = 0.04f; // (0.2 m/s)^2
|
||||
|
||||
@@ -154,6 +174,9 @@ public partial class PlayerCharacterController : MonoBehaviour
|
||||
private int _runningHash;
|
||||
private float _verticalVelocity;
|
||||
private Vector3 _horizontalVelocity; // smoothed horizontal move velocity (accel/decel ramp)
|
||||
private bool _sprinting; // sprint key state this frame (exposed via IsSprinting)
|
||||
private bool _isIdle; // snapshot: player essentially still this frame (exposed via IsIdle)
|
||||
private float _poseYOffset; // local-up model offset from the active pose (ceiling only); folded into SetMeshLean
|
||||
|
||||
// Ground contact normal from the latest Move (for slope sliding).
|
||||
private Vector3 _groundNormal = Vector3.up;
|
||||
@@ -241,6 +264,8 @@ public partial class PlayerCharacterController : MonoBehaviour
|
||||
#endif
|
||||
}
|
||||
|
||||
_sprinting = sprinting;
|
||||
|
||||
Vector3 inputDir = new Vector3(h, 0f, v);
|
||||
if (inputDir.sqrMagnitude > 1f)
|
||||
inputDir.Normalize();
|
||||
@@ -282,6 +307,7 @@ public partial class PlayerCharacterController : MonoBehaviour
|
||||
if (cameraOrbit)
|
||||
cameraOrbit.LookSuppressed = _offsetDragging;
|
||||
_horizontalVelocity = Vector3.zero; // drop ground momentum so resuming starts from rest
|
||||
_isIdle = ControlEnabled && (h * h + v * v) <= 1e-4f; // attached & no climb input = holding a pose
|
||||
SetAnimatorRunning(false); // climbing is its own pose, not the ground run
|
||||
return;
|
||||
}
|
||||
@@ -350,7 +376,9 @@ public partial class PlayerCharacterController : MonoBehaviour
|
||||
// Real horizontal speed, so pushing into a wall (blocked) reads as idle, not foot-sliding.
|
||||
Vector3 horizontalVel = _controller.velocity;
|
||||
horizontalVel.y = 0f;
|
||||
SetAnimatorRunning(_controller.isGrounded && horizontalVel.sqrMagnitude > RunningSpeedThresholdSqr);
|
||||
bool movingOnGround = _controller.isGrounded && horizontalVel.sqrMagnitude > RunningSpeedThresholdSqr;
|
||||
SetAnimatorRunning(movingOnGround);
|
||||
_isIdle = ControlEnabled && _controller.isGrounded && !movingOnGround; // standing still on the floor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -642,7 +670,9 @@ public partial class PlayerCharacterController : MonoBehaviour
|
||||
{
|
||||
if (!meshOffsetTarget) return;
|
||||
Vector3 worldOffset = dir * offset;
|
||||
meshOffsetTarget.localPosition = _meshBaseLocalPos + transform.InverseTransformVector(worldOffset);
|
||||
meshOffsetTarget.localPosition = _meshBaseLocalPos
|
||||
+ transform.InverseTransformVector(worldOffset)
|
||||
+ Vector3.up * _poseYOffset; // active pose's ceiling y-offset (0 except while hanging on a ceiling)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -657,6 +687,24 @@ public partial class PlayerCharacterController : MonoBehaviour
|
||||
SetMeshLean(_meshOffsetExitNormal, _meshOffsetResidual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a local-up offset applied to the visual model only, composed into the wall-lean's single
|
||||
/// write of <see cref="meshOffsetTarget"/>. Used by <see cref="PlayerPoseController"/> to hang a
|
||||
/// ceiling pose at the right height; 0 = none. Re-applies immediately so a change shows this frame.
|
||||
/// </summary>
|
||||
public void SetPoseLocalYOffset(float y)
|
||||
{
|
||||
if (_poseYOffset == y) return;
|
||||
_poseYOffset = y;
|
||||
if (!meshOffsetTarget) return;
|
||||
// While climbing the lean is the live _wallOffset along _wallNormal; otherwise re-apply along
|
||||
// whatever residual lean is easing home (both 0 when there's none, restoring the authored pose).
|
||||
if (_isWallClimbing)
|
||||
SetMeshLean(_wallNormal, _wallOffset);
|
||||
else
|
||||
SetMeshLean(_meshOffsetExitNormal, _meshOffsetResidual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raycasts from the character center toward the surface (along -_wallNormal) to find the
|
||||
/// current normal and the gap (surface clearance) to it. The capsule's support distance
|
||||
@@ -897,10 +945,10 @@ public partial class PlayerCharacterController : MonoBehaviour
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>Drives the animator's ground-run bool (null-safe if no animator is assigned).</summary>
|
||||
/// <summary>Drives the animator's ground-run bool (null-safe; skipped while a pose graph overrides the Animator).</summary>
|
||||
private void SetAnimatorRunning(bool running)
|
||||
{
|
||||
if (animator)
|
||||
if (animator && !AnimatorOverridden)
|
||||
animator.SetBool(_runningHash, running);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// A selectable player pose: an <see cref="AnimationClip"/> held while the player is idle, plus a
|
||||
/// y-offset applied to the visual model only while stuck to the ceiling (so the pose hangs at the
|
||||
/// right height). The first ScriptableObject in this project.
|
||||
///
|
||||
/// Named PlayerPose (not Pose) to avoid shadowing the built-in UnityEngine.Pose struct, mirroring
|
||||
/// why the controller is PlayerCharacterController and not just "PlayerController".
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "NewPose", menuName = "Chameleon/Pose")]
|
||||
public class PlayerPose : ScriptableObject
|
||||
{
|
||||
[Tooltip("Clip held while the player is idle in this pose (looped if the clip itself loops, " +
|
||||
"otherwise frozen on its last frame). Authored for the paintman generic rig; clips for " +
|
||||
"other hierarchies will not retarget.")]
|
||||
[SerializeField] private AnimationClip clip;
|
||||
|
||||
[Tooltip("Local-up offset added to the visual model ONLY while stuck to the ceiling, so the pose " +
|
||||
"hangs at the right height. Ignored on the ground and on walls. Meters.")]
|
||||
[SerializeField] private float ceilingYOffset;
|
||||
|
||||
/// <summary>Idle clip for this pose (may be null).</summary>
|
||||
public AnimationClip Clip => clip;
|
||||
|
||||
/// <summary>Local-up offset applied to the model only while on the ceiling.</summary>
|
||||
public float CeilingYOffset => ceilingYOffset;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3e6fee2893b9d848b8b1ccca743c14f
|
||||
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public partial class PlayerPoseController
|
||||
{
|
||||
// --- Persistence: the selected pose index ---
|
||||
//
|
||||
// Saved on quit / play-stop and restored on the next start, so the player keeps the pose they
|
||||
// had selected. Mirrors the project's other X.Persistence.cs partials (small JSON state under
|
||||
// the shared MeshPaint folder).
|
||||
|
||||
[Header("Persistence")]
|
||||
[Tooltip("Save the selected pose index on quit / play-stop and restore it on the next start. " +
|
||||
"Off = the selection starts at the default pose.")]
|
||||
public bool persistPose = true;
|
||||
|
||||
[Tooltip("Save file identifier. Empty = derived from the active scene + object name. Set " +
|
||||
"explicitly to keep a save stable across object renames.")]
|
||||
public string poseSaveId = "";
|
||||
|
||||
private const int PoseFileVersion = 1;
|
||||
private bool _poseSavedOnTeardown; // guards a double save across OnApplicationQuit + OnDestroy
|
||||
|
||||
private static string PoseSaveDir => Path.Combine(Application.persistentDataPath, "MeshPaint");
|
||||
|
||||
private string PoseSavePath()
|
||||
{
|
||||
string key = string.IsNullOrEmpty(poseSaveId)
|
||||
? SanitizePoseKey(SceneManager.GetActiveScene().name + "_" + gameObject.name)
|
||||
: SanitizePoseKey(poseSaveId);
|
||||
return Path.Combine(PoseSaveDir, key + ".pose");
|
||||
}
|
||||
|
||||
private static string SanitizePoseKey(string s)
|
||||
{
|
||||
foreach (char c in Path.GetInvalidFileNameChars()) s = s.Replace(c, '_');
|
||||
return s.Replace(' ', '_');
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class PoseState
|
||||
{
|
||||
public int version = PoseFileVersion;
|
||||
public int index;
|
||||
}
|
||||
|
||||
void Start() => RestorePoseState();
|
||||
|
||||
private void OnApplicationQuit() => SavePoseOnTeardown();
|
||||
private void OnDestroy() => SavePoseOnTeardown();
|
||||
|
||||
/// <summary>Saves once during teardown (OnApplicationQuit and OnDestroy both call this; only the first writes).</summary>
|
||||
private void SavePoseOnTeardown()
|
||||
{
|
||||
if (_poseSavedOnTeardown) return;
|
||||
_poseSavedOnTeardown = true;
|
||||
SavePoseState();
|
||||
}
|
||||
|
||||
/// <summary>Writes the current pose index to disk.</summary>
|
||||
public void SavePoseState()
|
||||
{
|
||||
if (!persistPose) return;
|
||||
|
||||
try
|
||||
{
|
||||
var state = new PoseState { index = _currentIndex };
|
||||
Directory.CreateDirectory(PoseSaveDir);
|
||||
File.WriteAllText(PoseSavePath(), JsonUtility.ToJson(state, true));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[PlayerPoseController] Saving pose state failed: {e.Message}", this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Restores the saved pose index, or does nothing if there is no save.</summary>
|
||||
private void RestorePoseState()
|
||||
{
|
||||
if (!persistPose) return;
|
||||
|
||||
var state = LoadPoseState();
|
||||
if (state == null) return;
|
||||
SetPoseIndex(state.index);
|
||||
}
|
||||
|
||||
private PoseState LoadPoseState()
|
||||
{
|
||||
string path = PoseSavePath();
|
||||
if (!File.Exists(path)) return null;
|
||||
|
||||
try
|
||||
{
|
||||
var state = JsonUtility.FromJson<PoseState>(File.ReadAllText(path));
|
||||
if (state == null || state.version != PoseFileVersion) return null;
|
||||
return state;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[PlayerPoseController] Loading pose state failed: {e.Message}", this);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Deletes the saved pose state (next start uses the default pose). Editor convenience.</summary>
|
||||
[ContextMenu("Clear Saved Pose State")]
|
||||
public void ClearSavedPoseState()
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = PoseSavePath();
|
||||
if (File.Exists(path)) File.Delete(path);
|
||||
Debug.Log($"[PlayerPoseController] Cleared saved pose state: {path}", this);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning($"[PlayerPoseController] Clearing saved pose state failed: {e.Message}", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 314a46cf262f78345a83e4bbe1c939f2
|
||||
@@ -0,0 +1,246 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Playables;
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
using UnityEngine.InputSystem;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Sits next to the <see cref="PlayerCharacterController"/> and holds a list of <see cref="PlayerPose"/>s
|
||||
/// plus the active index. The active pose is held continuously — while idle, walking, and sprinting
|
||||
/// alike — so cycling to the next pose, or the sprint reset to the default pose, shows up
|
||||
/// immediately instead of only once the player comes to a stop. One key cycles to the next pose
|
||||
/// (wrapping), and sprinting in any state (ground, air, wall, ceiling) snaps the selection back to the default pose.
|
||||
///
|
||||
/// The pose clip is played through a tiny <see cref="PlayableGraph"/> (an
|
||||
/// <see cref="AnimationClipPlayable"/> on an <see cref="AnimationPlayableOutput"/>) that overrides
|
||||
/// the Animator Controller's run/idle animation for as long as a pose is selected (it only hands the
|
||||
/// rig back when the list is empty / the clip is null). The per-pose ceiling y-offset is routed
|
||||
/// through the controller (the single writer of the model-offset transform) so it composes with the
|
||||
/// wall-lean instead of fighting it.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(PlayerCharacterController))]
|
||||
[DisallowMultipleComponent]
|
||||
// Run after PlayerCharacterController (default order 0) so the ceiling / sprint state polled below is
|
||||
// this frame's, and the ceiling offset resolves without a one-frame seam.
|
||||
[DefaultExecutionOrder(100)]
|
||||
public partial class PlayerPoseController : MonoBehaviour
|
||||
{
|
||||
[Header("Poses")]
|
||||
[Tooltip("Selectable poses. Index 0 is the default pose that sprinting resets to.")]
|
||||
[SerializeField] private List<PlayerPose> poses = new();
|
||||
|
||||
[Tooltip("Index the selection resets to while sprinting in any state (the default/standard pose).")]
|
||||
[Min(0)]
|
||||
[SerializeField] private int defaultPoseIndex = 0;
|
||||
|
||||
[Header("Input")]
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
[Tooltip("Key that cycles to the next pose (wraps at the end of the list).")]
|
||||
[SerializeField] private Key cycleKey = Key.C;
|
||||
#else
|
||||
[Tooltip("Key that cycles to the next pose (wraps at the end of the list).")]
|
||||
[SerializeField] private KeyCode cycleKey = KeyCode.C;
|
||||
#endif
|
||||
|
||||
private PlayerCharacterController _player;
|
||||
private Animator _animator;
|
||||
private string _graphName; // cached so building the graph allocates no string from the Update path
|
||||
|
||||
private int _currentIndex;
|
||||
|
||||
// Playables: a held clip that overrides the Animator Controller while idle.
|
||||
private PlayableGraph _graph;
|
||||
private AnimationPlayableOutput _output;
|
||||
private AnimationClipPlayable _clipPlayable;
|
||||
private AnimationClip _activeClip;
|
||||
private bool _posePlaying;
|
||||
|
||||
// Rest pose snapshot of the whole Animator subtree, taken in Awake before the Animator first
|
||||
// evaluates. An AnimationClipPlayable only writes the bones its curves cover, so a clip that
|
||||
// doesn't key a bone (an empty clip like the T-pose, or a partial one) would otherwise leave that
|
||||
// bone frozen on the previous animation. Restoring this before each pose start makes every pose
|
||||
// define the full body. meshOffsetTarget is an ancestor of the Animator, so it is never in this
|
||||
// set and the controller's lean/ceiling offset stays untouched.
|
||||
private Transform[] _restBones;
|
||||
private Vector3[] _restPos;
|
||||
private Quaternion[] _restRot;
|
||||
private Vector3[] _restScale;
|
||||
|
||||
/// <summary>Index of the currently selected pose.</summary>
|
||||
public int CurrentIndex => _currentIndex;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_player = GetComponent<PlayerCharacterController>();
|
||||
_animator = _player ? _player.animator : null;
|
||||
_graphName = $"{name}-Pose";
|
||||
if (_animator)
|
||||
CaptureRestPose();
|
||||
else
|
||||
Debug.LogWarning("[PlayerPoseController] No Animator on the PlayerCharacterController; poses cannot play.", this);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (CycleKeyPressed())
|
||||
NextPose();
|
||||
|
||||
// Sprinting in any state (ground, air, wall, ceiling) snaps the selection back to the default
|
||||
// pose. Held continuously below, so the reset shows up immediately, not only once back on the floor.
|
||||
if (_player.IsSprinting)
|
||||
_currentIndex = WrapIndex(defaultPoseIndex);
|
||||
|
||||
PlayerPose pose = ActivePose();
|
||||
|
||||
// Hold the pose continuously — idle, walking, and sprinting alike — so a selection change
|
||||
// (cycling, or the sprint reset to the default pose above) shows immediately instead of only
|
||||
// once the player stops. PlayPose hands the rig back to the controller only when there is no
|
||||
// clip to play (empty list / null clip).
|
||||
PlayPose(pose ? pose.Clip : null);
|
||||
|
||||
// Tell the controller the pose graph owns the Animator output so it stops poking the run-bool
|
||||
// (moot while overridden, and it would warn every frame). Read next frame, when this matches
|
||||
// the bound-graph state (both only change here).
|
||||
_player.AnimatorOverridden = _posePlaying;
|
||||
|
||||
// Ceiling y-offset: only while stuck to the ceiling, routed through the controller so it
|
||||
// shares the wall-lean's single write of the model transform.
|
||||
float ceilingOffset = (pose && _player.IsOnCeiling) ? pose.CeilingYOffset : 0f;
|
||||
_player.SetPoseLocalYOffset(ceilingOffset);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
// Hand the rig back to the Animator Controller and never leak a graph; rebuilt lazily on the
|
||||
// next idle frame. Also clear any ceiling offset we were holding.
|
||||
ReleasePose();
|
||||
if (_player)
|
||||
{
|
||||
_player.SetPoseLocalYOffset(0f);
|
||||
_player.AnimatorOverridden = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Advances to the next pose, wrapping at the end of the list.</summary>
|
||||
public void NextPose() => SetPoseIndex(_currentIndex + 1);
|
||||
|
||||
/// <summary>Steps back to the previous pose, wrapping at the start of the list.</summary>
|
||||
public void PreviousPose() => SetPoseIndex(_currentIndex - 1);
|
||||
|
||||
/// <summary>Selects a pose by index, wrapping into range so cycling never goes out of bounds.</summary>
|
||||
public void SetPoseIndex(int index) => _currentIndex = WrapIndex(index);
|
||||
|
||||
private int WrapIndex(int index)
|
||||
{
|
||||
int count = poses.Count;
|
||||
if (count == 0) return 0;
|
||||
return ((index % count) + count) % count;
|
||||
}
|
||||
|
||||
private PlayerPose ActivePose()
|
||||
{
|
||||
if (poses.Count == 0) return null;
|
||||
return poses[Mathf.Clamp(_currentIndex, 0, poses.Count - 1)];
|
||||
}
|
||||
|
||||
private bool CycleKeyPressed()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
var keyboard = Keyboard.current;
|
||||
return keyboard != null && keyboard[cycleKey].wasPressedThisFrame;
|
||||
#else
|
||||
return Input.GetKeyDown(cycleKey);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plays and holds the given clip through the Playables graph, overriding the Animator
|
||||
/// Controller. No-op while the same clip is already held, so idle re-apply never restarts it.
|
||||
/// A null clip (or no animator) releases back to the controller.
|
||||
/// </summary>
|
||||
private void PlayPose(AnimationClip clip)
|
||||
{
|
||||
if (!clip || !_animator)
|
||||
{
|
||||
ReleasePose();
|
||||
return;
|
||||
}
|
||||
if (_posePlaying && _activeClip == clip)
|
||||
return;
|
||||
|
||||
if (!_graph.IsValid())
|
||||
{
|
||||
_graph = PlayableGraph.Create(_graphName);
|
||||
_graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
|
||||
_output = AnimationPlayableOutput.Create(_graph, "Pose", _animator);
|
||||
}
|
||||
if (_clipPlayable.IsValid())
|
||||
_graph.DestroyPlayable(_clipPlayable);
|
||||
|
||||
// Snap un-keyed bones to rest first, so a partial or empty clip (e.g. the T-pose) defines the
|
||||
// whole body instead of inheriting the previous animation's pose. The clip then overrides the
|
||||
// bones it does key when the graph evaluates later this frame.
|
||||
ResetToRestPose();
|
||||
|
||||
_clipPlayable = AnimationClipPlayable.Create(_graph, clip);
|
||||
_output.SetSourcePlayable(_clipPlayable);
|
||||
if (!_graph.IsPlaying())
|
||||
_graph.Play();
|
||||
|
||||
_activeClip = clip;
|
||||
_posePlaying = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Snapshots every transform a pose clip can address (the Animator's whole subtree) in its
|
||||
/// authored rest pose. Taken in Awake before the Animator first evaluates, so it captures the rig
|
||||
/// at rest (the paintman rig's rest pose is its T-pose).
|
||||
/// </summary>
|
||||
private void CaptureRestPose()
|
||||
{
|
||||
_restBones = _animator.transform.GetComponentsInChildren<Transform>(true);
|
||||
int n = _restBones.Length;
|
||||
_restPos = new Vector3[n];
|
||||
_restRot = new Quaternion[n];
|
||||
_restScale = new Vector3[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
Transform t = _restBones[i];
|
||||
_restPos[i] = t.localPosition;
|
||||
_restRot[i] = t.localRotation;
|
||||
_restScale[i] = t.localScale;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Restores the captured rest pose so an empty or partial pose clip fully defines the body.</summary>
|
||||
private void ResetToRestPose()
|
||||
{
|
||||
if (_restBones == null)
|
||||
return;
|
||||
for (int i = 0; i < _restBones.Length; i++)
|
||||
{
|
||||
Transform t = _restBones[i];
|
||||
if (!t)
|
||||
continue;
|
||||
t.localPosition = _restPos[i];
|
||||
t.localRotation = _restRot[i];
|
||||
t.localScale = _restScale[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Destroys the graph so the Animator Controller (run/idle) drives the rig again.</summary>
|
||||
private void ReleasePose()
|
||||
{
|
||||
if (!_posePlaying)
|
||||
return;
|
||||
if (_graph.IsValid())
|
||||
_graph.Destroy();
|
||||
_graph = default;
|
||||
_output = default;
|
||||
_clipPlayable = default;
|
||||
_activeClip = null;
|
||||
_posePlaying = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 324ce9a23e6a5144096a195460dd567f
|
||||
Reference in new issue
Block a user