Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / bullet / normal / Bullet.cs
@小李xl 小李xl on 29 Jan 2024 9 KB 制作0010武器完成
  1.  
  2. using System;
  3. using System.Collections;
  4. using Godot;
  5. using Godot.Collections;
  6.  
  7. /// <summary>
  8. /// 子弹类
  9. /// </summary>
  10. [Tool]
  11. public partial class Bullet : ActivityObject, IBullet
  12. {
  13. public event Action OnReclaimEvent;
  14. public event Action OnLeavePoolEvent;
  15. public bool IsRecycled { get; set; }
  16. public string Logotype { get; set; }
  17. /// <summary>
  18. /// 子弹伤害碰撞区域
  19. /// </summary>
  20. [Export, ExportFillNode]
  21. public Area2D CollisionArea { get; set; }
  22. /// <summary>
  23. /// 子弹伤害碰撞检测形状
  24. /// </summary>
  25. [Export, ExportFillNode]
  26. public CollisionShape2D CollisionShape2D { get; set; }
  27. /// <summary>
  28. /// 子节点包含的例子特效, 在创建完成后自动播放
  29. /// </summary>
  30. [Export]
  31. public Array<GpuParticles2D> Particles2D { get; set; }
  32.  
  33. /// <summary>
  34. /// 攻击的层级
  35. /// </summary>
  36. public uint AttackLayer
  37. {
  38. get => CollisionArea.CollisionMask;
  39. set => CollisionArea.CollisionMask = value;
  40. }
  41.  
  42. public BulletData BulletData { get; private set; }
  43. /// <summary>
  44. /// 当前反弹次数
  45. /// </summary>
  46. public int CurrentBounce { get; protected set; } = 0;
  47.  
  48. /// <summary>
  49. /// 当前穿透次数
  50. /// </summary>
  51. public int CurrentPenetration { get; protected set; } = 0;
  52. /// <summary>
  53. /// 是否是敌人使用的子弹
  54. /// </summary>
  55. public bool IsEnemyBullet { get; private set; } = false;
  56.  
  57. //当前子弹已经飞行的距离
  58. private float CurrFlyDistance = 0;
  59.  
  60. private bool _init = false;
  61.  
  62. public override void OnInit()
  63. {
  64. base.OnInit();
  65. OutlineColor = new Color(2.5f, 0, 0);
  66. SetBlendColor(new Color(2.0f, 2.0f, 2.0f));
  67. }
  68.  
  69. public virtual void InitData(BulletData data, uint attackLayer)
  70. {
  71. if (!_init)
  72. {
  73. CollisionArea.AreaEntered += OnArea2dEntered;
  74. _init = true;
  75. }
  76. CurrentBounce = 0;
  77. CurrentPenetration = 0;
  78. CurrFlyDistance = 0;
  79. BulletData = data;
  80. AttackLayer = attackLayer;
  81. Rotation = data.Rotation;
  82. var triggerRole = data.TriggerRole;
  83. if (data.TriggerRole != null && data.TriggerRole.AffiliationArea != null) //设置所属区域
  84. {
  85. if (triggerRole.AffiliationArea != null)
  86. {
  87. triggerRole.AffiliationArea.InsertItem(this);
  88. }
  89. }
  90. Position = data.Position + new Vector2(0, data.Altitude);
  91. Altitude = data.Altitude;
  92. if (data.VerticalSpeed != 0)
  93. {
  94. VerticalSpeed = data.VerticalSpeed;
  95. }
  96. else
  97. {
  98. VerticalSpeed = 0;
  99. }
  100.  
  101. //BasisVelocity = new Vector2(data.FlySpeed, 0).Rotated(Rotation);
  102. MoveController.AddForce(new Vector2(data.FlySpeed, 0).Rotated(Rotation));
  103. //如果子弹会对玩家造成伤害, 则显示红色描边
  104. if (Player.Current.CollisionWithMask(attackLayer))
  105. {
  106. if (!IsEnemyBullet)
  107. {
  108. IsEnemyBullet = true;
  109. OnRefreshBulletColor(IsEnemyBullet);
  110. }
  111. }
  112. else if (IsEnemyBullet)
  113. {
  114. IsEnemyBullet = false;
  115. OnRefreshBulletColor(IsEnemyBullet);
  116. }
  117. PutDown(RoomLayerEnum.YSortLayer);
  118. //播放子弹移动动画
  119. PlaySpriteAnimation(AnimatorNames.Move);
  120. //强制更新下坠逻辑处理
  121. UpdateFall((float)GetProcessDeltaTime());
  122.  
  123. //过期销毁
  124. if (data.LifeTime > 0)
  125. {
  126. this.CallDelay(data.LifeTime, OnLimeOver);
  127. }
  128. if (Particles2D != null)
  129. {
  130. foreach (var particles2D in Particles2D)
  131. {
  132. particles2D.Restart();
  133. }
  134. }
  135. }
  136.  
  137. /// <summary>
  138. /// 刷新子弹的颜色
  139. /// </summary>
  140. /// <param name="isEnemyBullet">是否是敌人使用的子弹</param>
  141. public virtual void OnRefreshBulletColor(bool isEnemyBullet)
  142. {
  143. if (isEnemyBullet)
  144. {
  145. ShowOutline = true;
  146. SetBlendSchedule(1);
  147. }
  148. else
  149. {
  150. ShowOutline = false;
  151. SetBlendSchedule(0);
  152. }
  153. }
  154. public override void OnMoveCollision(KinematicCollision2D collision)
  155. {
  156. CurrentBounce++;
  157. if (CurrentBounce > BulletData.BounceCount) //反弹次数超过限制
  158. {
  159. //创建粒子特效
  160. OnPlayCollisionEffect(collision);
  161. DoReclaim();
  162. }
  163. }
  164.  
  165. /// <summary>
  166. /// 碰到目标
  167. /// </summary>
  168. public virtual void OnCollisionTarget(ActivityObject o)
  169. {
  170. if (o is Role role)
  171. {
  172. OnPlayDisappearEffect();
  173.  
  174. //击退
  175. if (role is not Player) //目标不是玩家才会触发击退
  176. {
  177. if (BulletData.Repel != 0)
  178. {
  179. role.AddRepelForce(Velocity.Normalized() * BulletData.Repel);
  180. }
  181. }
  182. //造成伤害
  183. role.CallDeferred(nameof(Role.Hurt), BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole, BulletData.Harm, Rotation);
  184.  
  185. //穿透次数
  186. CurrentPenetration++;
  187. if (CurrentPenetration > BulletData.Penetration)
  188. {
  189. DoReclaim();
  190. }
  191. }
  192. }
  193.  
  194. /// <summary>
  195. /// 到达最大运行距离
  196. /// </summary>
  197. public virtual void OnMaxDistance()
  198. {
  199. OnPlayDisappearEffect();
  200. DoReclaim();
  201. }
  202. /// <summary>
  203. /// 子弹生命周期结束
  204. /// </summary>
  205. public virtual void OnLimeOver()
  206. {
  207. OnPlayDisappearEffect();
  208. DoReclaim();
  209. }
  210. protected override void OnFallToGround()
  211. {
  212. //落地销毁
  213. OnPlayDisappearEffect();
  214. DoReclaim();
  215. }
  216. /// <summary>
  217. /// 显示红色描边
  218. /// </summary>
  219. public void ShowBorderFlashes()
  220. {
  221. ShowOutline = true;
  222. OutlineColor = new Color(1, 0, 0);
  223. StartCoroutine(BorderFlashes());
  224. }
  225. private IEnumerator BorderFlashes()
  226. {
  227. while (true)
  228. {
  229. ShowOutline = !ShowOutline;
  230. yield return new WaitForSeconds(0.12f);
  231. }
  232. }
  233.  
  234. /// <summary>
  235. /// 播放子弹消失的特效
  236. /// </summary>
  237. public virtual void OnPlayDisappearEffect()
  238. {
  239. PlayDisappearEffect(ResourcePath.prefab_effect_bullet_BulletDisappear0001_tscn);
  240. }
  241.  
  242. /// <summary>
  243. /// 播放撞墙特效
  244. /// </summary>
  245. public virtual void OnPlayCollisionEffect(KinematicCollision2D collision)
  246. {
  247. PlayCollisionEffect(collision, ResourcePath.prefab_effect_bullet_BulletSmoke0001_tscn);
  248. }
  249.  
  250. /// <summary>
  251. /// 播放子弹消失特效
  252. /// </summary>
  253. public void PlayDisappearEffect(string path)
  254. {
  255. var effect = ObjectManager.GetPoolItem<IEffect>(path);
  256. var node = (Node2D)effect;
  257. node.GlobalPosition = AnimatedSprite.GlobalPosition;
  258. node.AddToActivityRoot(RoomLayerEnum.YSortLayer);
  259. effect.PlayEffect();
  260. }
  261. /// <summary>
  262. /// 播放子弹撞墙消失特效
  263. /// </summary>
  264. public void PlayCollisionEffect(KinematicCollision2D collision, string path)
  265. {
  266. var effect = ObjectManager.GetPoolItem<IEffect>(path);
  267. var smoke = (Node2D)effect;
  268. var rotated = AnimatedSprite.Position.Rotated(Rotation);
  269. smoke.GlobalPosition = collision.GetPosition() + new Vector2(0, rotated.Y);
  270. smoke.GlobalRotation = collision.GetNormal().Angle();
  271. smoke.AddToActivityRoot(RoomLayerEnum.YSortLayer);
  272. effect.PlayEffect();
  273. }
  274. protected override void Process(float delta)
  275. {
  276. if (ActivityMaterial.DynamicCollision)
  277. {
  278. //子弹高度大于 16 关闭碰撞检测
  279. CollisionShape2D.Disabled = Altitude >= 16;
  280. }
  281. //距离太大, 自动销毁
  282. CurrFlyDistance += BulletData.FlySpeed * delta;
  283. if (CurrFlyDistance >= BulletData.MaxDistance)
  284. {
  285. OnMaxDistance();
  286. }
  287. }
  288. private void OnArea2dEntered(Area2D other)
  289. {
  290. if (IsDestroyed)
  291. {
  292. return;
  293. }
  294. var activityObject = other.AsActivityObject();
  295. OnCollisionTarget(activityObject);
  296. }
  297. public virtual void DoReclaim()
  298. {
  299. ObjectPool.Reclaim(this);
  300. }
  301. public virtual void OnReclaim()
  302. {
  303. Visible = false;
  304. if (Particles2D != null)
  305. {
  306. foreach (var particles2D in Particles2D)
  307. {
  308. particles2D.Emitting = false;
  309. }
  310. }
  311. if (OnReclaimEvent != null)
  312. {
  313. OnReclaimEvent();
  314. }
  315. if (AffiliationArea != null)
  316. {
  317. AffiliationArea.RemoveItem(this);
  318. }
  319. GetParent().CallDeferred(Node.MethodName.RemoveChild, this);
  320. }
  321.  
  322. public virtual void OnLeavePool()
  323. {
  324. Visible = true;
  325. MoveController.ClearForce();
  326. StopAllCoroutine();
  327. if (OnLeavePoolEvent != null)
  328. {
  329. OnLeavePoolEvent();
  330. }
  331. }
  332. }