Passion & UI
This commit is contained in:
@@ -36,6 +36,16 @@ namespace Cielonos.MainGame
|
||||
public bool canTriggerHitEvent = true;
|
||||
public List<string> tags = new List<string>();
|
||||
public Action updateAction;
|
||||
|
||||
/// <summary>
|
||||
/// 当前是否处于反应窗口(含 grace before/after)。无 TimeSubmodule 时回退到 isEnabling。
|
||||
/// </summary>
|
||||
public bool isReactionActive => timeSm?.IsReactionActive() ?? isEnabling;
|
||||
|
||||
/// <summary>
|
||||
/// 在 grace window 期间已成功反应(格挡/闪避)的目标,不再对其造成伤害。
|
||||
/// </summary>
|
||||
[HideInInspector] public HashSet<GameObject> reactedTargets = new HashSet<GameObject>();
|
||||
|
||||
[Title("Submodules")]
|
||||
[HideInEditorMode] public TransformSubmodule transformSm;
|
||||
@@ -60,6 +70,7 @@ namespace Cielonos.MainGame
|
||||
this.targetFractions = targetFractions.ToList();
|
||||
this.canTriggerHitEvent = true;
|
||||
this.tags = new List<string>();
|
||||
this.reactedTargets.Clear();
|
||||
|
||||
attackSm = null;
|
||||
timeSm = null;
|
||||
@@ -159,6 +170,16 @@ namespace Cielonos.MainGame
|
||||
timeSm = new TimeSubmodule(this, lifeTime, delayTime, enableTime, enableAction, timeOutAction);
|
||||
return this as T;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置带反应 grace window 的时间子模块。graceBefore/graceAfter 为 0 时行为与无 grace window 一致。
|
||||
/// </summary>
|
||||
public T SetTimeSubmodule<T>(float lifeTime, float delayTime, float enableTime,
|
||||
Action enableAction, Action timeOutAction, float graceBefore) where T : AttackAreaBase
|
||||
{
|
||||
timeSm = new TimeSubmodule(this, lifeTime, delayTime, enableTime, enableAction, timeOutAction, graceBefore);
|
||||
return this as T;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region HitSubmodule
|
||||
@@ -295,7 +316,8 @@ namespace Cielonos.MainGame
|
||||
|
||||
}
|
||||
|
||||
protected virtual void HitOnTarget(Collider hitCollider, Vector3 hitPosition, out Attack.Result attackResult)
|
||||
protected virtual void HitOnTarget(Collider hitCollider, Vector3 hitPosition,
|
||||
out Attack.Result attackResult, bool onlyCheckReaction = false)
|
||||
{
|
||||
CharacterBase target = hitCollider.GetComponentInParent<CharacterBase>();
|
||||
|
||||
@@ -316,6 +338,15 @@ namespace Cielonos.MainGame
|
||||
return;
|
||||
}
|
||||
|
||||
// Grace window 期间仅执行反应检测,不造成伤害和其他效果
|
||||
if (onlyCheckReaction)
|
||||
{
|
||||
attackResult.isBlocked = reactionSm?.CheckBlock(target, creator, hitPosition) ?? false;
|
||||
attackResult.isDodged = reactionSm?.CheckDodge(target) ?? false;
|
||||
attackResult.isReflected = reactionSm?.CheckReflection(target) ?? false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (moveSm is { stopWhenHit: true })
|
||||
{
|
||||
moveSm.canMove = false;
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace Cielonos.MainGame
|
||||
|
||||
public override void HitCharacter(Collider characterCollider, Vector3 hitPosition)
|
||||
{
|
||||
if (!isEnabling)
|
||||
// 既不在伤害阶段也不在反应窗口,直接跳过
|
||||
if (!isEnabling && !isReactionActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -30,13 +31,33 @@ namespace Cielonos.MainGame
|
||||
|
||||
if (!IsValidTarget(targetCharacter)) return;
|
||||
|
||||
// 已在 grace window 期间成功反应的目标不再处理
|
||||
if (reactedTargets.Contains(targetCharacter.gameObject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (hitSm.checkedObjects.Contains(targetCharacter.gameObject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hitSm.AddCheckedObject(targetCharacter.gameObject);
|
||||
|
||||
// 仅在反应窗口内(enable 阶段之前或之后),只做反应检测
|
||||
if (!isEnabling && isReactionActive)
|
||||
{
|
||||
HitOnTarget(characterCollider, areaCollider.ClosestPoint(targetCharacter.CenterPoint.position),
|
||||
out Attack.Result graceResult, onlyCheckReaction: true);
|
||||
if (graceResult.isBlocked || graceResult.isDodged)
|
||||
{
|
||||
reactedTargets.Add(targetCharacter.gameObject);
|
||||
hitSm.AddCheckedObject(targetCharacter.gameObject);
|
||||
Debug.Log($"[NormalArea] Target {targetCharacter.name} successfully reacted during grace window. Blocked: {graceResult.isBlocked}, Dodged: {graceResult.isDodged}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 正常 enable 阶段:造成伤害
|
||||
hitSm.AddCheckedObject(targetCharacter.gameObject);
|
||||
HitOnTarget(characterCollider, areaCollider.ClosestPoint(targetCharacter.CenterPoint.position), out _);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace Cielonos.MainGame
|
||||
|
||||
public override void HitCharacter(Collider characterCollider, Vector3 hitPosition)
|
||||
{
|
||||
if (!isEnabling)
|
||||
// 既不在伤害阶段也不在反应窗口,直接跳过
|
||||
if (!isEnabling && !isReactionActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -46,13 +47,31 @@ namespace Cielonos.MainGame
|
||||
|
||||
if (!IsValidTarget(targetCharacter)) return;
|
||||
|
||||
// 已在 grace window 期间成功反应的目标不再处理
|
||||
if (reactedTargets.Contains(targetCharacter.gameObject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (hitSm.checkedObjects.Contains(targetCharacter.gameObject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 仅在反应窗口内(enable 阶段之前或之后),只做反应检测
|
||||
if (!isEnabling && isReactionActive)
|
||||
{
|
||||
HitOnTarget(characterCollider, hitPosition, out Attack.Result graceResult, onlyCheckReaction: true);
|
||||
if (graceResult.isBlocked || graceResult.isDodged)
|
||||
{
|
||||
reactedTargets.Add(targetCharacter.gameObject);
|
||||
hitSm.AddCheckedObject(targetCharacter.gameObject);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 正常 enable 阶段:造成伤害
|
||||
hitSm.AddCheckedObject(targetCharacter.gameObject);
|
||||
|
||||
HitOnTarget(characterCollider, hitPosition, out _);
|
||||
}
|
||||
|
||||
@@ -81,9 +100,12 @@ namespace Cielonos.MainGame
|
||||
|
||||
public partial class Projectile
|
||||
{
|
||||
protected override void HitOnTarget(Collider hitCollider, Vector3 hitPosition, out Attack.Result result)
|
||||
protected override void HitOnTarget(Collider hitCollider, Vector3 hitPosition, out Attack.Result result,
|
||||
bool onlyCheckReaction = false)
|
||||
{
|
||||
base.HitOnTarget(hitCollider, hitPosition, out result);
|
||||
base.HitOnTarget(hitCollider, hitPosition, out result, onlyCheckReaction);
|
||||
|
||||
if (onlyCheckReaction) return;
|
||||
|
||||
if (!result.isReflected && ++currentPenetrateCount >= maximumPenetrateCount)
|
||||
{
|
||||
|
||||
@@ -59,15 +59,8 @@ namespace Cielonos.MainGame
|
||||
|
||||
if (characterBlockSm.isBlocking)
|
||||
{
|
||||
/*if (canBeBlocked)
|
||||
{
|
||||
|
||||
}*/
|
||||
|
||||
BlockSource firstBlockSource;
|
||||
|
||||
if (hasPerfectBlock && (!hasPerfectWindowTime || owner.timeSm.enablingTimer <= 0.2f)
|
||||
&& characterBlockSm.isPerfectBlocking)
|
||||
if (hasPerfectBlock && (!hasPerfectWindowTime || owner.timeSm.enablingTimer <= 0.2f) && characterBlockSm.isPerfectBlocking)
|
||||
{
|
||||
firstBlockSource = characterBlockSm.blockSources.Find(source =>
|
||||
source.perfectBlockType >= attackArea.attackSm.attackValue.breakthroughType && source.isDuringPerfectBlock);
|
||||
@@ -79,12 +72,13 @@ namespace Cielonos.MainGame
|
||||
perfectBlockAction?.Invoke(blocker);
|
||||
blocker.eventSm.onBlockSuccess.Invoke(attackArea, firstBlockSource);
|
||||
blocker.eventSm.onPerfectBlockSuccess.Invoke(attackArea, firstBlockSource);
|
||||
Debug.Log($"[ReactionSubmodule] Perfect block successful! Blocker: {blocker.name}, Attack: {attackArea.name}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
firstBlockSource = characterBlockSm.blockSources.Find(source =>
|
||||
firstBlockSource = characterBlockSm.blockSources.Find(source =>
|
||||
source.normalBlockType >= attackArea.attackSm.attackValue.breakthroughType);
|
||||
if (firstBlockSource != null)
|
||||
{
|
||||
@@ -93,6 +87,7 @@ namespace Cielonos.MainGame
|
||||
normalBlockAction?.Invoke(blocker);
|
||||
blocker.eventSm.onBlockSuccess.Invoke(attackArea, firstBlockSource);
|
||||
blocker.eventSm.onNormalBlockSuccess.Invoke(attackArea, firstBlockSource);
|
||||
Debug.Log($"[ReactionSubmodule] Normal block successful! Blocker: {blocker.name}, Attack: {attackArea.name}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -143,7 +138,7 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
DodgeSource firstDodgeSource;
|
||||
|
||||
if (hasPerfectDodge && owner.timeSm.enablingTimer <= 0.2f && characterDodgeSm.isPerfectDodging)
|
||||
if (hasPerfectDodge && owner.timeSm.enablingTimer <= 0.15f && characterDodgeSm.isPerfectDodging)
|
||||
{
|
||||
firstDodgeSource = characterDodgeSm.dodgeSources.Find(source => source.isDuringPerfectDodge);
|
||||
firstDodgeSource.PerfectDodge(owner);
|
||||
|
||||
@@ -17,6 +17,11 @@ namespace Cielonos.MainGame
|
||||
public List<ScheduledAction> scheduledActions;
|
||||
private List<ScheduledAction> toBeExecutedScheduledActions = new List<ScheduledAction>();
|
||||
|
||||
/// <summary>
|
||||
/// enable 阶段开始前允许反应的提前量(秒),默认 0 表示无提前 grace window。
|
||||
/// </summary>
|
||||
public float reactionGraceBefore;
|
||||
|
||||
public TimeSubmodule(AttackAreaBase attackArea, float lifeTime, Action timeOutAction = null) : base(attackArea)
|
||||
{
|
||||
this.isEnabling = true;
|
||||
@@ -51,7 +56,14 @@ namespace Cielonos.MainGame
|
||||
});
|
||||
}
|
||||
|
||||
public TimeSubmodule(AttackAreaBase attackArea, float lifeTime, float delayTime, float enableTime, Action enableAction, Action timeOutAction) : base(attackArea)
|
||||
public TimeSubmodule(AttackAreaBase attackArea, float lifeTime, float delayTime, float enableTime,
|
||||
Action enableAction, Action timeOutAction)
|
||||
: this(attackArea, lifeTime, delayTime, enableTime, enableAction, timeOutAction, 0f)
|
||||
{
|
||||
}
|
||||
|
||||
public TimeSubmodule(AttackAreaBase attackArea, float lifeTime, float delayTime, float enableTime,
|
||||
Action enableAction, Action timeOutAction, float graceBefore) : base(attackArea)
|
||||
{
|
||||
this.isEnabling = true;
|
||||
this.lifeTime = lifeTime;
|
||||
@@ -78,6 +90,8 @@ namespace Cielonos.MainGame
|
||||
this.enablingTimer = 0;
|
||||
this.remainingEnableTime = enableTime;
|
||||
this.enableAction = enableAction;
|
||||
|
||||
this.reactionGraceBefore = graceBefore;
|
||||
}
|
||||
|
||||
public TimeSubmodule AddScheduleAction(Action action, float delay)
|
||||
@@ -85,6 +99,28 @@ namespace Cielonos.MainGame
|
||||
scheduledActions.Add(new ScheduledAction(action, delay));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前时刻是否处于反应窗口内(包含 grace 区间和 enable 阶段本身)。
|
||||
/// before grace: delay 阶段末尾的 reactionGraceBefore 秒内。
|
||||
/// after grace: enable 结束后的 reactionGraceAfter 秒内。
|
||||
/// </summary>
|
||||
public bool IsReactionActive()
|
||||
{
|
||||
// 在 enable 阶段本身,反应始终可用
|
||||
if (attackArea.isEnabling)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// before grace: delay 尚未结束,但已进入 grace 窗口
|
||||
if (delayTime > 0f && reactionGraceBefore > 0f && delayTime <= reactionGraceBefore)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class TimeSubmodule
|
||||
|
||||
Reference in New Issue
Block a user