diff --git a/Assets/Scripts/SceneManagement/ActorKit/AbsActor.cs b/Assets/Scripts/SceneManagement/ActorKit/AbsActor.cs index 7aa83a843..64e198511 100644 --- a/Assets/Scripts/SceneManagement/ActorKit/AbsActor.cs +++ b/Assets/Scripts/SceneManagement/ActorKit/AbsActor.cs @@ -21,6 +21,9 @@ namespace AibisDream protected float _alpha; protected SpriteRenderer spriteRenderer; + private Tween _shakeTween; + private Vector3 _shakeOrigin; + public string ActorName => _actorName; public string SlotName => _slotName; public ActorType ActorType => _actorType; @@ -96,6 +99,7 @@ namespace AibisDream public void SetSlot(ActorSlot slot) { + StopShake(); transform.position = slot.Position; spriteRenderer.sortingOrder = slot.sortingOrder; spriteRenderer.sortingLayerID = slot.sortingLayer; @@ -103,6 +107,52 @@ namespace AibisDream _slotName = slot.slotName; } + /// + /// 持续振动角色立绘;再次调用会用新参数替换当前振动。 + /// + public void StartShake(float strength, float cycleDuration, int vibrato) + { + StopShake(); + + strength = Mathf.Max(0.001f, strength); + cycleDuration = Mathf.Max(0.05f, cycleDuration); + vibrato = Mathf.Max(1, vibrato); + _shakeOrigin = transform.position; + + _shakeTween = transform + .DOShakePosition( + cycleDuration, + new Vector3(strength, strength * 0.35f, 0f), + vibrato, + 90f, + false, + false, + ShakeRandomnessMode.Full) + .SetEase(Ease.Linear) + .SetLoops(-1, LoopType.Restart) + .SetLink(gameObject, LinkBehaviour.KillOnDestroy); + } + + /// + /// 停止振动,并将立绘恢复到开始振动前的位置。 + /// + public void StopShake() + { + if (_shakeTween == null) + { + return; + } + + _shakeTween.Kill(); + _shakeTween = null; + transform.position = _shakeOrigin; + } + + protected virtual void OnDestroy() + { + StopShake(); + } + public IEnumerator FadeInAsync(float duration) { _alpha = 1; diff --git a/Assets/Scripts/SceneManagement/ActorKit/ActorManager.cs b/Assets/Scripts/SceneManagement/ActorKit/ActorManager.cs index 056eae8c7..90a53822e 100644 --- a/Assets/Scripts/SceneManagement/ActorKit/ActorManager.cs +++ b/Assets/Scripts/SceneManagement/ActorKit/ActorManager.cs @@ -245,5 +245,34 @@ namespace AibisDream actor.SetFaceState(faceName); } } + + /// + /// 持续振动角色立绘。默认作用于诊室槽位,强度单位为世界坐标。 + /// 用法:<<start_actor_shake>> 或 <<start_actor_shake 火山 0.04 0.25 18>> + /// + [YarnCommand("start_actor_shake")] + public static void StartActorShake( + string actorName = ClinicSlotName, + float strength = 0.04f, + float cycleDuration = 0.25f, + int vibrato = 18) + { + if (ActorManager.Instance.TryFindActor(actorName, out var actor)) + { + actor.StartShake(strength, cycleDuration, vibrato); + } + } + + /// + /// 停止角色立绘振动并复位。默认作用于诊室槽位。 + /// + [YarnCommand("stop_actor_shake")] + public static void StopActorShake(string actorName = ClinicSlotName) + { + if (ActorManager.Instance.TryFindActor(actorName, out var actor)) + { + actor.StopShake(); + } + } } }