Files
daluandou/Assets/Scripts/投射物和特效/Projectile.cs
T
huadexuan 23c559d9f7 ```
feat(gameplay): 提升单位检测范围并添加法师属性

- 将所有单位的检测范围从默认值提升至100
- 为法师预制体添加护盾、等级等新属性
- 为法师添加暴击、吸血、伤害减免等战斗属性
- 更换法师弹丸预设并调整相关参数
- 添加锚点交战Z线控制功能
- 更新玩家数据中配备的召唤师技能
- 移除多余的纹理配置文件
```
2026-10-07 23:59:17 +08:00

177 lines
4.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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>();
WorldHealthBar targetHealthBar = hitObject.GetComponentInParent<WorldHealthBar>();
if (targetUnit == null && targetHealthBar == null)
{
return;
}
hasHit = true;
if (targetUnit != null)
{
targetUnit.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 (unit.lifestealRate > 0f)
{
WorldHealthBar ownerBar = unit.GetComponent<WorldHealthBar>();
if (ownerBar != null)
{
ownerBar.Heal(damage * unit.lifestealRate);
}
}
}
}
// 生成爆炸效果
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);
}
}