mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-06-26 11:24:46 +00:00
114 lines
3.6 KiB
C#
114 lines
3.6 KiB
C#
|
using UnityEngine;
|
|||
|
|
|||
|
namespace GAS.Runtime
|
|||
|
{
|
|||
|
internal sealed class GameplayEffectPeriodTicker : IEntity
|
|||
|
{
|
|||
|
public ulong InstanceId { get; private set; }
|
|||
|
|
|||
|
private float _periodRemaining;
|
|||
|
private GameplayEffectSpec _spec;
|
|||
|
|
|||
|
public void Awake(GameplayEffectSpec spec)
|
|||
|
{
|
|||
|
InstanceId = IdGenerator.Next;
|
|||
|
_spec = spec;
|
|||
|
_periodRemaining = Period;
|
|||
|
}
|
|||
|
|
|||
|
public void Release()
|
|||
|
{
|
|||
|
InstanceId = default;
|
|||
|
_spec = default;
|
|||
|
_periodRemaining = default;
|
|||
|
}
|
|||
|
|
|||
|
private float Period => _spec.GameplayEffect.Period;
|
|||
|
|
|||
|
public void Tick()
|
|||
|
{
|
|||
|
_spec.TriggerOnTick();
|
|||
|
|
|||
|
UpdatePeriod();
|
|||
|
|
|||
|
if (_spec.DurationPolicy == EffectsDurationPolicy.Duration && _spec.DurationRemaining() <= 0)
|
|||
|
{
|
|||
|
// 处理STACKING
|
|||
|
if (_spec.GameplayEffect.Stacking.stackingType == StackingType.None)
|
|||
|
{
|
|||
|
_spec.RemoveSelf();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (_spec.GameplayEffect.Stacking.expirationPolicy == ExpirationPolicy.ClearEntireStack)
|
|||
|
{
|
|||
|
_spec.RemoveSelf();
|
|||
|
}
|
|||
|
else if (_spec.GameplayEffect.Stacking.expirationPolicy ==
|
|||
|
ExpirationPolicy.RemoveSingleStackAndRefreshDuration)
|
|||
|
{
|
|||
|
if (_spec.StackCount > 1)
|
|||
|
{
|
|||
|
_spec.RefreshStack(_spec.StackCount - 1);
|
|||
|
_spec.RefreshDuration();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
_spec.RemoveSelf();
|
|||
|
}
|
|||
|
}
|
|||
|
else if (_spec.GameplayEffect.Stacking.expirationPolicy == ExpirationPolicy.RefreshDuration)
|
|||
|
{
|
|||
|
//持续时间结束时,再次刷新Duration,这相当于无限Duration,
|
|||
|
_spec.RefreshDuration();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 注意: Period 小于 0.01f 可能出现误差, 基本够用了
|
|||
|
/// </summary>
|
|||
|
private void UpdatePeriod()
|
|||
|
{
|
|||
|
// 前提: Period不会动态修改
|
|||
|
if (Period <= 0) return;
|
|||
|
|
|||
|
var actualDuration = Time.time - _spec.ActivationTime;
|
|||
|
if (actualDuration < Mathf.Epsilon)
|
|||
|
{
|
|||
|
// 第一次执行
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
var dt = Time.deltaTime;
|
|||
|
|
|||
|
if (_spec.DurationPolicy == EffectsDurationPolicy.Duration)
|
|||
|
{
|
|||
|
var excessDuration = actualDuration - _spec.Duration;
|
|||
|
if (excessDuration >= 0)
|
|||
|
{
|
|||
|
// 如果超出了持续时间,就减去超出的时间, 此时应该是最后一次执行
|
|||
|
dt -= excessDuration;
|
|||
|
// 为了避免误差, 保证最后一次边界得到执行机会
|
|||
|
dt += 0.0001f;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_periodRemaining -= dt;
|
|||
|
|
|||
|
while (_periodRemaining < 0)
|
|||
|
{
|
|||
|
// 不能直接将_periodRemaining重置为Period, 这将累计误差
|
|||
|
_periodRemaining += Period;
|
|||
|
_spec.PeriodExecution.Value?.TriggerOnExecute();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void ResetPeriod()
|
|||
|
{
|
|||
|
_periodRemaining = Period;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|