多轮审查和修复

This commit is contained in:
2026-05-12 15:34:08 +08:00
parent f55d2a57c3
commit ebbbb7332e
805 changed files with 838724 additions and 1905 deletions

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Core.Save;
@@ -21,6 +23,7 @@ namespace BaseGames.Player
[SerializeField] private IntEventChannelSO _onGeoChanged;
[SerializeField] private AbilityTypeEventChannelSO _onAbilityUnlocked;
[SerializeField] private VoidEventChannelSO _onPlayerDied;
[SerializeField] private DifficultyChangedEventChannel _onDifficultyChanged;
// ── 运行时数值 ─────────────────────────────────────────────────────────
public int CurrentHP { get; private set; }
@@ -40,14 +43,24 @@ namespace BaseGames.Player
private float _invincibleTimer;
private float _spiritRegenTimer;
private AbilityType _unlockedAbilities = AbilityType.None;
private bool _isGodMode;
private readonly CompositeDisposable _subs = new();
// ── 护符属性修改器 ─────────────────────────────────────────────────────────
private readonly Dictionary<StatType, float> _flatModifiers = new();
private readonly Dictionary<StatType, float> _percentModifiers = new();
private float _animatorSpeedBonus = 0f;
private int _soulCostReduction = 0;
/// <summary>动画速度倍率AttackSpeedEffect 调节,初始 1.0)。</summary>
public float AnimatorSpeedMultiplier => 1f + _animatorSpeedBonus;
/// <summary>法术灵力消耗减免SoulSpellEffect 叠加)。</summary>
public int SoulCostReduction => _soulCostReduction;
private void Awake()
{
if (_config == null)
{
Debug.LogWarning("[PlayerStats] PlayerStatsSO not assigned.", this);
return;
}
Debug.Assert(_config != null, "[PlayerStats] _config 未赋值,请在 Inspector 中指定 PlayerStatsSO。", this);
MaxHP = _config.MaxHP;
CurrentHP = MaxHP;
MaxSoulPower = _config.MaxSoulPower;
@@ -57,6 +70,21 @@ namespace BaseGames.Player
CurrentGeo = _config.InitialGeo;
}
private void OnEnable() => _onDifficultyChanged?.Subscribe(HandleDifficultyChanged).AddTo(_subs);
private void OnDisable() => _subs.Clear();
private void HandleDifficultyChanged(DifficultyLevel _)
{
var scaler = ServiceLocator.GetOrDefault<IDifficultyService>()?.CurrentScaler;
if (scaler == null) return;
// 按比例缩放当前 HP架构 19 §5难度切换时保持 HP 比例)
float hpRatio = MaxHP > 0 ? (float)CurrentHP / MaxHP : 1f;
MaxHP = Mathf.Max(1, Mathf.RoundToInt(_config.MaxHP * scaler.PlayerMaxHPMultiplier));
CurrentHP = Mathf.Clamp(Mathf.RoundToInt(MaxHP * hpRatio), IsAlive ? 1 : 0, MaxHP);
_onMaxHPChanged?.Raise(MaxHP);
_onHPChanged?.Raise(CurrentHP);
}
private void Update()
{
float dt = Time.deltaTime;
@@ -64,7 +92,7 @@ namespace BaseGames.Player
if (_invincibleTimer > 0f)
_invincibleTimer -= dt;
if (_config != null && _config.SpiritRegenRate > 0)
if (_config.SpiritRegenRate > 0)
{
_spiritRegenTimer += dt;
if (_spiritRegenTimer >= 1f)
@@ -74,13 +102,62 @@ namespace BaseGames.Player
}
}
}
// ── 护符修改器 API ─────────────────────────────────────────────────────
/// <summary>叠加属性修改器(护符效果装备时调用)。</summary>
public void AddModifier(StatType stat, float flat, float percent)
{
_flatModifiers[stat] = _flatModifiers.GetValueOrDefault(stat) + flat;
_percentModifiers[stat] = _percentModifiers.GetValueOrDefault(stat) + percent;
if (stat == StatType.MaxHP) RecalcMaxHP();
}
/// <summary>移除属性修改器(护符效果卸下时调用)。</summary>
public void RemoveModifier(StatType stat, float flat, float percent)
{
_flatModifiers[stat] = _flatModifiers.GetValueOrDefault(stat) - flat;
_percentModifiers[stat] = _percentModifiers.GetValueOrDefault(stat) - percent;
if (stat == StatType.MaxHP) RecalcMaxHP();
}
/// <summary>查询指定属性的固定加成(由 PlayerMovement、战斗等外部系统查询。</summary>
public float GetFlatModifier(StatType stat) => _flatModifiers.GetValueOrDefault(stat);
/// <summary>查询指定属性的百分比加成。</summary>
public float GetPercentModifier(StatType stat) => _percentModifiers.GetValueOrDefault(stat);
/// <summary>加载动画速度加成AttackSpeedEffect 装备时调用)。</summary>
public void AddAnimatorSpeedBonus(float delta) => _animatorSpeedBonus += delta;
/// <summary>移除动画速度加成AttackSpeedEffect 卸下时调用)。</summary>
public void RemoveAnimatorSpeedBonus(float delta) => _animatorSpeedBonus -= delta;
/// <summary>增加灵力消耗减免SoulSpellEffect 装备时调用)。</summary>
public void AddSoulCostReduction(int amount) => _soulCostReduction += amount;
/// <summary>移除灵力消耗减免SoulSpellEffect 卸下时调用)。</summary>
public void RemoveSoulCostReduction(int amount) => _soulCostReduction = Mathf.Max(0, _soulCostReduction - amount);
private void RecalcMaxHP()
{
float flat = _flatModifiers.GetValueOrDefault(StatType.MaxHP);
float percent = _percentModifiers.GetValueOrDefault(StatType.MaxHP);
int newMax = Mathf.Max(1, Mathf.RoundToInt(_config.MaxHP * (1f + percent) + flat));
SetMaxHP(newMax);
}
// ── HP ────────────────────────────────────────────────────────────────
/// <summary>受到伤害时触发(已扣血,不包含无敌/死亡情况)。</summary>
public event System.Action OnDamaged;
/// <summary>Debug开启/关闭无敌模式(不计入无敌帧,永久生效直至关闭)。</summary>
public void SetGodMode(bool v) { _isGodMode = v; }
public void TakeDamage(int amount)
{
if (IsInvincible || !IsAlive || amount <= 0) return;
if (_isGodMode || IsInvincible || !IsAlive || amount <= 0) return;
CurrentHP = Mathf.Max(0, CurrentHP - amount);
_onHPChanged?.Raise(CurrentHP);
OnDamaged?.Invoke();
if (CurrentHP == 0)
_onPlayerDied?.Raise();
}
@@ -119,6 +196,9 @@ namespace BaseGames.Player
_onSoulPowerChanged?.Raise(CurrentSoulPower);
}
/// <summary>AddSoul 是 AddSoulPower 的别名(架构 06_CombatModule §8 ParrySystem 使用此名称)。</summary>
public void AddSoul(int amount) => AddSoulPower(amount);
public bool ConsumeSoulPower(int amount)
{
if (CurrentSoulPower < amount) return false;
@@ -149,8 +229,7 @@ namespace BaseGames.Player
if (CurrentSpringCharges <= 0) return false;
CurrentSpringCharges--;
_onSpringChargesChanged?.Raise(CurrentSpringCharges);
if (_config != null)
HealHP(_config.SpringHealAmount);
HealHP(_config.SpringHealAmount);
return true;
}
@@ -163,7 +242,6 @@ namespace BaseGames.Player
public void AddKillPoints(int points = 1)
{
if (_config == null) return;
SpringKillPoints += points;
if (SpringKillPoints >= _config.SpringKillThreshold)
{
@@ -191,7 +269,7 @@ namespace BaseGames.Player
// ── Invincibility ─────────────────────────────────────────────────────
public void BeginInvincibility(float duration = -1f)
{
float d = duration >= 0f ? duration : (_config != null ? _config.InvincibilityDuration : 0.6f);
float d = duration >= 0f ? duration : _config.InvincibilityDuration;
_invincibleTimer = Mathf.Max(_invincibleTimer, d);
}