158 lines
4.8 KiB
C#
158 lines
4.8 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using DG.Tweening;
|
||
using DragonLi.Core;
|
||
using DragonLi.Frame;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine;
|
||
using Random = UnityEngine.Random;
|
||
|
||
public class LeviathanBullet : EnemyBullet
|
||
{
|
||
[Header("物理参数")]
|
||
private float groundDetectDistance = 0.7f; // 射线检测距离
|
||
|
||
private Rigidbody _rb;
|
||
private bool _initialized = false;
|
||
|
||
public bool isUpBullet;
|
||
public override void Awake()
|
||
{
|
||
base.Awake();
|
||
_rb = GetComponent<Rigidbody>();
|
||
// 确保物理驱动,重力生效
|
||
_rb.isKinematic = false;
|
||
_rb.useGravity = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从外部调用,设置初速度以打中 targetPoint
|
||
/// </summary>
|
||
public void Initialize(Vector3 startPos, Vector3 targetPoint, float flightTime)
|
||
{
|
||
transform.position = startPos;
|
||
|
||
// 计算初速度
|
||
Vector3 delta = targetPoint - startPos;
|
||
Vector3 g = Physics.gravity;
|
||
Vector3 v0 = delta / flightTime - 0.5f * g * flightTime;
|
||
_rb.velocity = v0;
|
||
|
||
// 初始朝向
|
||
if (v0.sqrMagnitude > 0.01f)
|
||
transform.rotation = Quaternion.LookRotation(v0.normalized);
|
||
_initialized = true;
|
||
}
|
||
|
||
private Vector3 _startPos;
|
||
private Vector3 _targetPos;
|
||
private float _flightTime;
|
||
private float _arcHeight;
|
||
private float _elapsed;
|
||
/// <summary>
|
||
/// 外部调用,初始化一次性发射参数
|
||
/// </summary>
|
||
public void Initialize(Vector3 startPos, Vector3 targetPos, float flightTime, float arcHeight)
|
||
{
|
||
_startPos = startPos;
|
||
_targetPos = targetPos;
|
||
_flightTime = flightTime;
|
||
_arcHeight = arcHeight;
|
||
_elapsed = 0f;
|
||
|
||
transform.position = _startPos;
|
||
// 初始朝向发射方向
|
||
Vector3 dir = (_targetPos - _startPos).normalized;
|
||
if (dir.sqrMagnitude > 0.01f)
|
||
transform.rotation = Quaternion.LookRotation(dir);
|
||
_initialized = true;
|
||
}
|
||
|
||
internal override void FixedUpdate()
|
||
{
|
||
if (!_initialized) return;
|
||
if (isUpBullet)
|
||
{
|
||
UpFly();
|
||
return;
|
||
}
|
||
Fly();
|
||
}
|
||
|
||
public void Fly()
|
||
{
|
||
// 始终面向速度方向
|
||
Vector3 vel = _rb.velocity;
|
||
if (vel.sqrMagnitude > 0.01f)
|
||
_rb.rotation = Quaternion.LookRotation(vel.normalized);
|
||
|
||
// —— 射线检测地面 ——
|
||
// 从导弹当前点向下发一条短射线,如果击中 groundLayer,就认定触地并爆炸
|
||
float checkDist = groundDetectDistance + vel.magnitude * Time.fixedDeltaTime;
|
||
if (Physics.Raycast(transform.position, Vector3.down, out RaycastHit hit, checkDist, targetHitLayer))
|
||
{
|
||
handlingHit = hit;
|
||
Explode();
|
||
}
|
||
}
|
||
|
||
public void UpFly()
|
||
{
|
||
_elapsed += Time.deltaTime;
|
||
float t = Mathf.Clamp01(_elapsed / _flightTime);
|
||
|
||
// 1. 直线插值
|
||
Vector3 basePos = Vector3.Lerp(_startPos, _targetPos, t);
|
||
// 2. 正弦叠加高度
|
||
float heightOffset = Mathf.Sin(Mathf.PI * t) * _arcHeight;
|
||
Vector3 curPos = basePos + Vector3.up * heightOffset;
|
||
transform.position = curPos;
|
||
|
||
// 3. 调整朝向:面向下一个位置
|
||
float nextT = Mathf.Min(t + 0.02f, 1f);
|
||
Vector3 nextBase = Vector3.Lerp(_startPos, _targetPos, nextT);
|
||
float nextHeight = Mathf.Sin(Mathf.PI * nextT) * _arcHeight;
|
||
Vector3 nextPos = nextBase + Vector3.up * nextHeight;
|
||
Vector3 forwardDir = (nextPos - curPos).normalized;
|
||
if (forwardDir.sqrMagnitude > 0.01f)
|
||
transform.rotation = Quaternion.LookRotation(forwardDir);
|
||
|
||
// 4. 到达终点
|
||
if (t >= 1f)
|
||
{
|
||
Explode();
|
||
}
|
||
}
|
||
|
||
private void Explode()
|
||
{
|
||
// 避免重复触发
|
||
if (!_initialized) return;
|
||
_initialized = false;
|
||
OnFixedUpdate();
|
||
SpawnImpact();
|
||
// 2. 范围伤害
|
||
Collider[] victims = Physics.OverlapSphere(transform.position, explosionRadius, targetHitLayer);
|
||
foreach (var item in victims)
|
||
{
|
||
var damagable = item.GetComponent<IDamagable>();
|
||
if (damagable!= null)
|
||
{
|
||
int randomDamage = GetDamage(out var isCriticalHit);
|
||
damagable.ApplyDamage(randomDamage, isCriticalHit, transform);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 辅助调试
|
||
private void OnDrawGizmosSelected()
|
||
{
|
||
// 可视化射线长度和爆炸范围
|
||
Gizmos.color = Color.cyan;
|
||
Gizmos.DrawLine(transform.position, transform.position + Vector3.down * groundDetectDistance);
|
||
Gizmos.color = Color.yellow;
|
||
Gizmos.DrawWireSphere(transform.position, explosionRadius);
|
||
}
|
||
}
|