Files
MinFt/Client/Assets/Editor/CampTool/CampToolEditor.cs
Liubing\LB 3d8d4d18f3 first commit
先修复一下,错误的场景

删除不必要的钓场资产

修复into场景

update:更新meta文件,修复报错

update:修复资源

修复第一章节建造

修复建造第三章

update:删除多余内容

update:更新README.md

update:还原图标

update:更新README

update:更新配置
2026-04-28 02:17:22 +08:00

318 lines
12 KiB
C#

using System.Collections.Generic;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
[CustomEditor(typeof(CampTool))]
public class CampToolEditor : Editor
{
CampTool Temp;
public override void OnInspectorGUI()
{
//DrawDefaultInspector();
Temp = (CampTool)target;
// 显示文件夹路径
EditorGUILayout.LabelField("保存路径: " + Temp.folderPath);
if (GUILayout.Button("选择"))
{
// Temp.folderPath = EditorUtility.OpenFolderPanel("选择文件夹", Temp.folderPath, "");
var absPath = EditorUtility.OpenFolderPanel("选择文件夹", Temp.folderPath, "");
Temp.folderPath = absPath.Substring(absPath.IndexOf("Assets/"));
EditorUtility.SetDirty(Temp);
EditorSceneManager.SaveOpenScenes();
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("dynamic"));
EditorGUILayout.BeginVertical("box");
EditorGUILayout.Space();
GUIStyle labelStyle = new GUIStyle(GUI.skin.label);
labelStyle.normal.textColor = Color.red; // Set the color you want
labelStyle.fontStyle = FontStyle.BoldAndItalic;
labelStyle.fontSize = 20;
labelStyle.wordWrap = true;
string labelText = "模版动画中每一个轨道,在动画最后一帧必须有关键帧,因为拿每一条轨道的最后一帧时间播放音效";
float labelHeight = labelStyle.CalcHeight(new GUIContent(labelText), EditorGUIUtility.currentViewWidth - 40);
EditorGUILayout.LabelField(labelText, labelStyle, GUILayout.Height(labelHeight));
EditorGUILayout.LabelField("生成初始动画", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(serializedObject.FindProperty("steps"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("targetLength"));
if (GUILayout.Button("Apply"))
{
Play();
}
EditorGUILayout.Space();
EditorGUILayout.EndVertical();
//间隔
EditorGUILayout.Space(10);
EditorGUILayout.BeginVertical("box");
EditorGUILayout.LabelField("后续修改音效", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(serializedObject.FindProperty("audioChangeDatas"));
if (GUILayout.Button("ChangeAudio"))
{
ChangeAudio();
}
EditorGUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
public void Play()
{
for (int n = 0; n < Temp.steps.Length; n++)
{
StepRootData step = Temp.steps[n];
Transform root2 = step.StepRoot;
Transform root1 = root2.parent;
string path1 = root1.name;
string path2 = root2.name;
//创建新的AnimationClip
AnimationClip newAni = new AnimationClip();
if (string.IsNullOrEmpty(step.newAniName))
{
newAni.name = $"{path1}_{path2}";
}
else
{
newAni.name = step.newAniName;
}
List<int> timeList = new List<int>();
EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(step.ani);
int count = root2.childCount;
float bindingTime = 0f;
for (int j = 0; j < bindings.Length; j++)
{
var binding = bindings[j];
AnimationCurve curve = AnimationUtility.GetEditorCurve(step.ani, binding);
// 获取关键帧的数量
int keyCount = curve.keys.Length;
// 移动关键帧的位置
for (int k = keyCount - 1; k >= 0; k--)
{
Keyframe key = curve.keys[k];
key.time += 0.02f;
if (bindingTime < key.time)
{
bindingTime = key.time;
}
curve.MoveKey(k, key);
}
for (int i = 0; i < count; i++)
{
// string trackName = $"{path1}/{path2}/{i + 1}/AnimRoot";
string trackName = $"{path1}/{path2}/{i + 1:D2}/AnimRoot";
EditorCurveBinding trackBinding = new EditorCurveBinding
{
type = binding.type,
path = trackName,
propertyName = binding.propertyName
};
// 将轨道添加到Clip中
AnimationUtility.SetEditorCurve(newAni, trackBinding, curve);
if (j == 0 && step.audioClip != null)
{
int keyTime = Mathf.RoundToInt(bindingTime * 10000);
if (!timeList.Contains(keyTime))
{
timeList.Add(keyTime);
}
}
// 移动关键帧的位置
for (int k = keyCount - 1; k >= 0; k--)
{
Keyframe key = curve.keys[k];
key.time += step.timeAniOffset;
if (bindingTime < key.time)
{
bindingTime = key.time;
}
curve.MoveKey(k, key);
}
}
}
if (step.audioClip != null)
{
SetBindingAudio(timeList, newAni, step.audioClip);
}
if (Temp.targetLength > 0)
{
// Get the original length of the clip
float originalLength = newAni.length;
if (originalLength <= 0)
{
Debug.LogWarning($"Clip '{newAni.name}' has no length to scale.");
continue;
}
// Calculate the new speed to scale the animation
float scaleFactor = originalLength / Temp.targetLength;
// Scale the animation clip speed by adjusting its frame rates
ScaleClip(newAni, scaleFactor);
}
AssetDatabase.CreateAsset(newAni, $"{Temp.folderPath}/{newAni.name}.anim");
}
//保存 Temp
AssetDatabase.SaveAssets();
}
void SetBindingAudio(List<int> timeList, AnimationClip newAni, AudioClip audioClip)
{
List<EditorCurveBinding> bindingAudio = new List<EditorCurveBinding>();
List<AnimationCurve> curveAudio = new List<AnimationCurve>();
int audioIndex = 0;
Keyframe keyframe = new Keyframe(0, 0, Mathf.Infinity, Mathf.Infinity);
string AudioRoot = "Audio";
Transform AudioTran = Temp.dynamic.Find(AudioRoot);
if (AudioTran == null)
{
GameObject go = new GameObject(AudioRoot);
go.transform.SetParent(Temp.dynamic);
AudioTran = go.transform;
}
int maxTime = 0;
for (int j = 0; j < timeList.Count; j++)
{
audioIndex %= 3;
Transform tran2 = AudioTran.Find($"{newAni.name}_{audioIndex}");
AudioSource aud;
if (tran2)
{
aud = tran2.GetComponent<AudioSource>();
}
else
{
var go = new GameObject($"{newAni.name}_{audioIndex}", typeof(AudioSource));
go.transform.SetParent(AudioTran);
aud = go.GetComponent<AudioSource>();
go.SetActive(false);
}
aud.clip = audioClip;
if (bindingAudio.Count <= audioIndex)
{
bindingAudio.Add(new EditorCurveBinding
{
type = typeof(GameObject),
path = $"{AudioRoot}/{newAni.name}_{audioIndex}",
propertyName = "m_IsActive"
});
}
if (curveAudio.Count <= audioIndex)
{
curveAudio.Add(new AnimationCurve());
curveAudio[audioIndex].AddKey(keyframe);
}
if (maxTime < timeList[j])
{
maxTime = timeList[j];
}
float time = timeList[j] / 10000f;
Keyframe key2 = new Keyframe(time - 0.02f, 0, Mathf.Infinity, Mathf.Infinity);
Keyframe key3 = new Keyframe(time, 1, Mathf.Infinity, Mathf.Infinity);
curveAudio[audioIndex].AddKey(key2);
curveAudio[audioIndex].AddKey(key3);
audioIndex++;
}
for (int i = 0; i < bindingAudio.Count; i++)
{
if (newAni == null || bindingAudio[i] == null || curveAudio[i] == null)
continue;
float time = maxTime / 10000f;
Keyframe key = new Keyframe(time, 0);
curveAudio[i].AddKey(key);
int lastKey = curveAudio[i].length - 1;
curveAudio[i].MoveKey(lastKey, key);
AnimationUtility.SetEditorCurve(newAni, bindingAudio[i], curveAudio[i]);
}
}
public void ChangeAudio()
{
for (int n = 0; n < Temp.audioChangeDatas.Length; n++)
{
AudioChangeData data = Temp.audioChangeDatas[n];
AnimationClip newAni = data.ani;
EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(data.ani);
List<int> timeList = new List<int>();
for (int j = 0; j < bindings.Length; j++)
{
var binding = bindings[j];
if (binding.path.Contains($"Audio/{newAni.name}"))
{
continue;
}
AnimationCurve curve = AnimationUtility.GetEditorCurve(data.ani, binding);
// 获取关键帧的数量
int keyCount = curve.keys.Length;
Keyframe key = curve.keys[keyCount - 1];
int keyTime = Mathf.RoundToInt(key.time * 10000);
if (!timeList.Contains(keyTime))
{
timeList.Add(keyTime);
}
}
SetBindingAudio(timeList, newAni, data.audioClip);
EditorUtility.SetDirty(data.ani);
}
AssetDatabase.SaveAssets();
}
private void ScaleClip(AnimationClip clip, float scaleFactor)
{
// Debug.Log($"<color=red>{scaleFactor} for {clip}</color>");
// Scale all curves in the clip
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
{
var curve = AnimationUtility.GetEditorCurve(clip, binding);
var curveKeyFrames = curve.keys;
// Adjust keyframe times
for (int i = 0; i < curveKeyFrames.Length; i++)
{
// Debug.Log($" before: {curveKeyFrames[i].time}");
// var t = curveKeyFrames[i].time / scaleFactor;
// curve.keys[i].time = t;
curveKeyFrames[i].time /= scaleFactor;
// Debug.Log($" after: {curveKeyFrames[i].time}");
// Debug.Log($" after t: {t}");
}
curve.keys = curveKeyFrames;
AnimationUtility.SetEditorCurve(clip, binding, curve);
}
foreach (var binding in AnimationUtility.GetObjectReferenceCurveBindings(clip))
{
var curve = AnimationUtility.GetEditorCurve(clip, binding);
for (int i = 0; i < curve.keys.Length; i++)
{
curve.keys[i].time /= scaleFactor;
}
AnimationUtility.SetEditorCurve(clip, binding, curve);
}
// Scale events
foreach (var animEvent in AnimationUtility.GetAnimationEvents(clip))
{
animEvent.time /= scaleFactor;
}
// Apply changes back to the clip
AnimationUtility.SetAnimationEvents(clip, AnimationUtility.GetAnimationEvents(clip));
Debug.Log($"Scaled clip '{clip.name}' to {clip.length / scaleFactor} seconds.");
}
}