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