Files
FueraDeEscala/Assets/Game/Test/Scripts/AntManScaleController.cs
Robii Aragon d5241c3bf7 Add AntMan scaling, ghost trail and test prefab
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.
2026-03-19 18:53:27 -07:00

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;
}
}