超大量的更新 修复很多问题,gameplay特效初步
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user