From ba19c2eff5eda3a53b60929fdf74d717432ded11 Mon Sep 17 00:00:00 2001 From: bottlefish <781230111@qq.com> Date: Sun, 19 Jul 2026 20:31:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(scene-mgmt):=20=E6=B7=BB=E5=8A=A0=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E7=AB=8B=E7=BB=98=E6=8C=81=E7=BB=AD=E6=8C=AF=E5=8A=A8?= =?UTF-8?q?=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SceneManagement/ActorKit/AbsActor.cs | 50 +++++++++++++++++++ .../SceneManagement/ActorKit/ActorManager.cs | 29 +++++++++++ 2 files changed, 79 insertions(+) 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(); + } + } } }