ADD: 신규 스크립트 추가. 스트리밍글-오브젝트무버 , 야모-오브젝트트래킹툴
This commit is contained in:
parent
b1c88dbb20
commit
f0b6a55649
@ -0,0 +1,39 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class ObjectMover : MonoBehaviour
|
||||
{
|
||||
[Header("이동할 오브젝트 리스트")]
|
||||
public List<GameObject> targetObjects = new List<GameObject>();
|
||||
|
||||
[Header("프리셋 위치 (GameObjects)")]
|
||||
public List<GameObject> presetPositions = new List<GameObject>();
|
||||
|
||||
/// <summary>
|
||||
/// targetObjects를 지정한 프리셋 위치로 이동합니다.
|
||||
/// </summary>
|
||||
public void Set(int presetIndex)
|
||||
{
|
||||
if (presetIndex < 0 || presetIndex >= presetPositions.Count)
|
||||
{
|
||||
Debug.LogWarning($"[ObjectMover] 잘못된 프리셋 인덱스: {presetIndex}, 유효 범위: 0-{presetPositions.Count - 1}");
|
||||
return;
|
||||
}
|
||||
|
||||
var preset = presetPositions[presetIndex];
|
||||
if (preset == null)
|
||||
{
|
||||
Debug.LogWarning($"[ObjectMover] 프리셋 위치가 null입니다: {presetIndex}");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var obj in targetObjects)
|
||||
{
|
||||
if (obj == null) continue;
|
||||
obj.transform.position = preset.transform.position;
|
||||
obj.transform.rotation = preset.transform.rotation;
|
||||
}
|
||||
|
||||
Debug.Log($"[ObjectMover] {targetObjects.Count}개 오브젝트를 프리셋 {presetIndex} ({preset.name})으로 이동");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8db7f272a7063a34e9e9abd932adffef
|
||||
8
Assets/YAMO.meta
Normal file
8
Assets/YAMO.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd539ee6303e28f44aa5a7604af84aca
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/YAMO/Editor.meta
Normal file
8
Assets/YAMO/Editor.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6780301a63522f479d7f559b12916fd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
222
Assets/YAMO/Editor/ElasticTrackerEditor.cs
Normal file
222
Assets/YAMO/Editor/ElasticTrackerEditor.cs
Normal file
@ -0,0 +1,222 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof(ElasticTracker))]
|
||||
public class ElasticTrackerEditor : Editor
|
||||
{
|
||||
private SerializedProperty enableFollow, followTargets, positionOffset;
|
||||
private SerializedProperty followSmoothSpeed, followDistanceElasticity, followFrameInterval;
|
||||
private SerializedProperty followX, followY, followZ;
|
||||
private SerializedProperty moveRatioX, moveRatioY, moveRatioZ;
|
||||
|
||||
private SerializedProperty enableLookAt, lookAtTargets, lookAtOffset;
|
||||
private SerializedProperty lookAtSmoothSpeed, worldUp, lookAtFrameInterval;
|
||||
private SerializedProperty rotateX, rotateY, rotateZ;
|
||||
private SerializedProperty rotateRatioX, rotateRatioY, rotateRatioZ;
|
||||
|
||||
private SerializedProperty enableOrbital, orbitCenters;
|
||||
private SerializedProperty orbitHorizontalRadius, orbitHorizontalSpeed, orbitHorizontalPhaseOffset;
|
||||
private SerializedProperty orbitVerticalRadius, orbitVerticalSpeed, orbitVerticalPhaseOffset;
|
||||
private SerializedProperty orbitVerticalAngleMin, orbitVerticalAngleMax;
|
||||
private SerializedProperty orbitHeightOffset;
|
||||
|
||||
private SerializedProperty enableNoise;
|
||||
private SerializedProperty posNoiseAmplitude, posNoiseFrequency;
|
||||
private SerializedProperty posNoiseX, posNoiseY, posNoiseZ;
|
||||
private SerializedProperty rotNoiseAmplitude, rotNoiseFrequency;
|
||||
private SerializedProperty rotNoiseX, rotNoiseY, rotNoiseZ;
|
||||
|
||||
private SerializedProperty updateInEditMode;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
enableFollow = serializedObject.FindProperty("enableFollow");
|
||||
followTargets = serializedObject.FindProperty("followTargets");
|
||||
positionOffset = serializedObject.FindProperty("positionOffset");
|
||||
followSmoothSpeed = serializedObject.FindProperty("followSmoothSpeed");
|
||||
followDistanceElasticity = serializedObject.FindProperty("followDistanceElasticity");
|
||||
followFrameInterval = serializedObject.FindProperty("followFrameInterval");
|
||||
followX = serializedObject.FindProperty("followX");
|
||||
followY = serializedObject.FindProperty("followY");
|
||||
followZ = serializedObject.FindProperty("followZ");
|
||||
moveRatioX = serializedObject.FindProperty("moveRatioX");
|
||||
moveRatioY = serializedObject.FindProperty("moveRatioY");
|
||||
moveRatioZ = serializedObject.FindProperty("moveRatioZ");
|
||||
|
||||
enableLookAt = serializedObject.FindProperty("enableLookAt");
|
||||
lookAtTargets = serializedObject.FindProperty("lookAtTargets");
|
||||
lookAtOffset = serializedObject.FindProperty("lookAtOffset");
|
||||
lookAtSmoothSpeed = serializedObject.FindProperty("lookAtSmoothSpeed");
|
||||
worldUp = serializedObject.FindProperty("worldUp");
|
||||
lookAtFrameInterval = serializedObject.FindProperty("lookAtFrameInterval");
|
||||
rotateX = serializedObject.FindProperty("rotateX");
|
||||
rotateY = serializedObject.FindProperty("rotateY");
|
||||
rotateZ = serializedObject.FindProperty("rotateZ");
|
||||
rotateRatioX = serializedObject.FindProperty("rotateRatioX");
|
||||
rotateRatioY = serializedObject.FindProperty("rotateRatioY");
|
||||
rotateRatioZ = serializedObject.FindProperty("rotateRatioZ");
|
||||
|
||||
enableOrbital = serializedObject.FindProperty("enableOrbital");
|
||||
orbitCenters = serializedObject.FindProperty("orbitCenters");
|
||||
orbitHorizontalRadius = serializedObject.FindProperty("orbitHorizontalRadius");
|
||||
orbitHorizontalSpeed = serializedObject.FindProperty("orbitHorizontalSpeed");
|
||||
orbitHorizontalPhaseOffset = serializedObject.FindProperty("orbitHorizontalPhaseOffset");
|
||||
orbitVerticalRadius = serializedObject.FindProperty("orbitVerticalRadius");
|
||||
orbitVerticalSpeed = serializedObject.FindProperty("orbitVerticalSpeed");
|
||||
orbitVerticalPhaseOffset = serializedObject.FindProperty("orbitVerticalPhaseOffset");
|
||||
orbitVerticalAngleMin = serializedObject.FindProperty("orbitVerticalAngleMin");
|
||||
orbitVerticalAngleMax = serializedObject.FindProperty("orbitVerticalAngleMax");
|
||||
orbitHeightOffset = serializedObject.FindProperty("orbitHeightOffset");
|
||||
|
||||
enableNoise = serializedObject.FindProperty("enableNoise");
|
||||
posNoiseAmplitude = serializedObject.FindProperty("posNoiseAmplitude");
|
||||
posNoiseFrequency = serializedObject.FindProperty("posNoiseFrequency");
|
||||
posNoiseX = serializedObject.FindProperty("posNoiseX");
|
||||
posNoiseY = serializedObject.FindProperty("posNoiseY");
|
||||
posNoiseZ = serializedObject.FindProperty("posNoiseZ");
|
||||
rotNoiseAmplitude = serializedObject.FindProperty("rotNoiseAmplitude");
|
||||
rotNoiseFrequency = serializedObject.FindProperty("rotNoiseFrequency");
|
||||
rotNoiseX = serializedObject.FindProperty("rotNoiseX");
|
||||
rotNoiseY = serializedObject.FindProperty("rotNoiseY");
|
||||
rotNoiseZ = serializedObject.FindProperty("rotNoiseZ");
|
||||
|
||||
updateInEditMode = serializedObject.FindProperty("updateInEditMode");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
// ── Follow Section ──
|
||||
DrawSectionHeader("Follow", enableFollow);
|
||||
if (enableFollow.boolValue)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(followTargets, new GUIContent("Targets"), true);
|
||||
EditorGUILayout.PropertyField(positionOffset, new GUIContent("Position Offset"));
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.PropertyField(followSmoothSpeed, new GUIContent("Smooth Speed"));
|
||||
EditorGUILayout.PropertyField(followDistanceElasticity, new GUIContent("Distance Elasticity"));
|
||||
EditorGUILayout.PropertyField(followFrameInterval, new GUIContent("Frame Interval"));
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.LabelField("Axis On/Off", EditorStyles.miniLabel);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
followX.boolValue = EditorGUILayout.ToggleLeft("X", followX.boolValue, GUILayout.Width(40));
|
||||
followY.boolValue = EditorGUILayout.ToggleLeft("Y", followY.boolValue, GUILayout.Width(40));
|
||||
followZ.boolValue = EditorGUILayout.ToggleLeft("Z", followZ.boolValue, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.Space(2);
|
||||
|
||||
EditorGUILayout.LabelField("Axis Move Ratio", EditorStyles.miniLabel);
|
||||
if (followX.boolValue) EditorGUILayout.Slider(moveRatioX, 0f, 100f, "X Ratio %");
|
||||
if (followY.boolValue) EditorGUILayout.Slider(moveRatioY, 0f, 100f, "Y Ratio %");
|
||||
if (followZ.boolValue) EditorGUILayout.Slider(moveRatioZ, 0f, 100f, "Z Ratio %");
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
|
||||
// ── LookAt Section ──
|
||||
DrawSectionHeader("LookAt", enableLookAt);
|
||||
if (enableLookAt.boolValue)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(lookAtTargets, new GUIContent("Targets"), true);
|
||||
EditorGUILayout.PropertyField(lookAtOffset, new GUIContent("Offset"));
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.PropertyField(lookAtSmoothSpeed, new GUIContent("Smooth Speed"));
|
||||
EditorGUILayout.PropertyField(worldUp, new GUIContent("World Up"));
|
||||
EditorGUILayout.PropertyField(lookAtFrameInterval, new GUIContent("Frame Interval"));
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.LabelField("Axis On/Off", EditorStyles.miniLabel);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
rotateX.boolValue = EditorGUILayout.ToggleLeft("X", rotateX.boolValue, GUILayout.Width(40));
|
||||
rotateY.boolValue = EditorGUILayout.ToggleLeft("Y", rotateY.boolValue, GUILayout.Width(40));
|
||||
rotateZ.boolValue = EditorGUILayout.ToggleLeft("Z", rotateZ.boolValue, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.Space(2);
|
||||
|
||||
EditorGUILayout.LabelField("Axis Rotate Ratio", EditorStyles.miniLabel);
|
||||
if (rotateX.boolValue) EditorGUILayout.Slider(rotateRatioX, 0f, 100f, "X Ratio %");
|
||||
if (rotateY.boolValue) EditorGUILayout.Slider(rotateRatioY, 0f, 100f, "Y Ratio %");
|
||||
if (rotateZ.boolValue) EditorGUILayout.Slider(rotateRatioZ, 0f, 100f, "Z Ratio %");
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
|
||||
// ── Orbital Section ──
|
||||
DrawSectionHeader("Orbital", enableOrbital);
|
||||
if (enableOrbital.boolValue)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(orbitCenters, new GUIContent("Centers (비워두면 Follow Targets)"), true);
|
||||
EditorGUILayout.PropertyField(orbitHeightOffset, new GUIContent("Height Offset"));
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.LabelField("Horizontal (360° Loop)", EditorStyles.miniLabel);
|
||||
EditorGUILayout.PropertyField(orbitHorizontalRadius, new GUIContent("Radius"));
|
||||
EditorGUILayout.PropertyField(orbitHorizontalSpeed, new GUIContent("Speed (°/s)"));
|
||||
EditorGUILayout.PropertyField(orbitHorizontalPhaseOffset, new GUIContent("Phase Offset (°)"));
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.LabelField("Vertical (Ping-Pong)", EditorStyles.miniLabel);
|
||||
EditorGUILayout.PropertyField(orbitVerticalRadius, new GUIContent("Radius"));
|
||||
EditorGUILayout.PropertyField(orbitVerticalSpeed, new GUIContent("Speed (°/s)"));
|
||||
EditorGUILayout.PropertyField(orbitVerticalPhaseOffset, new GUIContent("Phase Offset (°)"));
|
||||
EditorGUILayout.PropertyField(orbitVerticalAngleMin, new GUIContent("Angle Min (°)"));
|
||||
EditorGUILayout.PropertyField(orbitVerticalAngleMax, new GUIContent("Angle Max (°)"));
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
|
||||
// ── Noise Section ──
|
||||
DrawSectionHeader("Noise (Hand-held)", enableNoise);
|
||||
if (enableNoise.boolValue)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.LabelField("Position Noise", EditorStyles.miniLabel);
|
||||
EditorGUILayout.PropertyField(posNoiseAmplitude, new GUIContent("Amplitude (m)"));
|
||||
EditorGUILayout.PropertyField(posNoiseFrequency, new GUIContent("Frequency"));
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
posNoiseX.boolValue = EditorGUILayout.ToggleLeft("X", posNoiseX.boolValue, GUILayout.Width(40));
|
||||
posNoiseY.boolValue = EditorGUILayout.ToggleLeft("Y", posNoiseY.boolValue, GUILayout.Width(40));
|
||||
posNoiseZ.boolValue = EditorGUILayout.ToggleLeft("Z", posNoiseZ.boolValue, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.LabelField("Rotation Noise", EditorStyles.miniLabel);
|
||||
EditorGUILayout.PropertyField(rotNoiseAmplitude, new GUIContent("Amplitude (°)"));
|
||||
EditorGUILayout.PropertyField(rotNoiseFrequency, new GUIContent("Frequency"));
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
rotNoiseX.boolValue = EditorGUILayout.ToggleLeft("X", rotNoiseX.boolValue, GUILayout.Width(40));
|
||||
rotNoiseY.boolValue = EditorGUILayout.ToggleLeft("Y", rotNoiseY.boolValue, GUILayout.Width(40));
|
||||
rotNoiseZ.boolValue = EditorGUILayout.ToggleLeft("Z", rotNoiseZ.boolValue, GUILayout.Width(40));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
|
||||
// ── Editor Options ──
|
||||
EditorGUILayout.LabelField("Editor Options", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(updateInEditMode);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void DrawSectionHeader(string label, SerializedProperty toggle)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
toggle.boolValue = EditorGUILayout.Toggle(toggle.boolValue, GUILayout.Width(16));
|
||||
EditorGUILayout.LabelField(label, EditorStyles.boldLabel);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
2
Assets/YAMO/Editor/ElasticTrackerEditor.cs.meta
Normal file
2
Assets/YAMO/Editor/ElasticTrackerEditor.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11b450839bcc20a49989f3fbe201825a
|
||||
283
Assets/YAMO/ElasticTracker.cs
Normal file
283
Assets/YAMO/ElasticTracker.cs
Normal file
@ -0,0 +1,283 @@
|
||||
using UnityEngine;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
[ExecuteAlways]
|
||||
public class ElasticTracker : MonoBehaviour
|
||||
{
|
||||
// ── Follow ──
|
||||
public bool enableFollow = true;
|
||||
public Transform[] followTargets = new Transform[1];
|
||||
public Vector3 positionOffset;
|
||||
[Min(0f)] public float followSmoothSpeed = 5f;
|
||||
[Min(0f)] public float followDistanceElasticity = 1.5f;
|
||||
[Min(1)] public int followFrameInterval = 1;
|
||||
public bool followX = true;
|
||||
public bool followY = true;
|
||||
public bool followZ = true;
|
||||
[Range(0f, 100f)] public float moveRatioX = 100f;
|
||||
[Range(0f, 100f)] public float moveRatioY = 100f;
|
||||
[Range(0f, 100f)] public float moveRatioZ = 100f;
|
||||
|
||||
// ── LookAt ──
|
||||
public bool enableLookAt = true;
|
||||
public Transform[] lookAtTargets = new Transform[1];
|
||||
public Vector3 lookAtOffset;
|
||||
[Min(0f)] public float lookAtSmoothSpeed = 5f;
|
||||
public Vector3 worldUp = Vector3.up;
|
||||
[Min(1)] public int lookAtFrameInterval = 1;
|
||||
public bool rotateX = true;
|
||||
public bool rotateY = true;
|
||||
public bool rotateZ = true;
|
||||
[Range(0f, 100f)] public float rotateRatioX = 100f;
|
||||
[Range(0f, 100f)] public float rotateRatioY = 100f;
|
||||
[Range(0f, 100f)] public float rotateRatioZ = 100f;
|
||||
|
||||
// ── Orbital ──
|
||||
public bool enableOrbital = false;
|
||||
public Transform[] orbitCenters = new Transform[0];
|
||||
[Min(0f)] public float orbitHorizontalRadius = 5f;
|
||||
public float orbitHorizontalSpeed = 15f;
|
||||
public float orbitHorizontalPhaseOffset = 0f;
|
||||
[Min(0f)] public float orbitVerticalRadius = 1f;
|
||||
public float orbitVerticalSpeed = 8f;
|
||||
public float orbitVerticalPhaseOffset = 0f;
|
||||
public float orbitVerticalAngleMin = -20f;
|
||||
public float orbitVerticalAngleMax = 40f;
|
||||
public float orbitHeightOffset = 2f;
|
||||
|
||||
// ── Noise (Hand-held) ──
|
||||
public bool enableNoise = false;
|
||||
|
||||
[Min(0f)] public float posNoiseAmplitude = 0.003f;
|
||||
[Min(0f)] public float posNoiseFrequency = 0.4f;
|
||||
public bool posNoiseX = true;
|
||||
public bool posNoiseY = true;
|
||||
public bool posNoiseZ = true;
|
||||
|
||||
[Min(0f)] public float rotNoiseAmplitude = 0.25f;
|
||||
[Min(0f)] public float rotNoiseFrequency = 0.3f;
|
||||
public bool rotNoiseX = true;
|
||||
public bool rotNoiseY = true;
|
||||
public bool rotNoiseZ = false;
|
||||
|
||||
// ── Editor ──
|
||||
public bool updateInEditMode = true;
|
||||
|
||||
private int _followFrameCounter;
|
||||
private float _followAccDelta;
|
||||
private int _lookAtFrameCounter;
|
||||
private float _lookAtAccDelta;
|
||||
private float _orbitalTime;
|
||||
private float _noiseTime;
|
||||
private float _noiseSeedX, _noiseSeedY, _noiseSeedZ;
|
||||
private float _noiseSeedRX, _noiseSeedRY, _noiseSeedRZ;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private double _lastEditorTime;
|
||||
#endif
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_followFrameCounter = 0;
|
||||
_followAccDelta = 0f;
|
||||
_lookAtFrameCounter = 0;
|
||||
_lookAtAccDelta = 0f;
|
||||
_orbitalTime = 0f;
|
||||
_noiseTime = 0f;
|
||||
_noiseSeedX = Random.Range(0f, 1000f);
|
||||
_noiseSeedY = Random.Range(0f, 1000f);
|
||||
_noiseSeedZ = Random.Range(0f, 1000f);
|
||||
_noiseSeedRX = Random.Range(0f, 1000f);
|
||||
_noiseSeedRY = Random.Range(0f, 1000f);
|
||||
_noiseSeedRZ = Random.Range(0f, 1000f);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
_lastEditorTime = EditorApplication.timeSinceStartup;
|
||||
EditorApplication.update -= EditorTick;
|
||||
EditorApplication.update += EditorTick;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.update -= EditorTick;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!Application.isPlaying) return;
|
||||
|
||||
float dt = Time.deltaTime;
|
||||
|
||||
if (enableFollow)
|
||||
{
|
||||
_followAccDelta += dt;
|
||||
_followFrameCounter++;
|
||||
if (_followFrameCounter >= followFrameInterval)
|
||||
{
|
||||
ApplyFollow(_followAccDelta);
|
||||
_followFrameCounter = 0;
|
||||
_followAccDelta = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (enableOrbital)
|
||||
{
|
||||
ApplyOrbital(dt);
|
||||
}
|
||||
|
||||
if (enableLookAt)
|
||||
{
|
||||
_lookAtAccDelta += dt;
|
||||
_lookAtFrameCounter++;
|
||||
if (_lookAtFrameCounter >= lookAtFrameInterval)
|
||||
{
|
||||
ApplyLookAt(_lookAtAccDelta);
|
||||
_lookAtFrameCounter = 0;
|
||||
_lookAtAccDelta = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (enableNoise)
|
||||
{
|
||||
ApplyNoise(dt);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void EditorTick()
|
||||
{
|
||||
if (Application.isPlaying || !updateInEditMode || this == null || !isActiveAndEnabled) return;
|
||||
|
||||
double now = EditorApplication.timeSinceStartup;
|
||||
float deltaTime = Mathf.Max(0.0001f, (float)(now - _lastEditorTime));
|
||||
_lastEditorTime = now;
|
||||
|
||||
if (enableFollow) ApplyFollow(deltaTime);
|
||||
if (enableOrbital) ApplyOrbital(deltaTime);
|
||||
if (enableLookAt) ApplyLookAt(deltaTime);
|
||||
if (enableNoise) ApplyNoise(deltaTime);
|
||||
EditorApplication.QueuePlayerLoopUpdate();
|
||||
}
|
||||
#endif
|
||||
|
||||
private Vector3 GetCenterPosition(Transform[] targets)
|
||||
{
|
||||
Vector3 sum = Vector3.zero;
|
||||
int count = 0;
|
||||
for (int i = 0; i < targets.Length; i++)
|
||||
{
|
||||
if (targets[i] != null)
|
||||
{
|
||||
sum += targets[i].position;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 0) return transform.position;
|
||||
return sum / count;
|
||||
}
|
||||
|
||||
private void ApplyFollow(float deltaTime)
|
||||
{
|
||||
Vector3 centerPos = GetCenterPosition(followTargets);
|
||||
if (centerPos == transform.position && followTargets.Length > 0) return;
|
||||
|
||||
Vector3 targetPos = centerPos + positionOffset;
|
||||
Vector3 currentPos = transform.position;
|
||||
|
||||
float distance = Vector3.Distance(currentPos, targetPos);
|
||||
float speedMultiplier = 1f + (distance * followDistanceElasticity);
|
||||
float t = 1f - Mathf.Exp(-followSmoothSpeed * speedMultiplier * deltaTime);
|
||||
|
||||
Vector3 fullNextPos = Vector3.Lerp(currentPos, targetPos, t);
|
||||
|
||||
Vector3 nextPos = currentPos;
|
||||
if (followX) nextPos.x = Mathf.Lerp(currentPos.x, fullNextPos.x, moveRatioX * 0.01f);
|
||||
if (followY) nextPos.y = Mathf.Lerp(currentPos.y, fullNextPos.y, moveRatioY * 0.01f);
|
||||
if (followZ) nextPos.z = Mathf.Lerp(currentPos.z, fullNextPos.z, moveRatioZ * 0.01f);
|
||||
|
||||
transform.position = nextPos;
|
||||
}
|
||||
|
||||
private void ApplyOrbital(float deltaTime)
|
||||
{
|
||||
// orbitCenters가 비어있으면 followTargets를 폴백으로 사용
|
||||
Transform[] centers = (orbitCenters != null && orbitCenters.Length > 0) ? orbitCenters : followTargets;
|
||||
Vector3 centerPos = GetCenterPosition(centers);
|
||||
|
||||
_orbitalTime += deltaTime;
|
||||
|
||||
// Horizontal: continuous 360° loop
|
||||
float hAngleDeg = (orbitHorizontalPhaseOffset + orbitHorizontalSpeed * _orbitalTime) % 360f;
|
||||
float hAngleRad = hAngleDeg * Mathf.Deg2Rad;
|
||||
|
||||
// Vertical: ping-pong with sine easing for smooth turnaround
|
||||
float vCycle = orbitVerticalSpeed * _orbitalTime + orbitVerticalPhaseOffset;
|
||||
float vNormalized = (Mathf.Sin(vCycle * Mathf.Deg2Rad) + 1f) * 0.5f;
|
||||
float vAngleDeg = Mathf.Lerp(orbitVerticalAngleMin, orbitVerticalAngleMax, vNormalized);
|
||||
float vAngleRad = vAngleDeg * Mathf.Deg2Rad;
|
||||
|
||||
// Spherical to Cartesian offset
|
||||
float cosV = Mathf.Cos(vAngleRad);
|
||||
Vector3 orbitOffset = new Vector3(
|
||||
Mathf.Sin(hAngleRad) * orbitHorizontalRadius * cosV,
|
||||
Mathf.Sin(vAngleRad) * orbitVerticalRadius + orbitHeightOffset,
|
||||
Mathf.Cos(hAngleRad) * orbitHorizontalRadius * cosV
|
||||
);
|
||||
|
||||
transform.position = centerPos + orbitOffset;
|
||||
}
|
||||
|
||||
private void ApplyLookAt(float deltaTime)
|
||||
{
|
||||
Vector3 centerPos = GetCenterPosition(lookAtTargets);
|
||||
Vector3 lookPoint = centerPos + lookAtOffset;
|
||||
Vector3 direction = lookPoint - transform.position;
|
||||
if (direction.sqrMagnitude < 0.0001f) return;
|
||||
|
||||
Quaternion targetRot = Quaternion.LookRotation(direction.normalized, worldUp);
|
||||
|
||||
float t = 1f - Mathf.Exp(-lookAtSmoothSpeed * deltaTime);
|
||||
Quaternion fullRot = Quaternion.Slerp(transform.rotation, targetRot, t);
|
||||
|
||||
Vector3 currentEuler = transform.rotation.eulerAngles;
|
||||
Vector3 fullEuler = fullRot.eulerAngles;
|
||||
|
||||
Vector3 resultEuler = currentEuler;
|
||||
if (rotateX) resultEuler.x = Mathf.LerpAngle(currentEuler.x, fullEuler.x, rotateRatioX * 0.01f);
|
||||
if (rotateY) resultEuler.y = Mathf.LerpAngle(currentEuler.y, fullEuler.y, rotateRatioY * 0.01f);
|
||||
if (rotateZ) resultEuler.z = Mathf.LerpAngle(currentEuler.z, fullEuler.z, rotateRatioZ * 0.01f);
|
||||
|
||||
transform.rotation = Quaternion.Euler(resultEuler);
|
||||
}
|
||||
|
||||
private void ApplyNoise(float deltaTime)
|
||||
{
|
||||
_noiseTime += deltaTime;
|
||||
|
||||
// Position noise
|
||||
if (posNoiseAmplitude > 0f)
|
||||
{
|
||||
float pt = _noiseTime * posNoiseFrequency;
|
||||
float nx = posNoiseX ? (Mathf.PerlinNoise(_noiseSeedX + pt, 0f) - 0.5f) * 2f * posNoiseAmplitude : 0f;
|
||||
float ny = posNoiseY ? (Mathf.PerlinNoise(_noiseSeedY + pt, 0f) - 0.5f) * 2f * posNoiseAmplitude : 0f;
|
||||
float nz = posNoiseZ ? (Mathf.PerlinNoise(_noiseSeedZ + pt, 0f) - 0.5f) * 2f * posNoiseAmplitude : 0f;
|
||||
transform.position += transform.rotation * new Vector3(nx, ny, nz);
|
||||
}
|
||||
|
||||
// Rotation noise
|
||||
if (rotNoiseAmplitude > 0f)
|
||||
{
|
||||
float rt = _noiseTime * rotNoiseFrequency;
|
||||
float rx = rotNoiseX ? (Mathf.PerlinNoise(_noiseSeedRX + rt, 0f) - 0.5f) * 2f * rotNoiseAmplitude : 0f;
|
||||
float ry = rotNoiseY ? (Mathf.PerlinNoise(_noiseSeedRY + rt, 0f) - 0.5f) * 2f * rotNoiseAmplitude : 0f;
|
||||
float rz = rotNoiseZ ? (Mathf.PerlinNoise(_noiseSeedRZ + rt, 0f) - 0.5f) * 2f * rotNoiseAmplitude : 0f;
|
||||
transform.rotation *= Quaternion.Euler(rx, ry, rz);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/YAMO/ElasticTracker.cs.meta
Normal file
2
Assets/YAMO/ElasticTracker.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28712e1e7e1e78048b27efeed7cfe027
|
||||
Loading…
x
Reference in New Issue
Block a user