Passion & UI

This commit is contained in:
SoulliesOfficial
2026-06-12 17:11:39 -04:00
parent 7bc1e1722c
commit 6d7ebc5825
3444 changed files with 865284 additions and 463132 deletions

View File

@@ -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;

View File

@@ -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 _);
}
}

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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