2024-01-11 13:33:30 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using cfg.VehicleCfg;
|
|
|
|
|
|
using Framework;
|
2024-01-15 12:12:47 +08:00
|
|
|
|
using Gameplay.Utils;
|
2024-01-11 13:33:30 +08:00
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using UnityEditor.Animations;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
namespace VehicleBuilder
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 所有动作都可以没有
|
|
|
|
|
|
/// body使用的animator Assets/Art/Animations/animator/Vehicle/animator_vehicle.controller
|
|
|
|
|
|
/// body需要的动作 Assets/Art/Animations/Vehicle/C00001/ani_C00001_D_dead.fbx
|
|
|
|
|
|
/// dead
|
|
|
|
|
|
/// idle
|
|
|
|
|
|
/// move
|
|
|
|
|
|
/// restart
|
|
|
|
|
|
/// stop
|
|
|
|
|
|
/// skill
|
|
|
|
|
|
/// battery使用的animator Assets/Art/Animations/animator/Battery/animator_battery.controller
|
|
|
|
|
|
/// battery需要的动作 Assets/Art/Animations/Battery/R00001/ani_R00001_attack01.fbx
|
|
|
|
|
|
/// attack01
|
|
|
|
|
|
/// idle
|
|
|
|
|
|
/// skill
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class VehicleBuildData
|
|
|
|
|
|
{
|
|
|
|
|
|
public DataVehicle vehicleConfig;
|
|
|
|
|
|
|
|
|
|
|
|
public bool isChecked;
|
|
|
|
|
|
|
|
|
|
|
|
public string bodyName;
|
|
|
|
|
|
public string batteryName;
|
|
|
|
|
|
|
|
|
|
|
|
public string errorInfo;
|
|
|
|
|
|
|
|
|
|
|
|
private string _prefabPath;
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
private string[] _bodyAniNames = new string[]
|
|
|
|
|
|
{
|
|
|
|
|
|
"dead",
|
|
|
|
|
|
"idle",
|
|
|
|
|
|
"move",
|
|
|
|
|
|
"restart",
|
|
|
|
|
|
"stop",
|
|
|
|
|
|
// "skill",
|
|
|
|
|
|
};
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
public void Init()
|
|
|
|
|
|
{
|
2024-01-15 12:12:47 +08:00
|
|
|
|
var prefabPath = PathEx.GetVehicleSrcModelPath(vehicleConfig.PrefabPath);
|
2024-01-11 13:33:30 +08:00
|
|
|
|
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
|
|
|
|
|
if (prefab == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
errorInfo = $"载具预制体不存在:{prefabPath}";
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
_prefabPath = prefabPath;
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
var prefabName = prefab.name;
|
|
|
|
|
|
var splits = prefabName.Split('_');
|
2024-09-26 16:29:21 +08:00
|
|
|
|
if (splits.Length != 3)
|
2024-01-11 13:33:30 +08:00
|
|
|
|
{
|
|
|
|
|
|
errorInfo = $"prefab命名错误:{prefabName}";
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-09-26 16:29:21 +08:00
|
|
|
|
bodyName = splits[1];
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
// 检查所有bodyanims
|
|
|
|
|
|
for (var i = 0; i < _bodyAniNames.Length; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
var bodyAnimName = _bodyAniNames[i];
|
|
|
|
|
|
var combinePath = $"Assets/Art/Animations/Vehicle/{bodyName}/ani_{bodyName}_D_{bodyAnimName}.fbx";
|
|
|
|
|
|
var loadAnim = AssetDatabase.LoadAssetAtPath<AnimationClip>(combinePath);
|
|
|
|
|
|
if (loadAnim == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
errorInfo = $"不存在需求动作: {combinePath}";
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
public void DoBuild()
|
|
|
|
|
|
{
|
|
|
|
|
|
var savePath = string.Format(Constants.VEHICLE_OUTPUT_PATH, vehicleConfig.ID);
|
|
|
|
|
|
var realPath = savePath.Replace("Assets", Application.dataPath);
|
|
|
|
|
|
if (!Directory.Exists(realPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(realPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var loadPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(_prefabPath);
|
2024-09-25 17:29:25 +08:00
|
|
|
|
if (loadPrefab == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"找不到载具预制体:{_prefabPath}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
loadPrefab = Object.Instantiate(loadPrefab);
|
2024-01-11 13:33:30 +08:00
|
|
|
|
_HandlePrefab(loadPrefab, savePath);
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
var savePrefabPath = $"{savePath}/vehicle_{vehicleConfig.ID}.prefab";
|
|
|
|
|
|
PrefabUtility.SaveAsPrefabAsset(loadPrefab, savePrefabPath);
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-09-25 17:29:25 +08:00
|
|
|
|
// 销毁prefab
|
|
|
|
|
|
Object.DestroyImmediate(loadPrefab);
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
Debug.Log($"生成载具预制体:{savePrefabPath}");
|
|
|
|
|
|
}
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
private void _HandlePrefab(GameObject prefab, string savePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
var allTrans = new List<Transform>();
|
|
|
|
|
|
_DeepSearchTrans(prefab.transform, allTrans);
|
|
|
|
|
|
var findBody = _SearchByName(allTrans, bodyName);
|
|
|
|
|
|
if (findBody == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"找不到body:{bodyName}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-09-25 17:29:25 +08:00
|
|
|
|
// 删除炮台
|
|
|
|
|
|
var findBattery = _SearchByName(allTrans, "Battery_point01");
|
2024-09-26 16:47:52 +08:00
|
|
|
|
if (findBattery != null && findBattery.childCount > 0)
|
2024-01-11 13:33:30 +08:00
|
|
|
|
{
|
2024-09-25 17:29:25 +08:00
|
|
|
|
var child = findBattery.GetChild(0);
|
|
|
|
|
|
if (child != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Object.DestroyImmediate(child.gameObject);
|
|
|
|
|
|
}
|
2024-01-11 13:33:30 +08:00
|
|
|
|
}
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
// 处理body
|
|
|
|
|
|
_HandleBody(savePath, findBody);
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
EditorUtility.SetDirty(prefab);
|
|
|
|
|
|
AssetDatabase.SaveAssets();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void _HandleBattery(string savePath,
|
|
|
|
|
|
Transform findBattery)
|
|
|
|
|
|
{
|
|
|
|
|
|
var srcController = AssetDatabase.LoadAssetAtPath<AnimatorController>("Assets/Art/Animations/animator/Battery/animator_battery.controller");
|
|
|
|
|
|
if (srcController == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"找不到animator_battery.controller");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 创建一个overrideController
|
|
|
|
|
|
var overrideController = new AnimatorOverrideController();
|
|
|
|
|
|
overrideController.runtimeAnimatorController = srcController;
|
|
|
|
|
|
// 设置动作
|
|
|
|
|
|
var kvList = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
|
|
|
|
|
var oldClips = overrideController.animationClips;
|
|
|
|
|
|
for (int i = 0; i < oldClips.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var oldClip = oldClips[i];
|
|
|
|
|
|
var oldClipName = oldClip.name;
|
|
|
|
|
|
// ani_R00001_attack01
|
|
|
|
|
|
var splits = oldClipName.Split('_');
|
|
|
|
|
|
var finalName = splits[^1];
|
|
|
|
|
|
var newClipPath = $"Assets/Art/Animations/Battery/{batteryName}/ani_{batteryName}_{finalName}.fbx";
|
|
|
|
|
|
var newClip = AssetDatabase.LoadAssetAtPath<AnimationClip>(newClipPath);
|
|
|
|
|
|
if (newClip == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"找不到动作:{newClipPath}");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
kvList.Add(new KeyValuePair<AnimationClip, AnimationClip>(oldClip, newClip));
|
|
|
|
|
|
}
|
|
|
|
|
|
overrideController.ApplyOverrides(kvList);
|
|
|
|
|
|
// 保存controller
|
|
|
|
|
|
var saveControllerPath = $"{savePath}/ov_battery_{vehicleConfig.ID}.controller";
|
|
|
|
|
|
AssetDatabase.CreateAsset(overrideController, saveControllerPath);
|
|
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
|
|
overrideController = AssetDatabase.LoadAssetAtPath<AnimatorOverrideController>(saveControllerPath);
|
|
|
|
|
|
// 设置battery的animator
|
|
|
|
|
|
var batteryAnimator = findBattery.GetComponent<Animator>();
|
|
|
|
|
|
if (batteryAnimator == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
batteryAnimator = findBattery.gameObject.AddComponent<Animator>();
|
|
|
|
|
|
}
|
|
|
|
|
|
batteryAnimator.runtimeAnimatorController = overrideController;
|
|
|
|
|
|
batteryAnimator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
|
|
|
|
|
|
}
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
private void _HandleBody(string savePath,
|
|
|
|
|
|
Transform findBody)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
var srcController = AssetDatabase.LoadAssetAtPath<AnimatorController>("Assets/Art/Animations/animator/Vehicle/animator_vehicle.controller");
|
|
|
|
|
|
if (srcController == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"找不到animator_vehicle.controller");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 创建一个overrideController
|
|
|
|
|
|
var overrideController = new AnimatorOverrideController();
|
|
|
|
|
|
overrideController.runtimeAnimatorController = srcController;
|
|
|
|
|
|
// 设置动作
|
|
|
|
|
|
var kvList = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
|
|
|
|
|
var oldClips = overrideController.animationClips;
|
|
|
|
|
|
for (int i = 0; i < oldClips.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var oldClip = oldClips[i];
|
|
|
|
|
|
var oldClipName = oldClip.name;
|
|
|
|
|
|
// ani_C00001_D_idle
|
|
|
|
|
|
var splits = oldClipName.Split('_');
|
|
|
|
|
|
var finalName = splits[^1];
|
|
|
|
|
|
var newClipPath = $"Assets/Art/Animations/Vehicle/{bodyName}/ani_{bodyName}_D_{finalName}.fbx";
|
|
|
|
|
|
var newClip = AssetDatabase.LoadAssetAtPath<AnimationClip>(newClipPath);
|
|
|
|
|
|
if (newClip == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"找不到动作:{newClipPath}");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
kvList.Add(new KeyValuePair<AnimationClip, AnimationClip>(oldClip, newClip));
|
|
|
|
|
|
}
|
|
|
|
|
|
overrideController.ApplyOverrides(kvList);
|
2024-11-07 16:41:41 +08:00
|
|
|
|
_CompressOverrideController(overrideController);
|
|
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
// 保存controller
|
|
|
|
|
|
var saveControllerPath = $"{savePath}/ov_vehicle_{vehicleConfig.ID}.controller";
|
|
|
|
|
|
AssetDatabase.CreateAsset(overrideController, saveControllerPath);
|
|
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
|
|
overrideController = AssetDatabase.LoadAssetAtPath<AnimatorOverrideController>(saveControllerPath);
|
|
|
|
|
|
// 设置body的animator
|
|
|
|
|
|
var bodyAnimator = findBody.GetComponent<Animator>();
|
|
|
|
|
|
if (bodyAnimator == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
bodyAnimator = findBody.gameObject.AddComponent<Animator>();
|
|
|
|
|
|
}
|
|
|
|
|
|
bodyAnimator.runtimeAnimatorController = overrideController;
|
|
|
|
|
|
bodyAnimator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
|
|
|
|
|
|
}
|
2024-11-07 16:41:41 +08:00
|
|
|
|
|
|
|
|
|
|
private void _CompressOverrideController(AnimatorOverrideController overrideController)
|
|
|
|
|
|
{
|
|
|
|
|
|
var overrideClips = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
|
|
|
|
|
overrideController.GetOverrides(overrideClips);
|
|
|
|
|
|
var newClips = new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
|
|
|
|
|
foreach (var oldKV in overrideClips)
|
|
|
|
|
|
{
|
|
|
|
|
|
var srcClip = oldKV.Key;
|
|
|
|
|
|
var dstClip = oldKV.Value;
|
|
|
|
|
|
if (dstClip == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
dstClip = srcClip;
|
|
|
|
|
|
}
|
|
|
|
|
|
var newClip = LTCompressor.AutoCompress(dstClip);
|
|
|
|
|
|
newClips.Add(new KeyValuePair<AnimationClip, AnimationClip>(srcClip, newClip));
|
|
|
|
|
|
}
|
|
|
|
|
|
overrideController.ApplyOverrides(newClips);
|
|
|
|
|
|
}
|
2024-01-11 13:33:30 +08:00
|
|
|
|
|
|
|
|
|
|
private static Transform _SearchByName(List<Transform> searchList, string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < searchList.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var trans = searchList[i];
|
|
|
|
|
|
if (trans.name == name)
|
|
|
|
|
|
{
|
|
|
|
|
|
return trans;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void _DeepSearchTrans(Transform searchTrans, List<Transform> result)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add(searchTrans);
|
|
|
|
|
|
for (int i = 0; i < searchTrans.childCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var child = searchTrans.GetChild(i);
|
|
|
|
|
|
_DeepSearchTrans(child, result);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-09-26 16:47:52 +08:00
|
|
|
|
|
2024-01-11 13:33:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|