2025-12-14 11:32:38 +08:00

387 lines
13 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 DG.Tweening;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
using System.Collections;
using System.Linq;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UIElements;
namespace Assets.Scripts
{
public class Bullet : MonoBehaviour
{
[Tooltip("火力")]
public int power = 50;
///// <summary>
///// 已经击中的敌人个数
///// </summary>
//public int currentShotCount { get; set; } = 0;
/// <summary>
/// 当前命中的敌人位置
/// </summary>
public Vector3 currentHitPosition { get; set; } = Vector3.zero;
public TweenerCore<Vector3, Vector3, VectorOptions> Tweener { get; set; } = null;
public GameObject impactPrefab;
public GameObject explosionPrefab;
public float thrust;
public Rigidbody thisRigidbody;
public GameObject particleKillGroup;
private Collider thisCollider;
public bool IsShoting { get; set; } = false;
public bool IsNeedDestroyInRecycle { get; set; } = false;
public bool IsAutoLock { get; set; } = false;
///// <summary>
///// 是否已锁定目标
///// </summary>
//public bool IsLockedTarget { get; set; } = false;
public Enemy LockTarget { get; set; } = null;
public Enemy HitTarget { get; set; } = null;
public Enemy BeforeHitTarget { get; set; } = null;
private Vector3 _shotTargetPosition = Vector3.zero;
public Vector3 ShotTargetPosition
{
get
{
if (LockTarget != null)
{
_shotTargetPosition = LockTarget.transform.position;
//return LockTarget.transform.position;
}
return _shotTargetPosition;
}
set
{
_shotTargetPosition = value;
}
}
public bool LookRotation = true;
public bool Missile = false;
public Transform missileTarget;
public float projectileSpeed;
public float projectileSpeedMultiplier;
public bool ignorePrevRotation = false;
public bool explodeOnTimer = false;
public float explosionTimer;
float timer;
private Vector3 previousPosition;
private Camera _cam;
private int wallLayer = 0;
private void Awake()
{
wallLayer = LayerMask.NameToLayer("Wall");
_cam = Camera.main;
}
// Use this for initialization
void Start()
{
thisRigidbody = GetComponent<Rigidbody>();
if (Missile)
{
missileTarget = GameObject.FindWithTag("Target").transform;
}
thisCollider = GetComponentInChildren<Collider>();
previousPosition = transform.position;
}
// Update is called once per frame
void Update()
{
/* if(Input.GetButtonUp("Fire2"))
{
Explode();
}*/
timer += Time.deltaTime;
if (timer >= explosionTimer && explodeOnTimer == true)
{
Explode();
}
}
void FixedUpdate()
{
if (thisRigidbody != null)
{
if (Missile)
{
projectileSpeed += projectileSpeed * projectileSpeedMultiplier;
// transform.position = Vector3.MoveTowards(transform.position, missileTarget.transform.position, 0);
transform.LookAt(missileTarget);
thisRigidbody.AddForce(transform.forward * projectileSpeed);
}
if (LookRotation && timer >= 0.05f && !thisRigidbody.velocity.Equals(Vector3.zero))
{
transform.rotation = Quaternion.LookRotation(thisRigidbody.velocity);
}
}
CheckCollision(previousPosition);
previousPosition.Set(transform.position.x, transform.position.y, transform.position.z);
}
/// <summary>
/// 从RaycastHit数组中找到距离最近的碰撞
/// </summary>
/// <param name="hits">射线碰撞结果数组</param>
/// <param name="rthit">输出最近的碰撞信息</param>
/// <returns>是否找到有效碰撞</returns>
private Enemy FindEnemyHit(RaycastHit[] hits, out RaycastHit rthit)
{
rthit = new RaycastHit();
float minDistance = Mathf.Infinity;
// 遍历所有碰撞结果,找到距离最小的
foreach (RaycastHit hit in hits)
{
if (hit.collider.gameObject.layer == wallLayer)
{
rthit = hit;
return null;
}
var enemy = hit.collider.gameObject.GetComponent<Enemy>();
if (enemy != null && enemy != BeforeHitTarget)
{
rthit = hit;
minDistance = hit.distance;
return enemy;
}
//if (hit.distance < minDistance)
//{
// minDistance = hit.distance;
// closestHit = hit;
//}
}
// 如果minDistance还是无穷大说明没有碰撞
return null;// minDistance != Mathf.Infinity;
}
void CheckCollision(Vector3 prevPos)
{
if (IsShoting)
{
RaycastHit[] hits;
Vector3 direction = transform.position - prevPos;
Ray ray = new Ray(prevPos, direction);
//float halfLen = 0;
//if (thisCollider != null)
//{
// var extents = thisCollider.bounds.extents;
// halfLen = extents.magnitude * 0.5f;
//}
float dist = Vector3.Distance(transform.position, prevPos);
hits = Physics.RaycastAll(ray, dist);
if (hits.Length > 0)
{
var enemy = FindEnemyHit(hits, out RaycastHit hit);
if (hit.collider == null)
{
return;//穿过
}
//穿墙处理
if (hit.collider.gameObject == null)
{
return;//穿过
}
if (hit.collider.gameObject.layer == wallLayer)
{
return;//穿过
}
if (hit.collider.gameObject.GetComponentInParent<Tower>() != null)
{
return;//穿过
}
//if (hit.collider.gameObject.GetComponentInParent<ParticleSystem>() != null)
//{
// return;//穿过
//}
if (hit.collider.gameObject != gameObject && hit.collider.gameObject.GetComponent<Bullet>() != null)
{
return;//穿过
}
if (enemy != null)
{
////如果子弹在怪物前面或者相交
//if (CalcTool.IsTargetFrontOrIntersect(transform, enemy.transform))
//{
//if (_cam.orthographic)
//{
// if (VisibilityTool.IsObjectInFrustum(enemy.gameObject, _cam))
// {
// currentHitPosition = enemy.transform.position;
// isHitted = true;
// }
// //命中
// //isDestroyed = enemy.TakeDamage(this.power);
//}
//else
//{
// currentHitPosition = enemy.transform.position;
// isHitted = true;
//}
if (VisibilityTool.IsObjectInFrustum(enemy.gameObject, _cam))
{
if (BeforeHitTarget != enemy)
{
BeforeHitTarget = enemy;//保证只触发一次
HitTarget = enemy;
currentHitPosition = enemy.transform.position;
Hitted();
}
}
//}
}
////var impact = InitImpact(hit.point, hit.normal);
//if (!explodeOnTimer && Missile == false)
//{
// //ResetBullet(transform, impact);
// Tweener.Kill(true);
//}
//else if (Missile == true)
//{
// thisCollider.enabled = false;
// particleKillGroup.SetActive(false);
// thisRigidbody.velocity = Vector3.zero;
// //ResetBullet(transform, impact);
// Tweener.Kill(true);
//}
//if (isHitted)
//{
// LockTarget = enemy;
// Hitted();
// //ResetBullet(transform, impact);
// //transform.DOKill(true);
//}
}
}
}
public Transform InitImpact(Vector3 point, Vector3 toDirection, Transform impact)
{
transform.position = point;
Quaternion rot = Quaternion.FromToRotation(Vector3.forward, toDirection);
if (impact != null)
{
impact.position = point;
impact.rotation = rot;
impact.gameObject.SetActive(true);
return impact;
}
return null;
}
//void OnCollisionEnter(Collision collision)
//{
// if (IsShoting && collision.gameObject.tag != "FX")
// {
// ContactPoint contact = collision.contacts[0];
// Quaternion rot = Quaternion.FromToRotation(Vector3.forward, contact.normal);
// if (ignorePrevRotation)
// {
// rot = Quaternion.Euler(0, 0, 0);
// }
// Vector3 pos = contact.point;
// var impact = Instantiate(impactPrefab, pos, rot);
// if (!explodeOnTimer && Missile == false)
// {
// //ResetBullet(transform, impact.transform);
// Hitted();
// }
// else if (Missile == true)
// {
// thisCollider.enabled = false;
// particleKillGroup.SetActive(false);
// thisRigidbody.velocity = Vector3.zero;
// Hitted();
// //ResetBullet(transform, impact.transform);
// }
// }
//}
private void Hitted()
{
if (IsShoting)
{
IsShoting = false;
Tweener.Complete(true);
Tweener.Kill();
}
}
void Explode()
{
var impact = Instantiate(explosionPrefab, gameObject.transform.position, Quaternion.Euler(0, 0, 0));
//ResetBullet(transform, impact.transform);
Hitted();
}
/// <summary>
/// 重置锁定的敌方对象,以及击中的敌方对象
/// </summary>
public void ResetEnemyTargets()
{
//IsLockedTarget = false;
HitTarget = null;
LockTarget = null;
}
/// <summary>
/// 重置当前复用变量状态
/// </summary>
public void ResetBullet()
{
Tweener = null;
IsShoting = false;
currentHitPosition = Vector3.zero;
IsAutoLock = false;
ResetEnemyTargets();
BeforeHitTarget = null;
_shotTargetPosition = Vector3.zero;
//currentShotCount = 0;
//if (isDestroyLimit)
//{
// bullet.SetActive(false);
// Global.ShotBulletQueues[bullet.name.Replace("(Clone)", string.Empty)].Add(bullet.transform);
//}
//else
//{
// // 指定时间后触发指定方法
// DOTween.To(() => 0, x => { }, 0, Global.DeathTimer) // 空的补间(仅作为计时器)
// .OnComplete(() =>
// {
// bullet.SetActive(false);
// Global.ShotBulletQueues[bullet.name.Replace("(Clone)", string.Empty)].Add(bullet.transform);
// });
//}
}
}
}