2025-12-21 19:37:02 +08:00

817 lines
27 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 Assets.Scripts;
using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.InputSystem;
/// <summary>
/// 炮弹,子弹发射类
/// </summary>
public class Shot : MonoBehaviour
{
public RingManager ringManager;
public Transform impact;
public Transform muzzleFlare;
public Transform bullet;
[Tooltip("炮弹连续穿透并自动射击附近的敌人的次数")]
public int continueShotCount = 3;
public Transform turret;
public Transform gun;
[Tooltip("音效声音大小")]
public float audioVolume = 1f;
[Tooltip("发射音效")]
public AudioClip shotAudioClip;
[Tooltip("击中音效")]
public AudioClip hitAudioClip;
[Tooltip("发射时间间隔")]
public float shotDuration = 0.2f;
[Tooltip("连发发射时间间隔")]
public float shotNextDuration = 0.1f;
[Tooltip("发射距离")]
public float shotDistance = 50f;
[Tooltip("炮弹速度")]
public float shotSpeed = 1;
[Tooltip("初始化炮弹数量")]
public int initBulletCount = 300; // 修改为int类型
[Tooltip("发射Z坐标偏移前移动倍数相当于乘以gun.forward")]
public float shotOffsetZMul = 0;
[Tooltip("发射X坐标角度修正")]
public float shotFixAngleX = 0;
[Tooltip("炮台转向,炮管锁定速度")]
public float lerpSpeed = 5f;
[Tooltip("是否自动跟踪锁定最近的敌人")]
public bool isAutoLock = false;
[Tooltip("是否显示发射时候炮口的火焰")]
public bool isShowMuzzle = false;
//[Tooltip("子弹最多多少秒后自动销毁")]
//public float bulletMaxDuration = 3;
[Header("输入绑定")]
[SerializeField] private InputActionReference pressAction;
private bool isShoting = false;
//private Coroutine shotCoroutine = null;
//private bool isInitLookedEnemy = false;
//// 跟踪正在使用的对象,防止重复分配
//private HashSet<Transform> activeBullets = new HashSet<Transform>();
//private HashSet<Transform> activeMuzzles = new HashSet<Transform>();
private Vector3 turretLerpEuler = Vector3.zero;
private float smoothXAngle = 0f;
private float targetXAngle = 0f;
private float hitDistance = 0.2f; // 命中检测距离阈值
private bool isCanShot = false;
private bool isStartAttack = false;
private ConcurrentQueue<NextShotInfo> nextShotInfos = new();
private QiuObject[] _qiuObjects = new QiuObject[] { };
// 弹仓List避免重复分配对象
private ConcurrentQueue<Transform> bulletPool = new();
private ConcurrentQueue<Transform> muzzlePool = new();
private ConcurrentQueue<Transform> impactPool = new();
private List<Transform> activeBulletPool = new();
private List<Transform> activeImpactPool = new();
/// <summary>
/// 上一次发射的时间
/// </summary>
private static DateTime beforeShotTime = DateTime.Now;
private Camera _cam = null;
void Awake()
{
if (turret == null)
{
turret = new GameObject("Turret").transform;
turret.SetParent(transform);
turret.localPosition = Vector3.zero;
turret.localEulerAngles = Vector3.zero;
turret.localScale = Vector3.one;
}
if (gun == null)
{
gun = new GameObject("Gun").transform;
gun.SetParent(turret);
gun.localPosition = Vector3.zero;
gun.localScale = Vector3.one;
gun.forward = turret.forward;
}
turretLerpEuler = turret.eulerAngles;
smoothXAngle = gun.localEulerAngles.x;
isCanShot = true;// !isAutoLock;//如果不是自动锁定开火按钮设成True
_cam = Camera.main;
if (transform.parent != null)
{
_qiuObjects = transform.parent.GetComponentsInChildren<QiuObject>();
}
// 初始化对象池使用Queue而非全局List
InitializePool();
}
void Start()
{
StartCoroutine(ContinueShot());
StartCoroutine(QueueNextShot());
}
private void ClearCachePool()
{
foreach (var bullet in this.activeBulletPool)
{
var bulletComp = bullet.GetComponent<Bullet>();
bulletComp.IsNeedDestroyInRecycle = true;
}
// 清理所有对象
foreach (var bullet in this.bulletPool)
{
if (bullet != null)
{
bullet.DOKill(true);
Destroy(bullet.gameObject);
}
}
foreach (var muzzle in this.muzzlePool)
{
if (muzzle != null)
{
//muzzle.DOKill();
Destroy(muzzle.gameObject);
}
}
foreach (var impact in this.activeImpactPool)
{
if (impact != null)
{
//impact.DOKill();
var recycle = impact.GetComponent<RecycleImpact>();
recycle.IsNeedDestroyInRecycle = true;
}
}
foreach (var impact in this.impactPool)
{
if (impact != null)
{
//impact.DOKill(true);
Destroy(impact.gameObject);
}
}
//foreach (var bullet in activeBullets)
//{
// if (bullet != null)
// {
// bullet.DOKill();
// Destroy(bullet.gameObject);
// }
//}
//foreach (var muzzle in activeMuzzles)
//{
// if (muzzle != null)
// {
// muzzle.DOKill();
// Destroy(muzzle.gameObject);
// }
//}
// 清空旧数据
this.activeImpactPool.Clear();
this.activeBulletPool.Clear();
this.bulletPool.Clear();
this.muzzlePool.Clear();
this.impactPool.Clear();
}
private void RecycleImpactToPool(Transform impactTransform)
{
PoolTool.RecycleImpactToPool(impactTransform, impactPool);
}
public void InitializePool()
{
//activeBullets.Clear();
//activeMuzzles.Clear();
ClearCachePool();
// 创建子弹池
for (int i = 0; i < initBulletCount; i++)
{
// 子弹对象
var bulletObj = Instantiate(bullet);
bulletObj.gameObject.SetActive(false);
bulletObj.SetParent(null); // 强制设为世界对象
bulletObj.name = $"Bullet_{i}";
this.bulletPool.Enqueue(bulletObj);
if (isShowMuzzle)
{
// 枪口火焰对象
var muzzleObj = Instantiate(muzzleFlare);
muzzleObj.gameObject.SetActive(false);
muzzleObj.SetParent(null);
muzzleObj.name = $"Muzzle_{i}";
this.muzzlePool.Enqueue(muzzleObj);
}
//for (int j = 0; j < Mathf.Max(1, continueShotCount / 3); j++)
//{
// 爆炸火焰对象
var impactObj = Instantiate(impact);
impactObj.gameObject.SetActive(false);
impactObj.SetParent(null);
impactObj.name = $"Impact_{i}";
impactObj.GetComponent<RecycleImpact>().RecycleAction = this.RecycleImpactToPool;
this.impactPool.Enqueue(impactObj);
//}
}
}
private void OnDestroy()
{
// 停止协程
//if (shotCoroutine != null)
//{
// StopCoroutine(shotCoroutine);
//}
StopAllCoroutines();
}
private void OnEnable()
{
pressAction.action.performed += PressAction_performed;
pressAction.action.canceled += PressAction_canceled;
pressAction.action.Enable();
}
private void PressAction_performed(InputAction.CallbackContext ctx)
{
isShoting = true;
}
private void PressAction_canceled(InputAction.CallbackContext ctx)
{
isShoting = false;
}
/// <summary>
/// 连续发射炮弹的协程
/// </summary>
/// <returns></returns>
private IEnumerator ContinueShot()
{
//float duration = shotDistance / shotSpeed; // 正确的飞行时间计算:距离/速度
while (true)
{
if (isCanShot)
{
SingleShot(GetBullet(), lockEnemy, false);
//isCanShot = !isAutoLock;
}
yield return new WaitForSeconds(shotDuration);
}
}
/// <summary>
/// 弹射炮弹的协程
/// </summary>
/// <returns></returns>
private IEnumerator QueueNextShot()
{
//float duration = shotDistance / shotSpeed; // 正确的飞行时间计算:距离/速度
while (true)
{
if (shotNextDuration == 0)
{
yield return new WaitForEndOfFrame();
}
else
{
yield return new WaitForSeconds(shotNextDuration);
}
if (nextShotInfos.TryDequeue(out NextShotInfo info))
{
SingleShot(info.BulletObj, info.LockEnemy, true, info.CurrentShotCount, info.InitBulletPos, info.BeforeLockTarget);
}
}
}
/// <summary>
/// 从炮弹池中会去对象
/// </summary>
/// <returns></returns>
private Transform GetBullet()
{
Transform bulletObj = null;
if (bulletObj == null || bulletObj.IsDestroyed())
{
// 从池中获取对象
bulletObj = PoolTool.GetFromPool(this.bulletPool, this.activeBulletPool, this.activeImpactPool);
// 激活对象
bulletObj.gameObject.SetActive(true);
}
return bulletObj;
}
/// <summary>
/// 更新炮弹对象状态
/// </summary>
/// <param name="bulletComp">炮弹对象</param>
/// <param name="beforeHitTargetTransform">之前集中的目标,可为空</param>
private void BulletUpdate(Bullet bulletComp, Transform beforeHitTargetTransform)
{
if (isAutoLock)
{
if (bulletComp.LockTarget == null)
{
bulletComp.LockTarget = GetNearestEnemyFromTransform(bulletComp.transform, beforeHitTargetTransform);
//bulletComp.IsLockedTarget = true;
}
}
//if (bulletComp.ForwardTarget == null)
//{
// bulletComp.ForwardTarget = GetNearestEnemyFromTransform(bulletComp.transform, beforeHitTargetTransform);
//}
//if (bulletComp.ForwardTarget != null)
//{
// var pos = bulletComp.transform.position;
// pos.y = bulletComp.ForwardTarget.transform.position.y;
// bulletComp.transform.position = pos;
//}
// 修正弹体朝向(对准目标,更真实)
if (bulletComp.LockTarget != null && bulletComp.transform != null)
{
bulletComp.ShotTargetPosition = bulletComp.LockTarget.transform.position;
}
//if (isAutoLock)
//{
float x = bulletComp.transform.eulerAngles.x;
bulletComp.transform.LookAt(bulletComp.ShotTargetPosition);
var eulerAngles = bulletComp.transform.eulerAngles;
eulerAngles.Set(x, eulerAngles.y, eulerAngles.z);
bulletComp.transform.eulerAngles = eulerAngles;
//}
if (CalcBulletBoom(bulletComp))
{
bulletComp.transform.DOComplete(true);
bulletComp.transform.DOKill();
}
}
private void ShotBulletComplete(Bullet bulletComp, int currentShotCount, Transform muzzleObj)
{
bool isBulletHitted = CalcBulletBoom(bulletComp);
if (bulletComp.HitTarget != null)
{
if (hitAudioClip != null)
{
AudioTool.AudioSource.PlayOneShot(hitAudioClip, audioVolume);
}
currentShotCount++;
if (currentShotCount <= continueShotCount)
{
PoolTool.RecycleMuzzleToPool(muzzleObj, this.muzzlePool, this.activeImpactPool);
var nextLockTarget = GetNearestEnemyFromTransform(bulletComp.transform, bulletComp.HitTarget == null ? bulletComp.transform : bulletComp.HitTarget.transform);
if (nextLockTarget != null)
{
Vector3 initBulletPos = bulletComp.transform.position;
Transform hitTransform = null;
if (bulletComp.HitTarget != null)
{
hitTransform = bulletComp.HitTarget.transform;
initBulletPos = hitTransform.position;
}
CheckBulletBoom(isBulletHitted, bulletComp, false);
bulletComp.ResetEnemyTargets();
var beforeTarget = bulletComp.BeforeHitTarget;
PoolTool.RecycleBulletToPool(bulletComp.transform, this.bulletPool, this.activeBulletPool);
SingleShot(GetBullet(), nextLockTarget, true, currentShotCount, initBulletPos, beforeTarget);//连线射击
//nextShotInfos.Enqueue(new NextShotInfo { CurrentShotCount = currentShotCount, LockEnemy = nextLockTarget, InitBulletPos = initBulletPos, BulletObj = null, BeforeLockTarget = bulletComp.BeforeHitTarget });
}
else
{
CheckBulletBoom(isBulletHitted, bulletComp);
}
}
else
{
CheckBulletBoom(isBulletHitted, bulletComp);
}
}
else
{
CheckBulletBoom(isBulletHitted, bulletComp);
}
}
/// <summary>
/// 单次发射方法
/// </summary>
/// <param name="lockEnemy"></param>
/// <param name="isNextLineShot">是否弹射</param>
/// <param name="initBulletPos"></param>
/// <param name="bulletObj"></param>
private void SingleShot(Transform bulletObj, Enemy lockEnemy, bool isNextLineShot, int currentShotCount = 0, Vector3? initBulletPos = null, Enemy beforeLockTarget = null)
{
Transform muzzleObj = null;
if (isShowMuzzle && !isNextLineShot)
{
muzzleObj = PoolTool.GetFromPool(this.muzzlePool, this.activeBulletPool, this.activeImpactPool);
}
if (bulletObj != null)
{
// 1. 播放音效
if (!isNextLineShot && shotAudioClip != null)
{
if (DateTime.Now - beforeShotTime > TimeSpan.FromSeconds(shotDuration))
{
beforeShotTime = DateTime.Now;
AudioTool.AudioSource.PlayOneShot(shotAudioClip, audioVolume);
}
}
// 2. 计算发射位置(确保使用世界坐标)
Vector3 firePos = gun.position + gun.forward * shotOffsetZMul;
// 3. 设置初始位置(强制世界坐标)
if (initBulletPos == null)
{
bulletObj.position = gun.position;
}
else
{
bulletObj.position = initBulletPos.Value;
}
// 4. 获取子弹组件并重置状态
var bulletComp = bulletObj.GetComponent<Bullet>();
bulletComp.BeforeHitTarget = beforeLockTarget;
bulletComp.IsAutoLock = isAutoLock;
bulletComp.IsShoting = true;
var beforeHitTargetTransform = bulletComp.BeforeHitTarget == null ? null : bulletComp.BeforeHitTarget.transform;
// 5. 设置炮弹发射方向
if (isNextLineShot)
{
bulletComp.LockTarget = GetNearestEnemyFromTransform(bulletObj, beforeHitTargetTransform);
if (bulletComp.LockTarget != null)
{
bulletComp.ShotTargetPosition = bulletComp.LockTarget.transform.position;
}
else
{
var pos = gun.position + gun.forward * shotDistance;
pos.y = gun.position.y;
bulletComp.ShotTargetPosition = pos;
}
}
else if (isAutoLock && lockEnemy != null && !lockEnemy.IsDestroyed())
{
bulletComp.LockTarget = lockEnemy;
bulletComp.ShotTargetPosition = lockEnemy.transform.position;
// 6. 设置炮弹角度
bulletObj.transform.eulerAngles = Vector3.zero;
}
else
{
var pos = gun.position + gun.forward * shotDistance;
pos.y = gun.position.y;
bulletComp.ShotTargetPosition = pos;
// 6. 设置炮弹角度
bulletObj.transform.eulerAngles = Vector3.zero;
bulletObj.transform.LookAt(bulletComp.ShotTargetPosition);
}
// 7. 击中爆炸效果对象不为空,则设置相关参数
if (muzzleObj != null)
{
//设置炮口火焰父对象(可选)
muzzleObj.position = firePos;
muzzleObj.SetParent(gun);
muzzleObj.gameObject.SetActive(true);
muzzleObj.transform.LookAt(bulletComp.ShotTargetPosition);
}
// 8. 延迟一帧,等待下一帧状态更新后,开始炮弹动画和相关逻辑执行
DOVirtual.DelayedCall(Time.fixedDeltaTime, () =>
{
bulletComp.Tweener = DOTween.To(
() =>
{
return bulletObj == null ? transform.position : bulletObj.position; // 当前位置Getter
},
(Vector3 pos) =>
{
if (bulletObj != null)
{
bulletObj.position = Vector3.MoveTowards(bulletObj.position, bulletComp.ShotTargetPosition, Time.deltaTime * shotSpeed);
} // 更新位置Setter
},
bulletComp.ShotTargetPosition,//目标位置
shotSpeed
)
.SetSpeedBased()
.SetEase(Ease.Linear)
.SetUpdate(UpdateType.Manual)
.OnUpdate(() =>
{
//每帧更新炮弹状态参数
BulletUpdate(bulletComp, beforeHitTargetTransform);
})
.OnComplete(() =>
{
//动画完成处理(超出视距范围外,或者击中爆炸)
ShotBulletComplete(bulletComp, currentShotCount, muzzleObj);
});
if (muzzleObj != null)
{
// 9. 爆炸火焰自动隐藏0.2秒后)
DOVirtual.DelayedCall(0.2f, () =>
{
PoolTool.RecycleMuzzleToPool(muzzleObj, this.muzzlePool, this.activeImpactPool);
});
}
});
}
}
private void CheckBulletBoom(bool isBulletHitted, Bullet bulletComp, bool recycleToPool = true)
{
if (isBulletHitted)
{
CheckBulletBoom(bulletComp);
}
if (recycleToPool)
{
PoolTool.RecycleBulletToPool(bulletComp.transform, this.bulletPool, this.activeBulletPool);
}
}
private Vector3? CheckBulletBoom(Bullet bulletComp)
{
Vector3? hitPosition = null;
if (bulletComp.HitTarget != null)// && bulletComp.HitTarget != bulletComp.BeforeHitTarget)
{
//Calc is Boom
hitPosition = bulletComp.HitTarget.transform.position;
bool isDestroyed = bulletComp.HitTarget.TakeDamage(bulletComp.power);//对敌方造成伤害
Vector3 targetDir = (bulletComp.transform.position - hitPosition.Value).normalized;
var impact = PoolTool.GetFromPool(this.impactPool, this.activeBulletPool, this.activeImpactPool); //Instantiate(impactPrefab, point, rot);
bulletComp.InitImpact(hitPosition.Value, targetDir, impact);//爆炸效果
//if (bulletComp.Tweener != null)
//{
// bulletComp.Tweener.Complete(withCallback);
//}
//bulletComp.transform.DOKill();
if (isDestroyed)
{
lockEnemy = null;
}
}
return hitPosition;
}
private bool CalcBulletBoom(Bullet bulletComp)
{
bool isBulletHitted = false;
// 命中检测(距离达标则触发效果)
if (bulletComp.HitTarget != null)
{
return true;
}
else
{
//在摄像机看到的屏幕范围之外,销毁子弹
isBulletHitted = !VisibilityTool.IsObjectInFrustum(bulletComp.gameObject, _cam);
}
//if (!isBulletHitted && bulletComp.LockTarget != null)
//{
// if (bulletComp.LockTarget != bulletComp.BeforeHitTarget)
// {
// float currentDistance = Vector3.Distance(bulletComp.transform.position, bulletComp.LockTarget.transform.position);
// if (currentDistance < hitDistance)
// {
// isBulletHitted = true;
// bulletComp.currentHitPosition = bulletComp.LockTarget.transform.position;
// bulletComp.HitTarget = bulletComp.LockTarget;
// bulletComp.BeforeHitTarget = bulletComp.HitTarget;
// bulletComp.IsShoting = false;
// }
// }
//}
//if (isDestroyed)
//{
// bulletComp.Tweener.Kill(true);
// //bulletObj.DOKill(true); // 停止Tween
//}
// HitTarget(bulletObj, muzzleObj);
//}
return isBulletHitted;
}
// 计算弹体到目标的距离
private float GetDistanceToTarget(Transform bullet, Transform target)
{
if (target == null || target.IsDestroyed()) return float.MaxValue;
return Vector3.Distance(bullet.position, target.position);
}
private void OnDisable()
{
pressAction.action.performed -= PressAction_performed;
pressAction.action.canceled -= PressAction_canceled;
pressAction.action.Disable();
}
/// <summary>
/// 此发炮弹锁定的对象
/// </summary>
private Enemy lockEnemy = null;
private void Update()
{
//if (isAutoLock)
//{
// LockEnemy();
//}
LockEnemy();
LerpTurretAngle();
LerpGunsAngle();
}
private void LockEnemy()
{
if (lockEnemy == null || lockEnemy.IsDestroyed())
{
isStartAttack = false;
lockEnemy = GetNearestEnemyFromTransform(transform);
}
}
private Enemy GetNearestEnemyFromTransform(Transform bullet, Transform currentHitTarget = null)
{
Enemy result = null;
float minDistance = float.MaxValue;
for (int i = 0; i < Global.Enemies.Count; i++)
{
var enemy = Global.Enemies[i];
if (enemy != null)
{
if (enemy.transform == currentHitTarget)
{
continue;
}
float distance = GetDistanceToTarget(bullet, enemy.transform);
if (distance < minDistance && distance < shotDistance)// && (ringManager == null || distance > ringManager.radius * 1.2f))// && !Global.LockedEnemies.ContainsKey(enemy.GetHashCode()))
{
if (VisibilityTool.IsObjectInFrustum(enemy.gameObject, _cam))
{
minDistance = distance;
result = enemy;
}
}
}
}
return result;
}
private void LerpTurretAngle()
{
if (isAutoLock && lockEnemy != null && !lockEnemy.IsDestroyed())
{
float speed = 1f;
float distance = Vector3.Distance(lockEnemy.transform.position, gun.position);
if (distance > shotDistance)
{
//isCanShot = false;
lockEnemy = null;
turretLerpEuler.Set(turret.eulerAngles.x, turret.eulerAngles.y, turret.eulerAngles.z);
//ResetTurretEuler();
}
else
{
if (!Global.LockedEnemies.ContainsKey(lockEnemy.GetHashCode()))
{
Global.LockedEnemies.Add(lockEnemy.GetHashCode(), lockEnemy);
}
Vector3 enemyPos = lockEnemy.transform.position;
turretLerpEuler.Set(turret.eulerAngles.x, turret.eulerAngles.y, turret.eulerAngles.z);
speed = this.lerpSpeed;
// 1. 计算炮塔到敌人的方向向量仅考虑水平平面忽略y轴高度差
Vector3 directionToEnemy = enemyPos - turret.transform.position;
directionToEnemy.y = 0; // 只保留水平方向x-z平面
// 2. 计算方向向量对应的y轴欧拉角
float targetYAngle = Mathf.Atan2(directionToEnemy.x, directionToEnemy.z) * Mathf.Rad2Deg;
// 3. 赋值给turretLerpEuler的y轴
turretLerpEuler.y = targetYAngle;
turretLerpEuler.y = CalcTool.FixEulerAngle(turretLerpEuler.y, turret.eulerAngles.y);
}
turret.eulerAngles = Vector3.Lerp(turret.eulerAngles, turretLerpEuler, Time.deltaTime * speed);
}
else
{
turret.forward = transform.forward;
//isCanShot = isStartAttack && Global.Enemies.Any();
//ResetTurretEuler();
}
}
//private void ResetTurretEuler()
//{
// turretLerpEuler.Set(turret.eulerAngles.x, turret.eulerAngles.y + Time.deltaTime * this.lerpSpeed * 2, turret.eulerAngles.z);
// turret.eulerAngles = turretLerpEuler;
//}
private void LerpGunsAngle()
{
if (lockEnemy == null)
{
targetXAngle = 0;
}
else
{
Vector3 enemyPos = lockEnemy.transform.position;
// ========== 垂直索敌炮管x轴旋转 ==========
// 1. 计算从炮管到敌人的方向向量保留y轴高度差
Vector3 gunToEnemy = gun.transform.position - enemyPos;
// 2. 将方向向量转换为炮管的局部坐标系(避免炮塔旋转影响计算)
Vector3 localDir = gun.transform.InverseTransformDirection(gunToEnemy);
// 3. 计算垂直旋转角度x轴
targetXAngle = Mathf.Atan2(localDir.y, Mathf.Sqrt(localDir.x * localDir.x + localDir.z * localDir.z)) * Mathf.Rad2Deg;
//// 4. 限制俯仰角度范围(防止炮管旋转过度)
//targetXAngle = Mathf.Clamp(targetXAngle, minXAngle, maxXAngle);
}
// 处理360度环绕问题
smoothXAngle = Mathf.LerpAngle(smoothXAngle, targetXAngle, Time.deltaTime * this.lerpSpeed);
gun.localEulerAngles = new Vector3(smoothXAngle, gun.localEulerAngles.y, gun.localEulerAngles.z);
}
//// 调试在Scene视图中绘制发射位置
//private void OnDrawGizmosSelected()
//{
// if (gun != null)
// {
// Vector3 firePos = gun.TransformPoint(new Vector3(0, shotOffsetZ, 0));
// firePos.z = 0;
// Vector3 targetPos = new Vector3(firePos.x, firePos.y + shotDistance, 0);
// Gizmos.color = Color.green;
// Gizmos.DrawSphere(firePos, 0.1f);
// Gizmos.color = Color.red;
// Gizmos.DrawSphere(targetPos, 0.1f);
// Gizmos.color = Color.yellow;
// Gizmos.DrawLine(firePos, targetPos);
// }
//}
}