EditorTool3D/Assets/TriLib/TriLibSamples/LoadExtraAnimations/Scripts/LoadExtraAnimationsSample.cs

184 lines
7.4 KiB
C#

#pragma warning disable 649
using System.Collections.Generic;
using TriLibCore.Extensions;
using TriLibCore.Utils;
using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace TriLibCore.Samples
{
/// <summary>
/// Represents a sample that loads a base Model and adds extra Animations from other Models to it.
/// </summary>
public class LoadExtraAnimationsSample : MonoBehaviour
{
#if UNITY_EDITOR
/// <summary>
/// The Base Model asset used to locate the filename when running in Unity Editor.
/// </summary>
[SerializeField]
private Object BaseModelAsset;
#endif
/// <summary>
/// Returns the path to the base "BuddyBase.fbx" Model.
/// </summary>
private string BaseModelPath
{
get
{
#if UNITY_EDITOR
return AssetDatabase.GetAssetPath(BaseModelAsset);
#else
return "Models/BuddyBase.fbx";
#endif
}
}
/// <summary>
/// Button to instantiate when a new Animation is loaded.
/// </summary>
[SerializeField]
private Button _playAnimationTemplate;
/// <summary>
/// The Animation Component from the base Model.
/// </summary>
private Animation _baseAnimation;
/// <summary>
/// Gathers the AssetLoaderContext from the loaded Animations.
/// This list is used to process the Animations if the Animations are loaded before the base Model.
/// </summary>
private readonly IList<AssetLoaderContext> _loadedAnimations = new List<AssetLoaderContext>();
/// <summary>
/// Loads the "Models/BuddyBase.fbx" Model, then loads all the extra Animations in the same folder.
/// </summary>
private void Start()
{
LoadBaseModel();
LoadAnimation("BuddyIdle.fbx");
LoadAnimation("BuddyWalk.fbx");
LoadAnimation("BuddyJump.fbx");
}
/// <summary>
/// Loads the Animations from the given Model.
/// </summary>
/// <param name="modelFilename">The animated Model filename under the same folder as the base Model.</param>
private void LoadAnimation(string modelFilename)
{
var modelsDirectory = FileUtils.GetFileDirectory(BaseModelPath);
var modelPath = FileUtils.SanitizePath($"{modelsDirectory}/{modelFilename}");
var assetLoaderOptions = AssetLoader.CreateDefaultLoaderOptions();
assetLoaderOptions.ImportMeshes = false;
assetLoaderOptions.ImportTextures = false;
assetLoaderOptions.ImportMaterials = false;
AssetLoader.LoadModelFromFile(modelPath, OnAnimationModelLoad, null, OnProgress, OnError, gameObject, assetLoaderOptions);
}
/// <summary>
/// Gathers all Animations from the loaded Model and adds them to the base Model Animation Component.
/// </summary>
/// <param name="assetLoaderContext">The context used to load the Model.</param>
private void OnAnimationModelLoad(AssetLoaderContext assetLoaderContext)
{
Debug.Log($"Animation loaded: {FileUtils.GetShortFilename(assetLoaderContext.Filename)}");
if (_baseAnimation != null)
{
AddAnimation(assetLoaderContext);
}
else
{
_loadedAnimations.Add(assetLoaderContext);
}
assetLoaderContext.RootGameObject.SetActive(false);
}
/// <summary>
/// Adds the Animation Clips from the given AssetLoaderContext RootGameObject to the base Model Animations list.
/// </summary>
/// <param name="loadedAnimationContext">The AssetLoaderContext containing the loaded Animation component.</param>
private void AddAnimation(AssetLoaderContext loadedAnimationContext)
{
var rootGameObjectAnimation = loadedAnimationContext.RootGameObject.GetComponent<Animation>();
if (rootGameObjectAnimation != null)
{
var shortFilename = FileUtils.GetShortFilename(loadedAnimationContext.Filename);
var newAnimationClips = rootGameObjectAnimation.GetAllAnimationClips();
foreach (var newAnimationClip in newAnimationClips)
{
var animationName = $"{shortFilename}_{newAnimationClip.name}";
_baseAnimation.AddClip(newAnimationClip, animationName);
var playAnimationButton = Instantiate(_playAnimationTemplate, _playAnimationTemplate.transform.parent);
var playAnimationButtonText = playAnimationButton.GetComponentInChildren<Text>();
playAnimationButtonText.text = shortFilename;
playAnimationButton.gameObject.SetActive(true);
playAnimationButton.onClick.AddListener(delegate
{
_baseAnimation.CrossFade(animationName);
});
}
}
Destroy(loadedAnimationContext.RootGameObject);
}
/// <summary>
/// Loads the Model from BaseModelPath including all Model data.
/// </summary>
private void LoadBaseModel()
{
var assetLoaderOptions = AssetLoader.CreateDefaultLoaderOptions();
AssetLoader.LoadModelFromFile(BaseModelPath, OnBaseModelLoad, OnBaseModelMaterialsLoad, OnProgress, OnError, gameObject, assetLoaderOptions);
}
/// <summary>
/// Called when any error occurs.
/// </summary>
/// <param name="obj">The contextualized error, containing the original exception and the context passed to the method where the error was thrown.</param>
private void OnError(IContextualizedError obj)
{
Debug.LogError($"An error occurred while loading your Model: {obj.GetInnerException()}");
}
/// <summary>
/// Called when a Model loading progress changes.
/// </summary>
/// <param name="assetLoaderContext">The context used to load the Model.</param>
/// <param name="progress">The loading progress.</param>
private void OnProgress(AssetLoaderContext assetLoaderContext, float progress)
{
}
/// <summary>
/// Called when the Base Model (including Textures and Materials) has been fully loaded.
/// This method processes previously loaded Animations from the loaded Animations list.
/// </summary>
/// <param name="assetLoaderContext">The context used to load the Model.</param>
private void OnBaseModelMaterialsLoad(AssetLoaderContext assetLoaderContext)
{
Debug.Log($"Base Model loaded:{FileUtils.GetShortFilename(assetLoaderContext.Filename)}");
_baseAnimation = assetLoaderContext.RootGameObject.GetComponent<Animation>();
for (var i = _loadedAnimations.Count - 1; i >= 0; i--)
{
AddAnimation(_loadedAnimations[i]);
_loadedAnimations.RemoveAt(i);
}
}
/// <summary>
/// Called when the Base Model Meshes and hierarchy are loaded.
/// </summary>
/// <param name="assetLoaderContext">The context used to load the Model.</param>
private void OnBaseModelLoad(AssetLoaderContext assetLoaderContext)
{
}
}
}