根据提供的code differences信息,由于没有具体的代码变更内容,我将生成一个通用的commit message模板:

```
docs(readme): 更新文档说明

- 添加项目使用指南
- 完善API接口说明
- 修正错误的配置示例
```

注意:由于您提供的code differences部分为空,以上是一个示例模板。当您有具体的代码变更时,请提供详细的变更内容以便生成更准确的commit message。
This commit is contained in:
huadexuan committed 2026-10-04 22:58:39 +08:00
1 parent 11f1af357d
commit 7d9d0f52d1
83 files changed
+3510 -1493

No files matched your search

+88 -70
View File
@@ -76,13 +76,17 @@ public class UnitBase : MonoBehaviour
private bool summonerAttackEnabled = true;
[Header("无目标回位")]
[Tooltip("开启后,当前没有敌方单位时返回生成时的初始格位;不限制正常追击距离。")]
[Tooltip("开启后,当前没有敌方单位时返回生成时的初始格位。")]
public bool returnToAnchorWhenIdle = false;
[Min(0.1f)]
public float anchorArrivalDistance = 0.35f;
private Vector3 anchorPosition;
private bool anchorInitialized;
[Header("阵位守护")]
[Tooltip("开启后,只打「离自己阵位不超过 寻敌视野 detectionRange」的敌人,避免一路推到很远的地方。")]
public bool useAnchorLeash = false;
//角色状态
private State state = State.Alert;
@@ -112,6 +116,8 @@ public class UnitBase : MonoBehaviour
private float attackSpeedMultiplier = 1f;
private UnitSkill unitSkill;
private System.Action skillFinishedCallback;
private float skillElapsedTime;
private float skillTimeout;
//状态枚举
@@ -183,7 +189,7 @@ public class UnitBase : MonoBehaviour
navAgent.speed = speed;
navAgent.angularSpeed = 120f;
navAgent.acceleration = 8f;
navAgent.stoppingDistance = attackRange * 0.95f; // 接近攻击范围边缘时停止
navAgent.stoppingDistance = NormalStoppingDistance; // 接近攻击范围边缘时停止
navAgent.autoBraking = true;
// NavMesh 使用烘焙平面的高度,不能根据动画帧中的 Renderer 包围盒推算 baseOffset。
@@ -287,6 +293,13 @@ public class UnitBase : MonoBehaviour
// Attack 状态在上方单独处理,因此不会被这里打断或切换目标。
target = FindTarget();
// 阵位守护:目标离自己阵位超过寻敌视野(detectionRange)就不追了,留在阵位附近
if (target != null && useAnchorLeash && anchorInitialized
&& IsBeyondLeash(target.transform.position, detectionRange))
{
target = null;
}
if (target != null)
{
// 召唤师模式:不主动追击,站定且攻击开关开启时才攻击射程内目标。
@@ -374,6 +387,11 @@ public class UnitBase : MonoBehaviour
public void ApplyStun(float duration)
{
if (duration <= 0f)
{
return;
}
EnsureStatusEffectController().ApplyStun(duration);
}
@@ -455,6 +473,20 @@ public class UnitBase : MonoBehaviour
return Vector3.Distance(current, anchor) <= anchorArrivalDistance;
}
/// <summary>某个世界坐标是否离锚点超过了指定距离(只算水平距离)。</summary>
private bool IsBeyondLeash(Vector3 worldPosition, float maxDistance)
{
if (!anchorInitialized) return false;
Vector3 anchor = anchorPosition;
anchor.y = 0f;
Vector3 point = worldPosition;
point.y = 0f;
return Vector3.Distance(anchor, point) > maxDistance;
}
/// <summary>追击/接敌时用的停靠距离(贴着攻击范围边缘停下)。</summary>
private float NormalStoppingDistance => Mathf.Max(0f, attackRange * 0.95f);
/// <summary>
/// 重置锚点位置到当前位置(用于复活等场景)
/// </summary>
@@ -468,11 +500,7 @@ public class UnitBase : MonoBehaviour
{
if (navAgent == null || !anchorInitialized)
{
if (!summonerMode)
{
animator.SetInteger("speed", 0);
animator.speed = 1f; // 重置动画播放速度
}
RestoreIdleSpeed();
return;
}
@@ -483,11 +511,7 @@ public class UnitBase : MonoBehaviour
if (!navAgent.isOnNavMesh)
{
if (!summonerMode)
{
animator.SetInteger("speed", 0);
animator.speed = 1f; // 重置动画播放速度
}
RestoreIdleSpeed();
return;
}
@@ -497,22 +521,41 @@ public class UnitBase : MonoBehaviour
navAgent.ResetPath();
transform.position = new Vector3(anchorPosition.x, transform.position.y, anchorPosition.z);
navAgent.nextPosition = transform.position;
if (!summonerMode)
{
animator.SetInteger("speed", 0);
animator.speed = 1f; // 重置动画播放速度
}
RestoreIdleSpeed();
return;
}
navAgent.isStopped = false;
// 回位必须贴到锚点:攻击用的停靠距离会把 agent 挡在半路(远程角色尤其明显)
navAgent.stoppingDistance = 0f;
if (Time.time >= nextPathUpdateTime)
{
navAgent.SetDestination(anchorPosition);
nextPathUpdateTime = Time.time + PathUpdateInterval;
}
animator.SetInteger("speed", navAgent.velocity.sqrMagnitude > 0.01f ? 1 : 0);
animator.speed = 1f; // 确保移动时动画速度正常
// 用正常速度走回格位
navAgent.speed = speed;
if (!summonerMode)
{
animator.SetInteger("speed", navAgent.velocity.sqrMagnitude > 0.01f ? 1 : 0);
animator.speed = 1f; // 确保走路动画速度正常
}
}
/// <summary>回位结束或无法寻路时,把速度和动画恢复成正常站定状态。</summary>
private void RestoreIdleSpeed()
{
if (navAgent != null && navAgent.enabled)
{
navAgent.speed = speed;
navAgent.stoppingDistance = NormalStoppingDistance;
}
if (!summonerMode && animator != null)
{
animator.SetInteger("speed", 0);
animator.speed = 1f;
}
}
//目标决策:只寻找 detectionRange 内的敌方战斗单位;范围内没有敌人时原地待机或回到锚点。
@@ -837,21 +880,6 @@ public class UnitBase : MonoBehaviour
return;
}
CrystalMineCapture targetCrystalMine = opponent.GetComponentInParent<CrystalMineCapture>();
if (targetCrystalMine != null && targetCrystalMine.ReceiveCaptureDamage(attackPower, gameObject))
{
RegisterAttackHit();
return;
}
BuildingHealth targetBuilding = opponent.GetComponentInParent<BuildingHealth>();
if (targetBuilding != null && targetBuilding.ReceiveDamage(attackPower, gameObject))
{
RegisterAttackHit();
return;
}
// 召唤师等特殊单位(有 WorldHealthBar 但没有 UnitBase)
WorldHealthBar targetHealthBar = opponent.GetComponentInParent<WorldHealthBar>();
if (targetHealthBar != null)
{
@@ -871,18 +899,6 @@ public class UnitBase : MonoBehaviour
UnitBase targetUnit = target.GetComponentInParent<UnitBase>();
bool hit = targetUnit != null && targetUnit.ReceiveDamage(damage, gameObject);
if (!hit)
{
CrystalMineCapture targetCrystalMine = target.GetComponentInParent<CrystalMineCapture>();
hit = targetCrystalMine != null && targetCrystalMine.ReceiveCaptureDamage(damage, gameObject);
}
if (!hit)
{
BuildingHealth targetBuilding = target.GetComponentInParent<BuildingHealth>();
hit = targetBuilding != null && targetBuilding.ReceiveDamage(damage, gameObject);
}
if (!hit)
{
return;
@@ -937,22 +953,9 @@ public class UnitBase : MonoBehaviour
}
UnitBase targetUnit = opponent.GetComponentInParent<UnitBase>();
BuildingHealth targetBuilding = opponent.GetComponentInParent<BuildingHealth>();
WorldHealthBar healthBar = null;
if (targetUnit != null)
{
healthBar = targetUnit.GetComponent<WorldHealthBar>();
}
else if (targetBuilding != null)
{
healthBar = targetBuilding.GetComponent<WorldHealthBar>();
}
else
{
// 召唤师等特殊单位(有 WorldHealthBar 但没有 UnitBase)
healthBar = opponent.GetComponentInParent<WorldHealthBar>();
}
WorldHealthBar healthBar = targetUnit != null
? targetUnit.GetComponent<WorldHealthBar>()
: opponent.GetComponentInParent<WorldHealthBar>();
if (healthBar == null || !hitHealthBars.Add(healthBar))
{
@@ -963,13 +966,8 @@ public class UnitBase : MonoBehaviour
{
targetUnit.ReceiveDamage(damage, gameObject);
}
else if (targetBuilding != null)
else
{
targetBuilding.ReceiveDamage(damage, gameObject);
}
else if (healthBar != null)
{
// 召唤师等特殊单位
healthBar.TakeDamage(damage, gameObject);
}
}
@@ -999,6 +997,7 @@ public class UnitBase : MonoBehaviour
// 查找所有带 UnitTeam 的对象(包括单位和召唤师)
UnitTeam[] allTeams = FindObjectsOfType<UnitTeam>();
HashSet<UnitBase> hitUnits = new HashSet<UnitBase>();
HashSet<StatusEffectController> hitStatusEffects = new HashSet<StatusEffectController>();
foreach (UnitTeam targetTeam in allTeams)
{
@@ -1031,7 +1030,7 @@ public class UnitBase : MonoBehaviour
// 召唤师等特殊单位(有 StatusEffectController 但没有 UnitBase)
StatusEffectController statusEffect = opponent.GetComponentInParent<StatusEffectController>();
if (statusEffect != null)
if (statusEffect != null && hitStatusEffects.Add(statusEffect))
{
statusEffect.ApplyStun(duration);
}
@@ -1129,6 +1128,11 @@ public class UnitBase : MonoBehaviour
skillFinishedCallback = onFinished;
isPlayingSkill = true;
skillElapsedTime = 0f;
float animationDuration = GetSkillAnimationDuration();
skillTimeout = targetDuration > 0f
? targetDuration + 0.5f
: Mathf.Max(animationDuration + 0.5f, 2f);
state = State.Skill;
animator.speed = GetSkillAnimationSpeed(targetDuration);
animator.SetInteger("speed", 0);
@@ -1145,13 +1149,23 @@ public class UnitBase : MonoBehaviour
private void CheckSkillAnimationFinished()
{
if (!isPlayingSkill)
{
return;
}
skillElapsedTime += Time.deltaTime;
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (!stateInfo.IsName("skill") || stateInfo.normalizedTime < 1f)
bool animationFinished = stateInfo.IsName("skill") && stateInfo.normalizedTime >= 1f;
bool timedOut = skillElapsedTime >= skillTimeout;
if (!animationFinished && !timedOut)
{
return;
}
isPlayingSkill = false;
skillElapsedTime = 0f;
skillTimeout = 0f;
state = State.Alert;
animator.speed = attackSpeedMultiplier;
skillFinishedCallback?.Invoke();
@@ -1232,6 +1246,10 @@ public class UnitBase : MonoBehaviour
if (!navAgent.isOnNavMesh) return;
// 追击时用正常速度和正常停靠距离(可能刚从回位状态切回来)
navAgent.speed = speed;
navAgent.stoppingDistance = NormalStoppingDistance;
// 确保没有被停止
if (navAgent.isStopped)
{