Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / bullet / normal / Bullet.cs
@小李xl 小李xl on 21 Nov 2023 7 KB 添加击退函数
  1.  
  2. using System;
  3. using System.Collections;
  4. using Godot;
  5.  
  6. /// <summary>
  7. /// 子弹类
  8. /// </summary>
  9. [Tool]
  10. public partial class Bullet : ActivityObject, IBullet
  11. {
  12. public event Action OnReclaimEvent;
  13. public event Action OnLeavePoolEvent;
  14. public bool IsRecycled { get; set; }
  15. public string Logotype { get; set; }
  16. /// <summary>
  17. /// 子弹伤害碰撞区域
  18. /// </summary>
  19. [Export, ExportFillNode]
  20. public Area2D CollisionArea { get; set; }
  21. /// <summary>
  22. /// 子弹伤害碰撞检测形状
  23. /// </summary>
  24. [Export, ExportFillNode]
  25. public CollisionShape2D CollisionShape2D { get; set; }
  26.  
  27. /// <summary>
  28. /// 攻击的层级
  29. /// </summary>
  30. public uint AttackLayer
  31. {
  32. get => CollisionArea.CollisionMask;
  33. set => CollisionArea.CollisionMask = value;
  34. }
  35.  
  36. public BulletData BulletData { get; private set; }
  37. /// <summary>
  38. /// 当前反弹次数
  39. /// </summary>
  40. public int CurrentBounce { get; protected set; } = 0;
  41.  
  42. /// <summary>
  43. /// 当前穿透次数
  44. /// </summary>
  45. public int CurrentPenetration { get; protected set; } = 0;
  46. //当前子弹已经飞行的距离
  47. private float CurrFlyDistance = 0;
  48.  
  49. private bool _init = false;
  50. public virtual void InitData(BulletData data, uint attackLayer)
  51. {
  52. if (!_init)
  53. {
  54. CollisionArea.AreaEntered += OnArea2dEntered;
  55. _init = true;
  56. }
  57. CurrentBounce = 0;
  58. CurrentPenetration = 0;
  59. CurrFlyDistance = 0;
  60. BulletData = data;
  61. AttackLayer = attackLayer;
  62. Rotation = data.Rotation;
  63. var triggerRole = data.TriggerRole;
  64. if (data.TriggerRole != null && data.TriggerRole.AffiliationArea != null) //设置所属区域
  65. {
  66. if (triggerRole.AffiliationArea != null)
  67. {
  68. triggerRole.AffiliationArea.InsertItem(this);
  69. }
  70. }
  71. Position = data.Position + new Vector2(0, data.Altitude);
  72. Altitude = data.Altitude;
  73. if (data.VerticalSpeed != 0)
  74. {
  75. VerticalSpeed = data.VerticalSpeed;
  76. }
  77. else
  78. {
  79. VerticalSpeed = 0;
  80. }
  81.  
  82. //BasisVelocity = new Vector2(data.FlySpeed, 0).Rotated(Rotation);
  83. MoveController.AddForce(new Vector2(data.FlySpeed, 0).Rotated(Rotation));
  84. //如果子弹会对玩家造成伤害, 则显示红色描边
  85. if (Player.Current.CollisionWithMask(attackLayer))
  86. {
  87. ShowBorderFlashes();
  88. }
  89. PutDown(RoomLayerEnum.YSortLayer);
  90. //播放子弹移动动画
  91. PlaySpriteAnimation(AnimatorNames.Move);
  92. //强制更新下坠逻辑处理
  93. UpdateFall((float)GetProcessDeltaTime());
  94.  
  95. //过期销毁
  96. if (data.LifeTime > 0)
  97. {
  98. this.CallDelay(data.LifeTime, OnLimeOver);
  99. }
  100. }
  101.  
  102. public override void OnMoveCollision(KinematicCollision2D collision)
  103. {
  104. CurrentBounce++;
  105. if (CurrentBounce > BulletData.BounceCount) //反弹次数超过限制
  106. {
  107. //创建粒子特效
  108. var effect = ObjectManager.GetPoolItem<IEffect>(ResourcePath.prefab_effect_weapon_BulletSmoke_tscn);
  109. var smoke = (Node2D)effect;
  110. var rotated = AnimatedSprite.Position.Rotated(Rotation);
  111. smoke.GlobalPosition = collision.GetPosition() + new Vector2(0, rotated.Y);
  112. smoke.GlobalRotation = collision.GetNormal().Angle();
  113. smoke.AddToActivityRoot(RoomLayerEnum.YSortLayer);
  114. effect.PlayEffect();
  115. DoReclaim();
  116. }
  117. }
  118.  
  119. /// <summary>
  120. /// 碰到目标
  121. /// </summary>
  122. public virtual void OnCollisionTarget(ActivityObject o)
  123. {
  124. if (o is Role role)
  125. {
  126. PlayDisappearEffect();
  127.  
  128. //击退
  129. if (role is not Player) //目标不是玩家才会触发击退
  130. {
  131. if (BulletData.Repel != 0)
  132. {
  133. role.AddRepelForce(Velocity.Normalized() * BulletData.Repel);
  134. }
  135. }
  136. //造成伤害
  137. role.CallDeferred(nameof(Role.Hurt), BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole, BulletData.Harm, Rotation);
  138.  
  139. //穿透次数
  140. CurrentPenetration++;
  141. if (CurrentPenetration > BulletData.Penetration)
  142. {
  143. DoReclaim();
  144. }
  145. }
  146. }
  147.  
  148. /// <summary>
  149. /// 到达最大运行距离
  150. /// </summary>
  151. public virtual void OnMaxDistance()
  152. {
  153. PlayDisappearEffect();
  154. DoReclaim();
  155. }
  156. /// <summary>
  157. /// 子弹生命周期结束
  158. /// </summary>
  159. public virtual void OnLimeOver()
  160. {
  161. PlayDisappearEffect();
  162. DoReclaim();
  163. }
  164. protected override void OnFallToGround()
  165. {
  166. //落地销毁
  167. PlayDisappearEffect();
  168. DoReclaim();
  169. }
  170. /// <summary>
  171. /// 显示红色描边
  172. /// </summary>
  173. public void ShowBorderFlashes()
  174. {
  175. ShowOutline = true;
  176. OutlineColor = new Color(1, 0, 0);
  177. StartCoroutine(BorderFlashes());
  178. }
  179. private IEnumerator BorderFlashes()
  180. {
  181. while (true)
  182. {
  183. ShowOutline = !ShowOutline;
  184. yield return new WaitForSeconds(0.12f);
  185. }
  186. }
  187.  
  188. /// <summary>
  189. /// 播放子弹消失的特效
  190. /// </summary>
  191. public virtual void PlayDisappearEffect()
  192. {
  193. var effect = ObjectManager.GetPoolItem<IEffect>(ResourcePath.prefab_effect_weapon_BulletDisappear_tscn);
  194. var node = (Node2D)effect;
  195. node.GlobalPosition = AnimatedSprite.GlobalPosition;
  196. node.AddToActivityRoot(RoomLayerEnum.YSortLayer);
  197. effect.PlayEffect();
  198. }
  199. protected override void Process(float delta)
  200. {
  201. if (ActivityMaterial.DynamicCollision)
  202. {
  203. //子弹高度大于 16 关闭碰撞检测
  204. CollisionShape2D.Disabled = Altitude >= 16;
  205. }
  206. //距离太大, 自动销毁
  207. CurrFlyDistance += BulletData.FlySpeed * delta;
  208. if (CurrFlyDistance >= BulletData.MaxDistance)
  209. {
  210. OnMaxDistance();
  211. }
  212. }
  213. private void OnArea2dEntered(Area2D other)
  214. {
  215. if (IsDestroyed)
  216. {
  217. return;
  218. }
  219. var activityObject = other.AsActivityObject();
  220. OnCollisionTarget(activityObject);
  221. }
  222. public virtual void DoReclaim()
  223. {
  224. ObjectPool.Reclaim(this);
  225. }
  226. public virtual void OnReclaim()
  227. {
  228. if (OnReclaimEvent != null)
  229. {
  230. OnReclaimEvent();
  231. }
  232. if (AffiliationArea != null)
  233. {
  234. AffiliationArea.RemoveItem(this);
  235. }
  236. ShowOutline = false;
  237. GetParent().CallDeferred(Node.MethodName.RemoveChild, this);
  238. }
  239.  
  240. public virtual void OnLeavePool()
  241. {
  242. MoveController.ClearForce();
  243. StopAllCoroutine();
  244. if (OnLeavePoolEvent != null)
  245. {
  246. OnLeavePoolEvent();
  247. }
  248. }
  249. }