Animate enemies: client-derived Rukhanka rigs (Werewolf/Kaiju Husks)
Extends the DR-022 player pipeline to Husk enemies. A Husk is an ownerless interpolated ghost = structurally a remote player, so the new client-only EnemyAnimationDriveSystem mirrors PlayerAnimationDriveSystem's remote path: velocity from LocalTransform-delta (prevPos cache, pruned every frame), facing from LocalTransform.Rotation (AnimParamMath.PlanarForward), maxSpeed from baked EnemyStats, IsAttacking from the already-replicated AttackWindup telegraph. No new [GhostField], no server/asmdef/ghost-hash change. Monster-mash roster: Werewolf (Grunt), Werewolf-Undead (Swarmer), Kaiju (Brute), built by the reusable, GUID-preserving EnemyRigTools editor tool (materials + AC_EnemyTopDown + EnemyAttackWindup clip + 3 rigged prefabs). WaveSystem now preserves the baked variant Scale (was reset to 1 by LocalTransform.FromPosition). See DR-023. EditMode 208/208; validated in Play (rigs skin, scales replicate, locomotion + attack telegraph drive correctly). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,407 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1102 &-8102868851794693864
|
||||||
|
AnimatorState:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 1
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: Locomotion
|
||||||
|
m_Speed: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_Transitions:
|
||||||
|
- {fileID: 785731946183937007}
|
||||||
|
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: -481359581180607483}
|
||||||
|
m_Tag:
|
||||||
|
m_SpeedParameter:
|
||||||
|
m_MirrorParameter:
|
||||||
|
m_CycleOffsetParameter:
|
||||||
|
m_TimeParameter:
|
||||||
|
--- !u!1102 &-6438350710411496961
|
||||||
|
AnimatorState:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 1
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: Attack
|
||||||
|
m_Speed: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_Transitions:
|
||||||
|
- {fileID: 3568780310546908354}
|
||||||
|
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: dea3639d22b116947a6f839015a6075f, type: 2}
|
||||||
|
m_Tag:
|
||||||
|
m_SpeedParameter:
|
||||||
|
m_MirrorParameter:
|
||||||
|
m_CycleOffsetParameter:
|
||||||
|
m_TimeParameter:
|
||||||
|
--- !u!1101 &-4752793699339494306
|
||||||
|
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: IsAttacking
|
||||||
|
m_EventTreshold: 0
|
||||||
|
m_DstStateMachine: {fileID: 0}
|
||||||
|
m_DstState: {fileID: -6438350710411496961}
|
||||||
|
m_Solo: 0
|
||||||
|
m_Mute: 0
|
||||||
|
m_IsExit: 0
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TransitionDuration: 0.06
|
||||||
|
m_TransitionOffset: 0
|
||||||
|
m_ExitTime: 0.75
|
||||||
|
m_HasExitTime: 0
|
||||||
|
m_HasFixedDuration: 1
|
||||||
|
m_InterruptionSource: 0
|
||||||
|
m_OrderedInterruption: 1
|
||||||
|
m_CanTransitionToSelf: 0
|
||||||
|
--- !u!1101 &-1505565898738729052
|
||||||
|
AnimatorStateTransition:
|
||||||
|
m_ObjectHideFlags: 1
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name:
|
||||||
|
m_Conditions:
|
||||||
|
- m_ConditionMode: 3
|
||||||
|
m_ConditionEvent: Speed
|
||||||
|
m_EventTreshold: 0.1
|
||||||
|
m_DstStateMachine: {fileID: 0}
|
||||||
|
m_DstState: {fileID: -8102868851794693864}
|
||||||
|
m_Solo: 0
|
||||||
|
m_Mute: 0
|
||||||
|
m_IsExit: 0
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TransitionDuration: 0.15
|
||||||
|
m_TransitionOffset: 0
|
||||||
|
m_ExitTime: 0.9
|
||||||
|
m_HasExitTime: 0
|
||||||
|
m_HasFixedDuration: 1
|
||||||
|
m_InterruptionSource: 0
|
||||||
|
m_OrderedInterruption: 1
|
||||||
|
m_CanTransitionToSelf: 1
|
||||||
|
--- !u!206 &-481359581180607483
|
||||||
|
BlendTree:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: Locomotion
|
||||||
|
m_Childs:
|
||||||
|
- serializedVersion: 2
|
||||||
|
m_Motion: {fileID: 1827226128182048838, guid: a4b8f2deec6a99945987cfc59b1b4e54, type: 3}
|
||||||
|
m_Threshold: 0
|
||||||
|
m_Position: {x: 0, y: 0}
|
||||||
|
m_TimeScale: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_DirectBlendParameter: Blend
|
||||||
|
m_Mirror: 0
|
||||||
|
- serializedVersion: 2
|
||||||
|
m_Motion: {fileID: 1827226128182048838, guid: 4f79281e6eb3df54889369eba3aa1c67, type: 3}
|
||||||
|
m_Threshold: 0
|
||||||
|
m_Position: {x: 0, y: 1}
|
||||||
|
m_TimeScale: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_DirectBlendParameter: Blend
|
||||||
|
m_Mirror: 0
|
||||||
|
- serializedVersion: 2
|
||||||
|
m_Motion: {fileID: 1827226128182048838, guid: b982f3686334e9248b6b2020e5682d9e, type: 3}
|
||||||
|
m_Threshold: 0
|
||||||
|
m_Position: {x: 0.7, y: 0.7}
|
||||||
|
m_TimeScale: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_DirectBlendParameter: Blend
|
||||||
|
m_Mirror: 0
|
||||||
|
- serializedVersion: 2
|
||||||
|
m_Motion: {fileID: 1827226128182048838, guid: 4699ac7f1156bfc4dba616d9b3a05234, type: 3}
|
||||||
|
m_Threshold: 0
|
||||||
|
m_Position: {x: 1, y: 0}
|
||||||
|
m_TimeScale: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_DirectBlendParameter: Blend
|
||||||
|
m_Mirror: 0
|
||||||
|
- serializedVersion: 2
|
||||||
|
m_Motion: {fileID: 1827226128182048838, guid: ae899eb338d4f7443b77e2cc71e0b29e, type: 3}
|
||||||
|
m_Threshold: 0
|
||||||
|
m_Position: {x: 0.7, y: -0.7}
|
||||||
|
m_TimeScale: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_DirectBlendParameter: Blend
|
||||||
|
m_Mirror: 0
|
||||||
|
- serializedVersion: 2
|
||||||
|
m_Motion: {fileID: 1827226128182048838, guid: b28d41dc2454f694fac9ab766e54323a, type: 3}
|
||||||
|
m_Threshold: 0
|
||||||
|
m_Position: {x: 0, y: -1}
|
||||||
|
m_TimeScale: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_DirectBlendParameter: Blend
|
||||||
|
m_Mirror: 0
|
||||||
|
- serializedVersion: 2
|
||||||
|
m_Motion: {fileID: 1827226128182048838, guid: d466621781c6a7449aa01e5ac0dd2c0f, type: 3}
|
||||||
|
m_Threshold: 0
|
||||||
|
m_Position: {x: -0.7, y: -0.7}
|
||||||
|
m_TimeScale: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_DirectBlendParameter: Blend
|
||||||
|
m_Mirror: 0
|
||||||
|
- serializedVersion: 2
|
||||||
|
m_Motion: {fileID: 1827226128182048838, guid: d294a4226e928db4fbbd933c19ccf5a1, type: 3}
|
||||||
|
m_Threshold: 0
|
||||||
|
m_Position: {x: -1, y: 0}
|
||||||
|
m_TimeScale: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_DirectBlendParameter: Blend
|
||||||
|
m_Mirror: 0
|
||||||
|
- serializedVersion: 2
|
||||||
|
m_Motion: {fileID: 1827226128182048838, guid: 4c272e8ffeefc6a4ab141f84a6712559, type: 3}
|
||||||
|
m_Threshold: 0
|
||||||
|
m_Position: {x: -0.7, y: 0.7}
|
||||||
|
m_TimeScale: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_DirectBlendParameter: Blend
|
||||||
|
m_Mirror: 0
|
||||||
|
m_BlendParameter: MoveX
|
||||||
|
m_BlendParameterY: MoveZ
|
||||||
|
m_MinThreshold: 0
|
||||||
|
m_MaxThreshold: 1
|
||||||
|
m_UseAutomaticThresholds: 0
|
||||||
|
m_NormalizedBlendValues: 0
|
||||||
|
m_BlendType: 2
|
||||||
|
--- !u!91 &9100000
|
||||||
|
AnimatorController:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: AC_EnemyTopDown
|
||||||
|
serializedVersion: 6
|
||||||
|
m_AnimatorParameters:
|
||||||
|
- m_Name: MoveX
|
||||||
|
m_Type: 1
|
||||||
|
m_DefaultFloat: 0
|
||||||
|
m_DefaultInt: 0
|
||||||
|
m_DefaultBool: 0
|
||||||
|
m_Controller: {fileID: 9100000}
|
||||||
|
- m_Name: MoveZ
|
||||||
|
m_Type: 1
|
||||||
|
m_DefaultFloat: 0
|
||||||
|
m_DefaultInt: 0
|
||||||
|
m_DefaultBool: 0
|
||||||
|
m_Controller: {fileID: 9100000}
|
||||||
|
- m_Name: Speed
|
||||||
|
m_Type: 1
|
||||||
|
m_DefaultFloat: 0
|
||||||
|
m_DefaultInt: 0
|
||||||
|
m_DefaultBool: 0
|
||||||
|
m_Controller: {fileID: 9100000}
|
||||||
|
- m_Name: IsDead
|
||||||
|
m_Type: 4
|
||||||
|
m_DefaultFloat: 0
|
||||||
|
m_DefaultInt: 0
|
||||||
|
m_DefaultBool: 0
|
||||||
|
m_Controller: {fileID: 9100000}
|
||||||
|
- m_Name: IsAttacking
|
||||||
|
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: 5460501127914818087}
|
||||||
|
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}
|
||||||
|
m_EvaluateTransitionsOnStart: 1
|
||||||
|
--- !u!1101 &785731946183937007
|
||||||
|
AnimatorStateTransition:
|
||||||
|
m_ObjectHideFlags: 1
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name:
|
||||||
|
m_Conditions:
|
||||||
|
- m_ConditionMode: 4
|
||||||
|
m_ConditionEvent: Speed
|
||||||
|
m_EventTreshold: 0.1
|
||||||
|
m_DstStateMachine: {fileID: 0}
|
||||||
|
m_DstState: {fileID: 8302574255206078140}
|
||||||
|
m_Solo: 0
|
||||||
|
m_Mute: 0
|
||||||
|
m_IsExit: 0
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TransitionDuration: 0.15
|
||||||
|
m_TransitionOffset: 0
|
||||||
|
m_ExitTime: 0.9
|
||||||
|
m_HasExitTime: 0
|
||||||
|
m_HasFixedDuration: 1
|
||||||
|
m_InterruptionSource: 0
|
||||||
|
m_OrderedInterruption: 1
|
||||||
|
m_CanTransitionToSelf: 1
|
||||||
|
--- !u!1102 &1998880016702917871
|
||||||
|
AnimatorState:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 1
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: Death
|
||||||
|
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: 1827226128182048838, guid: 52a2eb3158000934eb33267c807b8b15, type: 3}
|
||||||
|
m_Tag:
|
||||||
|
m_SpeedParameter:
|
||||||
|
m_MirrorParameter:
|
||||||
|
m_CycleOffsetParameter:
|
||||||
|
m_TimeParameter:
|
||||||
|
--- !u!1101 &3568780310546908354
|
||||||
|
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: IsAttacking
|
||||||
|
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.12
|
||||||
|
m_TransitionOffset: 0
|
||||||
|
m_ExitTime: 0.9
|
||||||
|
m_HasExitTime: 0
|
||||||
|
m_HasFixedDuration: 1
|
||||||
|
m_InterruptionSource: 0
|
||||||
|
m_OrderedInterruption: 1
|
||||||
|
m_CanTransitionToSelf: 1
|
||||||
|
--- !u!1101 &5014557051428573475
|
||||||
|
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: IsDead
|
||||||
|
m_EventTreshold: 0
|
||||||
|
m_DstStateMachine: {fileID: 0}
|
||||||
|
m_DstState: {fileID: 1998880016702917871}
|
||||||
|
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: 0
|
||||||
|
--- !u!1107 &5460501127914818087
|
||||||
|
AnimatorStateMachine:
|
||||||
|
serializedVersion: 7
|
||||||
|
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: 8302574255206078140}
|
||||||
|
m_Position: {x: 200, y: 0, z: 0}
|
||||||
|
- serializedVersion: 1
|
||||||
|
m_State: {fileID: -8102868851794693864}
|
||||||
|
m_Position: {x: 235, y: 65, z: 0}
|
||||||
|
- serializedVersion: 1
|
||||||
|
m_State: {fileID: 1998880016702917871}
|
||||||
|
m_Position: {x: 270, y: 130, z: 0}
|
||||||
|
- serializedVersion: 1
|
||||||
|
m_State: {fileID: -6438350710411496961}
|
||||||
|
m_Position: {x: 305, y: 195, z: 0}
|
||||||
|
m_ChildStateMachines: []
|
||||||
|
m_AnyStateTransitions:
|
||||||
|
- {fileID: 5014557051428573475}
|
||||||
|
- {fileID: -4752793699339494306}
|
||||||
|
m_EntryTransitions: []
|
||||||
|
m_StateMachineTransitions: {}
|
||||||
|
m_StateMachineBehaviours: []
|
||||||
|
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||||
|
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||||
|
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||||
|
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||||
|
m_DefaultState: {fileID: 8302574255206078140}
|
||||||
|
--- !u!1102 &8302574255206078140
|
||||||
|
AnimatorState:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 1
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: Idle
|
||||||
|
m_Speed: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_Transitions:
|
||||||
|
- {fileID: -1505565898738729052}
|
||||||
|
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: 1827226128182048838, guid: a4b8f2deec6a99945987cfc59b1b4e54, type: 3}
|
||||||
|
m_Tag:
|
||||||
|
m_SpeedParameter:
|
||||||
|
m_MirrorParameter:
|
||||||
|
m_CycleOffsetParameter:
|
||||||
|
m_TimeParameter:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ea6213577111096448e54427c32087f3
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 9100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!74 &7400000
|
||||||
|
AnimationClip:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: EnemyAttackWindup
|
||||||
|
serializedVersion: 7
|
||||||
|
m_Legacy: 0
|
||||||
|
m_Compressed: 0
|
||||||
|
m_UseHighQualityCurve: 1
|
||||||
|
m_RotationCurves: []
|
||||||
|
m_CompressedRotationCurves: []
|
||||||
|
m_EulerCurves:
|
||||||
|
- curve:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Curve:
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0
|
||||||
|
value: {x: 0, y: 0, z: 0}
|
||||||
|
inSlope: {x: 0, y: 0, z: 0}
|
||||||
|
outSlope: {x: 0, y: 0, z: 0}
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: {x: 0, y: 0.33333334, z: 0.33333334}
|
||||||
|
outWeight: {x: 0, y: 0.33333334, z: 0.33333334}
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0.15
|
||||||
|
value: {x: 30, y: 0, z: 0}
|
||||||
|
inSlope: {x: 0, y: 0, z: 0}
|
||||||
|
outSlope: {x: 0, y: 0, z: 0}
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: {x: 0, y: 0.33333334, z: 0.33333334}
|
||||||
|
outWeight: {x: 0, y: 0.33333334, z: 0.33333334}
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0.4
|
||||||
|
value: {x: 0, y: 0, z: 0}
|
||||||
|
inSlope: {x: 0, y: 0, z: 0}
|
||||||
|
outSlope: {x: 0, y: 0, z: 0}
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: {x: 0, y: 0.33333334, z: 0.33333334}
|
||||||
|
outWeight: {x: 0, y: 0.33333334, z: 0.33333334}
|
||||||
|
m_PreInfinity: 2
|
||||||
|
m_PostInfinity: 2
|
||||||
|
m_RotationOrder: 4
|
||||||
|
path: Root
|
||||||
|
m_PositionCurves: []
|
||||||
|
m_ScaleCurves: []
|
||||||
|
m_FloatCurves: []
|
||||||
|
m_PPtrCurves: []
|
||||||
|
m_SampleRate: 30
|
||||||
|
m_WrapMode: 0
|
||||||
|
m_Bounds:
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
m_Extent: {x: 0, y: 0, z: 0}
|
||||||
|
m_ClipBindingConstant:
|
||||||
|
genericBindings:
|
||||||
|
- serializedVersion: 2
|
||||||
|
path: 3066451557
|
||||||
|
attribute: 4
|
||||||
|
script: {fileID: 0}
|
||||||
|
typeID: 4
|
||||||
|
customType: 4
|
||||||
|
isPPtrCurve: 0
|
||||||
|
isIntCurve: 0
|
||||||
|
isSerializeReferenceCurve: 0
|
||||||
|
pptrCurveMapping: []
|
||||||
|
m_AnimationClipSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||||
|
m_AdditiveReferencePoseTime: 0
|
||||||
|
m_StartTime: 0
|
||||||
|
m_StopTime: 0.4
|
||||||
|
m_OrientationOffsetY: 0
|
||||||
|
m_Level: 0
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_HasAdditiveReferencePose: 0
|
||||||
|
m_LoopTime: 0
|
||||||
|
m_LoopBlend: 0
|
||||||
|
m_LoopBlendOrientation: 0
|
||||||
|
m_LoopBlendPositionY: 0
|
||||||
|
m_LoopBlendPositionXZ: 0
|
||||||
|
m_KeepOriginalOrientation: 0
|
||||||
|
m_KeepOriginalPositionY: 1
|
||||||
|
m_KeepOriginalPositionXZ: 0
|
||||||
|
m_HeightFromFeet: 0
|
||||||
|
m_Mirror: 0
|
||||||
|
m_EditorCurves:
|
||||||
|
- serializedVersion: 2
|
||||||
|
curve:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Curve:
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0
|
||||||
|
value: 0
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0
|
||||||
|
outWeight: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0.15
|
||||||
|
value: 30
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0
|
||||||
|
outWeight: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0.4
|
||||||
|
value: 0
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0
|
||||||
|
outWeight: 0
|
||||||
|
m_PreInfinity: 2
|
||||||
|
m_PostInfinity: 2
|
||||||
|
m_RotationOrder: 4
|
||||||
|
attribute: localEulerAnglesRaw.x
|
||||||
|
path: Root
|
||||||
|
classID: 4
|
||||||
|
script: {fileID: 0}
|
||||||
|
flags: 16
|
||||||
|
m_EulerEditorCurves: []
|
||||||
|
m_HasGenericRootTransform: 0
|
||||||
|
m_HasMotionFloatCurves: 0
|
||||||
|
m_Events: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dea3639d22b116947a6f839015a6075f
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 7400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &-592490988042947487
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 11
|
||||||
|
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
|
||||||
|
version: 10
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 8
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: M_Enemy_Kaiju_Animated
|
||||||
|
m_Shader: {fileID: -6465566751694194690, guid: 32ea7846f763cb340950fafed798ecf6, type: 3}
|
||||||
|
m_Parent: {fileID: 0}
|
||||||
|
m_ModifiedSerializedProperties: 0
|
||||||
|
m_ValidKeywords:
|
||||||
|
- _USE_VERTEX_COLOR
|
||||||
|
m_InvalidKeywords: []
|
||||||
|
m_LightmapFlags: 2
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses:
|
||||||
|
- MOTIONVECTORS
|
||||||
|
m_LockedProperties:
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BaseColorMap:
|
||||||
|
m_Texture: {fileID: 2800000, guid: 945dfc020dc3ce1498514a9ef906766a, type: 3}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MaskMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _NormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_Lightmaps:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_LightmapsInd:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_ShadowMasks:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Ints: []
|
||||||
|
m_Floats:
|
||||||
|
- _DeformedMeshIndex: 0
|
||||||
|
- _Metallic: 0
|
||||||
|
- _QueueControl: 0
|
||||||
|
- _QueueOffset: 0
|
||||||
|
- _Smoothness: 0
|
||||||
|
- _USE_VERTEX_COLOR: 1
|
||||||
|
m_Colors:
|
||||||
|
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- _DeformationParamsForMotionVectors: {r: 0, g: 0, b: 0, a: 0}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
|
m_AllowLocking: 1
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9a5c679075aa4bb40a039cef41fcb319
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &-592490988042947487
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 11
|
||||||
|
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
|
||||||
|
version: 10
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 8
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: M_Enemy_WerewolfUndead_Animated
|
||||||
|
m_Shader: {fileID: -6465566751694194690, guid: 32ea7846f763cb340950fafed798ecf6, type: 3}
|
||||||
|
m_Parent: {fileID: 0}
|
||||||
|
m_ModifiedSerializedProperties: 0
|
||||||
|
m_ValidKeywords:
|
||||||
|
- _USE_VERTEX_COLOR
|
||||||
|
m_InvalidKeywords: []
|
||||||
|
m_LightmapFlags: 2
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses:
|
||||||
|
- MOTIONVECTORS
|
||||||
|
m_LockedProperties:
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BaseColorMap:
|
||||||
|
m_Texture: {fileID: 2800000, guid: 4a48e1348e08a5c4db622d04b7b0cfb1, type: 3}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MaskMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _NormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_Lightmaps:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_LightmapsInd:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_ShadowMasks:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Ints: []
|
||||||
|
m_Floats:
|
||||||
|
- _DeformedMeshIndex: 0
|
||||||
|
- _Metallic: 0
|
||||||
|
- _QueueControl: 0
|
||||||
|
- _QueueOffset: 0
|
||||||
|
- _Smoothness: 0
|
||||||
|
- _USE_VERTEX_COLOR: 1
|
||||||
|
m_Colors:
|
||||||
|
- _BaseColor: {r: 0.62, g: 0.78, b: 0.55, a: 1}
|
||||||
|
- _DeformationParamsForMotionVectors: {r: 0, g: 0, b: 0, a: 0}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
|
m_AllowLocking: 1
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f1688032987ef2c4bbf59ac071e5f2df
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &-592490988042947487
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 11
|
||||||
|
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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
|
||||||
|
version: 10
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 8
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: M_Enemy_Werewolf_Animated
|
||||||
|
m_Shader: {fileID: -6465566751694194690, guid: 32ea7846f763cb340950fafed798ecf6, type: 3}
|
||||||
|
m_Parent: {fileID: 0}
|
||||||
|
m_ModifiedSerializedProperties: 0
|
||||||
|
m_ValidKeywords:
|
||||||
|
- _USE_VERTEX_COLOR
|
||||||
|
m_InvalidKeywords: []
|
||||||
|
m_LightmapFlags: 2
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses:
|
||||||
|
- MOTIONVECTORS
|
||||||
|
m_LockedProperties:
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BaseColorMap:
|
||||||
|
m_Texture: {fileID: 2800000, guid: 4a48e1348e08a5c4db622d04b7b0cfb1, type: 3}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MaskMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _NormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_Lightmaps:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_LightmapsInd:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- unity_ShadowMasks:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Ints: []
|
||||||
|
m_Floats:
|
||||||
|
- _DeformedMeshIndex: 0
|
||||||
|
- _Metallic: 0
|
||||||
|
- _QueueControl: 0
|
||||||
|
- _QueueOffset: 0
|
||||||
|
- _Smoothness: 0
|
||||||
|
- _USE_VERTEX_COLOR: 1
|
||||||
|
m_Colors:
|
||||||
|
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- _DeformationParamsForMotionVectors: {r: 0, g: 0, b: 0, a: 0}
|
||||||
|
m_BuildTextureStacks: []
|
||||||
|
m_AllowLocking: 1
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8467d4af8af3dcf44b8386ddd5a901d1
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 31d233e9e507acf45a411f8ab0997bed
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a6c2004a3cc32cc44b1bb7a795f86519
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f77a36036567c814496e6c59c42b2082
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
using ProjectM.Simulation;
|
||||||
|
using Rukhanka; // FastAnimatorParameter, AnimatorParametersAspect, ParameterValue,
|
||||||
|
// AnimatorControllerParameterComponent, AnimatorControllerParameterIndexTableComponent,
|
||||||
|
// RukhankaAnimationSystemGroup
|
||||||
|
using Unity.Burst;
|
||||||
|
using Unity.Collections;
|
||||||
|
using Unity.Entities;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using Unity.Transforms; // LocalTransform
|
||||||
|
|
||||||
|
namespace ProjectM.Client
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Client-only animation driver for Husk ENEMIES. OBSERVES replicated state and writes Rukhanka animator
|
||||||
|
/// blend params; never mutates the sim (presentation-only). The enemy mirror of the REMOTE path of
|
||||||
|
/// <see cref="PlayerAnimationDriveSystem"/>: a Husk is an OWNERLESS INTERPOLATED ghost (server-moved by
|
||||||
|
/// EnemyAISystem, position+rotation via stock LocalTransform replication, no KinematicCharacterBody on the
|
||||||
|
/// client) — structurally identical to a remote player — so planar velocity is derived from replicated
|
||||||
|
/// <see cref="LocalTransform.Position"/> frame-deltas, facing from the replicated <see cref="LocalTransform.Rotation"/>
|
||||||
|
/// (the server faces the target each tick), and the run-blend normalizer from the baked-on-both-worlds
|
||||||
|
/// <see cref="EnemyStats.MoveSpeed"/>. The attack telegraph rides the already-replicated
|
||||||
|
/// <see cref="AttackWindup"/> [GhostField] (non-zero for the ~0.3s wind-up) — no new [GhostField], no server
|
||||||
|
/// change (Rukhanka is stripped server-side by ServerStripAnimationSystem), no ghost-hash change. See DR-023.
|
||||||
|
/// <para>
|
||||||
|
/// Runs in SimulationSystemGroup via [UpdateBefore(RukhankaAnimationSystemGroup)] so params are set before
|
||||||
|
/// Rukhanka's same-frame controller eval (no 1-tick lag) — the same documented exception to the
|
||||||
|
/// "all juice = PresentationSystemGroup" rule the player driver uses. Observe-only, never in the predicted loop.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// NOTE: deliberately NOT [RequireMatchingQueriesForUpdate]. Husks despawn far more often than players, so the
|
||||||
|
/// per-frame prevPos prune must run EVERY frame (even with zero live Husks) to reclaim the cache entry of a
|
||||||
|
/// just-killed Husk — otherwise one NativeParallelHashMap entry would leak per kill.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
[WorldSystemFilter(WorldSystemFilterFlags.LocalSimulation | WorldSystemFilterFlags.ClientSimulation)]
|
||||||
|
[UpdateBefore(typeof(RukhankaAnimationSystemGroup))]
|
||||||
|
public partial class EnemyAnimationDriveSystem : SystemBase
|
||||||
|
{
|
||||||
|
// Perfect-hash keys, built once. Names MUST match AC_EnemyTopDown.controller parameter names exactly.
|
||||||
|
static readonly FastAnimatorParameter k_MoveX = new FastAnimatorParameter("MoveX");
|
||||||
|
static readonly FastAnimatorParameter k_MoveZ = new FastAnimatorParameter("MoveZ");
|
||||||
|
static readonly FastAnimatorParameter k_Speed = new FastAnimatorParameter("Speed");
|
||||||
|
static readonly FastAnimatorParameter k_IsAttacking = new FastAnimatorParameter("IsAttacking");
|
||||||
|
|
||||||
|
// prevPos cache (per Husk Entity). Pruned every frame (a vanished Husk = a server-authoritative death).
|
||||||
|
NativeParallelHashMap<Entity, float3> _prevPos;
|
||||||
|
|
||||||
|
protected override void OnCreate()
|
||||||
|
{
|
||||||
|
_prevPos = new NativeParallelHashMap<Entity, float3>(64, Allocator.Persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDestroy()
|
||||||
|
{
|
||||||
|
if (_prevPos.IsCreated) _prevPos.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUpdate()
|
||||||
|
{
|
||||||
|
float dt = SystemAPI.Time.DeltaTime; // wall-frame delta is correct for presentation
|
||||||
|
if (dt < 1e-5f) dt = 1e-5f;
|
||||||
|
|
||||||
|
var seen = new NativeParallelHashSet<Entity>(64, Allocator.TempJob);
|
||||||
|
var job = new EnemyDriveJob
|
||||||
|
{
|
||||||
|
moveX = k_MoveX, moveZ = k_MoveZ, speed = k_Speed, isAttacking = k_IsAttacking,
|
||||||
|
dt = dt,
|
||||||
|
prevPos = _prevPos,
|
||||||
|
seen = seen,
|
||||||
|
};
|
||||||
|
Dependency = job.Schedule(Dependency); // .Schedule (not parallel): mutates _prevPos
|
||||||
|
// Prune stale entries (despawned Husks) AFTER the job, on the main thread.
|
||||||
|
Dependency.Complete();
|
||||||
|
PruneCache(seen);
|
||||||
|
seen.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PruneCache(NativeParallelHashSet<Entity> seen)
|
||||||
|
{
|
||||||
|
using var keys = _prevPos.GetKeyArray(Allocator.Temp);
|
||||||
|
for (int i = 0; i < keys.Length; i++)
|
||||||
|
if (!seen.Contains(keys[i])) _prevPos.Remove(keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Husks are ownerless interpolated ghosts: no local/remote split, no Dead enableable. Velocity from
|
||||||
|
// LocalTransform.Position delta; facing from LocalTransform.Rotation (server-faced); IsAttacking from the
|
||||||
|
// replicated AttackWindup telegraph. The Rukhanka param components match only rigged ghosts.
|
||||||
|
[BurstCompile]
|
||||||
|
[WithAll(typeof(EnemyTag))]
|
||||||
|
partial struct EnemyDriveJob : IJobEntity
|
||||||
|
{
|
||||||
|
public FastAnimatorParameter moveX, moveZ, speed, isAttacking;
|
||||||
|
public float dt;
|
||||||
|
public NativeParallelHashMap<Entity, float3> prevPos;
|
||||||
|
public NativeParallelHashSet<Entity> seen;
|
||||||
|
|
||||||
|
void Execute(
|
||||||
|
Entity e,
|
||||||
|
AnimatorControllerParameterIndexTableComponent indexTable,
|
||||||
|
DynamicBuffer<AnimatorControllerParameterComponent> parametersArr,
|
||||||
|
in LocalTransform xform,
|
||||||
|
in EnemyStats stats,
|
||||||
|
in AttackWindup windup)
|
||||||
|
{
|
||||||
|
seen.Add(e);
|
||||||
|
float3 cur = xform.Position;
|
||||||
|
float3 vel = float3.zero;
|
||||||
|
if (prevPos.TryGetValue(e, out var prev))
|
||||||
|
vel = (cur - prev) / dt;
|
||||||
|
prevPos[e] = cur;
|
||||||
|
|
||||||
|
float2 facing = AnimParamMath.PlanarForward(xform.Rotation);
|
||||||
|
float3 p = AnimParamMath.LocomotionParams(vel, facing, stats.MoveSpeed);
|
||||||
|
bool attacking = windup.WindUpUntilTick != 0;
|
||||||
|
|
||||||
|
var a = new AnimatorParametersAspect(parametersArr, indexTable);
|
||||||
|
if (a.HasParameter(moveX)) a.SetParameterValue(moveX, p.x);
|
||||||
|
if (a.HasParameter(moveZ)) a.SetParameterValue(moveZ, p.y);
|
||||||
|
if (a.HasParameter(speed)) a.SetParameterValue(speed, p.z);
|
||||||
|
if (a.HasParameter(isAttacking)) a.SetParameterValue(isAttacking, attacking);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 958c71f53bd0c744fab96f83164084f1
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ProjectM.EditorTools
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reusable editor pipeline that turns Synty Polygon character meshes into ANIMATED interpolated-ghost enemy
|
||||||
|
/// prefabs, mirroring the DR-022 player-rig recipe so the same Rukhanka client-derived animation works for
|
||||||
|
/// Husks (see DR-023). Three idempotent, re-runnable steps (menu: ProjectM/Animation):
|
||||||
|
/// 1. Build deformation materials (duplicate the player's AnimatedLitShader mat, swap the pack atlas).
|
||||||
|
/// 2. Build AC_EnemyTopDown (fork AC_PlayerTopDown + an Attack state) and the EnemyAttackWindup clip.
|
||||||
|
/// 3. Build the 3 animated enemy prefabs (clone the capsule ghost template, strip the capsule, flatten the
|
||||||
|
/// Synty skeleton + SMRs under the ghost root, add Animator + RigDefinitionAuthoring, set the deformation
|
||||||
|
/// material, offset the Root bone for feet-on-ground).
|
||||||
|
/// RigDefinitionAuthoring is set via reflection (no Rukhanka asmdef ref needed — same "by name" tactic as
|
||||||
|
/// ServerStripAnimationSystem). Outputs are NEW prefabs (templates stay pristine capsules); re-point the
|
||||||
|
/// gameplay subscene WaveDirector.EnemyPrefabs[] at them.
|
||||||
|
/// </summary>
|
||||||
|
public static class EnemyRigTools
|
||||||
|
{
|
||||||
|
const string PlayerMat = "Assets/_Project/Materials/M_SpaceSoldier_Animated.mat";
|
||||||
|
const string PlayerController = "Assets/_Project/Animation/AC_PlayerTopDown.controller";
|
||||||
|
const string EnemyController = "Assets/_Project/Animation/AC_EnemyTopDown.controller";
|
||||||
|
const string AttackClip = "Assets/_Project/Animation/EnemyAttackWindup.anim";
|
||||||
|
|
||||||
|
const string WerewolfAtlas = "Assets/Synty/PolygonWerewolf/Textures/PolygonWerewolf_01_A.png";
|
||||||
|
const string KaijuAtlas = "Assets/Synty/PolygonKaiju/Textures/PolygonKaiju_01.png";
|
||||||
|
|
||||||
|
const string MatWerewolf = "Assets/_Project/Materials/M_Enemy_Werewolf_Animated.mat";
|
||||||
|
const string MatWerewolfUndead = "Assets/_Project/Materials/M_Enemy_WerewolfUndead_Animated.mat";
|
||||||
|
const string MatKaiju = "Assets/_Project/Materials/M_Enemy_Kaiju_Animated.mat";
|
||||||
|
|
||||||
|
const string SyntyWerewolf = "Assets/Synty/PolygonWerewolf/Prefabs/Characters/SM_Chr_Werewolf_01.prefab";
|
||||||
|
const string SyntyKaiju = "Assets/Synty/PolygonKaiju/Prefabs/Characters/SM_Chr_Kaiju_01.prefab";
|
||||||
|
|
||||||
|
struct Variant
|
||||||
|
{
|
||||||
|
public string Name, Template, Synty, Output, Material;
|
||||||
|
public float RootY; // Root-bone local Y (capsule-center -> feet; tuned per scale in Play)
|
||||||
|
public float Scale; // 0 = keep the template's baked scale
|
||||||
|
}
|
||||||
|
|
||||||
|
static Variant[] Variants() => new[]
|
||||||
|
{
|
||||||
|
new Variant { Name = "Grunt (Werewolf)", Template = "Assets/_Project/Prefabs/Enemy.prefab", Synty = SyntyWerewolf, Output = "Assets/_Project/Prefabs/EnemyWerewolf.prefab", Material = MatWerewolf, RootY = -1.25f, Scale = 0f },
|
||||||
|
new Variant { Name = "Swarmer (Werewolf Undead)", Template = "Assets/_Project/Prefabs/EnemySwarmer.prefab", Synty = SyntyWerewolf, Output = "Assets/_Project/Prefabs/EnemyWerewolfUndead.prefab", Material = MatWerewolfUndead, RootY = -1.67f, Scale = 0f },
|
||||||
|
new Variant { Name = "Brute (Kaiju)", Template = "Assets/_Project/Prefabs/EnemyBrute.prefab", Synty = SyntyKaiju, Output = "Assets/_Project/Prefabs/EnemyKaiju.prefab", Material = MatKaiju, RootY = -0.52f, Scale = 0f },
|
||||||
|
};
|
||||||
|
|
||||||
|
[MenuItem("ProjectM/Animation/Enemy Rigs - Build All")]
|
||||||
|
public static void BuildAll()
|
||||||
|
{
|
||||||
|
BuildMaterials();
|
||||||
|
BuildControllerAndClip();
|
||||||
|
BuildPrefabs();
|
||||||
|
Debug.Log("[EnemyRigTools] Build All complete. Re-point WaveDirector.EnemyPrefabs[] at the new prefabs and re-bake the gameplay subscene.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 1. Materials ------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[MenuItem("ProjectM/Animation/Enemy Rigs - 1 Build Materials")]
|
||||||
|
public static void BuildMaterials()
|
||||||
|
{
|
||||||
|
MakeMat(MatWerewolf, WerewolfAtlas, null);
|
||||||
|
// Undead = the same werewolf atlas with a sickly desaturated-green tint so the Swarmer reads distinct.
|
||||||
|
MakeMat(MatWerewolfUndead, WerewolfAtlas, new Color(0.62f, 0.78f, 0.55f, 1f));
|
||||||
|
MakeMat(MatKaiju, KaijuAtlas, null);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
Debug.Log("[EnemyRigTools] Materials built.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MakeMat(string dst, string atlas, Color? tint)
|
||||||
|
{
|
||||||
|
if (AssetDatabase.LoadAssetAtPath<Material>(PlayerMat) == null)
|
||||||
|
{ Debug.LogError($"[EnemyRigTools] Source material missing: {PlayerMat}"); return; }
|
||||||
|
|
||||||
|
AssetDatabase.DeleteAsset(dst);
|
||||||
|
if (!AssetDatabase.CopyAsset(PlayerMat, dst))
|
||||||
|
{ Debug.LogError($"[EnemyRigTools] CopyAsset failed -> {dst}"); return; }
|
||||||
|
AssetDatabase.ImportAsset(dst);
|
||||||
|
|
||||||
|
var m = AssetDatabase.LoadAssetAtPath<Material>(dst);
|
||||||
|
var tex = AssetDatabase.LoadAssetAtPath<Texture>(atlas);
|
||||||
|
if (tex == null) Debug.LogWarning($"[EnemyRigTools] Atlas not found: {atlas}");
|
||||||
|
if (m.HasProperty("_BaseColorMap") && tex != null) m.SetTexture("_BaseColorMap", tex);
|
||||||
|
if (tint.HasValue && m.HasProperty("_BaseColor")) m.SetColor("_BaseColor", tint.Value);
|
||||||
|
EditorUtility.SetDirty(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 2. Controller + attack clip --------------------------------------------------------------------
|
||||||
|
|
||||||
|
[MenuItem("ProjectM/Animation/Enemy Rigs - 2 Build Controller")]
|
||||||
|
public static void BuildControllerAndClip()
|
||||||
|
{
|
||||||
|
// Attack wind-up: pitch the Root bone forward (whole-body lunge) and back, non-looping. Root is the
|
||||||
|
// top of every Synty Generic rig, so one clip fits all variants; the locomotion clips don't key Root,
|
||||||
|
// so no conflict and Root returns to its authored Y-offset when the state exits.
|
||||||
|
var clip = new AnimationClip { frameRate = 30f };
|
||||||
|
var pitch = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(0.15f, 30f), new Keyframe(0.40f, 0f));
|
||||||
|
AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve("Root", typeof(Transform), "localEulerAnglesRaw.x"), pitch);
|
||||||
|
var s = AnimationUtility.GetAnimationClipSettings(clip);
|
||||||
|
s.loopTime = false;
|
||||||
|
AnimationUtility.SetAnimationClipSettings(clip, s);
|
||||||
|
AssetDatabase.DeleteAsset(AttackClip);
|
||||||
|
AssetDatabase.CreateAsset(clip, AttackClip);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
|
if (AssetDatabase.LoadAssetAtPath<AnimatorController>(PlayerController) == null)
|
||||||
|
{ Debug.LogError($"[EnemyRigTools] Source controller missing: {PlayerController}"); return; }
|
||||||
|
|
||||||
|
AssetDatabase.DeleteAsset(EnemyController);
|
||||||
|
AssetDatabase.CopyAsset(PlayerController, EnemyController);
|
||||||
|
AssetDatabase.ImportAsset(EnemyController);
|
||||||
|
var ac = AssetDatabase.LoadAssetAtPath<AnimatorController>(EnemyController);
|
||||||
|
|
||||||
|
if (!HasParam(ac, "IsAttacking"))
|
||||||
|
ac.AddParameter("IsAttacking", AnimatorControllerParameterType.Bool);
|
||||||
|
|
||||||
|
var sm = ac.layers[0].stateMachine;
|
||||||
|
var attackClipAsset = AssetDatabase.LoadAssetAtPath<AnimationClip>(AttackClip);
|
||||||
|
var attack = sm.AddState("Attack");
|
||||||
|
attack.motion = attackClipAsset;
|
||||||
|
attack.writeDefaultValues = true;
|
||||||
|
|
||||||
|
var toAttack = sm.AddAnyStateTransition(attack);
|
||||||
|
toAttack.hasExitTime = false;
|
||||||
|
toAttack.duration = 0.06f;
|
||||||
|
toAttack.canTransitionToSelf = false;
|
||||||
|
toAttack.AddCondition(AnimatorConditionMode.If, 0f, "IsAttacking");
|
||||||
|
|
||||||
|
var fromAttack = attack.AddExitTransition();
|
||||||
|
fromAttack.hasExitTime = false;
|
||||||
|
fromAttack.duration = 0.12f;
|
||||||
|
fromAttack.AddCondition(AnimatorConditionMode.IfNot, 0f, "IsAttacking");
|
||||||
|
|
||||||
|
EditorUtility.SetDirty(ac);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
Debug.Log("[EnemyRigTools] AC_EnemyTopDown + EnemyAttackWindup clip built.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HasParam(AnimatorController ac, string name)
|
||||||
|
{
|
||||||
|
foreach (var p in ac.parameters) if (p.name == name) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 3. Prefabs --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[MenuItem("ProjectM/Animation/Enemy Rigs - 3 Build Prefabs")]
|
||||||
|
public static void BuildPrefabs()
|
||||||
|
{
|
||||||
|
foreach (var v in Variants()) BuildOne(v);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
Debug.Log("[EnemyRigTools] Animated enemy prefabs built. Re-point WaveDirector.EnemyPrefabs[] and re-bake.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void BuildOne(Variant v)
|
||||||
|
{
|
||||||
|
if (AssetDatabase.LoadAssetAtPath<GameObject>(v.Template) == null)
|
||||||
|
{ Debug.LogError($"[EnemyRigTools] Template missing: {v.Template}"); return; }
|
||||||
|
if (AssetDatabase.LoadAssetAtPath<GameObject>(v.Synty) == null)
|
||||||
|
{ Debug.LogError($"[EnemyRigTools] Synty char prefab missing: {v.Synty}"); return; }
|
||||||
|
|
||||||
|
// GUID-preserving: COPY the template only on the FIRST build (mints the output + its GUID). On a
|
||||||
|
// re-run, modify the existing output IN PLACE so its GUID stays stable -> the gameplay subscene's
|
||||||
|
// WaveDirector.EnemyPrefabs[] references never break. (DeleteAsset+CopyAsset would mint a new GUID
|
||||||
|
// each run and silently orphan those refs.)
|
||||||
|
if (AssetDatabase.LoadAssetAtPath<GameObject>(v.Output) == null)
|
||||||
|
{
|
||||||
|
if (!AssetDatabase.CopyAsset(v.Template, v.Output))
|
||||||
|
{ Debug.LogError($"[EnemyRigTools] CopyAsset failed -> {v.Output}"); return; }
|
||||||
|
AssetDatabase.ImportAsset(v.Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
var root = PrefabUtility.LoadPrefabContents(v.Output);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Clean slate for idempotent re-runs: drop any previously-built rig (children + rig components)
|
||||||
|
// and the primitive capsule visual; keep the root's ghost/authoring components + transform.
|
||||||
|
var kids = new List<Transform>();
|
||||||
|
foreach (Transform c in root.transform) kids.Add(c);
|
||||||
|
foreach (var c in kids) UnityEngine.Object.DestroyImmediate(c.gameObject);
|
||||||
|
foreach (var mf in root.GetComponents<MeshFilter>()) UnityEngine.Object.DestroyImmediate(mf);
|
||||||
|
foreach (var mr in root.GetComponents<MeshRenderer>()) UnityEngine.Object.DestroyImmediate(mr);
|
||||||
|
foreach (var an in root.GetComponents<Animator>()) UnityEngine.Object.DestroyImmediate(an);
|
||||||
|
var oldRda = FindType("Rukhanka.Hybrid.RigDefinitionAuthoring");
|
||||||
|
if (oldRda != null) { var ex = root.GetComponent(oldRda); if (ex != null) UnityEngine.Object.DestroyImmediate(ex); }
|
||||||
|
|
||||||
|
// Optional scale override (else keep the template's baked variant scale).
|
||||||
|
if (v.Scale > 0f) root.transform.localScale = new Vector3(v.Scale, v.Scale, v.Scale);
|
||||||
|
|
||||||
|
// Clone the Synty character (unlinked) and flatten its skeleton + SMRs under the ghost root.
|
||||||
|
var syntyAsset = AssetDatabase.LoadAssetAtPath<GameObject>(v.Synty);
|
||||||
|
var clone = (GameObject)UnityEngine.Object.Instantiate(syntyAsset);
|
||||||
|
var srcAnimator = clone.GetComponentInChildren<Animator>();
|
||||||
|
var avatar = srcAnimator != null ? srcAnimator.avatar : null;
|
||||||
|
|
||||||
|
var children = new List<Transform>();
|
||||||
|
foreach (Transform c in clone.transform) children.Add(c);
|
||||||
|
foreach (var c in children) c.SetParent(root.transform, false); // keep local transforms
|
||||||
|
UnityEngine.Object.DestroyImmediate(clone);
|
||||||
|
|
||||||
|
// Feet-on-ground: offset the un-keyed Root bone (entity origin = capsule center ~1m up).
|
||||||
|
var rootBone = root.transform.Find("Root");
|
||||||
|
if (rootBone != null)
|
||||||
|
{
|
||||||
|
var lp = rootBone.localPosition;
|
||||||
|
lp.y = v.RootY;
|
||||||
|
rootBone.localPosition = lp;
|
||||||
|
}
|
||||||
|
else Debug.LogWarning($"[EnemyRigTools] No 'Root' bone under {v.Output}; feet offset skipped.");
|
||||||
|
|
||||||
|
// Deformation material on every SMR slot (else unskinned-static + "does not support skinning").
|
||||||
|
var mat = AssetDatabase.LoadAssetAtPath<Material>(v.Material);
|
||||||
|
if (mat == null) Debug.LogWarning($"[EnemyRigTools] Material missing: {v.Material}");
|
||||||
|
foreach (var smr in root.GetComponentsInChildren<SkinnedMeshRenderer>(true))
|
||||||
|
{
|
||||||
|
var mats = smr.sharedMaterials;
|
||||||
|
for (int i = 0; i < mats.Length; i++) mats[i] = mat;
|
||||||
|
smr.sharedMaterials = mats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animator on the ghost root (the entity that holds EnemyAuthoring + the Rukhanka param buffer).
|
||||||
|
var anim = root.GetComponent<Animator>();
|
||||||
|
if (anim == null) anim = root.AddComponent<Animator>();
|
||||||
|
anim.avatar = avatar;
|
||||||
|
anim.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath<RuntimeAnimatorController>(EnemyController);
|
||||||
|
anim.applyRootMotion = false;
|
||||||
|
|
||||||
|
// RigDefinitionAuthoring (Rukhanka.Hybrid) via reflection — CPU engine, match the player rig.
|
||||||
|
AddRigDefinition(root);
|
||||||
|
|
||||||
|
PrefabUtility.SaveAsPrefabAsset(root, v.Output);
|
||||||
|
Debug.Log($"[EnemyRigTools] Built {v.Name} -> {v.Output} (rootY={v.RootY}).");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
PrefabUtility.UnloadPrefabContents(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AddRigDefinition(GameObject root)
|
||||||
|
{
|
||||||
|
var t = FindType("Rukhanka.Hybrid.RigDefinitionAuthoring");
|
||||||
|
if (t == null) { Debug.LogError("[EnemyRigTools] RigDefinitionAuthoring type not found (Rukhanka.Hybrid)."); return; }
|
||||||
|
var rda = root.GetComponent(t);
|
||||||
|
if (rda == null) rda = root.AddComponent(t);
|
||||||
|
SetMember(rda, "applyRootMotion", false);
|
||||||
|
SetMember(rda, "boneEntityStrippingMode", 1); // match Player.prefab
|
||||||
|
SetMember(rda, "animationEngine", 0); // 0 = CPU
|
||||||
|
EditorUtility.SetDirty(rda);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Type FindType(string fullName)
|
||||||
|
{
|
||||||
|
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
|
{
|
||||||
|
var t = asm.GetType(fullName);
|
||||||
|
if (t != null) return t;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetMember(object o, string name, object val)
|
||||||
|
{
|
||||||
|
const BindingFlags BF = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||||
|
var f = o.GetType().GetField(name, BF);
|
||||||
|
if (f != null)
|
||||||
|
{
|
||||||
|
object v = f.FieldType.IsEnum ? Enum.ToObject(f.FieldType, Convert.ToInt32(val))
|
||||||
|
: Convert.ChangeType(val, f.FieldType);
|
||||||
|
f.SetValue(o, v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var p = o.GetType().GetProperty(name, BF);
|
||||||
|
if (p != null && p.CanWrite)
|
||||||
|
{
|
||||||
|
object v = p.PropertyType.IsEnum ? Enum.ToObject(p.PropertyType, Convert.ToInt32(val))
|
||||||
|
: Convert.ChangeType(val, p.PropertyType);
|
||||||
|
p.SetValue(o, v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.LogWarning($"[EnemyRigTools] Field/prop '{name}' not found on {o.GetType().Name}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 181b2a09275156c498049e0c8ba54125
|
||||||
@@ -86,7 +86,10 @@ namespace ProjectM.Server
|
|||||||
|
|
||||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||||
var husk = ecb.Instantiate(prefabs[prefabIdx].Prefab);
|
var husk = ecb.Instantiate(prefabs[prefabIdx].Prefab);
|
||||||
ecb.SetComponent(husk, LocalTransform.FromPosition(pos));
|
// Preserve the prefab's baked variant Scale (a replicated [GhostField]) + rotation;
|
||||||
|
// LocalTransform.FromPosition() would reset Scale->1, shrinking/growing animated variants.
|
||||||
|
var baked = state.EntityManager.GetComponentData<LocalTransform>(prefabs[prefabIdx].Prefab);
|
||||||
|
ecb.SetComponent(husk, baked.WithPosition(pos));
|
||||||
// Husks belong to the base region (hidden from expedition players by relevancy).
|
// Husks belong to the base region (hidden from expedition players by relevancy).
|
||||||
ecb.AddComponent(husk, new RegionTag { Region = RegionId.Base });
|
ecb.AddComponent(husk, new RegionTag { Region = RegionId.Base });
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
|||||||
@@ -28,5 +28,16 @@ namespace ProjectM.Simulation
|
|||||||
local = math.clamp(local, -1f, 1f);
|
local = math.clamp(local, -1f, 1f);
|
||||||
return new float3(local.x, local.y, speed);
|
return new float3(local.x, local.y, speed);
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Planar (XZ) forward from a world rotation, normalized. Degenerate -> world +Z. Used as the facing
|
||||||
|
/// for enemies (the server writes LocalTransform.Rotation toward the target each tick in EnemyAISystem).
|
||||||
|
/// </summary>
|
||||||
|
public static float2 PlanarForward(quaternion rot)
|
||||||
|
{
|
||||||
|
float3 f = math.mul(rot, new float3(0f, 0f, 1f));
|
||||||
|
float2 p = f.xz;
|
||||||
|
return math.lengthsq(p) > 1e-6f ? math.normalize(p) : new float2(0f, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -705,9 +705,9 @@ MonoBehaviour:
|
|||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.WaveDirectorAuthoring
|
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.WaveDirectorAuthoring
|
||||||
EnemyPrefabs:
|
EnemyPrefabs:
|
||||||
- {fileID: 3885353946372160549, guid: 84c92c40b6b720441ac3a78870c0bba4, type: 3}
|
- {fileID: 3885353946372160549, guid: a6c2004a3cc32cc44b1bb7a795f86519, type: 3}
|
||||||
- {fileID: 3885353946372160549, guid: 9855c5a5d578bb74ba2fb0d41a73a3b9, type: 3}
|
- {fileID: 3885353946372160549, guid: f77a36036567c814496e6c59c42b2082, type: 3}
|
||||||
- {fileID: 3885353946372160549, guid: 1bc4c3736da534a42a7040fcbe9c92d5, type: 3}
|
- {fileID: 3885353946372160549, guid: 31d233e9e507acf45a411f8ab0997bed, type: 3}
|
||||||
RingRadius: 16
|
RingRadius: 16
|
||||||
RingSlots: 10
|
RingSlots: 10
|
||||||
BaseCount: 4
|
BaseCount: 4
|
||||||
|
|||||||
Reference in New Issue
Block a user