超大量的更新 修复很多问题,gameplay特效初步

This commit is contained in:
2026-02-14 23:46:20 +08:00
parent ef8eb67259
commit 3a7a0b4669
360 changed files with 85670 additions and 4144 deletions
+94 -14
View File
@@ -1,9 +1,9 @@
using System;
using System;
using System.Collections.Generic;
using UnityEngine;
// EnemyCombatant ǵϵ˵ʱ֣е˹ͬһ GameObject˳dz
// ʵ ICombatant EffectSystem/SkillBuilder
// Documentation text normalized.
// Documentation text normalized.
public class EnemyCombatant : MonoBehaviour, ICombatant
{
public EnemyData_SO sourceData;
@@ -16,6 +16,10 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
public float damageResistance = 0f;
public int attack = 0;
// Keep an unbuffed attack baseline so temporary Buff.attackMultiplier can be applied/reverted correctly.
private int _attackBaseUnbuffed = 0;
private bool _attackBaseInitialized = false;
private List<Buff> activeBuffs = new List<Buff>();
// Events to notify manager/UI
@@ -30,22 +34,28 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
gameObject.name = "thisEnemy";
}
// ʼ/Ϊָ EnemyData_SO
// Documentation text normalized.
public void InitializeFromSO(EnemyData_SO so)
{
// This enemy GameObject can be reused for multiple enemy entries in sequence.
// Clear any runtime buffs so they don't leak across enemy transitions.
activeBuffs.Clear();
_attackBaseInitialized = false;
_attackBaseUnbuffed = 0;
sourceData = so;
if (so != null)
{
maxHP = Mathf.Max(1, so.enemy_maxHP);
damageResistance = so.enemy_damageResistance;
attack = so.enemy_baseAttack;
SetAttack(so.enemy_baseAttack);
maxMana = Mathf.Max(0, so.GetEffectiveMaxMana());
}
else
{
maxHP = 100;
damageResistance = 0f;
attack = 0;
SetAttack(0);
maxMana = 0;
}
@@ -67,7 +77,7 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
TryTriggerPrimarySkill(SkillDefinition.SkillTrigger.OnEnemyRevive);
}
// Դ primary skillƥʱ SkillBuilder
// Documentation text normalized.
private void TryTriggerPrimarySkill(SkillDefinition.SkillTrigger when)
{
if (sourceData == null) return;
@@ -93,7 +103,15 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
}
float totalAmount = perTick;
if (!def.IsSingleInstance)
bool scaleByTicks =
!def.IsSingleInstance &&
(def.effectType == EffectType.DamageOverTimeEnemy ||
def.effectType == EffectType.DamageOverTimeAlly ||
def.effectType == EffectType.HealOverTimeEnemy ||
def.effectType == EffectType.HealOverTimeSelf ||
def.effectType == EffectType.HealGroupOverTime ||
def.effectType == EffectType.IncreaseManaOverTime);
if (scaleByTicks)
{
float tickInterval = def.GetEffectiveTickInterval();
int ticks = Mathf.Max(1, Mathf.CeilToInt(def.defaultDuration / tickInterval));
@@ -132,7 +150,8 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
public void ReceiveHeal(float amount, GameObject source)
{
if (isDead) return;
int delta = Mathf.CeilToInt(amount);
float mult = GetTotalHealReceivedMultiplier();
int delta = Mathf.CeilToInt(amount * mult);
currentHP = Mathf.Clamp(currentHP + delta, 0, maxHP);
}
@@ -140,8 +159,8 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
{
if (buff == null) return;
activeBuffs.Add(buff);
// Simple apply: only modify healReceivedMultiplier or attackMultiplier as example
if (buff.attackMultiplier != 1f) attack = Mathf.RoundToInt(attack * buff.attackMultiplier);
// Apply reversible multipliers. attackMultiplier is applied via baseline+recalc to ensure it can be reverted.
if (buff.attackMultiplier != 1f) RecalculateAttackFromBuffs();
}
public void RemoveBuff(string buffId)
@@ -150,9 +169,62 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
if (b != null)
{
activeBuffs.Remove(b);
if (b.attackMultiplier != 1f) RecalculateAttackFromBuffs();
}
}
private void EnsureAttackBaseInitialized()
{
if (_attackBaseInitialized) return;
_attackBaseInitialized = true;
_attackBaseUnbuffed = Mathf.Max(0, attack);
}
private float GetTotalAttackMultiplier()
{
float mult = 1f;
for (int i = 0; i < activeBuffs.Count; i++)
{
var b = activeBuffs[i];
if (b == null) continue;
mult *= b.attackMultiplier;
}
return mult;
}
private float GetTotalHealReceivedMultiplier()
{
float mult = 1f;
for (int i = 0; i < activeBuffs.Count; i++)
{
var b = activeBuffs[i];
if (b == null) continue;
mult *= b.healReceivedMultiplier;
}
return mult;
}
private void RecalculateAttackFromBuffs()
{
EnsureAttackBaseInitialized();
float mult = GetTotalAttackMultiplier();
attack = Mathf.Max(0, Mathf.RoundToInt(_attackBaseUnbuffed * mult));
}
public void ModifyAttack(int delta)
{
EnsureAttackBaseInitialized();
_attackBaseUnbuffed = Mathf.Max(0, _attackBaseUnbuffed + delta);
RecalculateAttackFromBuffs();
}
public void SetAttack(int value)
{
EnsureAttackBaseInitialized();
_attackBaseUnbuffed = Mathf.Max(0, value);
RecalculateAttackFromBuffs();
}
public void ModifyHP(int delta)
{
if (isDead && delta > 0) return;
@@ -189,6 +261,17 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
{
if (isDead) return;
// Finally mark dead so further damage/heal is ignored.
// We set this EARLY because listeners (OnEnemyDied) might re-initialize this instance
// for the next enemy in sequence, which would set isDead = false.
isDead = true;
// 播放 KO 特效
if (GfxController.Instance != null)
{
GfxController.Instance.PlayKOFX(this.gameObject);
}
// Notify SkillBuilder so allies can react to each enemy death BEFORE listeners that may reuse this Enemy instance
if (Application.isPlaying)
{
@@ -262,9 +345,6 @@ public class EnemyCombatant : MonoBehaviour, ICombatant
Debug.LogError($"[EnemyCombatant] Error while checking all-enemies-defeated: {ex}");
}
}
// Finally mark dead so further damage/heal is ignored
isDead = true;
}
// Utility: expose a read-only status