182 lines
8.1 KiB
C#
182 lines
8.1 KiB
C#
#if UNITY_EDITOR
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using UnityEditor.Animations;
|
|
using UnityEngine;
|
|
|
|
public static class BuildZibuAnimator
|
|
{
|
|
[MenuItem("Tools/Zibu/Build Animator Controller")]
|
|
public static void Build()
|
|
{
|
|
const string animationsFolder = "Assets/Animations";
|
|
const string controllerPath = "Assets/Zibu_Animator.controller";
|
|
|
|
var allClips = AssetDatabase.FindAssets("t:AnimationClip", new[] { animationsFolder })
|
|
.Select(AssetDatabase.GUIDToAssetPath)
|
|
.Select(AssetDatabase.LoadAssetAtPath<AnimationClip>)
|
|
.Where(c => c != null)
|
|
.ToList();
|
|
|
|
AnimationClip Find(string contains)
|
|
=> allClips.FirstOrDefault(c => c.name.ToLower().Contains(contains.ToLower()));
|
|
|
|
// Core clips
|
|
var idle = Find("Zibu_Idle") ?? Find("Idle");
|
|
var run = Find("Zibu_Run");
|
|
var runFast = Find("Zibu_RunFast");
|
|
var sprint = Find("Zibu_Sprint");
|
|
var runBackward = Find("Run_Backward");
|
|
var jumpStart = Find("JumpStart") ?? Find("Jump_Start_IPC") ?? Find("JumpOriginal");
|
|
var airLoop = Find("Falling_Loop") ?? Find("Falling") ?? Find("Fall");
|
|
var land = Find("JumpEnd") ?? Find("JumpEnd_Add") ?? Find("JumpEndOld");
|
|
var dblJump = Find("DoubleJump_inPlace_Short") ?? Find("DoubleJump_inPlace") ?? Find("DoubleJump");
|
|
|
|
var kickL = Find("Side_Kick_L");
|
|
var kickR = Find("Side_Kick_R");
|
|
var charge = Find("Shu_Charge");
|
|
|
|
var leanL = Find("Run_Lean_L");
|
|
var leanR = Find("Run_Lean_R");
|
|
|
|
// Create controller
|
|
var controller = AnimatorController.CreateAnimatorControllerAtPath(controllerPath);
|
|
var rootSM = controller.layers[0].stateMachine;
|
|
|
|
// Parameters
|
|
controller.AddParameter("Speed", AnimatorControllerParameterType.Float);
|
|
controller.AddParameter("Turn", AnimatorControllerParameterType.Float);
|
|
controller.AddParameter("IsGrounded", AnimatorControllerParameterType.Bool);
|
|
controller.AddParameter("Jump", AnimatorControllerParameterType.Trigger);
|
|
controller.AddParameter("DoubleJump", AnimatorControllerParameterType.Trigger);
|
|
controller.AddParameter("Land", AnimatorControllerParameterType.Trigger);
|
|
controller.AddParameter("AttackType", AnimatorControllerParameterType.Int);
|
|
controller.AddParameter("Hit", AnimatorControllerParameterType.Trigger);
|
|
|
|
// States
|
|
var idleState = rootSM.AddState("Idle");
|
|
idleState.motion = idle;
|
|
|
|
// Locomotion blend tree
|
|
var locomotion = rootSM.AddState("Locomotion");
|
|
var bt = new BlendTree { name = "BT_Locomotion", blendParameter = "Speed", useAutomaticThresholds = false };
|
|
AssetDatabase.AddObjectToAsset(bt, controller);
|
|
locomotion.motion = bt;
|
|
|
|
var motions = new List<(AnimationClip clip, float thr)>
|
|
{
|
|
(idle, 0f),
|
|
(run, 1f),
|
|
(runFast, 2f),
|
|
(sprint, 3f),
|
|
}.Where(m => m.clip != null).ToList();
|
|
|
|
bt.children = motions.Select(m => new ChildMotion { motion = m.clip, threshold = m.thr }).ToArray();
|
|
|
|
// Backward (optional)
|
|
AnimatorState backwardState = null;
|
|
if (runBackward != null)
|
|
{
|
|
backwardState = rootSM.AddState("RunBackward");
|
|
backwardState.motion = runBackward;
|
|
}
|
|
|
|
// Jump sub-state machine
|
|
var jumpSM = rootSM.AddStateMachine("Jump");
|
|
var stJumpStart = jumpSM.AddState("JumpStart"); stJumpStart.motion = jumpStart;
|
|
var stAirLoop = jumpSM.AddState("AirLoop"); stAirLoop.motion = airLoop;
|
|
var stDouble = jumpSM.AddState("DoubleJump"); stDouble.motion = dblJump;
|
|
var stLand = jumpSM.AddState("Land"); stLand.motion = land;
|
|
|
|
// Entry → JumpStart
|
|
jumpSM.defaultState = stJumpStart;
|
|
stJumpStart.AddTransition(stAirLoop).hasExitTime = true;
|
|
|
|
// AirLoop → DoubleJump (on trigger)
|
|
var tAirToDouble = stAirLoop.AddTransition(stDouble);
|
|
tAirToDouble.hasExitTime = false; tAirToDouble.AddCondition(AnimatorConditionMode.If, 0, "DoubleJump");
|
|
|
|
// AirLoop → Land (when grounded)
|
|
var tAirToLand = stAirLoop.AddTransition(stLand);
|
|
tAirToLand.hasExitTime = false; tAirToLand.AddCondition(AnimatorConditionMode.If, 0, "IsGrounded");
|
|
|
|
// Land → Exit
|
|
var tLandExit = stLand.AddExitTransition(); tLandExit.hasExitTime = true; tLandExit.exitTime = 0.9f;
|
|
|
|
// Base transitions
|
|
// Idle <-> Locomotion
|
|
var tIdleToLoc = idleState.AddTransition(locomotion); tIdleToLoc.hasExitTime = false;
|
|
tIdleToLoc.AddCondition(AnimatorConditionMode.Greater, 0.1f, "Speed");
|
|
var tLocToIdle = locomotion.AddTransition(idleState); tLocToIdle.hasExitTime = false;
|
|
tLocToIdle.AddCondition(AnimatorConditionMode.Less, 0.1f, "Speed");
|
|
|
|
// Backward
|
|
if (backwardState != null)
|
|
{
|
|
var tLocToBack = locomotion.AddTransition(backwardState); tLocToBack.hasExitTime = false;
|
|
tLocToBack.AddCondition(AnimatorConditionMode.Less, -0.1f, "Speed");
|
|
var tBackToLoc = backwardState.AddTransition(locomotion); tBackToLoc.hasExitTime = false;
|
|
tBackToLoc.AddCondition(AnimatorConditionMode.Greater, 0.1f, "Speed");
|
|
}
|
|
|
|
// AnyState → Jump (trigger)
|
|
var tAnyToJump = rootSM.AddAnyStateTransition(jumpSM.defaultState);
|
|
tAnyToJump.hasExitTime = false; tAnyToJump.AddCondition(AnimatorConditionMode.If, 0, "Jump");
|
|
|
|
// Jump Land → Locomotion when grounded
|
|
var tLandToLoc = stLand.AddTransition(locomotion);
|
|
tLandToLoc.hasExitTime = false;
|
|
tLandToLoc.AddCondition(AnimatorConditionMode.If, 0, "IsGrounded");
|
|
// Attack Upper Body Layer
|
|
var upper = new AnimatorControllerLayer { name = "UpperBody", defaultWeight = 1f, stateMachine = new AnimatorStateMachine() };
|
|
AssetDatabase.AddObjectToAsset(upper.stateMachine, controller);
|
|
controller.AddLayer(upper);
|
|
var smU = upper.stateMachine;
|
|
if (kickL != null) smU.AddState("SideKickL").motion = kickL;
|
|
if (kickR != null) smU.AddState("SideKickR").motion = kickR;
|
|
if (charge != null) smU.AddState("Charge").motion = charge;
|
|
|
|
// Simple routing by AttackType
|
|
if (kickL != null)
|
|
{
|
|
var t = smU.AddAnyStateTransition(smU.states.First(s => s.state.name == "SideKickL").state);
|
|
t.hasExitTime = false; t.AddCondition(AnimatorConditionMode.Equals, 1, "AttackType");
|
|
}
|
|
if (kickR != null)
|
|
{
|
|
var t = smU.AddAnyStateTransition(smU.states.First(s => s.state.name == "SideKickR").state);
|
|
t.hasExitTime = false; t.AddCondition(AnimatorConditionMode.Equals, 2, "AttackType");
|
|
}
|
|
if (charge != null)
|
|
{
|
|
var t = smU.AddAnyStateTransition(smU.states.First(s => s.state.name == "Charge").state);
|
|
t.hasExitTime = false; t.AddCondition(AnimatorConditionMode.Equals, 3, "AttackType");
|
|
}
|
|
|
|
// Optional Lean Additive Layer
|
|
if (leanL != null && leanR != null)
|
|
{
|
|
var leanLayer = new AnimatorControllerLayer { name = "LeanAdd", defaultWeight = 1f, stateMachine = new AnimatorStateMachine(), blendingMode = AnimatorLayerBlendingMode.Additive };
|
|
AssetDatabase.AddObjectToAsset(leanLayer.stateMachine, controller);
|
|
controller.AddLayer(leanLayer);
|
|
var smLean = leanLayer.stateMachine;
|
|
|
|
var btLean = new BlendTree { name = "BT_Lean", blendParameter = "Turn", useAutomaticThresholds = false };
|
|
AssetDatabase.AddObjectToAsset(btLean, controller);
|
|
btLean.children = new[]
|
|
{
|
|
new ChildMotion { motion = leanL, threshold = -1f },
|
|
new ChildMotion { motion = leanR, threshold = 1f },
|
|
};
|
|
var leanState = smLean.AddState("LeanBlend");
|
|
leanState.motion = btLean;
|
|
}
|
|
|
|
EditorUtility.SetDirty(controller);
|
|
AssetDatabase.SaveAssets();
|
|
Debug.Log("Zibu Animator built at: " + controllerPath);
|
|
}
|
|
}
|
|
#endif
|