387 lines
13 KiB
C#
387 lines
13 KiB
C#
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);
|
||
// });
|
||
//}
|
||
}
|
||
}
|
||
} |