Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / bullet / laser / Laser.cs
@小李xl 小李xl on 21 Nov 2023 5 KB 添加击退函数
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using Godot;
  5.  
  6. /// <summary>
  7. /// 激光子弹
  8. /// </summary>
  9. public partial class Laser : Area2D, IBullet
  10. {
  11. public CollisionShape2D Collision { get; private set; }
  12. public Sprite2D LineSprite { get; private set; }
  13. public RectangleShape2D Shape { get; private set; }
  14.  
  15. public event Action OnReclaimEvent;
  16. public event Action OnLeavePoolEvent;
  17. public bool IsRecycled { get; set; }
  18. public string Logotype { get; set; }
  19.  
  20. public uint AttackLayer
  21. {
  22. get => CollisionMask;
  23. set => CollisionMask = value;
  24. }
  25.  
  26. public BulletData BulletData { get; private set; }
  27.  
  28. public bool IsDestroyed { get; private set; }
  29. public float Width { get; set; }
  30. //开启的协程
  31. private List<CoroutineData> _coroutineList;
  32. private float _pixelScale;
  33. private float _speed = 2000;
  34. private Tween _tween;
  35. private bool _init = false;
  36.  
  37. public void InitData(BulletData data, uint attackLayer)
  38. {
  39. InitData(data, attackLayer, 5);
  40. }
  41. public void InitData(BulletData data, uint attackLayer, float width)
  42. {
  43. if (!_init)
  44. {
  45. Collision = GetNodeOrNull<CollisionShape2D>("CollisionShape2D");
  46. Collision.Disabled = true;
  47. Shape = (RectangleShape2D)Collision.Shape;
  48. LineSprite = GetNodeOrNull<Sprite2D>("LineSprite");
  49. _pixelScale = 1f / LineSprite.Texture.GetHeight();
  50.  
  51. AreaEntered += OnArea2dEntered;
  52. _init = true;
  53. }
  54. BulletData = data;
  55. AttackLayer = attackLayer;
  56. Position = data.Position;
  57. Rotation = data.Rotation;
  58.  
  59. //计算射线最大距离, 也就是撞到墙壁的距离
  60. var targetPosition = data.Position + Vector2.FromAngle(data.Rotation) * data.MaxDistance;
  61. var parameters = PhysicsRayQueryParameters2D.Create(data.Position, targetPosition, PhysicsLayer.Wall);
  62. var result = GetWorld2D().DirectSpaceState.IntersectRay(parameters);
  63. float distance;
  64. if (result != null && result.TryGetValue("position", out var point))
  65. {
  66. distance = Position.DistanceTo((Vector2)point);
  67. }
  68. else
  69. {
  70. distance = data.MaxDistance;
  71. }
  72. Collision.SetDeferred(CollisionShape2D.PropertyName.Disabled, false);
  73. Collision.Position = Vector2.Zero;
  74. Shape.Size = Vector2.Zero;
  75. LineSprite.Scale = new Vector2(0, width * _pixelScale);
  76.  
  77. //如果子弹会对玩家造成伤害, 则显示成红色
  78. if (Player.Current.CollisionWithMask(attackLayer))
  79. {
  80. LineSprite.Modulate = new Color(2.5f, 0.5f, 0.5f);
  81. }
  82. else
  83. {
  84. LineSprite.Modulate = new Color(1.5f, 1.5f, 1.5f);
  85. }
  86. //激光飞行时间
  87. var time = distance / _speed;
  88.  
  89. _tween = CreateTween();
  90. _tween.SetParallel();
  91. _tween.TweenProperty(LineSprite, "scale", new Vector2(distance, width * _pixelScale), time);
  92. _tween.TweenProperty(Collision, "position", new Vector2(distance * 0.5f, 0), time);
  93. _tween.TweenProperty(Shape, "size", new Vector2(distance, width), time);
  94. _tween.Chain();
  95. //持续时间
  96. // tween.TweenInterval(0.2f);
  97. // tween.Chain();
  98. _tween.TweenCallback(Callable.From(() =>
  99. {
  100. Collision.SetDeferred(CollisionShape2D.PropertyName.Disabled, false);
  101. }));
  102. _tween.Chain();
  103. _tween.TweenProperty(LineSprite, "scale", new Vector2(distance, 0), 0.3f);
  104. _tween.Chain();
  105. _tween.TweenCallback(Callable.From(() =>
  106. {
  107. _tween = null;
  108. DoReclaim();
  109. }));
  110. _tween.Play();
  111. }
  112.  
  113. public override void _Process(double delta)
  114. {
  115. ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, (float)delta);
  116. }
  117.  
  118. public void Destroy()
  119. {
  120. if (IsDestroyed)
  121. {
  122. return;
  123. }
  124. QueueFree();
  125. }
  126. private void OnArea2dEntered(Area2D other)
  127. {
  128. var role = other.AsActivityObject<Role>();
  129. if (role != null)
  130. {
  131. //击退
  132. if (BulletData.Repel != 0)
  133. {
  134. role.AddRepelForce(Vector2.FromAngle(Rotation) * BulletData.Repel);
  135. }
  136. //造成伤害
  137. role.CallDeferred(nameof(Role.Hurt), BulletData.TriggerRole.IsDestroyed ? null : BulletData.TriggerRole, BulletData.Harm, Rotation);
  138. }
  139. }
  140.  
  141. public long StartCoroutine(IEnumerator able)
  142. {
  143. return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able);
  144. }
  145.  
  146. public void StopCoroutine(long coroutineId)
  147. {
  148. ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId);
  149. }
  150.  
  151. public bool IsCoroutineOver(long coroutineId)
  152. {
  153. return ProxyCoroutineHandler.ProxyIsCoroutineOver(ref _coroutineList, coroutineId);
  154. }
  155.  
  156. public void StopAllCoroutine()
  157. {
  158. ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList);
  159. }
  160. public void DoReclaim()
  161. {
  162. ObjectPool.Reclaim(this);
  163. }
  164. public virtual void OnReclaim()
  165. {
  166. if (OnReclaimEvent != null)
  167. {
  168. OnReclaimEvent();
  169. }
  170.  
  171. if (_tween != null)
  172. {
  173. _tween.Dispose();
  174. _tween = null;
  175. }
  176. GetParent().CallDeferred(Node.MethodName.RemoveChild, this);
  177. }
  178.  
  179. public virtual void OnLeavePool()
  180. {
  181. StopAllCoroutine();
  182. if (OnLeavePoolEvent != null)
  183. {
  184. OnLeavePoolEvent();
  185. }
  186. }
  187. }