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();
+ }
+ }
}
}