Newer
Older
DungeonShooting / DungeonShooting_Godot / src / weapon / gun / Gun.cs
  1. using Godot;
  2. using System;
  3.  
  4. /// <summary>
  5. /// 枪的基类
  6. /// </summary>
  7. public abstract class Gun : Area2D, IProp
  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. /// <value></value>
  40. public AnimationPlayer AnimationPlayer { get; private set; }
  41.  
  42. /// <summary>
  43. /// 枪攻击的目标阵营
  44. /// </summary>
  45. public CampEnum TargetCamp { get; set; }
  46.  
  47. /// <summary>
  48. /// 该武器的拥有者
  49. /// </summary>
  50. public Role Master { get; private set; }
  51.  
  52. /// <summary>
  53. /// 当前弹夹弹药剩余量
  54. /// </summary>
  55. public int CurrAmmo { get; private set; }
  56. /// <summary>
  57. /// 剩余弹药量
  58. /// </summary>
  59. public int ResidueAmmo { get; private set; }
  60.  
  61. /// <summary>
  62. /// 枪管的开火点
  63. /// </summary>
  64. public Position2D FirePoint { get; private set; }
  65. /// <summary>
  66. /// 枪管的原点
  67. /// </summary>
  68. public Position2D OriginPoint { get; private set; }
  69. /// <summary>
  70. /// 弹壳抛出的点
  71. /// </summary>
  72. public Position2D ShellPoint { get; private set; }
  73. /// <summary>
  74. /// 碰撞器节点
  75. /// </summary>
  76. /// <value></value>
  77. public CollisionShape2D CollisionShape2D { get; private set; }
  78. /// <summary>
  79. /// 枪的当前散射半径
  80. /// </summary>
  81. public float CurrScatteringRange { get; private set; } = 0;
  82. /// <summary>
  83. /// 是否在换弹中
  84. /// </summary>
  85. /// <value></value>
  86. public bool Reloading { get; private set; } = false;
  87. /// <summary>
  88. /// 换弹计时器
  89. /// </summary>
  90. public float ReloadTimer { get; private set; } = 0;
  91.  
  92. //是否按下
  93. private bool triggerFlag = false;
  94. //扳机计时器
  95. private float triggerTimer = 0;
  96. //开火前延时时间
  97. private float delayedTime = 0;
  98. //开火间隙时间
  99. private float fireInterval = 0;
  100. //开火枪口角度
  101. private float fireAngle = 0;
  102. //攻击冷却计时
  103. private float attackTimer = 0;
  104. //攻击状态
  105. private bool attackFlag = false;
  106. //按下的时间
  107. private float downTimer = 0;
  108. //松开的时间
  109. private float upTimer = 0;
  110. //连发次数
  111. private float continuousCount = 0;
  112. //连发状态记录
  113. private bool continuousShootFlag = false;
  114.  
  115. /// <summary>
  116. /// 初始化时调用
  117. /// </summary>
  118. protected abstract void Init();
  119.  
  120. /// <summary>
  121. /// 单次开火时调用的函数
  122. /// </summary>
  123. protected abstract void OnFire();
  124.  
  125. /// <summary>
  126. /// 换弹时调用
  127. /// </summary>
  128. protected abstract void OnReload();
  129.  
  130. /// <summary>
  131. /// 发射子弹时调用的函数, 每发射一枚子弹调用一次,
  132. /// 如果做霰弹枪效果, 一次开火发射5枚子弹, 则该函数调用5次
  133. /// </summary>
  134. protected abstract void OnShootBullet();
  135.  
  136. /// <summary>
  137. /// 当武器被拾起时调用
  138. /// </summary>
  139. /// <param name="master">拾起该武器的角色</param>
  140. protected abstract void OnPickUp(Role master);
  141.  
  142. /// <summary>
  143. /// 当武器被扔掉时调用
  144. /// </summary>
  145. protected abstract void OnThrowOut();
  146.  
  147. /// <summary>
  148. /// 当武器被激活时调用, 也就是使用当武器是调用
  149. /// </summary>
  150. protected abstract void OnActive();
  151.  
  152. /// <summary>
  153. /// 当武器被收起时调用
  154. /// </summary>
  155. protected abstract void OnConceal();
  156.  
  157. public override void _Process(float delta)
  158. {
  159. if (Master == null) //这把武器被扔在地上
  160. {
  161. Reloading = false;
  162. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  163. triggerFlag = false;
  164. attackFlag = false;
  165. attackTimer = attackTimer > 0 ? attackTimer - delta : 0;
  166. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
  167. continuousCount = 0;
  168. delayedTime = 0;
  169. }
  170. else if (Master.Holster.ActiveGun != this) //当前武器没有被使用
  171. {
  172. Reloading = false;
  173. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  174. triggerFlag = false;
  175. attackFlag = false;
  176. attackTimer = attackTimer > 0 ? attackTimer - delta : 0;
  177. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
  178. continuousCount = 0;
  179. delayedTime = 0;
  180. }
  181. else //正在使用中
  182. {
  183.  
  184. //换弹
  185. if (Reloading)
  186. {
  187. ReloadTimer -= delta;
  188. if (ReloadTimer <= 0)
  189. {
  190. ReloadTimer = 0;
  191. ReloadSuccess();
  192. }
  193. }
  194.  
  195. if (triggerFlag)
  196. {
  197. if (upTimer > 0) //第一帧按下扳机
  198. {
  199. upTimer = 0;
  200. DownTrigger();
  201. }
  202. downTimer += delta;
  203. }
  204. else
  205. {
  206. if (downTimer > 0) //第一帧松开扳机
  207. {
  208. downTimer = 0;
  209. UpTriggern();
  210. }
  211. upTimer += delta;
  212. }
  213.  
  214. // 攻击的计时器
  215. if (attackTimer > 0)
  216. {
  217. attackTimer -= delta;
  218. if (attackTimer < 0)
  219. {
  220. delayedTime += attackTimer;
  221. attackTimer = 0;
  222. }
  223. }
  224. else if (delayedTime > 0) //攻击延时
  225. {
  226. delayedTime -= delta;
  227. if (attackTimer < 0)
  228. {
  229. delayedTime = 0;
  230. }
  231. }
  232.  
  233. //连发判断
  234. if (continuousCount > 0 && delayedTime <= 0 && attackTimer <= 0)
  235. {
  236. //开火
  237. TriggernFire();
  238. }
  239.  
  240. if (!attackFlag && attackTimer <= 0)
  241. {
  242. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
  243. }
  244. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  245. triggerFlag = false;
  246. attackFlag = false;
  247.  
  248. //枪身回归
  249. Position = Position.MoveToward(Vector2.Zero, 35 * delta);
  250. if (fireInterval == 0)
  251. {
  252. RotationDegrees = 0;
  253. }
  254. else
  255. {
  256. RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval);
  257. }
  258. }
  259. }
  260.  
  261. public void Init(GunAttribute attribute)
  262. {
  263. if (_attribute != null)
  264. {
  265. throw new Exception("当前武器已经初始化过了!");
  266. }
  267.  
  268. GunSprite = GetNode<Sprite>("GunSprite");
  269. FirePoint = GetNode<Position2D>("FirePoint");
  270. OriginPoint = GetNode<Position2D>("OriginPoint");
  271. ShellPoint = GetNode<Position2D>("ShellPoint");
  272. AnimationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
  273. CollisionShape2D = GetNode<CollisionShape2D>("Collision");
  274.  
  275. Attribute = attribute;
  276. //更新图片
  277. GunSprite.Texture = attribute.Sprite;
  278. GunSprite.Position = Attribute.CenterPosition;
  279. //开火位置
  280. FirePoint.Position = new Vector2(attribute.FirePosition.x, -attribute.FirePosition.y);
  281. OriginPoint.Position = new Vector2(0, -attribute.FirePosition.y);
  282.  
  283. //弹药量
  284. CurrAmmo = attribute.CartridgeCapacity;
  285. //剩余弹药量
  286. ResidueAmmo = attribute.MaxCartridgeCapacity - attribute.CartridgeCapacity;
  287.  
  288. Init();
  289. }
  290.  
  291. /// <summary>
  292. /// 扳机函数, 调用即视为扣动扳机
  293. /// </summary>
  294. public void Trigger()
  295. {
  296. //是否第一帧按下
  297. var justDown = downTimer == 0;
  298. //是否能发射
  299. var flag = false;
  300. if (continuousCount <= 0) //不能处于连发状态下
  301. {
  302. if (Attribute.ContinuousShoot) //自动射击
  303. {
  304. if (triggerTimer > 0)
  305. {
  306. if (continuousShootFlag)
  307. {
  308. flag = true;
  309. }
  310. }
  311. else
  312. {
  313. flag = true;
  314. if (delayedTime <= 0 && attackTimer <= 0)
  315. {
  316. continuousShootFlag = true;
  317. }
  318. }
  319. }
  320. else //半自动
  321. {
  322. if (justDown && triggerTimer <= 0)
  323. {
  324. flag = true;
  325. }
  326. }
  327. }
  328.  
  329. if (flag)
  330. {
  331. if (Reloading)
  332. {
  333. //换弹中
  334. GD.Print("换弹中..." + (ReloadTimer / Attribute.ReloadTime));
  335. }
  336. else if (CurrAmmo <= 0)
  337. {
  338. //子弹不够
  339. GD.Print("弹夹打空了, 按R换弹!");
  340. }
  341. else
  342. {
  343. if (justDown)
  344. {
  345. //开火前延时
  346. delayedTime = Attribute.DelayedTime;
  347. //扳机按下间隔
  348. triggerTimer = Attribute.TriggerInterval;
  349. //连发数量
  350. if (!Attribute.ContinuousShoot)
  351. {
  352. continuousCount = MathUtils.RandRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount);
  353. }
  354. }
  355. if (delayedTime <= 0 && attackTimer <= 0)
  356. {
  357. TriggernFire();
  358. }
  359. attackFlag = true;
  360. }
  361.  
  362. }
  363. triggerFlag = true;
  364. }
  365.  
  366. /// <summary>
  367. /// 刚按下扳机
  368. /// </summary>
  369. private void DownTrigger()
  370. {
  371.  
  372. }
  373.  
  374. /// <summary>
  375. /// 刚松开扳机
  376. /// </summary>
  377. private void UpTriggern()
  378. {
  379. continuousShootFlag = false;
  380. if (delayedTime > 0)
  381. {
  382. continuousCount = 0;
  383. }
  384. }
  385.  
  386. /// <summary>
  387. /// 触发开火
  388. /// </summary>
  389. private void TriggernFire()
  390. {
  391. continuousCount = continuousCount > 0 ? continuousCount - 1 : 0;
  392.  
  393. //减子弹数量
  394. CurrAmmo--;
  395. //开火间隙
  396. fireInterval = 60 / Attribute.StartFiringSpeed;
  397. //攻击冷却
  398. attackTimer += fireInterval;
  399.  
  400. //触发开火函数
  401. OnFire();
  402.  
  403. //开火发射的子弹数量
  404. var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount);
  405. //枪口角度
  406. var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();
  407.  
  408. //创建子弹
  409. for (int i = 0; i < bulletCount; i++)
  410. {
  411. //先算枪口方向
  412. Rotation = (float)GD.RandRange(-angle, angle);
  413. //发射子弹
  414. OnShootBullet();
  415. }
  416.  
  417. //当前的散射半径
  418. CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange);
  419. //枪的旋转角度
  420. RotationDegrees -= Attribute.UpliftAngle;
  421. fireAngle = RotationDegrees;
  422. //枪身位置
  423. Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y);
  424.  
  425. if (FireEvent != null)
  426. {
  427. FireEvent(this);
  428. }
  429. }
  430.  
  431. /// <summary>
  432. /// 触发换弹
  433. /// </summary>
  434. public void _Reload()
  435. {
  436. if (CurrAmmo < Attribute.CartridgeCapacity && ResidueAmmo > 0 && !Reloading)
  437. {
  438. Reloading = true;
  439. ReloadTimer = Attribute.ReloadTime;
  440. OnReload();
  441. }
  442. }
  443.  
  444. /// <summary>
  445. /// 换弹计时器时间到, 执行换弹操作
  446. /// </summary>
  447. private void ReloadSuccess()
  448. {
  449. if (Attribute.AloneReload) //单独装填
  450. {
  451.  
  452. }
  453. else //换弹结束
  454. {
  455. Reloading = false;
  456. if (ResidueAmmo >= Attribute.CartridgeCapacity)
  457. {
  458. ResidueAmmo -= Attribute.CartridgeCapacity;
  459. CurrAmmo = Attribute.CartridgeCapacity;
  460. }
  461. else
  462. {
  463. CurrAmmo = ResidueAmmo;
  464. ResidueAmmo = 0;
  465. }
  466. }
  467. }
  468.  
  469. public void Tnteractive(Role master)
  470. {
  471. var parent = GetParent();
  472. parent.RemoveChild(this);
  473. master.Holster.PickupGun(this);
  474. parent.QueueFree();
  475. }
  476.  
  477. /// <summary>
  478. /// 触发落到地面
  479. /// </summary>
  480. public void _FallToGround()
  481. {
  482. //启用碰撞
  483. CollisionShape2D.Disabled = false;
  484. }
  485.  
  486. /// <summary>
  487. /// 触发拾起
  488. /// </summary>
  489. public void _PickUpGun(Role master)
  490. {
  491. Master = master;
  492. //握把位置
  493. GunSprite.Position = Attribute.HoldPosition;
  494. AnimationPlayer.Play("RESET");
  495. ZIndex = 0;
  496. //禁用碰撞
  497. CollisionShape2D.Disabled = true;
  498. OnPickUp(master);
  499. }
  500.  
  501. /// <summary>
  502. /// 触发抛出
  503. /// </summary>
  504. public void _ThrowOutGun()
  505. {
  506. Master = null;
  507. GunSprite.Position = Attribute.CenterPosition;
  508. AnimationPlayer.Play("Floodlight");
  509. OnThrowOut();
  510. }
  511.  
  512. /// <summary>
  513. /// 触发启用武器
  514. /// </summary>
  515. public void _Active()
  516. {
  517. OnActive();
  518. }
  519.  
  520. /// <summary>
  521. /// 触发收起武器
  522. /// </summary>
  523. public void _Conceal()
  524. {
  525. OnConceal();
  526. }
  527.  
  528. /// <summary>
  529. /// 实例化并返回子弹对象
  530. /// </summary>
  531. /// <param name="bulletPack">子弹的预制体</param>
  532. protected T CreateBullet<T>(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null) where T : Node2D, IBullet
  533. {
  534. return (T)CreateBullet(bulletPack, globalPostion, globalRotation, parent);
  535. }
  536.  
  537. /// <summary>
  538. /// 实例化并返回子弹对象
  539. /// </summary>
  540. /// <param name="bulletPack">子弹的预制体</param>
  541. protected IBullet CreateBullet(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null)
  542. {
  543. // 实例化子弹
  544. Node2D bullet = bulletPack.Instance<Node2D>();
  545. // 设置坐标
  546. bullet.GlobalPosition = globalPostion;
  547. // 旋转角度
  548. bullet.GlobalRotation = globalRotation;
  549. if (parent == null)
  550. {
  551. RoomManager.Current.SortRoot.AddChild(bullet);
  552. }
  553. else
  554. {
  555. parent.AddChild(bullet);
  556. }
  557. // 调用初始化
  558. IBullet result = (IBullet)bullet;
  559. result.Init(TargetCamp, this, null);
  560. return result;
  561. }
  562. }