Newer
Older
DungeonShooting / src / gun / Gun.cs
@小李xl 小李xl on 30 May 2022 8 KB 更改目录结构
  1. using Godot;
  2. using System;
  3.  
  4. /// <summary>
  5. /// 枪的基类
  6. /// </summary>
  7. public abstract class Gun : Node2D
  8. {
  9. /// <summary>
  10. /// 开火回调事件
  11. /// </summary>
  12. public event Action<Gun> FireEvent;
  13.  
  14. /// <summary>
  15. /// 属性数据
  16. /// </summary>
  17. public GunAttribute Attribute
  18. {
  19. get
  20. {
  21. if (_attribute == null)
  22. {
  23. throw new Exception("请先调用Init来初始化枪的属性");
  24. }
  25. return _attribute;
  26. }
  27. private set => _attribute = value;
  28. }
  29. private GunAttribute _attribute;
  30.  
  31. /// <summary>
  32. /// 枪的图片
  33. /// </summary>
  34. public Sprite GunSprite { get; private set; }
  35.  
  36. /// <summary>
  37. /// 枪攻击的目标阵营
  38. /// </summary>
  39. public CampEnum TargetCamp { get; set; }
  40. /// <summary>
  41. /// 枪管的开火点
  42. /// </summary>
  43. public Position2D FirePoint { get; private set; }
  44. /// <summary>
  45. /// 枪管的原点
  46. /// </summary>
  47. public Position2D OriginPoint { get; private set; }
  48. /// <summary>
  49. /// 枪的当前散射半径
  50. /// </summary>
  51. public float CurrScatteringRange { get; private set; } = 0;
  52.  
  53. //是否按下
  54. private bool triggerFlag = false;
  55. //扳机计时器
  56. private float triggerTimer = 0;
  57. //开火前延时时间
  58. private float delayedTime = 0;
  59. //开火间隙时间
  60. private float fireInterval = 0;
  61. //开火枪口角度
  62. private float fireAngle = 0;
  63. //攻击冷却计时
  64. private float attackTimer = 0;
  65. //攻击状态
  66. private bool attackFlag = false;
  67. //按下的时间
  68. private float downTimer = 0;
  69. //松开的时间
  70. private float upTimer = 0;
  71. //连发次数
  72. private float continuousCount = 0;
  73. private bool continuousShootFlag = false;
  74.  
  75. public override void _EnterTree()
  76. {
  77. GunSprite = GetNode<Sprite>("GunSprite");
  78. FirePoint = GetNode<Position2D>("FirePoint");
  79. OriginPoint = GetNode<Position2D>("OriginPoint");
  80. }
  81.  
  82. public override void _Process(float delta)
  83. {
  84. if (triggerFlag)
  85. {
  86. if (upTimer > 0) //第一帧按下扳机
  87. {
  88. upTimer = 0;
  89. DownTrigger();
  90. }
  91. downTimer += delta;
  92. }
  93. else
  94. {
  95. if (downTimer > 0) //第一帧松开扳机
  96. {
  97. downTimer = 0;
  98. UpTriggern();
  99. }
  100. upTimer += delta;
  101. }
  102.  
  103. // 攻击的计时器
  104. if (attackTimer > 0)
  105. {
  106. attackTimer -= delta;
  107. if (attackTimer < 0)
  108. {
  109. delayedTime += attackTimer;
  110. attackTimer = 0;
  111. }
  112. }
  113. else if (delayedTime > 0) //攻击延时
  114. {
  115. delayedTime -= delta;
  116. if (attackTimer < 0)
  117. {
  118. delayedTime = 0;
  119. }
  120. }
  121.  
  122. //连发判断
  123. if (continuousCount > 0 && delayedTime <= 0 && attackTimer <= 0)
  124. {
  125. TriggernFire();
  126. }
  127.  
  128. if (!attackFlag && attackTimer <= 0)
  129. {
  130. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
  131. }
  132. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  133. triggerFlag = false;
  134. attackFlag = false;
  135.  
  136. //枪身回归
  137. Position = Position.MoveToward(Vector2.Zero, 35 * delta);
  138. if (fireInterval == 0)
  139. {
  140. RotationDegrees = 0;
  141. }
  142. else
  143. {
  144. RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval);
  145. }
  146. }
  147.  
  148. public void Init(GunAttribute attribute)
  149. {
  150. if (_attribute != null)
  151. {
  152. throw new Exception("当前武器已经初始化过了!");
  153. }
  154.  
  155. Attribute = attribute;
  156. //更新图片
  157. var texture = ResourceLoader.Load<Texture>(attribute.Sprite);
  158. GunSprite.Texture = texture;
  159. //开火位置
  160. FirePoint.Position = new Vector2(attribute.FirePosition.x, -attribute.FirePosition.y);
  161. OriginPoint.Position = new Vector2(0, -attribute.FirePosition.y);
  162. //握把位置
  163. GunSprite.Position = attribute.HoldPosition;
  164.  
  165. Init();
  166. }
  167.  
  168. /// <summary>
  169. /// 扳机函数, 调用即视为扣动扳机
  170. /// </summary>
  171. public void Trigger()
  172. {
  173. //是否第一帧按下
  174. var justDown = downTimer == 0;
  175. //是否能发射
  176. var flag = false;
  177. if (continuousCount <= 0) //不能处于连发状态下
  178. {
  179. if (Attribute.ContinuousShoot) //自动射击
  180. {
  181. if (triggerTimer > 0)
  182. {
  183. if (continuousShootFlag)
  184. {
  185. flag = true;
  186. }
  187. }
  188. else
  189. {
  190. flag = true;
  191. if (delayedTime <= 0 && attackTimer <= 0)
  192. {
  193. continuousShootFlag = true;
  194. }
  195. }
  196. }
  197. else //半自动
  198. {
  199. if (justDown && triggerTimer <= 0)
  200. {
  201. flag = true;
  202. }
  203. }
  204. }
  205.  
  206. if (flag)
  207. {
  208. if (justDown)
  209. {
  210. //开火前延时
  211. delayedTime = Attribute.DelayedTime;
  212. //扳机按下间隔
  213. triggerTimer = Attribute.TriggerInterval;
  214. //连发数量
  215. if (!Attribute.ContinuousShoot)
  216. {
  217. continuousCount = MathUtils.RandRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount);
  218. }
  219. }
  220. if (delayedTime <= 0 && attackTimer <= 0)
  221. {
  222. TriggernFire();
  223. }
  224. attackFlag = true;
  225. }
  226. triggerFlag = true;
  227. }
  228.  
  229. /// <summary>
  230. /// 刚按下扳机
  231. /// </summary>
  232. private void DownTrigger()
  233. {
  234.  
  235. }
  236.  
  237. /// <summary>
  238. /// 刚松开扳机
  239. /// </summary>
  240. private void UpTriggern()
  241. {
  242. continuousShootFlag = false;
  243. if (delayedTime > 0)
  244. {
  245. continuousCount = 0;
  246. }
  247. }
  248.  
  249. /// <summary>
  250. /// 触发开火
  251. /// </summary>
  252. private void TriggernFire()
  253. {
  254. continuousCount = continuousCount > 0 ? continuousCount - 1 : 0;
  255. fireInterval = 60 / Attribute.StartFiringSpeed;
  256. attackTimer += fireInterval;
  257. //触发开火函数
  258. Fire();
  259. //开火发射的子弹数量
  260. var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount);
  261. //枪口角度
  262. var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();
  263.  
  264. //创建子弹
  265. for (int i = 0; i < bulletCount; i++)
  266. {
  267. //先算枪口方向
  268. Rotation = (float)GD.RandRange(-angle, angle);
  269. //发射子弹
  270. ShootBullet();
  271. }
  272.  
  273. //当前的散射半径
  274. CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange);
  275. //枪的旋转角度
  276. RotationDegrees -= Attribute.UpliftAngle;
  277. fireAngle = RotationDegrees;
  278. //枪身位置
  279. Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y);
  280.  
  281. if (FireEvent != null)
  282. {
  283. FireEvent(this);
  284. }
  285. }
  286.  
  287. /// <summary>
  288. /// 初始化时调用
  289. /// </summary>
  290. protected abstract void Init();
  291.  
  292. /// <summary>
  293. /// 单次开火时调用的函数
  294. /// </summary>
  295. protected abstract void Fire();
  296.  
  297. /// <summary>
  298. /// 发射子弹时调用的函数, 每发射一枚子弹调用一次,
  299. /// 如果做霰弹枪效果, 一次开火发射5枚子弹, 则该函数调用5次
  300. /// </summary>
  301. protected abstract void ShootBullet();
  302. }