unity脚本收集
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class AddParentToSelected : Editor
|
||||
{
|
||||
[MenuItem("Tools/Add Parent To Selected Objects")]
|
||||
public static void AddParentForSelectedObjects()
|
||||
{
|
||||
GameObject[] selectedObjects = Selection.gameObjects;
|
||||
|
||||
if (selectedObjects.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("No objects selected. Please select objects in the Hierarchy.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (GameObject obj in selectedObjects)
|
||||
{
|
||||
int siblingIndex = obj.transform.GetSiblingIndex();
|
||||
Transform parent = obj.transform.parent;
|
||||
|
||||
GameObject newParent = new GameObject($"{obj.name}_Root");
|
||||
Undo.RegisterCreatedObjectUndo(newParent, "Create Parent Object");
|
||||
if (parent != null)
|
||||
{
|
||||
newParent.transform.SetParent(parent);
|
||||
}
|
||||
newParent.transform.position = obj.transform.position;
|
||||
newParent.transform.rotation = obj.transform.rotation;
|
||||
newParent.transform.localScale = obj.transform.localScale;
|
||||
|
||||
newParent.transform.position = obj.transform.position;
|
||||
|
||||
|
||||
Undo.SetTransformParent(obj.transform, newParent.transform, "Set New Parent");
|
||||
newParent.transform.SetSiblingIndex(siblingIndex);
|
||||
obj.transform.localRotation = Quaternion.identity;
|
||||
obj.transform.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
Debug.Log("New parent objects created for selected objects.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
|
||||
public class ChildSort : Editor
|
||||
{
|
||||
[MenuItem("Tools/Sort Children By Name")]
|
||||
private static void SortChildrenByNameMenu()
|
||||
{
|
||||
// 获取当前选中的物体
|
||||
GameObject selected = Selection.activeGameObject;
|
||||
|
||||
if (selected == null)
|
||||
{
|
||||
Debug.LogError("请先选择一个父物体!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有子物体
|
||||
List<Transform> children = new List<Transform>();
|
||||
foreach (Transform child in selected.transform)
|
||||
{
|
||||
children.Add(child);
|
||||
}
|
||||
|
||||
// 排序逻辑(按名字中的数字)
|
||||
children = children.OrderBy(child =>
|
||||
{
|
||||
string name = child.name;
|
||||
int number = ExtractNumber(name);
|
||||
return number;
|
||||
}).ToList();
|
||||
|
||||
// 按排序结果重新设置子物体的层级
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
{
|
||||
children[i].SetSiblingIndex(i);
|
||||
}
|
||||
|
||||
Debug.Log($"已对 {selected.name} 下的子物体按名字排序!");
|
||||
}
|
||||
|
||||
static int ExtractNumber(string name)
|
||||
{
|
||||
int number = 0;
|
||||
string digits = new string(name.Where(char.IsDigit).ToArray());
|
||||
int.TryParse(digits, out number);
|
||||
return number;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEngine.Playables;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[ExecuteAlways]
|
||||
public class EditorTimelinePathTracker : MonoBehaviour
|
||||
{
|
||||
public Color pathColor = Color.green;
|
||||
public int maxPoints = 1000;
|
||||
|
||||
private List<Vector3> pathPoints = new List<Vector3>();
|
||||
private List<float> timeStamps = new List<float>();
|
||||
private Vector3 lastPosition;
|
||||
private PlayableDirector director;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
director = GetComponent<PlayableDirector>();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.update += EditorUpdate;
|
||||
#endif
|
||||
pathPoints.Clear();
|
||||
timeStamps.Clear();
|
||||
lastPosition = transform.position;
|
||||
pathPoints.Add(lastPosition);
|
||||
timeStamps.Add(GetTimelineTime());
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.update -= EditorUpdate;
|
||||
#endif
|
||||
}
|
||||
|
||||
private float GetTimelineTime()
|
||||
{
|
||||
if (director != null && director.playableGraph.IsValid())
|
||||
{
|
||||
return (float)director.time;
|
||||
}
|
||||
return Time.realtimeSinceStartup; // fallback 时间戳
|
||||
}
|
||||
|
||||
private float GetTimelineDuration()
|
||||
{
|
||||
return director != null ? (float)director.duration : -1f;
|
||||
}
|
||||
|
||||
private void EditorUpdate()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
return;
|
||||
|
||||
Vector3 currentPosition = transform.position;
|
||||
float currentTime = GetTimelineTime();
|
||||
|
||||
if (Vector3.Distance(currentPosition, lastPosition) > 0.01f)
|
||||
{
|
||||
lastPosition = currentPosition;
|
||||
pathPoints.Add(currentPosition);
|
||||
timeStamps.Add(currentTime);
|
||||
|
||||
if (pathPoints.Count > maxPoints)
|
||||
{
|
||||
pathPoints.RemoveAt(0);
|
||||
timeStamps.RemoveAt(0);
|
||||
}
|
||||
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (pathPoints == null || pathPoints.Count < 2)
|
||||
return;
|
||||
|
||||
float timelineDuration = GetTimelineDuration();
|
||||
bool useTimeline = director != null && timelineDuration > 0;
|
||||
|
||||
Gizmos.color = pathColor;
|
||||
for (int i = 1; i < pathPoints.Count; i++)
|
||||
{
|
||||
// 若启用Timeline,仅绘制在时间范围内的轨迹
|
||||
if (useTimeline && (timeStamps[i - 1] > timelineDuration || timeStamps[i] > timelineDuration))
|
||||
continue;
|
||||
|
||||
Gizmos.DrawLine(pathPoints[i - 1], pathPoints[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using TMPro;
|
||||
|
||||
public class NumberScrollPlayableBehaviour : PlayableBehaviour
|
||||
{
|
||||
public TMP_Text textMesh;
|
||||
public int startValue;
|
||||
public int endValue;
|
||||
|
||||
private double clipDuration;
|
||||
|
||||
public override void OnGraphStart(Playable playable)
|
||||
{
|
||||
clipDuration = playable.GetDuration();
|
||||
}
|
||||
|
||||
public override void OnGraphStop(Playable playable)
|
||||
{
|
||||
if (textMesh != null)
|
||||
{
|
||||
textMesh.text = endValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnBehaviourPlay(Playable playable, FrameData info)
|
||||
{
|
||||
if (textMesh != null)
|
||||
{
|
||||
textMesh.text = startValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnBehaviourPause(Playable playable, FrameData info)
|
||||
{
|
||||
if (textMesh != null && playable.GetTime() >= clipDuration)
|
||||
{
|
||||
textMesh.text = endValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
|
||||
{
|
||||
if (textMesh == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double normalizedTime = playable.GetTime() / clipDuration;
|
||||
float currentValue = Mathf.Lerp(startValue, endValue, (float)normalizedTime);
|
||||
textMesh.text = Mathf.FloorToInt(currentValue).ToString();
|
||||
|
||||
// Ensure the text is set to the end value if the normalized time is 1.0 or more
|
||||
if (normalizedTime >= 1.0)
|
||||
{
|
||||
textMesh.text = endValue.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
|
||||
[RequireComponent(typeof(TextMesh))]
|
||||
public class NumberScrollPlayable : MonoBehaviour, INotificationReceiver
|
||||
{
|
||||
public PlayableDirector director;
|
||||
|
||||
public void OnNotify(Playable origin, INotification notification, object context)
|
||||
{
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (director != null)
|
||||
{
|
||||
director.Play();
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (director != null && director.state != PlayState.Playing)
|
||||
{
|
||||
director.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Timeline;
|
||||
using TMPro;
|
||||
|
||||
[System.Serializable]
|
||||
public class NumberScrollPlayableAsset : PlayableAsset
|
||||
{
|
||||
public ExposedReference<TMP_Text> textMesh;
|
||||
public int startValue;
|
||||
public int endValue;
|
||||
|
||||
public ClipCaps clipCaps
|
||||
{
|
||||
get { return ClipCaps.None; }
|
||||
}
|
||||
|
||||
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
|
||||
{
|
||||
var playable = ScriptPlayable<NumberScrollPlayableBehaviour>.Create(graph);
|
||||
|
||||
NumberScrollPlayableBehaviour behaviour = playable.GetBehaviour();
|
||||
behaviour.textMesh = textMesh.Resolve(graph.GetResolver());
|
||||
behaviour.startValue = startValue;
|
||||
behaviour.endValue = endValue;
|
||||
|
||||
return playable;
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class NumberScrollBehaviour : PlayableBehaviour
|
||||
{
|
||||
public float startValue;
|
||||
public float endValue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
[TrackColor(0.1f, 0.2f, 0.8f)]
|
||||
[TrackClipType(typeof(NumberScrollPlayableAsset))]
|
||||
[TrackBindingType(typeof(TextMesh))]
|
||||
public class NumberScrollTrack : TrackAsset
|
||||
{
|
||||
public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
|
||||
{
|
||||
return ScriptPlayable<NumberScrollPlayableBehaviour>.Create(graph, inputCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[ExecuteInEditMode] // 让脚本在编辑器模式下也能执行
|
||||
public class ParticleAttractionPoint : MonoBehaviour
|
||||
{
|
||||
[Header("吸附参数")]
|
||||
[Tooltip("粒子吸附目标点")]
|
||||
public Transform attractionPoint; // 吸附目标点
|
||||
[Tooltip("粒子生成多久后开始进行吸附")]
|
||||
[Range(0.0f, 100.0f)]
|
||||
public float delayTime = 0.0f; // 延迟时间
|
||||
[Tooltip("粒子开始进行吸附计算后的大小变化曲线")]
|
||||
public AnimationCurve SizeCurve = new AnimationCurve(); // 控制移动的曲线
|
||||
[Tooltip("是否使用距离比例计算")]
|
||||
public bool UseDistance = false;
|
||||
|
||||
[Header("逐帧计算")]
|
||||
public float attractionSpeed=50.0f;
|
||||
|
||||
[Header("距离比例计算")]
|
||||
[Range(0.001f, 2.0f)] // 限制时间缩放的最大值和最小值
|
||||
public float timeScale = 1.0f; // 时间缩放
|
||||
|
||||
private ParticleSystem particleSystemComponent;
|
||||
private ParticleSystem.Particle[] particles;
|
||||
|
||||
void OnEnable() // 改用OnEnable替代Start,这样在编辑器中也能初始化
|
||||
{
|
||||
particleSystemComponent = GetComponent<ParticleSystem>();
|
||||
particles = new ParticleSystem.Particle[particleSystemComponent.main.maxParticles];
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if(!particleSystemComponent) return; // 添加空检查
|
||||
|
||||
int particleCount = particleSystemComponent.GetParticles(particles);
|
||||
|
||||
if(attractionPoint == null) return; // 添加目标点空检查
|
||||
|
||||
for (int i = 0; i < particleCount; i++)
|
||||
{
|
||||
float lifePercent = 1.0f - (particles[i].remainingLifetime / particles[i].startLifetime);
|
||||
|
||||
// 只有当粒子存在时间超过延迟时间才开始移动
|
||||
if(particles[i].startLifetime - particles[i].remainingLifetime >= delayTime)
|
||||
{
|
||||
//暂存粒子位置
|
||||
Vector3 startPos=particles[i].position;
|
||||
|
||||
if (UseDistance)
|
||||
{
|
||||
// 位置计算方法1 重新计算剩余的距离比例
|
||||
float adjustedLifePercent = (particles[i].startLifetime - particles[i].remainingLifetime - delayTime) /
|
||||
(particles[i].startLifetime - delayTime);
|
||||
// 根据距离比例计算位置
|
||||
particles[i].position = Vector3.Lerp(particles[i].position, attractionPoint.position, adjustedLifePercent*timeScale);
|
||||
} else
|
||||
{
|
||||
// 位置计算方法2 朝向吸附点移动
|
||||
Vector3 direction = (attractionPoint.position - particles[i].position).normalized;
|
||||
particles[i].position += direction * attractionSpeed * Time.deltaTime;
|
||||
}
|
||||
|
||||
// 修正粒子size
|
||||
float distancePercent=Vector3.Distance(startPos, particles[i].position) / Vector3.Distance(startPos, attractionPoint.position);
|
||||
particles[i].startSize = particles[i].startSize * SizeCurve.Evaluate(distancePercent);
|
||||
|
||||
// 当粒子到达目标点时立即消失,可能会有大量粒子,引起优化问题
|
||||
// if(Vector3.Distance(particles[i].position, attractionPoint.position) <= 0.9f)
|
||||
// {
|
||||
// particles[i].remainingLifetime = 0.0f;
|
||||
// }
|
||||
|
||||
// // 优化方法1 通过使用SqrMagnitude,可以避免开方运算
|
||||
// if (Vector3.SqrMagnitude(particles[i].position - attractionPoint.position) <= 0.9f * 0.9f)
|
||||
// {
|
||||
// particles[i].remainingLifetime = 0.0f;
|
||||
// }
|
||||
|
||||
// 优化方法2 使用Mathf.Approximately进行比较
|
||||
if (Mathf.Approximately(Vector3.Distance(particles[i].position, attractionPoint.position), 0.0f) ||
|
||||
Vector3.Distance(particles[i].position, attractionPoint.position) <= 0.9f)
|
||||
{
|
||||
particles[i].remainingLifetime = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
particleSystemComponent.SetParticles(particles, particleCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Timeline;
|
||||
using System.Linq;
|
||||
|
||||
public class TimelineBindingCopier : Editor
|
||||
{
|
||||
private const string SourcePlayableDirectorKey = "SourcePlayableDirector"; // EditorPrefs 存储源 PlayableDirector 的键
|
||||
|
||||
[MenuItem("CONTEXT/PlayableDirector/Copy Bindings")]
|
||||
public static void CopyBindings()
|
||||
{
|
||||
PlayableDirector source = Selection.activeGameObject?.GetComponent<PlayableDirector>();
|
||||
if (source == null)
|
||||
{
|
||||
Debug.LogError("Please select a PlayableDirector to copy bindings from.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存当前选择的 PlayableDirector 到 EditorPrefs
|
||||
EditorPrefs.SetString(SourcePlayableDirectorKey, source.gameObject.name);
|
||||
Debug.Log($"Source PlayableDirector '{source.name}' saved. Now select the target PlayableDirector.");
|
||||
}
|
||||
|
||||
[MenuItem("CONTEXT/PlayableDirector/Paste Bindings")]
|
||||
public static void PasteBindings()
|
||||
{
|
||||
PlayableDirector target = Selection.activeGameObject?.GetComponent<PlayableDirector>();
|
||||
if (target == null)
|
||||
{
|
||||
Debug.LogError("Please select a PlayableDirector to paste bindings to.");
|
||||
return;
|
||||
}
|
||||
|
||||
string sourceObjectName = EditorPrefs.GetString(SourcePlayableDirectorKey, "");
|
||||
if (string.IsNullOrEmpty(sourceObjectName))
|
||||
{
|
||||
Debug.LogError("No source PlayableDirector saved. Please use 'Copy Bindings' first.");
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject sourceObject = GameObject.Find(sourceObjectName);
|
||||
if (sourceObject == null)
|
||||
{
|
||||
Debug.LogError($"Source PlayableDirector '{sourceObjectName}' not found. Please copy bindings again.");
|
||||
return;
|
||||
}
|
||||
|
||||
PlayableDirector source = sourceObject.GetComponent<PlayableDirector>();
|
||||
if (source == null)
|
||||
{
|
||||
Debug.LogError($"Source PlayableDirector '{sourceObjectName}' does not have a PlayableDirector component.");
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceAsset = source.playableAsset as TimelineAsset;
|
||||
var targetAsset = target.playableAsset as TimelineAsset;
|
||||
|
||||
if (sourceAsset == null || targetAsset == null)
|
||||
{
|
||||
Debug.LogError("Source or Target PlayableDirector does not contain a valid Timeline.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Paste bindings based on track indices
|
||||
PasteBindingsInternal(source, target, sourceAsset, targetAsset);
|
||||
}
|
||||
|
||||
private static void PasteBindingsInternal(PlayableDirector source, PlayableDirector target, TimelineAsset sourceAsset, TimelineAsset targetAsset)
|
||||
{
|
||||
var sourceTracks = sourceAsset.GetOutputTracks().ToArray(); // Convert to array
|
||||
var targetTracks = targetAsset.GetOutputTracks().ToArray(); // Convert to array
|
||||
|
||||
if (sourceTracks.Length != targetTracks.Length)
|
||||
{
|
||||
Debug.LogError("Source and Target timelines have different number of tracks.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sourceTracks.Length; i++)
|
||||
{
|
||||
TrackAsset sourceTrack = sourceTracks[i];
|
||||
TrackAsset targetTrack = targetTracks[i];
|
||||
|
||||
if (sourceTrack == null || targetTrack == null)
|
||||
{
|
||||
Debug.Log($"Skipping track at index {i} because it is null.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var sourceBinding = source.GetGenericBinding(sourceTrack);
|
||||
if (sourceBinding != null)
|
||||
{
|
||||
// Set the binding for the target PlayableDirector
|
||||
target.SetGenericBinding(targetTrack, sourceBinding);
|
||||
Debug.Log($"Binding pasted for track '{sourceTrack.name}' (Index {i}).");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"No binding found for track '{sourceTrack.name}' (Index {i}), skipping...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
|
||||
public class RenameSelectedObjects : EditorWindow
|
||||
{
|
||||
private string baseName = "NewObject";
|
||||
|
||||
[MenuItem("Tools/Rename Selected Objects")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
GetWindow<RenameSelectedObjects>("Rename Objects");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Label("Rename Selected Objects", EditorStyles.boldLabel);
|
||||
baseName = EditorGUILayout.TextField("Base Name", baseName);
|
||||
|
||||
if (GUILayout.Button("Rename"))
|
||||
{
|
||||
RenameObjects();
|
||||
}
|
||||
}
|
||||
|
||||
private void RenameObjects()
|
||||
{
|
||||
var selectedObjects = Selection.gameObjects;
|
||||
|
||||
if (selectedObjects.Length == 0)
|
||||
{
|
||||
EditorUtility.DisplayDialog("No Objects Selected", "Please select at least one object in the Hierarchy.", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort selected objects by their sibling index (Hierarchy order)
|
||||
var sortedObjects = selectedObjects
|
||||
.OrderBy(obj => obj.transform.GetSiblingIndex())
|
||||
.ToArray();
|
||||
|
||||
Undo.RecordObjects(sortedObjects, "Rename Objects");
|
||||
|
||||
for (int i = 0; i < sortedObjects.Length; i++)
|
||||
{
|
||||
sortedObjects[i].name = $"{baseName} ({i + 1})";
|
||||
}
|
||||
|
||||
EditorUtility.DisplayDialog("Rename Complete", $"Renamed {sortedObjects.Length} objects.", "OK");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
public class ReplaceWithPrefabWindow : EditorWindow
|
||||
{
|
||||
private GameObject _prefab;
|
||||
private bool inheritPosition = true;
|
||||
private bool inheritScale = true;
|
||||
private bool inheritRotation = true;
|
||||
|
||||
[MenuItem("Tools/Replace Selected with Prefab")]
|
||||
static void ShowWindow()
|
||||
{
|
||||
GetWindow<ReplaceWithPrefabWindow>("Replace With Prefab");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Label("Select Prefab to Replace With", EditorStyles.boldLabel);
|
||||
|
||||
_prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", _prefab, typeof(GameObject), false);
|
||||
|
||||
inheritPosition = EditorGUILayout.Toggle("Inherit Position", inheritPosition);
|
||||
inheritRotation = EditorGUILayout.Toggle("Inherit Rotation", inheritRotation);
|
||||
inheritScale = EditorGUILayout.Toggle("Inherit Scale", inheritScale);
|
||||
|
||||
if (GUILayout.Button("Replace"))
|
||||
{
|
||||
ReplaceSelectedObjects();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReplaceSelectedObjects()
|
||||
{
|
||||
if (_prefab == null)
|
||||
{
|
||||
Debug.LogWarning("No prefab selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Selection.gameObjects.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("No objects selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject[] selectedObjects = Selection.gameObjects;
|
||||
|
||||
foreach (GameObject selectedObject in selectedObjects)
|
||||
{
|
||||
// 创建新对象并记录到撤销历史
|
||||
GameObject newObject = (GameObject)PrefabUtility.InstantiatePrefab(_prefab);
|
||||
Undo.RegisterCreatedObjectUndo(newObject, "Replace with Prefab");
|
||||
|
||||
newObject.transform.SetParent(selectedObject.transform.parent);
|
||||
|
||||
// 继承属性
|
||||
if (inheritPosition)
|
||||
newObject.transform.position = selectedObject.transform.position;
|
||||
|
||||
if (inheritRotation)
|
||||
newObject.transform.rotation = selectedObject.transform.rotation;
|
||||
|
||||
if (inheritScale)
|
||||
newObject.transform.localScale = selectedObject.transform.localScale;
|
||||
|
||||
// 删除原始对象并记录到撤销历史
|
||||
Undo.DestroyObjectImmediate(selectedObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 使用 LineRenderer 绘制绳索,通过简化的质点-弹簧系统模拟绳索形态。
|
||||
/// 支持物理模拟(质量、弹性、阻尼、重力),绳索总长保持不变,
|
||||
/// 并支持在设定时间内“缓慢拉直”至紧绷状态。
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(LineRenderer))]
|
||||
public class RopeSimulator : MonoBehaviour
|
||||
{
|
||||
[Header("绳索控制点(起点与终点)")]
|
||||
public Transform StartPoint; // 绳索起点,受位置驱动
|
||||
public Transform EndPoint; // 绳索终点,受位置驱动
|
||||
|
||||
[Header("绳索参数")]
|
||||
public int SegmentCount = 20; // 绳索段数(节点数量 = 段数)
|
||||
public float Mass = 1f; // 每个中间节点的质量
|
||||
public float Spring = 50f; // 弹性系数(控制连接的柔软程度)
|
||||
public float Damping = 5f; // 阻尼系数(用于减缓振荡)
|
||||
public float Gravity = 9.8f; // 重力加速度(作用于每个节点)
|
||||
public float TotalLength = 5f; // 绳索总长(约束节点间距)
|
||||
|
||||
[Header("拉直开关(true 表示启动拉直动画)")]
|
||||
public bool Straight = false; // 是否处于拉直状态,true 会触发缓慢收紧过程
|
||||
|
||||
[Header("速度衰减")]
|
||||
[Range(0f, 1f)]
|
||||
public float SpeedAttenuation = 0.98f; // 控制速度每帧的衰减,防止抖动
|
||||
|
||||
[Header("缓慢拉直参数")]
|
||||
public float TightenDuration = 0.2f; // 拉直动画持续时间(单位:秒)
|
||||
|
||||
// 绘制与模拟用的内部变量
|
||||
private LineRenderer lineRenderer;
|
||||
private Vector3[] positions; // 当前所有节点的位置
|
||||
private Vector3[] velocities; // 节点当前速度
|
||||
private Vector3[] simulatedPositions; // 缓慢拉直前记录的原始模拟位置
|
||||
|
||||
// 拉直动画控制变量
|
||||
private float tightenProgress = 0f; // 拉直进度(0~1)
|
||||
private bool isTightening = false; // 当前是否正在拉直动画中
|
||||
|
||||
void Start()
|
||||
{
|
||||
// 初始化 LineRenderer
|
||||
lineRenderer = GetComponent<LineRenderer>();
|
||||
lineRenderer.positionCount = SegmentCount;
|
||||
|
||||
// 初始化节点位置与速度数组
|
||||
positions = new Vector3[SegmentCount];
|
||||
velocities = new Vector3[SegmentCount];
|
||||
simulatedPositions = new Vector3[SegmentCount];
|
||||
|
||||
// 初始化所有节点位置(线性插值)
|
||||
for (int i = 0; i < SegmentCount; i++)
|
||||
{
|
||||
float t = (float)i / (SegmentCount - 1);
|
||||
positions[i] = Vector3.Lerp(StartPoint.position, EndPoint.position, t);
|
||||
velocities[i] = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
// 在固定帧率下执行模拟、约束和绘制
|
||||
Simulate(Time.fixedDeltaTime);
|
||||
ApplyConstraints();
|
||||
DrawLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模拟每帧节点的受力与位置更新
|
||||
/// 包括弹簧力、阻尼、重力,并支持缓慢进入“拉直状态”
|
||||
/// </summary>
|
||||
void Simulate(float dt)
|
||||
{
|
||||
// 如果开启拉直
|
||||
if (Straight)
|
||||
{
|
||||
// 如果是第一次开始拉直
|
||||
if (!isTightening)
|
||||
{
|
||||
isTightening = true;
|
||||
tightenProgress = 0f;
|
||||
|
||||
// 记录当前模拟位置,用于插值过渡
|
||||
for (int i = 0; i < SegmentCount; i++)
|
||||
simulatedPositions[i] = positions[i];
|
||||
}
|
||||
|
||||
// 根据拉直时间推进进度(0~1)
|
||||
if (TightenDuration > 0f)
|
||||
tightenProgress += dt / TightenDuration;
|
||||
else
|
||||
tightenProgress = 1f; // 防止除以0
|
||||
|
||||
tightenProgress = Mathf.Clamp01(tightenProgress);
|
||||
|
||||
// 插值绘制节点向绷直目标靠拢
|
||||
for (int i = 0; i < SegmentCount; i++)
|
||||
{
|
||||
float t = (float)i / (SegmentCount - 1);
|
||||
Vector3 tightTarget = Vector3.Lerp(StartPoint.position, EndPoint.position, t);
|
||||
positions[i] = Vector3.Lerp(simulatedPositions[i], tightTarget, tightenProgress);
|
||||
velocities[i] = Vector3.zero;
|
||||
}
|
||||
|
||||
return; // 当前为拉直动画阶段,不执行物理模拟
|
||||
}
|
||||
else
|
||||
{
|
||||
// 退出拉直状态,恢复常规模拟
|
||||
isTightening = false;
|
||||
tightenProgress = 0f;
|
||||
}
|
||||
|
||||
// 常规模拟(弹簧 + 阻尼 + 重力)
|
||||
positions[0] = StartPoint.position;
|
||||
positions[SegmentCount - 1] = EndPoint.position;
|
||||
|
||||
float restLength = TotalLength / (SegmentCount - 1); // 理想段长
|
||||
|
||||
for (int i = 1; i < SegmentCount - 1; i++)
|
||||
{
|
||||
Vector3 force = Vector3.zero;
|
||||
|
||||
// 计算弹簧力(左右节点)
|
||||
Vector3 left = positions[i - 1];
|
||||
Vector3 right = positions[i + 1];
|
||||
|
||||
Vector3 leftDir = positions[i] - left;
|
||||
Vector3 rightDir = positions[i] - right;
|
||||
|
||||
force += -Spring * (leftDir.normalized * (leftDir.magnitude - restLength));
|
||||
force += -Spring * (rightDir.normalized * (rightDir.magnitude - restLength));
|
||||
|
||||
// 添加阻尼力
|
||||
force += -velocities[i] * Damping;
|
||||
|
||||
// 添加重力
|
||||
force += Vector3.down * Gravity * Mass;
|
||||
|
||||
// 更新速度和位置
|
||||
Vector3 acceleration = force / Mass;
|
||||
velocities[i] += acceleration * dt;
|
||||
velocities[i] *= SpeedAttenuation;
|
||||
positions[i] += velocities[i] * dt;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每帧执行多轮“段长约束修正”,使总绳索长度保持不变
|
||||
/// </summary>
|
||||
void ApplyConstraints()
|
||||
{
|
||||
if (Straight) return; // 绷直中不做物理约束
|
||||
|
||||
float segmentLength = TotalLength / (SegmentCount - 1);
|
||||
int iterations = 10; // 越多越稳定
|
||||
|
||||
for (int k = 0; k < iterations; k++)
|
||||
{
|
||||
positions[0] = StartPoint.position;
|
||||
positions[SegmentCount - 1] = EndPoint.position;
|
||||
|
||||
for (int i = 0; i < SegmentCount - 1; i++)
|
||||
{
|
||||
Vector3 p1 = positions[i];
|
||||
Vector3 p2 = positions[i + 1];
|
||||
Vector3 delta = p2 - p1;
|
||||
float dist = delta.magnitude;
|
||||
float error = dist - segmentLength;
|
||||
|
||||
Vector3 correction = delta.normalized * (error * 0.5f);
|
||||
|
||||
if (i != 0)
|
||||
positions[i] += correction;
|
||||
if (i + 1 != SegmentCount - 1)
|
||||
positions[i + 1] -= correction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新 LineRenderer 可视化节点位置
|
||||
/// </summary>
|
||||
void DrawLine()
|
||||
{
|
||||
lineRenderer.positionCount = SegmentCount;
|
||||
lineRenderer.SetPositions(positions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using DG.Tweening;
|
||||
|
||||
public class ScaleAniChild : MonoBehaviour
|
||||
{
|
||||
Vector3 _defaultScale = Vector3.one;
|
||||
private void Awake()
|
||||
{
|
||||
_defaultScale = transform.localScale;
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
transform.localScale = Vector3.zero;
|
||||
}
|
||||
|
||||
public void Show(float delay, float aniLength, AnimationCurve cur)
|
||||
{
|
||||
transform.DOKill();
|
||||
transform.localScale = Vector3.zero;
|
||||
transform.DOScale(_defaultScale, aniLength).SetEase(cur).SetDelay(delay);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class ScreenShotWindow : EditorWindow
|
||||
{
|
||||
private Camera m_Camera;
|
||||
private string filePath;
|
||||
private bool m_IsEnableAlpha = false;
|
||||
private CameraClearFlags m_CameraClearFlags;
|
||||
|
||||
[MenuItem("Tools/ScreenShotWindow")]
|
||||
private static void Init()
|
||||
{
|
||||
ScreenShotWindow window = GetWindowWithRect<ScreenShotWindow>(new Rect(0, 0, 300, 150));
|
||||
window.titleContent = new GUIContent("屏幕截图");
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
m_Camera = EditorGUILayout.ObjectField("选择摄像机", m_Camera, typeof(Camera), true) as Camera;
|
||||
|
||||
if (GUILayout.Button("保存位置"))
|
||||
{
|
||||
filePath = EditorUtility.OpenFolderPanel("", "", "");
|
||||
}
|
||||
|
||||
m_IsEnableAlpha = EditorGUILayout.Toggle("是否开启透明通道", m_IsEnableAlpha);
|
||||
EditorGUILayout.Space();
|
||||
if (GUILayout.Button("截图"))
|
||||
{
|
||||
TakeShot();
|
||||
}
|
||||
EditorGUILayout.Space();
|
||||
if (GUILayout.Button("打开导出文件夹"))
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
Debug.LogError("<color=red>" + "没有选择截图保存位置" + "</color>");
|
||||
return;
|
||||
}
|
||||
Application.OpenURL("file://" + filePath);
|
||||
}
|
||||
}
|
||||
|
||||
private void TakeShot()
|
||||
{
|
||||
if (m_Camera == null)
|
||||
{
|
||||
Debug.LogError("<color=red>" + "没有选择摄像机" + "</color>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
Debug.LogError("<color=red>" + "没有选择截图保存位置" + "</color>");
|
||||
return;
|
||||
}
|
||||
|
||||
m_CameraClearFlags = m_Camera.clearFlags;
|
||||
if (m_IsEnableAlpha)
|
||||
{
|
||||
m_Camera.clearFlags = CameraClearFlags.Depth;
|
||||
}
|
||||
|
||||
int resolutionX = (int)Handles.GetMainGameViewSize().x;
|
||||
int resolutionY = (int)Handles.GetMainGameViewSize().y;
|
||||
RenderTexture rt = new RenderTexture(resolutionX, resolutionY, 24);
|
||||
m_Camera.targetTexture = rt;
|
||||
Texture2D screenShot = new Texture2D(resolutionX, resolutionY, TextureFormat.ARGB32, false);
|
||||
m_Camera.Render();
|
||||
RenderTexture.active = rt;
|
||||
screenShot.ReadPixels(new Rect(0, 0, resolutionX, resolutionY), 0, 0);
|
||||
m_Camera.targetTexture = null;
|
||||
RenderTexture.active = null;
|
||||
m_Camera.clearFlags = m_CameraClearFlags;
|
||||
//Destroy(rt);
|
||||
byte[] bytes = screenShot.EncodeToPNG();
|
||||
string fileName = filePath + "/" + $"{System.DateTime.Now:yyyy-MM-dd_HH-mm-ss}" + ".png";
|
||||
File.WriteAllBytes(fileName, bytes);
|
||||
Debug.Log("截图成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
/// Credit glennpow
|
||||
/// Sourced from - http://forum.unity3d.com/threads/free-script-particle-systems-in-ui-screen-space-overlay.406862/
|
||||
/// *Note - experimental. Currently renders in scene view and not game view.
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
#if UNITY_5_3_OR_NEWER
|
||||
[ExecuteInEditMode]
|
||||
[RequireComponent(typeof(CanvasRenderer), typeof(ParticleSystem))]
|
||||
[AddComponentMenu("UI/Effects/Extensions/UIParticleSystem")]
|
||||
public class UIParticleSystem : MaskableGraphic
|
||||
{
|
||||
[Tooltip("Having this enabled run the system in LateUpdate rather than in Update making it faster but less precise (more clunky)")]
|
||||
public bool fixedTime = true;
|
||||
|
||||
private Transform _transform;
|
||||
private ParticleSystem pSystem;
|
||||
private ParticleSystem.Particle[] particles;
|
||||
private UIVertex[] _quad = new UIVertex[4];
|
||||
private Vector4 imageUV = Vector4.zero;
|
||||
private ParticleSystem.TextureSheetAnimationModule textureSheetAnimation;
|
||||
private int textureSheetAnimationFrames;
|
||||
private Vector2 textureSheetAnimationFrameSize;
|
||||
private ParticleSystemRenderer pRenderer;
|
||||
|
||||
private Material currentMaterial;
|
||||
|
||||
private Texture currentTexture;
|
||||
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
private ParticleSystem.MainModule mainModule;
|
||||
#endif
|
||||
|
||||
public override Texture mainTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
return currentTexture;
|
||||
}
|
||||
}
|
||||
|
||||
protected bool Initialize()
|
||||
{
|
||||
// initialize members
|
||||
if (_transform == null)
|
||||
{
|
||||
_transform = transform;
|
||||
}
|
||||
if (pSystem == null)
|
||||
{
|
||||
pSystem = GetComponent<ParticleSystem>();
|
||||
|
||||
if (pSystem == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
mainModule = pSystem.main;
|
||||
if (pSystem.main.maxParticles > 14000)
|
||||
{
|
||||
mainModule.maxParticles = 14000;
|
||||
}
|
||||
#else
|
||||
if (pSystem.maxParticles > 14000)
|
||||
pSystem.maxParticles = 14000;
|
||||
#endif
|
||||
|
||||
pRenderer = pSystem.GetComponent<ParticleSystemRenderer>();
|
||||
if (pRenderer != null)
|
||||
pRenderer.enabled = false;
|
||||
|
||||
Shader foundShader = Shader.Find("UI Extensions/Particles/Additive");
|
||||
Material pMaterial = new Material(foundShader);
|
||||
|
||||
if (material == null)
|
||||
material = pMaterial;
|
||||
|
||||
currentMaterial = material;
|
||||
if (currentMaterial && currentMaterial.HasProperty("_MainTex"))
|
||||
{
|
||||
currentTexture = currentMaterial.mainTexture;
|
||||
if (currentTexture == null)
|
||||
currentTexture = Texture2D.whiteTexture;
|
||||
}
|
||||
material = currentMaterial;
|
||||
// automatically set scaling
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
mainModule.scalingMode = ParticleSystemScalingMode.Hierarchy;
|
||||
#else
|
||||
pSystem.scalingMode = ParticleSystemScalingMode.Hierarchy;
|
||||
#endif
|
||||
|
||||
particles = null;
|
||||
}
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
if (particles == null)
|
||||
particles = new ParticleSystem.Particle[pSystem.main.maxParticles];
|
||||
#else
|
||||
if (particles == null)
|
||||
particles = new ParticleSystem.Particle[pSystem.maxParticles];
|
||||
#endif
|
||||
|
||||
imageUV = new Vector4(0, 0, 1, 1);
|
||||
|
||||
// prepare texture sheet animation
|
||||
textureSheetAnimation = pSystem.textureSheetAnimation;
|
||||
textureSheetAnimationFrames = 0;
|
||||
textureSheetAnimationFrameSize = Vector2.zero;
|
||||
if (textureSheetAnimation.enabled)
|
||||
{
|
||||
textureSheetAnimationFrames = textureSheetAnimation.numTilesX * textureSheetAnimation.numTilesY;
|
||||
textureSheetAnimationFrameSize = new Vector2(1f / textureSheetAnimation.numTilesX, 1f / textureSheetAnimation.numTilesY);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
if (!Initialize())
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// prepare vertices
|
||||
vh.Clear();
|
||||
|
||||
if (!gameObject.activeInHierarchy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 temp = Vector2.zero;
|
||||
Vector2 corner1 = Vector2.zero;
|
||||
Vector2 corner2 = Vector2.zero;
|
||||
// iterate through current particles
|
||||
int count = pSystem.GetParticles(particles);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
ParticleSystem.Particle particle = particles[i];
|
||||
|
||||
// get particle properties
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
Vector2 position = (mainModule.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
|
||||
#else
|
||||
Vector2 position = (pSystem.simulationSpace == ParticleSystemSimulationSpace.Local ? particle.position : _transform.InverseTransformPoint(particle.position));
|
||||
#endif
|
||||
float rotation = -particle.rotation * Mathf.Deg2Rad;
|
||||
float rotation90 = rotation + Mathf.PI / 2;
|
||||
Color32 color = particle.GetCurrentColor(pSystem);
|
||||
float size = particle.GetCurrentSize(pSystem) * 0.5f;
|
||||
|
||||
// apply scale
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
if (mainModule.scalingMode == ParticleSystemScalingMode.Shape)
|
||||
position /= canvas.scaleFactor;
|
||||
#else
|
||||
if (pSystem.scalingMode == ParticleSystemScalingMode.Shape)
|
||||
position /= canvas.scaleFactor;
|
||||
#endif
|
||||
|
||||
// apply texture sheet animation
|
||||
Vector4 particleUV = imageUV;
|
||||
if (textureSheetAnimation.enabled)
|
||||
{
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
float frameProgress = 1 - (particle.remainingLifetime / particle.startLifetime);
|
||||
|
||||
if (textureSheetAnimation.frameOverTime.curveMin != null)
|
||||
{
|
||||
frameProgress = textureSheetAnimation.frameOverTime.curveMin.Evaluate(1 - (particle.remainingLifetime / particle.startLifetime));
|
||||
}
|
||||
else if (textureSheetAnimation.frameOverTime.curve != null)
|
||||
{
|
||||
frameProgress = textureSheetAnimation.frameOverTime.curve.Evaluate(1 - (particle.remainingLifetime / particle.startLifetime));
|
||||
}
|
||||
else if (textureSheetAnimation.frameOverTime.constant > 0)
|
||||
{
|
||||
frameProgress = textureSheetAnimation.frameOverTime.constant - (particle.remainingLifetime / particle.startLifetime);
|
||||
}
|
||||
#else
|
||||
float frameProgress = 1 - (particle.lifetime / particle.startLifetime);
|
||||
#endif
|
||||
|
||||
frameProgress = Mathf.Repeat(frameProgress * textureSheetAnimation.cycleCount, 1);
|
||||
int frame = 0;
|
||||
|
||||
switch (textureSheetAnimation.animation)
|
||||
{
|
||||
|
||||
case ParticleSystemAnimationType.WholeSheet:
|
||||
frame = Mathf.FloorToInt(frameProgress * textureSheetAnimationFrames);
|
||||
break;
|
||||
|
||||
case ParticleSystemAnimationType.SingleRow:
|
||||
frame = Mathf.FloorToInt(frameProgress * textureSheetAnimation.numTilesX);
|
||||
|
||||
int row = textureSheetAnimation.rowIndex;
|
||||
// if (textureSheetAnimation.useRandomRow) { // FIXME - is this handled internally by rowIndex?
|
||||
// row = Random.Range(0, textureSheetAnimation.numTilesY, using: particle.randomSeed);
|
||||
// }
|
||||
frame += row * textureSheetAnimation.numTilesX;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
frame %= textureSheetAnimationFrames;
|
||||
|
||||
particleUV.x = (frame % textureSheetAnimation.numTilesX) * textureSheetAnimationFrameSize.x;
|
||||
particleUV.y = Mathf.FloorToInt(frame / textureSheetAnimation.numTilesX) * textureSheetAnimationFrameSize.y;
|
||||
particleUV.z = particleUV.x + textureSheetAnimationFrameSize.x;
|
||||
particleUV.w = particleUV.y + textureSheetAnimationFrameSize.y;
|
||||
}
|
||||
|
||||
temp.x = particleUV.x;
|
||||
temp.y = particleUV.y;
|
||||
|
||||
_quad[0] = UIVertex.simpleVert;
|
||||
_quad[0].color = color;
|
||||
_quad[0].uv0 = temp;
|
||||
|
||||
temp.x = particleUV.x;
|
||||
temp.y = particleUV.w;
|
||||
_quad[1] = UIVertex.simpleVert;
|
||||
_quad[1].color = color;
|
||||
_quad[1].uv0 = temp;
|
||||
|
||||
temp.x = particleUV.z;
|
||||
temp.y = particleUV.w;
|
||||
_quad[2] = UIVertex.simpleVert;
|
||||
_quad[2].color = color;
|
||||
_quad[2].uv0 = temp;
|
||||
|
||||
temp.x = particleUV.z;
|
||||
temp.y = particleUV.y;
|
||||
_quad[3] = UIVertex.simpleVert;
|
||||
_quad[3].color = color;
|
||||
_quad[3].uv0 = temp;
|
||||
|
||||
if (rotation == 0)
|
||||
{
|
||||
// no rotation
|
||||
corner1.x = position.x - size;
|
||||
corner1.y = position.y - size;
|
||||
corner2.x = position.x + size;
|
||||
corner2.y = position.y + size;
|
||||
|
||||
temp.x = corner1.x;
|
||||
temp.y = corner1.y;
|
||||
_quad[0].position = temp;
|
||||
temp.x = corner1.x;
|
||||
temp.y = corner2.y;
|
||||
_quad[1].position = temp;
|
||||
temp.x = corner2.x;
|
||||
temp.y = corner2.y;
|
||||
_quad[2].position = temp;
|
||||
temp.x = corner2.x;
|
||||
temp.y = corner1.y;
|
||||
_quad[3].position = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// apply rotation
|
||||
Vector2 right = new Vector2(Mathf.Cos(rotation), Mathf.Sin(rotation)) * size;
|
||||
Vector2 up = new Vector2(Mathf.Cos(rotation90), Mathf.Sin(rotation90)) * size;
|
||||
|
||||
_quad[0].position = position - right - up;
|
||||
_quad[1].position = position - right + up;
|
||||
_quad[2].position = position + right + up;
|
||||
_quad[3].position = position + right - up;
|
||||
}
|
||||
|
||||
vh.AddUIVertexQuad(_quad);
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!fixedTime && Application.isPlaying)
|
||||
{
|
||||
pSystem.Simulate(Time.unscaledDeltaTime, false, false, true);
|
||||
SetAllDirty();
|
||||
|
||||
if ((currentMaterial != null && currentTexture != currentMaterial.mainTexture) ||
|
||||
(material != null && currentMaterial != null && material.shader != currentMaterial.shader))
|
||||
{
|
||||
pSystem = null;
|
||||
Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
SetAllDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fixedTime)
|
||||
{
|
||||
pSystem.Simulate(Time.unscaledDeltaTime, false, false, true);
|
||||
SetAllDirty();
|
||||
if ((currentMaterial != null && currentTexture != currentMaterial.mainTexture) ||
|
||||
(material != null && currentMaterial != null && material.shader != currentMaterial.shader))
|
||||
{
|
||||
pSystem = null;
|
||||
Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (material == currentMaterial)
|
||||
return;
|
||||
pSystem = null;
|
||||
Initialize();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+34
-1
@@ -1,2 +1,35 @@
|
||||
1.DependencyOrganizer.cs
|
||||
脚本需要放在unity工程的Asset/Editor下面,然后菜单工具栏(Tool)下面会出现相关工具按钮
|
||||
脚本需要放在unity工程的Asset/Editor下面,然后菜单工具栏(Tool)下面会出现相关工具按钮
|
||||
|
||||
2.AddParentToSelected.cs
|
||||
添加父对象脚本
|
||||
|
||||
3.PlayableDirectorContextMenu.cs
|
||||
timeline轨道绑定复制脚本(针对轨道绑定丢失)
|
||||
|
||||
4.RenameSelectObjects.cs
|
||||
批量重命名选中对象脚本
|
||||
|
||||
5.ReplaceWithPrefabWindow.cs
|
||||
预制体替换选中对象(窗口化脚本)
|
||||
|
||||
6.DrawPathInEditor.cs
|
||||
编辑器模式中绘制路径轨迹小工具(未完善)
|
||||
|
||||
7.ChildSort.cs
|
||||
对子对象排序
|
||||
|
||||
8.NumberScrollMixerBehaviour.cs NumberScrollPlayable.cs NumberScrollPlayableAsset.cs NumberScrollTrack.cs
|
||||
timeline中对TMP文本进行数字滚动
|
||||
|
||||
9.ParticleAttractionPoint.cs
|
||||
粒子吸引点脚本(未完善,但可用)
|
||||
|
||||
10.RopeSimulator.cs
|
||||
绳索模拟脚本
|
||||
|
||||
11.ScaleAniChild.cs
|
||||
对当前对象的子Ani节点进行动画脚本
|
||||
|
||||
12.UIParticleSystem.cs
|
||||
粒子ui化脚本
|
||||
Reference in New Issue
Block a user