Fix snake animation by using original controller with state name overrides

Instead of replacing the Viper's animator controller (which broke bone
bindings for cross-FBX Generic animations), keep the original
Viper_anim_controller and add configurable state name overrides to
AnimalEffect. SnakeEffect now maps walk→glide and eat→hiss so the
Viper's native state names are used without controller replacement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-15 16:35:13 -07:00
co-authored by Claude Opus 4.6
parent caf334208e
commit 8479197684
4 changed files with 22 additions and 167 deletions
@@ -27,6 +27,12 @@ namespace eagle {
"Per-prefab controller overrides (index matches animalPrefabs); takes priority over animatorController")]
public RuntimeAnimatorController[] animatorControllers;
[Header("State Name Overrides")]
[Tooltip("Override walk state name for prefabs with non-standard names (e.g. 'glide')")]
public string walkStateName;
[Tooltip("Override eat state name for prefabs with non-standard names (e.g. 'hiss')")]
public string eatStateName;
[Header("Behavior Timing")]
public float minIdleDuration = 1f;
public float maxIdleDuration = 3f;
@@ -53,7 +59,16 @@ namespace eagle {
private static readonly int AttackHash = Animator.StringToHash("attack");
private static readonly int DieHash = Animator.StringToHash("die");
void Start() { SpawnAnimals(); }
private int _walkHash;
private int _eatHash;
void Start() {
_walkHash = string.IsNullOrEmpty(walkStateName) ? WalkHash
: Animator.StringToHash(walkStateName);
_eatHash = string.IsNullOrEmpty(eatStateName) ? EatHash
: Animator.StringToHash(eatStateName);
SpawnAnimals();
}
private void SpawnAnimals() {
if (animalPrefabs == null || animalPrefabs.Length == 0) { return; }
@@ -177,7 +192,7 @@ namespace eagle {
animal.targetPosition = RandomWanderPoint();
animal.state = AnimalStateType.Walking;
if (animal.animator != null) { animal.animator.Play(WalkHash); }
if (animal.animator != null) { animal.animator.Play(_walkHash); }
UpdateFacing(animal);
}
@@ -196,7 +211,7 @@ namespace eagle {
animal.state = AnimalStateType.Action;
animal.timer = actionDuration;
if (animal.animator != null) {
var actionHash = Random.value < 0.5f ? EatHash : AttackHash;
var actionHash = Random.value < 0.5f ? _eatHash : AttackHash;
animal.animator.Play(actionHash);
}
} else {
@@ -233,10 +248,10 @@ namespace eagle {
public void TestAllIdle() { ForEachAnimal(a => a.animator?.Play(IdleHash)); }
[ContextMenu("Test: All Walk")]
public void TestAllWalk() { ForEachAnimal(a => a.animator?.Play(WalkHash)); }
public void TestAllWalk() { ForEachAnimal(a => a.animator?.Play(_walkHash)); }
[ContextMenu("Test: All Eat")]
public void TestAllEat() { ForEachAnimal(a => a.animator?.Play(EatHash)); }
public void TestAllEat() { ForEachAnimal(a => a.animator?.Play(_eatHash)); }
[ContextMenu("Test: All Attack")]
public void TestAllAttack() { ForEachAnimal(a => a.animator?.Play(AttackHash)); }
@@ -54,7 +54,8 @@ MonoBehaviour:
wanderRadius: 25
moveSpeed: 15
animalScale: 15
animatorController: {fileID: 9100000, guid: f694a1bb8f8748a4bf2937a7afd60a29, type: 2}
walkStateName: glide
eatStateName: hiss
minIdleDuration: 1
maxIdleDuration: 3
actionChance: 0.3
@@ -1,153 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: SnakeMapAnims
serializedVersion: 5
m_AnimatorParameters: []
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base Layer
m_StateMachine: {fileID: 1107000000000000001}
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!1102 &1102000000000000001
AnimatorState:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: 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: 974b76380f4081b4d8b71e8e71866148, type: 3}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &1102000000000000002
AnimatorState:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: walk
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: 2490283384abd97439078698349e4df6, type: 3}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &1102000000000000003
AnimatorState:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: eat
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: a82e9ab873cf7684f976bfbbab5ea248, type: 3}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &1102000000000000004
AnimatorState:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: attack
m_Speed: 1.5
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: ece558e9746786a4da7e6f14c27ae3e8, type: 3}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &1107000000000000001
AnimatorStateMachine:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Base Layer
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 1102000000000000001}
m_Position: {x: 300, y: 100, z: 0}
- serializedVersion: 1
m_State: {fileID: 1102000000000000002}
m_Position: {x: 300, y: 200, z: 0}
- serializedVersion: 1
m_State: {fileID: 1102000000000000003}
m_Position: {x: 300, y: 300, z: 0}
- serializedVersion: 1
m_State: {fileID: 1102000000000000004}
m_Position: {x: 300, y: 400, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
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: 1102000000000000001}
@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: f694a1bb8f8748a4bf2937a7afd60a29
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant: