Bullet.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. using Base.Common;
  2. using Sirenix.OdinInspector;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using UnityEngine.Events;
  7. public enum BulletType
  8. {
  9. Single = 0, //单体目标,触发后即销毁
  10. Penetrate = 1, //穿透,可击中多个目标
  11. Bomb = 2, //击中目标后爆炸
  12. Boomerang = 3, //回旋镖
  13. Throw = 4, //投掷类
  14. }
  15. public class Bullet : MonoBehaviour
  16. {
  17. public bool isBulletMove = true;
  18. [Header("组件")]
  19. public Character owner;
  20. public AttackController.AttackMethod attackMethod;
  21. public Rigidbody rb;
  22. public List<BeHitTrigger> trigedObjs;
  23. public BulletType bulletType;
  24. [ShowIf("@bulletType == BulletType.Throw")]
  25. public float stopTime;
  26. [ShowIf("@bulletType == BulletType.Boomerang")]
  27. [LabelText("回旋镖移动时间")] public float backDuration;
  28. [ShowIf("@bulletType == BulletType.Boomerang")]
  29. [LabelText("停留时间")] public float stopDuration;
  30. [ShowIf("@bulletType == BulletType.Boomerang")]
  31. [LabelText("坠落速度")] public float extraFallGravity;
  32. [ShowIf("@bulletType == BulletType.Boomerang")]
  33. [DisplayOnly] public BoomerangWeaponController BoomerangWeaponController;
  34. [ShowIf("@bulletType == BulletType.Boomerang")]
  35. public AttackTrigger attackTrigger;
  36. [ShowIf("@bulletType == BulletType.Boomerang")]
  37. public CameraController cameraController;
  38. [ShowIf("@bulletType == BulletType.Boomerang")]
  39. public Animator attackAni;
  40. private Vector3 originalPos;
  41. public bool isGetTarget = false;
  42. public float speed;
  43. public float maxFlyTime = 2f;
  44. public float flyTime;
  45. public Character trackTarget;
  46. [Header("击中特效")]
  47. public GameObject effect;
  48. private Vector3 effectPos;
  49. [Header("未击中,到时长后的消失特效")]
  50. public GameObject disappearEffect;
  51. [Header("传送门")]
  52. public bool canTransmit; //子弹是否能被传送门传送
  53. public bool haveTransmit; //刚传送过
  54. [HideInInspector]
  55. public float transmitTime; //传送CD
  56. private bool isInVain; //攻击无效
  57. public UnityAction OnBulletHit;
  58. [FoldoutGroup("条件")] [LabelText("是否留下箭种")] public bool canStop;
  59. [FoldoutGroup("条件")] [LabelText("子弹是否追踪")] [Tooltip("不勾选则水平往前射出")] public bool isTrack;
  60. [FoldoutGroup("条件")] [LabelText("子弹是否始终追踪")] [Tooltip("勾选:子弹会跟着目标转,不勾选:子弹斜着往前直飞")] public bool canAlwaysTrack;
  61. [FoldoutGroup("条件")] [LabelText("是否由士兵起手式创建")] public bool isCreatedByDemonicSummon = false;
  62. [FoldoutGroup("条件")] [LabelText("是否能穿过地面")] public bool canPassGround;
  63. public Vector3 originalScale;
  64. private Vector3 dir;
  65. private void Awake()
  66. {
  67. rb = GetComponent<Rigidbody>();
  68. originalScale = transform.localScale;
  69. }
  70. public virtual void Update()
  71. {
  72. if (haveTransmit)
  73. {
  74. transmitTime -= Time.deltaTime;
  75. if (transmitTime <= 0)
  76. {
  77. haveTransmit = false;
  78. }
  79. }
  80. }
  81. private void FixedUpdate()
  82. {
  83. if (!isBulletMove)
  84. {
  85. return;
  86. }
  87. if (bulletType == BulletType.Boomerang && BoomerangWeaponController.isFallDown)
  88. {
  89. Vector3 myPos = transform.position;
  90. if(myPos.y < 0)
  91. {
  92. myPos.y = 0;
  93. rb.useGravity = false;
  94. rb.velocity = Vector3.zero;
  95. transform.position = myPos;
  96. attackAni.gameObject.SetActive(false);
  97. attackTrigger.gameObject.SetActive(false);
  98. isInVain = true;
  99. }
  100. else
  101. {
  102. Vector3 velocity = rb.velocity;
  103. velocity.y += extraFallGravity * Time.deltaTime;
  104. if(velocity.x > 0.1f)
  105. {
  106. velocity.x += extraFallGravity * Time.deltaTime;
  107. }
  108. else if(velocity.x < -0.1f)
  109. {
  110. velocity.x -= extraFallGravity * Time.deltaTime;
  111. }
  112. else
  113. {
  114. velocity.x = 0;
  115. }
  116. if (transform.position.x <= cameraController.leftBoundary || transform.position.x >= cameraController.rightBoundary)
  117. {
  118. velocity.x = 0;
  119. }
  120. rb.velocity = velocity;
  121. }
  122. return;
  123. }
  124. flyTime += Time.deltaTime;
  125. if (flyTime >= maxFlyTime)
  126. {
  127. isGetTarget = true;
  128. DisappearEffect();
  129. gameObject.SetActive(false);
  130. return;
  131. }
  132. if (isTrack && trackTarget != null && !trackTarget.isDie && trackTarget.gameObject.activeInHierarchy)
  133. {
  134. if (bulletType == BulletType.Boomerang)
  135. {
  136. float addTime = backDuration + stopDuration;
  137. if (flyTime >= addTime)
  138. {
  139. if (attackTrigger.gameObject.activeSelf)
  140. {
  141. trigedObjs.Clear();
  142. attackTrigger.gameObject.SetActive(false);
  143. }
  144. transform.position = Vector3.Lerp(originalPos, BoomerangWeaponController.transform.position, (flyTime - addTime) /(maxFlyTime - addTime));
  145. }
  146. else if(flyTime >= backDuration)
  147. {
  148. rb.velocity = Vector3.zero;
  149. originalPos = transform.position;
  150. attackTrigger.gameObject.SetActive(true);
  151. }
  152. else
  153. {
  154. Vector3 velocity ;
  155. if(transform.position.y > 0.5f)
  156. {
  157. velocity = dir * speed * (1 - flyTime / backDuration);
  158. if(transform.position.x <= cameraController.leftBoundary || transform.position.x >= cameraController.rightBoundary)
  159. {
  160. velocity = Vector3.zero;
  161. }
  162. }
  163. else
  164. {
  165. velocity = Vector3.zero;
  166. }
  167. rb.velocity = velocity;
  168. }
  169. }
  170. if (canAlwaysTrack)
  171. {
  172. Vector3 tarDir = (trackTarget.beSearchTrigger.transform.position - transform.position).normalized;
  173. tarDir.z = 0;
  174. transform.right = Vector3.Lerp(transform.right, -tarDir, 0.2f);
  175. rb.velocity = Vector3.Lerp(rb.velocity, speed * tarDir, 0.2f);
  176. }
  177. }
  178. }
  179. public virtual void BeShoot(Character own, Vector3 shootPos = default, Vector3 dir = default, bool aim = false, bool alwaysTrack = false, Character target = null, AttackController.AttackMethod attackMethod = default)
  180. {
  181. transform.position = shootPos;
  182. transform.right = -dir;
  183. //假如有拖尾渲染器,初始化时清空拖尾效果
  184. TrailRenderer trailRenderer = GetComponentInChildren<TrailRenderer>();
  185. if (trailRenderer != null)
  186. {
  187. trailRenderer.Clear();
  188. }
  189. isTrack = aim;
  190. rb.velocity = dir * speed;
  191. this.dir = dir;
  192. trackTarget = target;
  193. owner = own;
  194. if (isTrack && trackTarget != null && !trackTarget.isDie && trackTarget.gameObject.activeInHierarchy)
  195. {
  196. Vector3 tarDir = (trackTarget.beSearchTrigger.transform.position - transform.position).normalized;
  197. tarDir.z = 0;
  198. transform.right = -tarDir;
  199. rb.velocity = speed * tarDir;
  200. }
  201. gameObject.SetActive(true);
  202. isGetTarget = false;
  203. canAlwaysTrack = alwaysTrack;
  204. flyTime = 0;
  205. if(EqualityComparer<AttackController.AttackMethod>.Default.Equals(attackMethod,default))
  206. {
  207. this.attackMethod = own.attackController.curAttackMethod;
  208. }
  209. else
  210. {
  211. this.attackMethod = attackMethod;
  212. }
  213. if (attackTrigger)
  214. {
  215. attackTrigger.owner = owner;
  216. attackTrigger.attackMethod = attackMethod;
  217. attackTrigger.gameObject.SetActive(false);
  218. }
  219. if (attackAni)
  220. {
  221. attackAni.gameObject.SetActive(true);
  222. }
  223. isInVain = false;
  224. }
  225. private void GetEffectPos(Collider other)
  226. {
  227. effectPos = other.bounds.ClosestPoint(transform.position);
  228. }
  229. private void OnTriggerEnter(Collider other)
  230. {
  231. if (isGetTarget || isInVain /*|| (bulletType == BulletType.Throw && rb.velocity.y > 0)*/)
  232. {
  233. return;
  234. }
  235. Platform platform = other.GetComponent<Platform>();
  236. if (platform != null && !platform.canPenetrateBullets)
  237. {
  238. if (bulletType == BulletType.Single || bulletType == BulletType.Throw)
  239. {
  240. DisappearEffect();
  241. gameObject.SetActive(false);
  242. return;
  243. }
  244. }
  245. if(!canPassGround && other.CompareTag("Ground"))
  246. {
  247. DisappearEffect();
  248. gameObject.SetActive(false);
  249. return;
  250. }
  251. BeHitTrigger hitTrigger = other.GetComponent<BeHitTrigger>();
  252. if (hitTrigger != null)
  253. {
  254. bool triged = false;
  255. for (int i = 0; i < trigedObjs.Count; i++)
  256. {
  257. if (trigedObjs[i] == hitTrigger)
  258. {
  259. triged = true;
  260. break;
  261. }
  262. }
  263. if (!triged)
  264. {
  265. trigedObjs.Add(hitTrigger);
  266. if (Util.CheckCanHit(owner.tag, hitTrigger.owner.tag) && !hitTrigger.owner.isDie)
  267. {
  268. if (isCreatedByDemonicSummon)
  269. {
  270. attackMethod.AddAdditionalEffects();
  271. //Debug.Log("飞剑起手式命中敌人");
  272. }
  273. hitTrigger.BeHit(attackMethod, owner);
  274. BeHitEffect(other, hitTrigger);
  275. switch (bulletType)
  276. {
  277. case BulletType.Single:
  278. case BulletType.Throw:
  279. isGetTarget = true;
  280. if (canStop && (hitTrigger.owner.CompareTag("Player") || hitTrigger.owner.CompareTag("Demonic")))
  281. {
  282. rb.velocity = Vector3.zero;
  283. rb.isKinematic = true;
  284. GetComponent<Collider>().enabled = false;
  285. transform.parent = hitTrigger.transform;
  286. BulletStop bs = GetComponent<BulletStop>();
  287. if (bs)
  288. {
  289. bs.enabled = true;
  290. }
  291. else
  292. {
  293. bs = gameObject.AddComponent<BulletStop>();
  294. }
  295. bs.SetDisappearTime(stopTime);
  296. enabled = false;
  297. }
  298. else
  299. {
  300. if (isBulletMove)
  301. gameObject.SetActive(false);
  302. else OnBulletHit?.Invoke();
  303. }
  304. break;
  305. case BulletType.Penetrate:
  306. break;
  307. case BulletType.Bomb:
  308. break;
  309. default:
  310. break;
  311. }
  312. }
  313. }
  314. }
  315. }
  316. protected void BeHitEffect(Collider other, BeHitTrigger bht)
  317. {
  318. if (effect)
  319. {
  320. GetEffectPos(other);
  321. PoolManager.Instantiate(effect, effectPos, new Quaternion(0, 0, 0, 0));
  322. }
  323. }
  324. private void DisappearEffect()
  325. {
  326. if (disappearEffect)
  327. {
  328. PoolManager.Instantiate(disappearEffect, transform.position, new Quaternion(0, 0, 0, 0));
  329. }
  330. }
  331. private void OnEnable()
  332. {
  333. trigedObjs.Clear();
  334. }
  335. }