Introduce a set of test tools and demo assets for an AntMan-style scaling effect: - Add AntManScaleController: handles smooth scale transitions (absolute/relative modes), pivot preservation, queued toggles and events. - Add GhostTrailEmitter and GhostTrailGhost: spawn fading ghost meshes (supports skinned mesh baking, material fallback, lifetime and pooling limit). - Add GKTInventoryScaleToggle: inventory-gated input wrapper to toggle scale with optional Ctrl bypass and auto reference resolution. - Add AntManTestSceneBootstrap and TestBootstrap prefab to quickly construct a test scene (cube, light, camera) with components configured. - Add AntManScaleTest scene and related prefab/meta files, plus .vsconfig for Unity workload. - Update SampleScene LFS pointer (scene file checksum/size). These changes provide a reusable demo and components to test scaling visuals and interactions during development.
195 lines
5.0 KiB
C#
195 lines
5.0 KiB
C#
using System;
|
|
using System.Collections;
|
|
using UnityEngine;
|
|
|
|
public class AntManScaleController : MonoBehaviour
|
|
{
|
|
private enum ScaleMode
|
|
{
|
|
Absolute,
|
|
RelativeToInitial
|
|
}
|
|
|
|
[Header("Input")]
|
|
[SerializeField] private bool readToggleInput = true;
|
|
[SerializeField] private KeyCode toggleKey = KeyCode.Space;
|
|
|
|
[Header("Objetivo de Escala")]
|
|
[SerializeField] private Transform scaleTarget;
|
|
[SerializeField] private bool keepPivotWorldPosition = true;
|
|
[SerializeField] private Transform pivotReference;
|
|
|
|
[Header("Escalas")]
|
|
[SerializeField] private ScaleMode scaleMode = ScaleMode.RelativeToInitial;
|
|
[SerializeField] private Vector3 smallScale = Vector3.one;
|
|
[SerializeField] private Vector3 largeScale = new Vector3(20f, 20f, 20f);
|
|
[SerializeField] [Min(0.001f)] private float smallScaleMultiplier = 0.2f;
|
|
[SerializeField] [Min(0.001f)] private float largeScaleMultiplier = 1f;
|
|
[SerializeField] private bool startLarge;
|
|
|
|
[Header("Transicion")]
|
|
[SerializeField] [Min(0.01f)] private float transitionDuration = 0.45f;
|
|
[SerializeField] private AnimationCurve transitionCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
|
|
|
|
[Header("Debug")]
|
|
[SerializeField] private bool showStateLogs;
|
|
|
|
public event Action<Vector3, Vector3> TransitionStarted;
|
|
public event Action<Vector3> TransitionCompleted;
|
|
|
|
public bool IsTransitioning => _transitionRoutine != null;
|
|
public bool IsLarge => _isLarge;
|
|
public Transform ScaleTarget => scaleTarget;
|
|
|
|
private bool _isLarge;
|
|
private bool _hasQueuedToggle;
|
|
private Coroutine _transitionRoutine;
|
|
private Vector3 _initialScale;
|
|
|
|
private void Awake()
|
|
{
|
|
if (scaleTarget == null)
|
|
{
|
|
scaleTarget = transform;
|
|
}
|
|
|
|
if (pivotReference == null)
|
|
{
|
|
pivotReference = scaleTarget;
|
|
}
|
|
|
|
_initialScale = scaleTarget.localScale;
|
|
|
|
_isLarge = startLarge;
|
|
ApplyScale(_isLarge ? GetLargeScale() : GetSmallScale());
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!readToggleInput)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Input.GetKeyDown(toggleKey))
|
|
{
|
|
RequestToggle();
|
|
}
|
|
}
|
|
|
|
public void SetReadToggleInputState(bool state)
|
|
{
|
|
readToggleInput = state;
|
|
}
|
|
|
|
public Vector3 GetCurrentScale()
|
|
{
|
|
if (scaleTarget == null)
|
|
{
|
|
return transform.localScale;
|
|
}
|
|
|
|
return scaleTarget.localScale;
|
|
}
|
|
|
|
public void RequestToggle()
|
|
{
|
|
if (IsTransitioning)
|
|
{
|
|
_hasQueuedToggle = !_hasQueuedToggle;
|
|
if (showStateLogs)
|
|
{
|
|
Debug.Log($"[AntManScaleController] Toggle en cola: {_hasQueuedToggle}", this);
|
|
}
|
|
return;
|
|
}
|
|
|
|
StartScaleTransition();
|
|
}
|
|
|
|
private void StartScaleTransition()
|
|
{
|
|
Vector3 from = scaleTarget.localScale;
|
|
_isLarge = !_isLarge;
|
|
Vector3 to = _isLarge ? GetLargeScale() : GetSmallScale();
|
|
|
|
_transitionRoutine = StartCoroutine(TransitionRoutine(from, to));
|
|
}
|
|
|
|
private IEnumerator TransitionRoutine(Vector3 from, Vector3 to)
|
|
{
|
|
if (showStateLogs)
|
|
{
|
|
Debug.Log($"[AntManScaleController] Transicion {from} -> {to}", this);
|
|
}
|
|
|
|
TransitionStarted?.Invoke(from, to);
|
|
|
|
float elapsed = 0f;
|
|
while (elapsed < transitionDuration)
|
|
{
|
|
elapsed += Time.deltaTime;
|
|
float t = Mathf.Clamp01(elapsed / transitionDuration);
|
|
float eased = transitionCurve.Evaluate(t);
|
|
ApplyScale(Vector3.LerpUnclamped(from, to, eased));
|
|
yield return null;
|
|
}
|
|
|
|
ApplyScale(to);
|
|
TransitionCompleted?.Invoke(to);
|
|
|
|
if (showStateLogs)
|
|
{
|
|
Debug.Log($"[AntManScaleController] Escala final: {to}", this);
|
|
}
|
|
|
|
_transitionRoutine = null;
|
|
|
|
if (_hasQueuedToggle)
|
|
{
|
|
_hasQueuedToggle = false;
|
|
StartScaleTransition();
|
|
}
|
|
}
|
|
|
|
private void ApplyScale(Vector3 newScale)
|
|
{
|
|
if (scaleTarget == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!keepPivotWorldPosition || pivotReference == null)
|
|
{
|
|
scaleTarget.localScale = newScale;
|
|
return;
|
|
}
|
|
|
|
Vector3 pivotPositionBefore = pivotReference.position;
|
|
scaleTarget.localScale = newScale;
|
|
Vector3 pivotPositionAfter = pivotReference.position;
|
|
Vector3 delta = pivotPositionBefore - pivotPositionAfter;
|
|
scaleTarget.position += delta;
|
|
}
|
|
|
|
private Vector3 GetSmallScale()
|
|
{
|
|
if (scaleMode == ScaleMode.RelativeToInitial)
|
|
{
|
|
return _initialScale * smallScaleMultiplier;
|
|
}
|
|
|
|
return smallScale;
|
|
}
|
|
|
|
private Vector3 GetLargeScale()
|
|
{
|
|
if (scaleMode == ScaleMode.RelativeToInitial)
|
|
{
|
|
return _initialScale * largeScaleMultiplier;
|
|
}
|
|
|
|
return largeScale;
|
|
}
|
|
}
|