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

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

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

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

No files matched your search

@@ -0,0 +1,177 @@
using UnityEngine;
public class Projectile : MonoBehaviour
{
[Header("爆炸效果(可选)")]
public GameObject explosionPrefab; // 爆炸特效预制体,留空则没有爆炸效果
private GameObject target;
private GameObject owner;
private float damage;
private float speed;
private float lifetime;
private bool registerEnergyOnHit;
private bool initialized;
private bool hasHit;
public void Initialize(
GameObject targetObject,
float damageAmount,
GameObject ownerObject,
float moveSpeed,
float lifeTime,
bool registerEnergy = true)
{
target = targetObject;
damage = damageAmount;
owner = ownerObject;
speed = moveSpeed;
lifetime = lifeTime;
registerEnergyOnHit = registerEnergy;
initialized = true;
hasHit = false;
// The projectile uses its own raycast hit check. Disable the collider so
// it cannot be destroyed or disturbed by the owner's launch socket.
foreach (var collider in GetComponentsInChildren<Collider>(true))
{
collider.enabled = false;
}
if (lifetime > 0f)
{
Destroy(gameObject, lifetime);
}
}
private void Update()
{
if (!initialized)
{
return;
}
if (target == null)
{
Destroy(gameObject);
return;
}
// 目标根节点位于脚底,只取水平差值,让箭保持当前高度平行飞行。
Vector3 offset = target.transform.position - transform.position;
offset.y = 0f;
if (offset.sqrMagnitude <= 0.01f)
{
HitTarget(target);
return;
}
Vector3 direction = offset.normalized;
float distance = speed * Time.deltaTime;
if (distance >= offset.magnitude)
{
HitTarget(target);
return;
}
// 投射物保持水平飞行,并让根节点前方始终指向当前目标。
transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
if (Physics.Raycast(transform.position, direction, out RaycastHit hit, distance))
{
TryHit(hit.collider.gameObject);
if (hit.collider.transform.root == target.transform.root)
{
return;
}
}
// 火球保持 Prefab 固定角度,不随飞行方向旋转
// transform.forward = direction;
transform.position += direction * distance;
}
private void OnTriggerEnter(Collider other)
{
TryHit(other.gameObject);
}
private void OnCollisionEnter(Collision collision)
{
TryHit(collision.gameObject);
}
private void TryHit(GameObject hitObject)
{
if (!initialized || hitObject == null || target == null || IsOwner(hitObject))
{
return;
}
if (hitObject.transform.root == target.transform.root)
{
HitTarget(hitObject);
}
}
private void HitTarget(GameObject hitObject)
{
if (hasHit)
{
return;
}
UnitBase targetUnit = hitObject.GetComponentInParent<UnitBase>();
CrystalMineCapture crystalMine = hitObject.GetComponentInParent<CrystalMineCapture>();
BuildingHealth targetBuilding = hitObject.GetComponentInParent<BuildingHealth>();
WorldHealthBar targetHealthBar = hitObject.GetComponentInParent<WorldHealthBar>();
if (targetUnit == null && crystalMine == null && targetBuilding == null && targetHealthBar == null)
{
return;
}
hasHit = true;
if (targetUnit != null)
{
targetUnit.ReceiveDamage(damage, owner);
}
else if (crystalMine != null)
{
crystalMine.ReceiveCaptureDamage(damage, owner);
}
else if (targetBuilding != null)
{
targetBuilding.ReceiveDamage(damage, owner);
}
else if (targetHealthBar != null)
{
// 召唤师等特殊单位(有 WorldHealthBar 但没有 UnitBase)
targetHealthBar.TakeDamage(damage, owner);
}
if (registerEnergyOnHit && owner != null)
{
UnitBase unit = owner.GetComponent<UnitBase>();
if (unit != null)
{
unit.RegisterAttackHit();
}
}
// 生成爆炸效果
if (explosionPrefab != null)
{
Instantiate(explosionPrefab, transform.position, Quaternion.identity);
}
Destroy(gameObject);
}
private bool IsOwner(GameObject hitObject)
{
return owner != null &&
(hitObject == owner || hitObject.transform.root == owner.transform.root);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: BykWtHz4ACmy6F8Kvn3Hf5OfB+YboFb74aULp8lFAVCZxth46GKpB9g=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,138 @@
using UnityEngine;
public class ShieldBarrier : MonoBehaviour
{
[Header("盾牌状态")]
[Min(0f)]
public float maxDurability = 220f;
[Min(0f)]
public float currentDurability;
[Min(0f)]
public float duration = 6f;
[Range(-1f, 1f)]
public float frontDotThreshold = 0.15f;
private UnitBase owner;
private Collider barrierCollider;
private float remainingTime;
public UnitBase Owner => owner;
public float CurrentDurability => currentDurability;
public bool IsActive =>
isActiveAndEnabled &&
barrierCollider != null &&
barrierCollider.enabled &&
currentDurability > 0f &&
remainingTime > 0f;
public void Configure(UnitBase shieldOwner, Collider shieldCollider)
{
owner = shieldOwner;
barrierCollider = shieldCollider;
}
public void Refresh(float durability, float activeDuration, Vector3 localPosition, Vector3 localSize)
{
if (barrierCollider == null)
{
barrierCollider = GetComponent<Collider>();
}
if (owner == null)
{
owner = GetComponentInParent<UnitBase>();
}
transform.localPosition = localPosition;
transform.localRotation = Quaternion.identity;
BoxCollider boxCollider = barrierCollider as BoxCollider;
if (boxCollider != null)
{
boxCollider.center = Vector3.zero;
boxCollider.size = localSize;
boxCollider.isTrigger = true;
}
maxDurability = Mathf.Max(0.01f, durability);
currentDurability = maxDurability;
duration = Mathf.Max(0.01f, activeDuration);
remainingTime = duration;
gameObject.SetActive(true);
if (barrierCollider != null)
{
barrierCollider.enabled = true;
}
}
public bool TryBlock(GameObject attacker, float damage)
{
if (!IsActive || damage <= 0f)
{
return false;
}
if (attacker != null && !IsIncomingFromFront(attacker))
{
return false;
}
currentDurability -= damage;
if (currentDurability <= 0f)
{
DisableBarrier();
}
return true;
}
public void DisableBarrier()
{
currentDurability = 0f;
remainingTime = 0f;
if (barrierCollider != null)
{
barrierCollider.enabled = false;
}
gameObject.SetActive(false);
}
private void Update()
{
if (!IsActive)
{
return;
}
remainingTime -= Time.deltaTime;
if (remainingTime <= 0f)
{
DisableBarrier();
}
}
private bool IsIncomingFromFront(GameObject attacker)
{
if (owner == null)
{
return true;
}
Vector3 direction = attacker.transform.position - owner.transform.position;
direction.y = 0f;
if (direction.sqrMagnitude <= 0.0001f)
{
return true;
}
return Vector3.Dot(owner.transform.forward, direction.normalized) >= frontDotThreshold;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: DSxN5iutVn7vYWZihot5eHq3WxYgtPA7YmvQEIefFazDgNVA+Ol4fxA=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,120 @@
using UnityEngine;
/// <summary>
/// 控制冲击波扩散效果
/// 可通过代码动态调整颜色、大小、速度等参数,实现不同技能的复用
/// </summary>
public class ShockwaveEffect : MonoBehaviour
{
[Header("扩散参数")]
[Tooltip("扩散持续时间(秒)")]
public float duration = 1f;
[Tooltip("扩散完成后是否自动销毁")]
public bool autoDestroy = true;
[Header("运行时可配置参数(可选)")]
[Tooltip("覆盖材质颜色(Alpha=0时不覆盖)")]
public Color overrideColor = new Color(0, 0, 0, 0);
[Tooltip("覆盖扩散半径(<=0时使用Transform.localScale)")]
public float overrideRadius = 0f;
[Tooltip("覆盖圆环粗细(<=0时使用材质默认值)")]
public float overrideRingWidth = 0f;
private Material material;
private float elapsed;
private bool isPlaying;
private Vector3 initialScale;
private void Start()
{
// 获取材质实例(不影响原材质)
var renderer = GetComponent<MeshRenderer>();
if (renderer != null)
{
material = renderer.material; // 自动创建材质实例
// 应用覆盖参数
if (overrideColor.a > 0f)
{
material.SetColor("_RingColor", overrideColor);
}
if (overrideRingWidth > 0f)
{
material.SetFloat("_RingWidth", overrideRingWidth);
}
if (overrideRadius > 0f)
{
// 根据半径计算所需的Scale
// Quad默认1x1,半径0.5,所以 Scale = radius * 2
float scale = overrideRadius * 2f;
transform.localScale = new Vector3(scale, scale, scale);
}
// 从0开始扩散
material.SetFloat("_Progress", 0f);
isPlaying = true;
elapsed = 0f;
}
else
{
Debug.LogWarning("ShockwaveEffect: 找不到MeshRenderer组件");
if (autoDestroy)
{
Destroy(gameObject);
}
}
}
private void Update()
{
if (!isPlaying || material == null)
{
return;
}
elapsed += Time.deltaTime;
float progress = Mathf.Clamp01(elapsed / duration);
// 更新Progress参数(0到1)
material.SetFloat("_Progress", progress);
// 扩散完成
if (progress >= 1f)
{
isPlaying = false;
if (autoDestroy)
{
Destroy(gameObject);
}
}
}
private void OnDestroy()
{
// 清理材质实例
if (material != null)
{
Destroy(material);
}
}
/// <summary>
/// 快捷方法:设置扩散参数
/// </summary>
public void SetupEffect(float radius, float duration, Color color, float ringWidth = 0f)
{
this.overrideRadius = radius;
this.duration = duration;
this.overrideColor = color;
if (ringWidth > 0f)
{
this.overrideRingWidth = ringWidth;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: BixO4yurUijnu64p8+3f1u2vjWk9JK3rjKwwJMBeodVwKJbnJRniptQ=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: