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

```
chore(config): 更新配置文件设置

- 调整项目配置参数
- 优化构建流程设置
- 更新依赖包版本信息
```

注意:由于未提供具体的代码差异信息,此为示例模板。实际使用时请根据具体变更内容调整type、scope、subject和body部分。
This commit is contained in:
huadexuan committed 2026-09-02 23:57:30 +08:00
1 parent dcb87d5393
commit fb353c45a7
37 files changed
+1651 -2461

No files matched your search

+140
View File
@@ -0,0 +1,140 @@
using UnityEngine;
public class StatusEffectController : MonoBehaviour
{
[Header("通用眩晕显示")]
[SerializeField] private bool showStunIndicator = true;
[SerializeField] private float indicatorHeight = 0.35f;
[SerializeField] private float indicatorSize = 0.5f;
private Animator animator;
private float stunnedRemaining;
private float animatorSpeedBeforeStun = 1f;
private GameObject stunIndicator;
private Transform indicatorTransform;
public bool IsStunned => stunnedRemaining > 0f;
public float StunnedRemaining => Mathf.Max(0f, stunnedRemaining);
private void Awake()
{
animator = GetComponent<Animator>();
}
public void ApplyStun(float duration)
{
if (duration <= 0f)
{
return;
}
if (!IsStunned && animator != null)
{
animatorSpeedBeforeStun = animator.speed;
}
stunnedRemaining = Mathf.Max(stunnedRemaining, duration);
if (animator != null)
{
animator.speed = 0f;
}
if (showStunIndicator)
{
EnsureIndicator();
}
}
private void Update()
{
if (!IsStunned)
{
return;
}
stunnedRemaining -= Time.deltaTime;
if (animator != null)
{
animator.speed = 0f;
}
if (stunnedRemaining <= 0f)
{
stunnedRemaining = 0f;
if (animator != null)
{
animator.speed = Mathf.Max(0.01f, animatorSpeedBeforeStun);
}
DestroyIndicator();
}
}
private void LateUpdate()
{
if (indicatorTransform == null)
{
return;
}
Bounds bounds = new Bounds(transform.position, Vector3.zero);
Renderer[] renderers = GetComponentsInChildren<Renderer>(true);
if (renderers.Length > 0)
{
bounds = renderers[0].bounds;
for (int i = 1; i < renderers.Length; i++)
{
bounds.Encapsulate(renderers[i].bounds);
}
}
indicatorTransform.position = new Vector3(
bounds.center.x,
bounds.max.y + indicatorHeight,
bounds.center.z);
Camera camera = Camera.main;
if (camera != null)
{
indicatorTransform.rotation = Quaternion.LookRotation(
camera.transform.position - indicatorTransform.position,
camera.transform.up)
* Quaternion.Euler(0f, 0f, Time.unscaledTime * 180f);
}
}
private void EnsureIndicator()
{
if (stunIndicator != null)
{
return;
}
stunIndicator = new GameObject("StunIndicator_Star");
indicatorTransform = stunIndicator.transform;
TextMesh text = stunIndicator.AddComponent<TextMesh>();
text.text = "★";
text.anchor = TextAnchor.MiddleCenter;
text.alignment = TextAlignment.Center;
text.fontSize = 64;
text.characterSize = indicatorSize;
text.fontStyle = FontStyle.Bold;
text.color = new Color(1f, 0.85f, 0.05f, 1f);
}
private void DestroyIndicator()
{
if (stunIndicator != null)
{
Destroy(stunIndicator);
}
stunIndicator = null;
indicatorTransform = null;
}
private void OnDestroy()
{
DestroyIndicator();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: B3gatX/8UXLhzK2o+FhBOnvCE/cCS+iZRCUxmwg/CJ8qjZpm3ifTg08=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+5 -1
View File
@@ -9,6 +9,9 @@ public class StoneGolemSkill : UnitSkill
[Min(0.1f)]
public float skillRadius = 2f;
[Min(0f)]
public float stunDuration = 1f;
[Header("技能动画")]
[Min(0f)]
public float skillAnimationDuration = 0f;
@@ -26,7 +29,7 @@ public class StoneGolemSkill : UnitSkill
unit.PlaySkillAnimation(OnSkillFinished, skillAnimationDuration);
}
// 添加到地裂技能动画的命中帧;眩晕效果暂不处理。
// 添加到地裂技能动画的命中帧;在命中帧结算伤害和眩晕。
public void OnSkillHit1()
{
if (!isSkillReady)
@@ -35,6 +38,7 @@ public class StoneGolemSkill : UnitSkill
}
unit.ApplyAreaSkillDamage(skillRadius, skillDamage, false);
unit.ApplyAreaStun(skillRadius, stunDuration);
isSkillReady = false;
}
+109 -11
View File
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(StatusEffectController))]
public class UnitBase : MonoBehaviour
{
@@ -19,6 +20,10 @@ public class UnitBase : MonoBehaviour
//攻击范围
public float attackRange = 5f;
//模型自身前方相对逻辑前方的水平修正角度。
[Header("模型朝向修正")]
public float modelFacingOffset = 0f;
//基础攻击力,实际伤害结算逻辑后续接入
[Min(0f)]
public float attackPower = 10f;
@@ -79,11 +84,14 @@ public class UnitBase : MonoBehaviour
// 自身的血条组件,同时负责显示技能能量条。
private WorldHealthBar worldHealthBar;
// 通用状态效果组件。
private StatusEffectController statusEffectController;
//垂直速度
private float verticalVelocity;
//当前攻击开始时间,用于在没有结束 Event 时释放攻击状态。
private float attackStartTime;
// 攻击动画的有效经过时间;眩晕期间不增加。
private float attackElapsedTime;
private bool isPlayingSkill;
private float attackSpeedMultiplier = 1f;
@@ -119,6 +127,7 @@ public class UnitBase : MonoBehaviour
animator = GetComponent<Animator>();
controller = GetComponent<CharacterController>();
worldHealthBar = GetComponent<WorldHealthBar>();
statusEffectController = EnsureStatusEffectController();
unitSkill = GetComponent<UnitSkill>();
// 位移和朝向由 CharacterController 与 UnitBase 控制,避免攻击动画的根运动叠加旋转。
@@ -128,15 +137,37 @@ public class UnitBase : MonoBehaviour
randomTargetPos();
}
private StatusEffectController EnsureStatusEffectController()
{
if (statusEffectController == null)
{
statusEffectController = GetComponent<StatusEffectController>();
}
if (statusEffectController == null)
{
statusEffectController = gameObject.AddComponent<StatusEffectController>();
}
return statusEffectController;
}
// Update is called once per frame
void Update()
{
if (statusEffectController != null && statusEffectController.IsStunned)
{
animator.SetInteger("speed", 0);
applyGravity();
return;
}
//攻击状态下等待Animator报告攻击动画播放完成。
if (state == State.Attack)
{
animator.SetInteger("speed", 0);
attackElapsedTime += Time.deltaTime;
applyGravity();
CheckAttackAnimationFinished();
return;
@@ -181,6 +212,13 @@ public class UnitBase : MonoBehaviour
public float AttackSpeedMultiplier => attackSpeedMultiplier;
public bool IsStunned => statusEffectController != null && statusEffectController.IsStunned;
public void ApplyStun(float duration)
{
EnsureStatusEffectController().ApplyStun(duration);
}
//根据自身Tag找到敌对Tag
private string GetOpponentTag()
{
@@ -377,7 +415,7 @@ public class UnitBase : MonoBehaviour
animator.SetInteger("speed", 0);
animator.SetTrigger("attack");
state = State.Attack;
attackStartTime = Time.time;
attackElapsedTime = 0f;
}
private void FaceTarget(GameObject opponent)
@@ -394,14 +432,28 @@ public class UnitBase : MonoBehaviour
return;
}
ApplyFacingRotation(direction);
}
private void ApplyFacingRotation(Vector3 direction)
{
direction.y = 0f;
if (direction.sqrMagnitude <= 0.0001f)
{
return;
}
Quaternion targetRotation = Quaternion.LookRotation(direction, Vector3.up);
transform.rotation = Quaternion.Euler(0f, targetRotation.eulerAngles.y, 0f);
transform.rotation = Quaternion.Euler(
0f,
targetRotation.eulerAngles.y + modelFacingOffset,
0f);
}
//由攻击动画中最合适的帧通过 Animation Event 调用。
public void OnAttackEffect()
{
if (state != State.Attack || target == null)
if (IsStunned || state != State.Attack || target == null)
{
return;
}
@@ -434,7 +486,7 @@ public class UnitBase : MonoBehaviour
public void ApplySkillHit(float damageMultiplier, bool registerEnergy)
{
if (target == null)
if (IsStunned || target == null)
{
return;
}
@@ -499,8 +551,55 @@ public class UnitBase : MonoBehaviour
}
}
public void ApplyAreaStun(float radius, float duration)
{
if (duration <= 0f)
{
return;
}
string opponentTag = GetOpponentTag();
if (string.IsNullOrEmpty(opponentTag))
{
return;
}
float clampedRadius = Mathf.Max(0f, radius);
float radiusSquared = clampedRadius * clampedRadius;
GameObject[] opponents = GameObject.FindGameObjectsWithTag(opponentTag);
HashSet<UnitBase> hitUnits = new HashSet<UnitBase>();
foreach (GameObject opponent in opponents)
{
if (opponent == null || opponent == gameObject || opponent.transform.root == transform.root)
{
continue;
}
Vector3 offset = opponent.transform.position - transform.position;
offset.y = 0f;
if (offset.sqrMagnitude > radiusSquared)
{
continue;
}
UnitBase unit = opponent.GetComponentInParent<UnitBase>();
if (unit == null || !hitUnits.Add(unit))
{
continue;
}
unit.ApplyStun(duration);
}
}
public void RegisterAttackHit()
{
if (IsStunned)
{
return;
}
AddAttackEnergy();
}
@@ -590,7 +689,6 @@ public class UnitBase : MonoBehaviour
animator.speed = GetSkillAnimationSpeed(targetDuration);
animator.SetInteger("speed", 0);
animator.SetTrigger("skill");
attackStartTime = Time.time;
}
public void MultiplyAttackSpeed(float multiplier, float limit)
@@ -624,7 +722,7 @@ public class UnitBase : MonoBehaviour
? attackDuration
: GetAttackAnimationDuration();
if (animationDuration > 0f && Time.time - attackStartTime >= animationDuration)
if (animationDuration > 0f && attackElapsedTime >= animationDuration)
{
FinishAttack();
return;
@@ -696,9 +794,9 @@ public class UnitBase : MonoBehaviour
Vector3 velocity = movement.normalized * speed;
velocity.y = getVerticalVelocity();
controller.Move(velocity * Time.deltaTime);
//改变角色朝向目标点,只改变y轴
transform.rotation = Quaternion.LookRotation(movement, Vector3.up);
transform.rotation = Quaternion.Euler(0, transform.rotation.eulerAngles.y, 0);
//移动时模型正面朝向移动方向;模型朝向修正只用于攻击动作。
Quaternion movementRotation = Quaternion.LookRotation(movement, Vector3.up);
transform.rotation = Quaternion.Euler(0f, movementRotation.eulerAngles.y, 0f);
}