feat(gameplay): 添加建筑系统和改进摄像机控制 - 移除人类士兵数据资产文件,重构为建筑放置系统 - 在CharacterData中添加productionInterval和buildingCost字段用于建筑生产 - 实现CameraFollow脚本的完整重写,支持键盘WASD拖动、鼠标拖动、触摸拖动 - 添加摄像机缩放功能,支持上下键和触摸双指缩放 - 更新Projecttile.cs以同时处理单位和建筑目标的伤害检测 - 修改SummonCardButton从法力值召唤改为金币建筑放置模式 - 在UnitBase.cs中更新攻击逻辑以支持对建筑造成伤害 - 升级WorldHealthBar以显示建筑生产进度和更好的缩放补偿 - 修复MainCharacterDebugMovement移除键盘移动输入冲突 - 更新包管理器中的codely.bridge版本从1.0.80到1.0.81 ```
151 lines
3.7 KiB
C#
151 lines
3.7 KiB
C#
using UnityEngine;
|
|
|
|
public class Projectile : MonoBehaviour
|
|
{
|
|
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;
|
|
}
|
|
|
|
if (Physics.Raycast(transform.position, direction, out RaycastHit hit, distance))
|
|
{
|
|
TryHit(hit.collider.gameObject);
|
|
if (hit.collider.transform.root == target.transform.root)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
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>();
|
|
BuildingHealth targetBuilding = hitObject.GetComponentInParent<BuildingHealth>();
|
|
if (targetUnit == null && targetBuilding == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
hasHit = true;
|
|
if (targetUnit != null)
|
|
{
|
|
targetUnit.ReceiveDamage(damage, owner);
|
|
}
|
|
else
|
|
{
|
|
targetBuilding.ReceiveDamage(damage, owner);
|
|
}
|
|
if (registerEnergyOnHit && owner != null)
|
|
{
|
|
UnitBase unit = owner.GetComponent<UnitBase>();
|
|
if (unit != null)
|
|
{
|
|
unit.RegisterAttackHit();
|
|
}
|
|
}
|
|
|
|
Destroy(gameObject);
|
|
}
|
|
|
|
private bool IsOwner(GameObject hitObject)
|
|
{
|
|
return owner != null &&
|
|
(hitObject == owner || hitObject.transform.root == owner.transform.root);
|
|
}
|
|
}
|