Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / weapon / Weapon.cs
  1. using Godot;
  2. using System;
  3. using System.Collections.Generic;
  4. using Config;
  5.  
  6. /// <summary>
  7. /// 武器的基类
  8. /// </summary>
  9. public abstract partial class Weapon : ActivityObject, IPackageItem<Role>
  10. {
  11. /// <summary>
  12. /// 武器使用的属性数据, 该属性会根据是否是玩家使用武器, 如果是Ai使用武器, 则会返回 AiUseAttribute 的属性对象
  13. /// </summary>
  14. public ExcelConfig.WeaponBase Attribute => _weaponAttribute;
  15.  
  16. /// <summary>
  17. /// Ai使用该武器的属性
  18. /// </summary>
  19. public ExcelConfig.WeaponBase AiUseAttribute => _aiWeaponAttribute;
  20.  
  21. /// <summary>
  22. /// 玩家使用该武器的属性
  23. /// </summary>
  24. public ExcelConfig.WeaponBase PlayerUseAttribute => _playerWeaponAttribute;
  25. private ExcelConfig.WeaponBase _weaponAttribute;
  26. private ExcelConfig.WeaponBase _playerWeaponAttribute;
  27. private ExcelConfig.WeaponBase _aiWeaponAttribute;
  28.  
  29. /// <summary>
  30. /// 武器攻击的目标阵营
  31. /// </summary>
  32. public CampEnum TargetCamp { get; set; }
  33.  
  34. public Role Master { get; set; }
  35.  
  36. public int PackageIndex { get; set; } = -1;
  37.  
  38. /// <summary>
  39. /// 当前弹夹弹药剩余量
  40. /// </summary>
  41. public int CurrAmmo { get; private set; }
  42.  
  43. /// <summary>
  44. /// 剩余弹药量(备用弹药)
  45. /// </summary>
  46. public int ResidueAmmo { get; private set; }
  47. /// <summary>
  48. /// 总弹药量(备用弹药 + 当前弹夹弹药)
  49. /// </summary>
  50. public int TotalAmmon => CurrAmmo + ResidueAmmo;
  51.  
  52. /// <summary>
  53. /// 武器管的开火点
  54. /// </summary>
  55. [Export, ExportFillNode]
  56. public Marker2D FirePoint { get; set; }
  57.  
  58. /// <summary>
  59. /// 弹壳抛出的点
  60. /// </summary>
  61. [Export, ExportFillNode]
  62. public Marker2D ShellPoint { get; set; }
  63. /// <summary>
  64. /// 武器的当前散射半径
  65. /// </summary>
  66. public float CurrScatteringRange { get; private set; } = 0;
  67.  
  68. /// <summary>
  69. /// 是否在换弹中
  70. /// </summary>
  71. /// <value></value>
  72. public bool Reloading { get; private set; } = false;
  73.  
  74. /// <summary>
  75. /// 换弹进度 (从 0 到 1)
  76. /// </summary>
  77. public float ReloadProgress
  78. {
  79. get
  80. {
  81. if (!Reloading)
  82. {
  83. return 1;
  84. }
  85.  
  86. if (Attribute.AloneReload)
  87. {
  88. //总时间
  89. var total = Attribute.AloneReloadBeginIntervalTime + (Attribute.ReloadTime * Attribute.AmmoCapacity) + Attribute.AloneReloadFinishIntervalTime;
  90. //当前时间
  91. float current;
  92. if (_aloneReloadState == 1)
  93. {
  94. current = (Attribute.AloneReloadBeginIntervalTime - _reloadTimer) + Attribute.ReloadTime * CurrAmmo;
  95. }
  96. else if (_aloneReloadState == 2)
  97. {
  98. current = Attribute.AloneReloadBeginIntervalTime + (Attribute.ReloadTime * (CurrAmmo + (1 - _reloadTimer / Attribute.ReloadTime)));
  99. }
  100. else
  101. {
  102. current = Attribute.AloneReloadBeginIntervalTime + (Attribute.ReloadTime * CurrAmmo) + (Attribute.AloneReloadFinishIntervalTime - _reloadTimer);
  103. }
  104.  
  105. return current / total;
  106. }
  107.  
  108. return 1 - _reloadTimer / Attribute.ReloadTime;
  109. }
  110. }
  111.  
  112. /// <summary>
  113. /// 返回是否在蓄力中,
  114. /// 注意, 属性仅在 Attribute.LooseShoot == false 时有正确的返回值, 否则返回 false
  115. /// </summary>
  116. public bool IsCharging => _looseShootFlag;
  117.  
  118. /// <summary>
  119. /// 返回武器是否在武器背包中
  120. /// </summary>
  121. public bool IsInHolster => Master != null;
  122.  
  123. /// <summary>
  124. /// 返回是否真正使用该武器
  125. /// </summary>
  126. public bool IsActive => Master != null && Master.WeaponPack.ActiveItem == this;
  127. /// <summary>
  128. /// 动画播放器
  129. /// </summary>
  130. [Export, ExportFillNode]
  131. public AnimationPlayer AnimationPlayer { get; set; }
  132.  
  133. /// <summary>
  134. /// 是否自动播放 SpriteFrames 的动画
  135. /// </summary>
  136. public bool IsAutoPlaySpriteFrames { get; set; } = true;
  137.  
  138. /// <summary>
  139. /// 在没有所属 Master 的时候是否可以触发扳机
  140. /// </summary>
  141. public bool NoMasterCanTrigger { get; set; } = true;
  142. /// <summary>
  143. /// 上一次触发改武器开火的角色, 可能为 null
  144. /// </summary>
  145. public Role TriggerRole { get; private set; }
  146. /// <summary>
  147. /// 上一次触发改武器开火的触发开火攻击的层级, 数据源自于: <see cref="PhysicsLayer"/>
  148. /// </summary>
  149. public long TriggerRoleAttackLayer { get; private set; }
  150. /// <summary>
  151. /// 武器当前射速
  152. /// </summary>
  153. public float CurrentFiringSpeed { get; private set; }
  154. //--------------------------------------------------------------------------------------------
  155.  
  156. //触发板机是是否计算弹药消耗
  157. private bool _triggerCalcAmmon = true;
  158. //用于记录是否有角色操作过这把武器
  159. private bool _triggerRoleFlag = false;
  160. //是否按下
  161. private bool _triggerFlag = false;
  162.  
  163. //扳机计时器
  164. private float _triggerTimer = 0;
  165.  
  166. //开火前延时时间
  167. private float _delayedTime = 0;
  168.  
  169. //开火间隙时间
  170. private float _fireInterval = 0;
  171.  
  172. //开火武器口角度
  173. private float _fireAngle = 0;
  174.  
  175. //攻击冷却计时
  176. private float _attackTimer = 0;
  177.  
  178. //攻击状态
  179. private bool _attackFlag = false;
  180. //多久没开火了
  181. private float _noAttackTime = 0;
  182.  
  183. //按下的时间
  184. private float _downTimer = 0;
  185.  
  186. //松开的时间
  187. private float _upTimer = 0;
  188.  
  189. //连发次数
  190. private int _continuousCount = 0;
  191.  
  192. //连发状态记录
  193. private bool _continuousShootFlag = false;
  194.  
  195. //松开扳机是否开火
  196. private bool _looseShootFlag = false;
  197.  
  198. //蓄力攻击时长
  199. private float _chargeTime = 0;
  200.  
  201. //是否需要重置武器数据
  202. private bool _dirtyFlag = false;
  203.  
  204. //当前后坐力导致的偏移长度
  205. private float _currBacklashLength = 0;
  206.  
  207. //握把位置
  208. private Vector2 _gripPoint;
  209.  
  210. //持握时 Sprite 偏移
  211. private Vector2 _gripOffset;
  212.  
  213. //碰撞器位置
  214. private Vector2 _collPoint1;
  215. private Vector2 _collPoint2;
  216.  
  217. //换弹计时器
  218. private float _reloadTimer = 0;
  219. //单独换弹设置下的换弹状态, 0: 未换弹, 1: 装第一颗子弹之前, 2: 单独装弹中, 3: 单独装弹完成
  220. private byte _aloneReloadState = 3;
  221.  
  222. //单独换弹状态下是否强制结束换弹过程
  223. private bool _aloneReloadStop = false;
  224. //本次换弹已用时间
  225. private float _reloadUseTime = 0;
  226.  
  227. //是否播放过换弹完成音效
  228. private bool _playReloadFinishSoundFlag = false;
  229.  
  230. //上膛状态,-1: 等待执行自动上膛 , 0: 未上膛, 1: 上膛中, 2: 已经完成上膛
  231. private sbyte _beLoadedState = 2;
  232.  
  233. //上膛计时器
  234. private float _beLoadedStateTimer = -1;
  235.  
  236. //换弹投抛弹壳记录
  237. private bool _reloadShellFlag = false;
  238.  
  239. //抖动强度
  240. private float _shakeStrength = 0;
  241. //抖动间隔
  242. private float _shakeInterval = 1 / 60f;
  243. //抖动计时器
  244. private float _shakeTimer = 0;
  245.  
  246. //换弹完成后播放的动画
  247. private string _reloadNextAnimation;
  248. // ----------------------------------------------
  249. private uint _tempLayer;
  250.  
  251. private static bool _init = false;
  252. private static Dictionary<string, ExcelConfig.WeaponBase> _weaponAttributeMap =
  253. new Dictionary<string, ExcelConfig.WeaponBase>();
  254.  
  255. /// <summary>
  256. /// 初始化武器属性数据
  257. /// </summary>
  258. public static void InitWeaponAttribute()
  259. {
  260. if (_init)
  261. {
  262. return;
  263. }
  264.  
  265. _init = true;
  266. foreach (var weaponAttr in ExcelConfig.WeaponBase_List)
  267. {
  268. if (weaponAttr.Activity != null)
  269. {
  270. if (!_weaponAttributeMap.TryAdd(weaponAttr.Activity.Id, weaponAttr))
  271. {
  272. Debug.LogError("发现重复注册的武器属性: " + weaponAttr.Id);
  273. }
  274. }
  275. }
  276. }
  277. /// <summary>
  278. /// 根据 ActivityBase.Id 获取对应武器的属性数据
  279. /// </summary>
  280. public static ExcelConfig.WeaponBase GetWeaponAttribute(string itemId)
  281. {
  282. if (itemId == null)
  283. {
  284. return null;
  285. }
  286. if (_weaponAttributeMap.TryGetValue(itemId, out var attr))
  287. {
  288. return attr;
  289. }
  290.  
  291. throw new Exception($"武器'{itemId}'没有在 WeaponBase 表中配置属性数据!");
  292. }
  293. public override void OnInit()
  294. {
  295. InitWeapon(GetWeaponAttribute(ActivityBase.Id).Clone());
  296. AnimatedSprite.AnimationFinished += OnAnimatedSpriteFinished;
  297. AnimationPlayer.AnimationFinished += OnAnimationPlayerFinished;
  298. _gripPoint = AnimatedSprite.Position;
  299. _gripOffset = AnimatedSprite.Offset;
  300. _collPoint1 = Collision.Position;
  301. _collPoint2 = _collPoint1 - AnimatedSprite.Offset - AnimatedSprite.Position;
  302. AnimatedSprite.Position = Vector2.Zero;
  303. AnimatedSprite.Offset = Vector2.Zero;
  304. Collision.Position = _collPoint2;
  305. }
  306.  
  307. /// <summary>
  308. /// 初始化武器属性
  309. /// </summary>
  310. private void InitWeapon(ExcelConfig.WeaponBase attribute)
  311. {
  312. _playerWeaponAttribute = attribute;
  313. SetCurrentWeaponAttribute(attribute);
  314. if (ExcelConfig.WeaponBase_Map.TryGetValue(attribute.Id + "_ai", out var aiAttr))
  315. {
  316. _aiWeaponAttribute = aiAttr;
  317. }
  318. else
  319. {
  320. Debug.LogError("警告: 未找到 AI 武器属性: " + attribute.Id);
  321. _aiWeaponAttribute = attribute;
  322. }
  323.  
  324. if (Attribute.AmmoCapacity > Attribute.MaxAmmoCapacity)
  325. {
  326. Attribute.AmmoCapacity = Attribute.MaxAmmoCapacity;
  327. Debug.LogError("弹夹的容量不能超过弹药上限, 武器id: " + ActivityBase.Id);
  328. }
  329. //弹药量
  330. CurrAmmo = Attribute.AmmoCapacity;
  331. //剩余弹药量
  332. ResidueAmmo = Mathf.Min(Attribute.StandbyAmmoCapacity + CurrAmmo, Attribute.MaxAmmoCapacity) - CurrAmmo;
  333. }
  334.  
  335. /// <summary>
  336. /// 单次开火时调用的函数
  337. /// </summary>
  338. protected abstract void OnFire();
  339.  
  340. /// <summary>
  341. /// 发射子弹时调用的函数, 每发射一枚子弹调用一次,
  342. /// 如果做霰弹武器效果, 一次开火发射5枚子弹, 则该函数调用5次
  343. /// </summary>
  344. /// <param name="fireRotation">开火时枪口旋转角度, 弧度制</param>
  345. protected abstract void OnShoot(float fireRotation);
  346.  
  347. /// <summary>
  348. /// 上膛开始时调用
  349. /// </summary>
  350. protected virtual void OnBeginBeLoaded()
  351. {
  352. }
  353. /// <summary>
  354. /// 上膛结束时调用
  355. /// </summary>
  356. protected virtual void OnBeLoadedFinish()
  357. {
  358. }
  359. /// <summary>
  360. /// 当按下扳机时调用
  361. /// </summary>
  362. protected virtual void OnDownTrigger()
  363. {
  364. }
  365.  
  366. /// <summary>
  367. /// 当松开扳机时调用
  368. /// </summary>
  369. protected virtual void OnUpTrigger()
  370. {
  371. }
  372.  
  373. /// <summary>
  374. /// 开始蓄力时调用,
  375. /// 注意, 该函数仅在 Attribute.LooseShoot == false 时才能被调用
  376. /// </summary>
  377. protected virtual void OnBeginCharge()
  378. {
  379. }
  380.  
  381. /// <summary>
  382. /// 结束蓄力时调用
  383. /// 注意, 该函数仅在 Attribute.LooseShoot == false 时才能被调用
  384. /// </summary>
  385. protected virtual void OnEndCharge()
  386. {
  387. }
  388. /// <summary>
  389. /// 蓄力完成时调用
  390. /// </summary>
  391. protected virtual void OnChargeFinish()
  392. {
  393. }
  394. /// <summary>
  395. /// 蓄力时每帧调用
  396. /// 注意, 该函数仅在 Attribute.LooseShoot == false 时才能被调用
  397. /// </summary>
  398. /// <param name="delta"></param>
  399. /// <param name="charge">蓄力时长</param>
  400. protected virtual void OnChargeProcess(float delta, float charge)
  401. {
  402. }
  403.  
  404. /// <summary>
  405. /// 当换弹时调用, 如果设置单独装弹, 则每装一次弹调用一次该函数
  406. /// </summary>
  407. protected virtual void OnReload()
  408. {
  409. }
  410.  
  411. /// <summary>
  412. /// 当开始换弹时调用
  413. /// </summary>
  414. protected virtual void OnBeginReload()
  415. {
  416. }
  417. /// <summary>
  418. /// 当换弹完成时调用
  419. /// </summary>
  420. protected virtual void OnReloadFinish()
  421. {
  422. }
  423.  
  424. /// <summary>
  425. /// 单独装弹完成时调用
  426. /// </summary>
  427. protected virtual void OnAloneReloadStateFinish()
  428. {
  429. }
  430. /// <summary>
  431. /// 当武器被拾起时调用
  432. /// </summary>
  433. /// <param name="master">拾起该武器的角色</param>
  434. protected virtual void OnPickUp(Role master)
  435. {
  436. }
  437.  
  438. /// <summary>
  439. /// 当武器从武器背包中移除时调用
  440. /// </summary>
  441. /// <param name="master">移除该武器的角色</param>
  442. protected virtual void OnRemove(Role master)
  443. {
  444. }
  445.  
  446. /// <summary>
  447. /// 当武器被激活时调用, 也就是使用当武器时调用
  448. /// </summary>
  449. protected virtual void OnActive()
  450. {
  451. }
  452.  
  453. /// <summary>
  454. /// 当武器被收起时调用
  455. /// </summary>
  456. protected virtual void OnConceal()
  457. {
  458. }
  459.  
  460. /// <summary>
  461. /// 射击时调用, 返回消耗弹药数量, 默认为1, 如果返回为 0, 则不消耗弹药
  462. /// </summary>
  463. protected virtual int UseAmmoCount()
  464. {
  465. return 1;
  466. }
  467.  
  468. public override void EnterTree()
  469. {
  470. //收集落在地上的武器
  471. if (IsInGround())
  472. {
  473. World.Weapon_UnclaimedWeapons.Add(this);
  474. }
  475. }
  476.  
  477. public override void ExitTree()
  478. {
  479. World.Weapon_UnclaimedWeapons.Remove(this);
  480. }
  481.  
  482. protected override void Process(float delta)
  483. {
  484. //抖动 AnimatedSprite
  485. if (_shakeStrength != 0)
  486. {
  487. _shakeTimer += delta;
  488. if (_shakeTimer >= _shakeInterval)
  489. {
  490. _shakeTimer = 0;
  491. AnimatedSprite.Offset = new Vector2(
  492. Utils.Random.RandomRangeFloat(-_shakeStrength, _shakeStrength),
  493. Utils.Random.RandomRangeFloat(-_shakeStrength, _shakeStrength)
  494. );
  495. }
  496. }
  497. else
  498. {
  499. _shakeTimer = 0;
  500. }
  501. //未开火时间
  502. _noAttackTime += delta;
  503. //这把武器被扔在地上, 或者当前武器没有被使用
  504. //if (Master == null || Master.WeaponPack.ActiveItem != this)
  505. if ((Master != null && Master.WeaponPack.ActiveItem != this) || !_triggerRoleFlag) //在背上, 或者被扔出去了
  506. {
  507. //_triggerTimer
  508. _triggerTimer = _triggerTimer > 0 ? _triggerTimer - delta : 0;
  509. //攻击冷却计时
  510. _attackTimer = _attackTimer > 0 ? _attackTimer - delta : 0;
  511. //武器的当前散射半径
  512. ScatteringRangeBackHandler(delta);
  513. //武器当前射速
  514. FiringSpeedBackHandler(delta);
  515. //松开扳机
  516. if (_triggerFlag || _downTimer > 0)
  517. {
  518. UpTrigger();
  519. _downTimer = 0;
  520. }
  521. _triggerFlag = false;
  522.  
  523. //重置数据
  524. if (_dirtyFlag)
  525. {
  526. _dirtyFlag = false;
  527. //_aloneReloadState = 0;
  528. StopReload();
  529. _attackFlag = false;
  530. _continuousCount = 0;
  531. _delayedTime = 0;
  532. _upTimer = 0;
  533. _looseShootFlag = false;
  534. _chargeTime = 0;
  535. _beLoadedStateTimer = -1;
  536. }
  537. }
  538. else //正在使用中
  539. {
  540. _dirtyFlag = true;
  541. //上膛
  542. if (_beLoadedState == 1)
  543. {
  544. _beLoadedStateTimer -= delta;
  545. //上膛完成
  546. if (_beLoadedStateTimer <= 0)
  547. {
  548. _beLoadedStateTimer = -1;
  549. _beLoadedState = 2;
  550. OnBeLoadedFinish();
  551. }
  552. }
  553. //换弹
  554. if (Reloading)
  555. {
  556. //换弹用时
  557. _reloadUseTime += delta;
  558. _reloadTimer -= delta;
  559.  
  560. if (Attribute.AloneReload) //单独装弹模式
  561. {
  562. switch (_aloneReloadState)
  563. {
  564. case 0:
  565. Debug.LogError("AloneReload状态错误!");
  566. break;
  567. case 1: //装第一颗子弹之前
  568. {
  569. if (_reloadTimer <= 0)
  570. {
  571. //开始装第一颗子弹
  572. _aloneReloadState = 2;
  573. ReloadHandler();
  574. }
  575. _aloneReloadStop = false;
  576. }
  577. break;
  578. case 2: //单独装弹中
  579. {
  580. if (_reloadTimer <= 0)
  581. {
  582. ReloadSuccess();
  583. if (_aloneReloadStop || ResidueAmmo == 0 || CurrAmmo == Attribute.AmmoCapacity) //单独装弹完成
  584. {
  585. AloneReloadStateFinish();
  586. if (Attribute.AloneReloadFinishIntervalTime <= 0)
  587. {
  588. //换弹完成
  589. StopReload();
  590. ReloadFinishHandler();
  591. }
  592. else
  593. {
  594. _reloadTimer = Attribute.AloneReloadFinishIntervalTime;
  595. _aloneReloadState = 3;
  596. }
  597. }
  598. }
  599. }
  600. break;
  601. case 3: //单独装弹完成
  602. {
  603. //播放换弹完成音效
  604. if (!_playReloadFinishSoundFlag && Attribute.ReloadFinishSound != null && _reloadTimer <= Attribute.ReloadFinishSoundAdvanceTime)
  605. {
  606. _playReloadFinishSoundFlag = true;
  607. // Debug.Log("播放换弹完成音效.");
  608. PlayReloadFinishSound();
  609. }
  610. if (_reloadTimer <= 0)
  611. {
  612. //换弹完成
  613. StopReload();
  614. ReloadFinishHandler();
  615. }
  616. _aloneReloadStop = false;
  617. }
  618. break;
  619. }
  620. }
  621. else //普通换弹模式
  622. {
  623. //播放换弹完成音效
  624. if (!_playReloadFinishSoundFlag && Attribute.ReloadFinishSound != null && _reloadTimer <= Attribute.ReloadFinishSoundAdvanceTime)
  625. {
  626. _playReloadFinishSoundFlag = true;
  627. // Debug.Log("播放换弹完成音效.");
  628. PlayReloadFinishSound();
  629. }
  630.  
  631. if (_reloadTimer <= 0)
  632. {
  633. ReloadSuccess();
  634. }
  635. }
  636. }
  637.  
  638. //攻击的计时器
  639. if (_attackTimer > 0)
  640. {
  641. _attackTimer -= delta;
  642. if (_attackTimer < 0)
  643. {
  644. _delayedTime += _attackTimer;
  645. _attackTimer = 0;
  646. //枪口默认角度
  647. if (Master != null)
  648. {
  649. RotationDegrees = -Attribute.DefaultAngle;
  650. }
  651.  
  652. //自动上膛
  653. if (_beLoadedState == -1)
  654. {
  655. BeLoaded();
  656. }
  657. //子弹换弹
  658. if (CurrAmmo <= 0 && Attribute.AutoReload)
  659. {
  660. Reload();
  661. }
  662. }
  663. }
  664. else if (_delayedTime > 0) //攻击延时
  665. {
  666. _delayedTime -= delta;
  667. if (_attackTimer < 0)
  668. {
  669. _delayedTime = 0;
  670. }
  671. }
  672. //扳机判定
  673. if (_triggerFlag)
  674. {
  675. if (_looseShootFlag) //蓄力时长
  676. {
  677. var pv = _chargeTime;
  678. _chargeTime += delta;
  679. OnChargeProcess(delta, _chargeTime);
  680. //蓄力完成
  681. if (pv < Attribute.MinChargeTime && _chargeTime >= Attribute.MinChargeTime)
  682. {
  683. OnChargeFinish();
  684. }
  685. }
  686.  
  687. _downTimer += delta;
  688. if (_upTimer > 0) //第一帧按下扳机
  689. {
  690. DownTrigger();
  691. _upTimer = 0;
  692. }
  693. }
  694. else
  695. {
  696. _upTimer += delta;
  697. if (_downTimer > 0) //第一帧松开扳机
  698. {
  699. UpTrigger();
  700. _downTimer = 0;
  701. }
  702. }
  703.  
  704. //连发判断
  705. if (!_looseShootFlag && _continuousCount > 0 && _delayedTime <= 0 && _attackTimer <= 0)
  706. {
  707. //连发开火
  708. TriggerFire();
  709. //连发最后一发打完了
  710. if (Attribute.ManualBeLoaded && _continuousCount <= 0)
  711. {
  712. //执行上膛逻辑
  713. RunBeLoaded();
  714. }
  715. }
  716.  
  717. //散射值消退
  718. if (_noAttackTime >= Attribute.ScatteringRangeBackDelayTime)
  719. {
  720. ScatteringRangeBackHandler(delta);
  721. }
  722.  
  723. if (_triggerFlag) //射速增加
  724. {
  725. FiringSpeedAddHandler(delta);
  726. }
  727. else if (_noAttackTime >= Attribute.FiringSpeedBackTime) //射速消退
  728. {
  729. FiringSpeedBackHandler(delta);
  730. }
  731.  
  732. _triggerTimer = _triggerTimer > 0 ? _triggerTimer - delta : 0;
  733. _triggerFlag = false;
  734. _attackFlag = false;
  735. //武器身回归
  736. //Position = Position.MoveToward(Vector2.Zero, Attribute.BacklashRegressionSpeed * delta).Rotated(Rotation);
  737. _currBacklashLength = Mathf.MoveToward(_currBacklashLength, 0, Attribute.BacklashRegressionSpeed * delta);
  738. if (Master != null)
  739. {
  740. Position = new Vector2(_currBacklashLength, 0).Rotated(Rotation);
  741. if (_attackTimer > 0)
  742. {
  743. RotationDegrees = Mathf.Lerp(
  744. _fireAngle, -Attribute.DefaultAngle,
  745. Mathf.Clamp((_fireInterval - _attackTimer) * Attribute.UpliftAngleRestore / _fireInterval, 0, 1)
  746. );
  747. }
  748. }
  749. }
  750. }
  751.  
  752. /// <summary>
  753. /// 设置抖动强度
  754. /// </summary>
  755. public void SetShake(float strength)
  756. {
  757. _shakeStrength = strength;
  758. }
  759. /// <summary>
  760. /// 设置抖动间隔
  761. /// </summary>
  762. public void SetShakeInterval(float interval)
  763. {
  764. _shakeInterval = interval;
  765. }
  766.  
  767. /// <summary>
  768. /// 返回武器是否在地上
  769. /// </summary>
  770. /// <returns></returns>
  771. public bool IsInGround()
  772. {
  773. return Master == null && GetParent() == World.Current.NormalLayer;
  774. }
  775.  
  776. /// <summary>
  777. /// 清除触发角色开火标记数据
  778. /// </summary>
  779. public void ClearTriggerRole()
  780. {
  781. _triggerRoleFlag = false;
  782. if (Master == null)
  783. {
  784. if (Reloading)
  785. {
  786. _reloadNextAnimation = AnimatorNames.Floodlight;
  787. }
  788. else
  789. {
  790. AnimationPlayer.Play(AnimatorNames.Floodlight);
  791. }
  792. }
  793. }
  794.  
  795. /// <summary>
  796. /// 扳机函数, 调用即视为按下扳机
  797. /// </summary>
  798. /// <param name="triggerRole">按下扳机的角色, 如果传 null, 则视为走火</param>
  799. /// <param name="calcAmmo">是否计算弹药消耗</param>
  800. public void Trigger(Role triggerRole, bool calcAmmo = true)
  801. {
  802. //不能触发扳机
  803. if (!NoMasterCanTrigger && Master == null) return;
  804.  
  805. //这一帧已经按过了, 不需要再按下
  806. if (_triggerFlag) return;
  807.  
  808. //更新武器属性信息
  809. _triggerFlag = true;
  810. if (!_triggerRoleFlag && AnimationPlayer.CurrentAnimation == AnimatorNames.Floodlight)
  811. {
  812. AnimationPlayer.Play(AnimatorNames.Reset);
  813. }
  814. _triggerRoleFlag = true;
  815. _triggerCalcAmmon = calcAmmo;
  816. if (triggerRole != null)
  817. {
  818. TriggerRole = triggerRole;
  819. TriggerRoleAttackLayer = triggerRole.AttackLayer;
  820. SetCurrentWeaponAttribute(triggerRole.IsAi ? _aiWeaponAttribute : _playerWeaponAttribute);
  821. }
  822. else if (Master != null)
  823. {
  824. TriggerRole = Master;
  825. TriggerRoleAttackLayer = Master.AttackLayer;
  826. SetCurrentWeaponAttribute(Master.IsAi ? _aiWeaponAttribute : _playerWeaponAttribute);
  827. }
  828.  
  829. //是否第一帧按下
  830. var justDown = _downTimer == 0;
  831. if (_beLoadedState == 0 || _beLoadedState == -1) //需要执行上膛操作
  832. {
  833. if (justDown && !Reloading && triggerRole != null)
  834. {
  835. if (CurrAmmo <= 0)
  836. {
  837. //子弹不够, 触发换弹
  838. Reload();
  839. }
  840. else if (_attackTimer <= 0)
  841. {
  842. //触发上膛操作
  843. BeLoaded();
  844. }
  845. }
  846. }
  847. else if (_beLoadedState == 1) //上膛中
  848. {
  849.  
  850. }
  851. else //上膛完成
  852. {
  853. //是否能发射
  854. var flag = false;
  855. if (_continuousCount <= 0) //不能处于连发状态下
  856. {
  857. if (Attribute.ContinuousShoot) //自动射击
  858. {
  859. if (_triggerTimer > 0)
  860. {
  861. if (_continuousShootFlag)
  862. {
  863. flag = true;
  864. }
  865. }
  866. else
  867. {
  868. flag = true;
  869. if (_delayedTime <= 0 && _attackTimer <= 0)
  870. {
  871. _continuousShootFlag = true;
  872. }
  873. }
  874. }
  875. else //半自动
  876. {
  877. if (justDown && _triggerTimer <= 0 && _attackTimer <= 0)
  878. {
  879. flag = true;
  880. }
  881. }
  882. }
  883.  
  884. if (flag)
  885. {
  886. var fireFlag = true; //是否能开火
  887. if (Reloading) //换弹中
  888. {
  889. fireFlag = false;
  890. if (CurrAmmo > 0 && Attribute.AloneReload && Attribute.AloneReloadCanShoot)
  891. {
  892. //检查是否允许停止换弹
  893. if (_aloneReloadState == 2 || _aloneReloadState == 1)
  894. {
  895. //强制结束
  896. _aloneReloadStop = true;
  897. }
  898. }
  899. }
  900. else if (CurrAmmo <= 0) //子弹不够
  901. {
  902. fireFlag = false;
  903. if (justDown && triggerRole != null)
  904. {
  905. //第一帧按下, 触发换弹
  906. Reload();
  907. }
  908. }
  909.  
  910. if (fireFlag)
  911. {
  912. if (justDown)
  913. {
  914. //开火前延时
  915. if (!Attribute.LooseShoot)
  916. {
  917. _delayedTime = Attribute.DelayedTime;
  918. }
  919.  
  920. //扳机按下间隔
  921. _triggerTimer = Attribute.TriggerInterval;
  922. //连发数量
  923. if (!Attribute.ContinuousShoot)
  924. {
  925. _continuousCount = Utils.Random.RandomConfigRange(Attribute.ContinuousCountRange);
  926. }
  927. }
  928.  
  929. if (_delayedTime <= 0 && _attackTimer <= 0)
  930. {
  931. if (Attribute.LooseShoot) //松发开火
  932. {
  933. _looseShootFlag = true;
  934. OnBeginCharge();
  935. }
  936. else
  937. {
  938. //开火
  939. TriggerFire();
  940.  
  941. //非连射模式
  942. if (!Attribute.ContinuousShoot && Attribute.ManualBeLoaded && _continuousCount <= 0)
  943. {
  944. //执行上膛逻辑
  945. RunBeLoaded();
  946. }
  947. }
  948. }
  949. }
  950. }
  951. else //不能开火
  952. {
  953. if (CurrAmmo <= 0 && justDown && triggerRole != null) //子弹不够
  954. {
  955. //第一帧按下, 触发换弹
  956. Reload();
  957. }
  958. }
  959. }
  960. }
  961.  
  962. /// <summary>
  963. /// 返回是否按下扳机
  964. /// </summary>
  965. public bool IsPressTrigger()
  966. {
  967. return _triggerFlag;
  968. }
  969. /// <summary>
  970. /// 获取本次扳机按下的时长, 单位: 秒
  971. /// </summary>
  972. public float GetTriggerDownTime()
  973. {
  974. return _downTimer;
  975. }
  976.  
  977. /// <summary>
  978. /// 获取扳机蓄力时长, 计算按下扳机后从可以开火到当前一共经过了多长时间, 可用于计算蓄力攻击
  979. /// 注意, 该函数仅在 Attribute.LooseShoot == false 时有正确的返回值, 否则返回 0
  980. /// </summary>
  981. public float GetTriggerChargeTime()
  982. {
  983. return _chargeTime;
  984. }
  985. /// <summary>
  986. /// 获取蓄力是否结束
  987. /// 注意, 该函数仅在 Attribute.LooseShoot == false 时有正确的返回值, 否则返回 false
  988. /// </summary>
  989. public bool IsChargeFinish()
  990. {
  991. return _chargeTime >= Attribute.MinChargeTime;
  992. }
  993. /// <summary>
  994. /// 获取延时射击倒计时, 单位: 秒
  995. /// </summary>
  996. public float GetDelayedAttackTime()
  997. {
  998. return _delayedTime;
  999. }
  1000.  
  1001. /// <summary>
  1002. /// 获取当前需要连发弹药的数量, 配置了 ContinuousCountRange 时生效
  1003. /// </summary>
  1004. public int GetContinuousCount()
  1005. {
  1006. return _continuousCount;
  1007. }
  1008.  
  1009. /// <summary>
  1010. /// 获取攻击冷却计时时间, 小于等于 0 表示冷却完成
  1011. /// </summary>
  1012. public float GetAttackTimer()
  1013. {
  1014. return _attackTimer;
  1015. }
  1016.  
  1017. /// <summary>
  1018. /// 返回是否是攻击间隙时间
  1019. /// </summary>
  1020. public bool IsAttackIntervalTime()
  1021. {
  1022. return _attackTimer > 0 || _triggerTimer > 0;
  1023. }
  1024.  
  1025. /// <summary>
  1026. /// 是否可以按下扳机并发射了
  1027. /// </summary>
  1028. public bool TriggerIsReady()
  1029. {
  1030. return GetBeLoadedStateState() >= 2 && !IsAttackIntervalTime();
  1031. }
  1032.  
  1033. /// <summary>
  1034. /// 获取上膛状态,-1: 等待执行自动上膛 , 0: 未上膛, 1: 上膛中, 2: 已经完成上膛
  1035. /// </summary>
  1036. public sbyte GetBeLoadedStateState()
  1037. {
  1038. return _beLoadedState;
  1039. }
  1040. /// <summary>
  1041. /// 刚按下扳机
  1042. /// </summary>
  1043. private void DownTrigger()
  1044. {
  1045. OnDownTrigger();
  1046. }
  1047.  
  1048. /// <summary>
  1049. /// 刚松开扳机
  1050. /// </summary>
  1051. private void UpTrigger()
  1052. {
  1053. _continuousShootFlag = false;
  1054. if (_delayedTime > 0)
  1055. {
  1056. _continuousCount = 0;
  1057. }
  1058.  
  1059. //松发开火执行
  1060. if (_looseShootFlag)
  1061. {
  1062. _looseShootFlag = false;
  1063. if (_chargeTime >= Attribute.MinChargeTime) //判断蓄力是否够了
  1064. {
  1065. TriggerFire();
  1066. //非连射模式
  1067. if (!Attribute.ContinuousShoot && Attribute.ManualBeLoaded && _continuousCount <= 0)
  1068. {
  1069. //执行上膛逻辑
  1070. RunBeLoaded();
  1071. }
  1072. }
  1073. else //不能攻击
  1074. {
  1075. _continuousCount = 0;
  1076. }
  1077. _chargeTime = 0;
  1078. OnEndCharge();
  1079. }
  1080.  
  1081. OnUpTrigger();
  1082. }
  1083.  
  1084. /// <summary>
  1085. /// 触发开火
  1086. /// </summary>
  1087. private void TriggerFire()
  1088. {
  1089. _attackFlag = true;
  1090. _noAttackTime = 0;
  1091. _reloadShellFlag = false;
  1092.  
  1093. //减子弹数量
  1094. if (_triggerCalcAmmon)
  1095. {
  1096. if (_playerWeaponAttribute != _weaponAttribute) //Ai使用该武器, 有一定概率不消耗弹药
  1097. {
  1098. var count = UseAmmoCount();
  1099. CurrAmmo -= count;
  1100. if (Utils.Random.RandomRangeFloat(0, 1) >= _weaponAttribute.AiAttackAttr.AmmoConsumptionProbability) //不消耗弹药
  1101. {
  1102. ResidueAmmo += count;
  1103. }
  1104. }
  1105. else
  1106. {
  1107. CurrAmmo -= UseAmmoCount();
  1108. }
  1109. }
  1110. else //不消耗弹药
  1111. {
  1112. var count = UseAmmoCount();
  1113. CurrAmmo -= count;
  1114. ResidueAmmo += count;
  1115. }
  1116.  
  1117. if (CurrAmmo == 0)
  1118. {
  1119. _continuousCount = 0;
  1120. }
  1121. else
  1122. {
  1123. _continuousCount = _continuousCount > 0 ? _continuousCount - 1 : 0;
  1124. }
  1125.  
  1126. //开火间隙, 这里的60指的是60秒
  1127. _fireInterval = 60 / CurrentFiringSpeed;
  1128. //攻击冷却
  1129. _attackTimer += _fireInterval;
  1130.  
  1131. //播放开火动画
  1132. if (IsAutoPlaySpriteFrames)
  1133. {
  1134. PlaySpriteAnimation(AnimatorNames.Fire);
  1135. PlayAnimationPlayer(AnimatorNames.Fire);
  1136. }
  1137.  
  1138. //播放射击音效
  1139. PlayShootSound();
  1140. //抛弹
  1141. if (!Attribute.ReloadThrowShell && (Attribute.ContinuousShoot || !Attribute.ManualBeLoaded))
  1142. {
  1143. ThrowShellHandler(1f);
  1144. }
  1145. //触发开火函数
  1146. OnFire();
  1147.  
  1148.  
  1149. //武器口角度
  1150. var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();
  1151.  
  1152. //先算武器口方向
  1153. var tempRotation = Utils.Random.RandomRangeFloat(-angle, angle);
  1154. var tempAngle = Mathf.RadToDeg(tempRotation);
  1155.  
  1156. //开火时枪口角度
  1157. var fireRotation = tempRotation;
  1158. //开火发射的子弹数量
  1159. var bulletCount = Utils.Random.RandomConfigRange(Attribute.FireBulletCountRange);
  1160. if (Master != null)
  1161. {
  1162. bulletCount = Master.RoleState.CalcBulletCount(bulletCount);
  1163. fireRotation += Master.MountPoint.RealRotation;
  1164. }
  1165. else
  1166. {
  1167. fireRotation += GlobalRotation;
  1168. }
  1169.  
  1170. //创建子弹
  1171. for (var i = 0; i < bulletCount; i++)
  1172. {
  1173. //发射子弹
  1174. OnShoot(fireRotation);
  1175. }
  1176.  
  1177. //开火添加散射值
  1178. ScatteringRangeAddHandler();
  1179. //武器的旋转角度
  1180. tempAngle -= Attribute.UpliftAngle;
  1181. _fireAngle = tempAngle;
  1182. if (Master != null) //被拾起
  1183. {
  1184. //武器身位置
  1185. var max = Mathf.Abs(Mathf.Max(Utils.GetConfigRangeStart(Attribute.BacklashRange), Utils.GetConfigRangeEnd(Attribute.BacklashRange)));
  1186. _currBacklashLength = Mathf.Clamp(
  1187. _currBacklashLength - Utils.Random.RandomConfigRange(Attribute.BacklashRange),
  1188. -max, max
  1189. );
  1190. Position = new Vector2(_currBacklashLength, 0).Rotated(Rotation);
  1191. RotationDegrees = tempAngle;
  1192. }
  1193. else //在地上
  1194. {
  1195. var v = Utils.Random.RandomConfigRange(Attribute.BacklashRange) * 5;
  1196. var externalForce = MoveController.AddForce(new Vector2(-v, 0).Rotated(Rotation));
  1197. externalForce.RotationSpeed = -Mathf.DegToRad(40);
  1198. externalForce.RotationResistance = Mathf.DegToRad(80);
  1199. }
  1200.  
  1201. if (IsInGround())
  1202. {
  1203. //在地上弹药打光
  1204. if (IsTotalAmmoEmpty())
  1205. {
  1206. //停止动画
  1207. AnimationPlayer.Stop();
  1208. //清除泛白效果
  1209. SetBlendSchedule(0);
  1210. }
  1211. }
  1212. }
  1213.  
  1214. // /// <summary>
  1215. // /// 触发武器的近战攻击
  1216. // /// </summary>
  1217. // public virtual void TriggerMeleeAttack(Role trigger)
  1218. // {
  1219. //
  1220. // }
  1221.  
  1222. /// <summary>
  1223. /// 根据触扳机的角色对象判断该角色使用的武器数据
  1224. /// </summary>
  1225. public ExcelConfig.WeaponBase GetUseAttribute(Role triggerRole)
  1226. {
  1227. if (triggerRole == null || !triggerRole.IsAi)
  1228. {
  1229. return PlayerUseAttribute;
  1230. }
  1231.  
  1232. return AiUseAttribute;
  1233. }
  1234. /// <summary>
  1235. /// 获取武器攻击的目标层级
  1236. /// </summary>
  1237. /// <returns></returns>
  1238. public uint GetAttackLayer()
  1239. {
  1240. if (TriggerRoleAttackLayer > 0)
  1241. {
  1242. return (uint)TriggerRoleAttackLayer;
  1243. }
  1244. return Master != null ? Master.AttackLayer : Role.DefaultAttackLayer;
  1245. }
  1246. /// <summary>
  1247. /// 返回弹药是否到达上限
  1248. /// </summary>
  1249. public bool IsAmmoFull()
  1250. {
  1251. return CurrAmmo + ResidueAmmo >= Attribute.MaxAmmoCapacity;
  1252. }
  1253.  
  1254. /// <summary>
  1255. /// 返回弹夹是否打空
  1256. /// </summary>
  1257. public bool IsAmmoEmpty()
  1258. {
  1259. return CurrAmmo == 0;
  1260. }
  1261. /// <summary>
  1262. /// 返回是否弹药耗尽
  1263. /// </summary>
  1264. public bool IsTotalAmmoEmpty()
  1265. {
  1266. return CurrAmmo + ResidueAmmo == 0;
  1267. }
  1268.  
  1269. /// <summary>
  1270. /// 强制修改当前弹夹弹药量
  1271. /// </summary>
  1272. public void SetCurrAmmo(int count)
  1273. {
  1274. CurrAmmo = Mathf.Clamp(count, 0, Attribute.AmmoCapacity);
  1275. }
  1276.  
  1277. /// <summary>
  1278. /// 强制修改备用弹药量
  1279. /// </summary>
  1280. public void SetResidueAmmo(int count)
  1281. {
  1282. ResidueAmmo = Mathf.Clamp(count, 0, Attribute.MaxAmmoCapacity - CurrAmmo);
  1283. }
  1284. /// <summary>
  1285. /// 强制修改弹药量, 优先改动备用弹药
  1286. /// </summary>
  1287. public void SetTotalAmmo(int total)
  1288. {
  1289. if (total < 0)
  1290. {
  1291. return;
  1292. }
  1293. var totalAmmo = CurrAmmo + ResidueAmmo;
  1294. if (totalAmmo == total)
  1295. {
  1296. return;
  1297. }
  1298. if (total > totalAmmo) //弹药增加
  1299. {
  1300. ResidueAmmo = Mathf.Min(total - CurrAmmo, Attribute.MaxAmmoCapacity - CurrAmmo);
  1301. }
  1302. else //弹药减少
  1303. {
  1304. if (CurrAmmo < total)
  1305. {
  1306. ResidueAmmo = total - CurrAmmo;
  1307. }
  1308. else
  1309. {
  1310. CurrAmmo = total;
  1311. ResidueAmmo = 0;
  1312. }
  1313. }
  1314. }
  1315.  
  1316. /// <summary>
  1317. /// 拾起的弹药数量, 如果到达容量上限, 则返回拾取完毕后剩余的弹药数量
  1318. /// </summary>
  1319. /// <param name="count">弹药数量</param>
  1320. private int PickUpAmmo(int count)
  1321. {
  1322. var num = ResidueAmmo;
  1323. ResidueAmmo = Mathf.Min(ResidueAmmo + count, Attribute.MaxAmmoCapacity - CurrAmmo);
  1324. return count - ResidueAmmo + num;
  1325. }
  1326.  
  1327. /// <summary>
  1328. /// 触发换弹
  1329. /// </summary>
  1330. public void Reload()
  1331. {
  1332. if (!Reloading && CurrAmmo < Attribute.AmmoCapacity && ResidueAmmo > 0 && _beLoadedState != 1)
  1333. {
  1334. Reloading = true;
  1335. _playReloadFinishSoundFlag = false;
  1336.  
  1337. //播放开始换弹音效
  1338. PlayBeginReloadSound();
  1339. // Debug.Log("开始换弹.");
  1340. //抛弹
  1341. if (!Attribute.ReloadThrowShell && !Attribute.ContinuousShoot &&
  1342. (_beLoadedState == 0 || _beLoadedState == -1) && Attribute.BeLoadedTime > 0)
  1343. {
  1344. ThrowShellHandler(0.6f);
  1345. }
  1346. //第一次换弹
  1347. OnBeginReload();
  1348.  
  1349. if (Attribute.AloneReload)
  1350. {
  1351. //单独换弹, 特殊处理
  1352. AloneReloadHandler();
  1353. }
  1354. else
  1355. {
  1356. //普通换弹处理
  1357. ReloadHandler();
  1358. }
  1359. //上膛标记完成
  1360. _beLoadedState = 2;
  1361. }
  1362. }
  1363.  
  1364. /// <summary>
  1365. /// 强制停止换弹, 或者结束换弹状态
  1366. /// </summary>
  1367. public void StopReload()
  1368. {
  1369. _aloneReloadState = 0;
  1370. if (_beLoadedState == -1)
  1371. {
  1372. _beLoadedState = 0;
  1373. }
  1374. else if (_beLoadedState == 1)
  1375. {
  1376. _beLoadedState = 2;
  1377. }
  1378.  
  1379. Reloading = false;
  1380. _reloadTimer = 0;
  1381. _reloadUseTime = 0;
  1382. }
  1383.  
  1384. /// <summary>
  1385. /// 触发上膛
  1386. /// </summary>
  1387. public void BeLoaded()
  1388. {
  1389. if (_beLoadedState > 0)
  1390. {
  1391. return;
  1392. }
  1393. //上膛抛弹
  1394. if (!Attribute.ReloadThrowShell && !Attribute.ContinuousShoot && Attribute.BeLoadedTime > 0)
  1395. {
  1396. ThrowShellHandler(0.6f);
  1397. }
  1398.  
  1399. //开始上膛
  1400. OnBeginBeLoaded();
  1401.  
  1402. //上膛时间为0, 直接结束上膛
  1403. if (Attribute.BeLoadedTime <= 0)
  1404. {
  1405. //直接上膛完成
  1406. _beLoadedState = 2;
  1407. OnBeLoadedFinish();
  1408. return;
  1409. }
  1410. //上膛中
  1411. _beLoadedState = 1;
  1412. _beLoadedStateTimer = Attribute.BeLoadedTime;
  1413. //播放上膛动画
  1414. if (IsAutoPlaySpriteFrames)
  1415. {
  1416. if (Attribute.BeLoadedSoundDelayTime <= 0)
  1417. {
  1418. PlaySpriteAnimation(AnimatorNames.BeLoaded);
  1419. PlayAnimationPlayer(AnimatorNames.BeLoaded);
  1420. }
  1421. else
  1422. {
  1423. this.CallDelay(Attribute.BeLoadedSoundDelayTime, () =>
  1424. {
  1425. PlaySpriteAnimation(AnimatorNames.BeLoaded);
  1426. PlayAnimationPlayer(AnimatorNames.BeLoaded);
  1427. });
  1428. }
  1429. }
  1430.  
  1431. //播放上膛音效
  1432. PlayBeLoadedSound();
  1433. }
  1434. //播放换弹开始音效
  1435. private void PlayBeginReloadSound()
  1436. {
  1437. if (Attribute.BeginReloadSound != null)
  1438. {
  1439. if (Attribute.BeginReloadSoundDelayTime <= 0)
  1440. {
  1441. SoundManager.PlaySoundByConfig(Attribute.BeginReloadSound, GlobalPosition, TriggerRole);
  1442. }
  1443. else
  1444. {
  1445. SoundManager.PlaySoundByConfigDelay(Attribute.BeginReloadSound, GlobalPosition, Attribute.BeginReloadSoundDelayTime, TriggerRole);
  1446. }
  1447. }
  1448. }
  1449. //播放换弹音效
  1450. private void PlayReloadSound()
  1451. {
  1452. if (Attribute.ReloadSound != null)
  1453. {
  1454. if (Attribute.ReloadSoundDelayTime <= 0)
  1455. {
  1456. SoundManager.PlaySoundByConfig(Attribute.ReloadSound, GlobalPosition, TriggerRole);
  1457. }
  1458. else
  1459. {
  1460. SoundManager.PlaySoundByConfigDelay(Attribute.ReloadSound, GlobalPosition, Attribute.ReloadSoundDelayTime, TriggerRole);
  1461. }
  1462. }
  1463. }
  1464. //播放换弹完成音效
  1465. private void PlayReloadFinishSound()
  1466. {
  1467. if (Attribute.ReloadFinishSound != null)
  1468. {
  1469. SoundManager.PlaySoundByConfig(Attribute.ReloadFinishSound, GlobalPosition, TriggerRole);
  1470. }
  1471. }
  1472.  
  1473. //播放射击音效
  1474. private void PlayShootSound()
  1475. {
  1476. if (Attribute.ShootSound != null)
  1477. {
  1478. SoundManager.PlaySoundByConfig(Attribute.ShootSound, GlobalPosition, TriggerRole);
  1479. }
  1480. }
  1481.  
  1482. //播放上膛音效
  1483. private void PlayBeLoadedSound()
  1484. {
  1485. if (Attribute.BeLoadedSound != null)
  1486. {
  1487. if (Attribute.BeLoadedSoundDelayTime <= 0)
  1488. {
  1489. SoundManager.PlaySoundByConfig(Attribute.BeLoadedSound, GlobalPosition, TriggerRole);
  1490. }
  1491. else
  1492. {
  1493. SoundManager.PlaySoundByConfigDelay(Attribute.BeLoadedSound, GlobalPosition, Attribute.BeLoadedSoundDelayTime, TriggerRole);
  1494. }
  1495. }
  1496. }
  1497.  
  1498. //执行上膛逻辑
  1499. private void RunBeLoaded()
  1500. {
  1501. if (Attribute.AutoManualBeLoaded)
  1502. {
  1503. if (_attackTimer <= 0)
  1504. {
  1505. //执行自动上膛
  1506. BeLoaded();
  1507. }
  1508. else if (CurrAmmo > 0)
  1509. {
  1510. //等待执行自动上膛
  1511. _beLoadedState = -1;
  1512. }
  1513. else
  1514. {
  1515. //没子弹了, 需要手动上膛
  1516. _beLoadedState = 0;
  1517. }
  1518. }
  1519. else
  1520. {
  1521. //手动上膛
  1522. _beLoadedState = 0;
  1523. }
  1524. }
  1525.  
  1526. //单独换弹处理
  1527. private void AloneReloadHandler()
  1528. {
  1529. if (Attribute.AloneReloadBeginIntervalTime <= 0)
  1530. {
  1531. //开始装第一颗子弹
  1532. _aloneReloadState = 2;
  1533. ReloadHandler();
  1534. }
  1535. else
  1536. {
  1537. _aloneReloadState = 1;
  1538. _reloadTimer = Attribute.AloneReloadBeginIntervalTime;
  1539. }
  1540. }
  1541.  
  1542. //换弹处理逻辑
  1543. private void ReloadHandler()
  1544. {
  1545. _reloadTimer = Attribute.ReloadTime;
  1546. //播放换弹动画
  1547. if (IsAutoPlaySpriteFrames)
  1548. {
  1549. PlaySpriteAnimation(AnimatorNames.Reloading);
  1550. PlayAnimationPlayer(AnimatorNames.Reloading);
  1551. }
  1552. //播放换弹音效
  1553. PlayReloadSound();
  1554. //抛出弹壳
  1555. if (Attribute.ReloadThrowShell && !_reloadShellFlag)
  1556. {
  1557. ThrowShellHandler(0.6f);
  1558. }
  1559. OnReload();
  1560. // Debug.Log("装弹.");
  1561. }
  1562. //换弹完成处理逻辑
  1563. private void ReloadFinishHandler()
  1564. {
  1565. // Debug.Log("装弹完成.");
  1566. if (_reloadNextAnimation != null)
  1567. {
  1568. AnimationPlayer.Play(_reloadNextAnimation);
  1569. _reloadNextAnimation = null;
  1570. }
  1571. OnReloadFinish();
  1572. }
  1573.  
  1574. //单独装弹完成
  1575. private void AloneReloadStateFinish()
  1576. {
  1577. // Debug.Log("单独装弹完成.");
  1578. OnAloneReloadStateFinish();
  1579. }
  1580.  
  1581. //抛弹逻辑
  1582. private void ThrowShellHandler(float speedScale)
  1583. {
  1584. var attribute = Attribute;
  1585. if (attribute.Shell == null)
  1586. {
  1587. return;
  1588. }
  1589. //创建一个弹壳
  1590. if (attribute.ThrowShellDelayTime > 0)
  1591. {
  1592. this.CallDelay(attribute.ThrowShellDelayTime, () =>
  1593. {
  1594. _reloadShellFlag = true;
  1595. for (var i = 0; i < attribute.ThrowShellCount; i++)
  1596. {
  1597. FireManager.ThrowShell(this, attribute.Shell, speedScale);
  1598. }
  1599. });
  1600. }
  1601. else if (attribute.ThrowShellDelayTime == 0)
  1602. {
  1603. _reloadShellFlag = true;
  1604. for (var i = 0; i < attribute.ThrowShellCount; i++)
  1605. {
  1606. FireManager.ThrowShell(this, attribute.Shell, speedScale);
  1607. }
  1608. }
  1609. }
  1610.  
  1611. //散射值消退处理
  1612. private void ScatteringRangeBackHandler(float delta)
  1613. {
  1614. var startScatteringRange = Attribute.StartScatteringRange;
  1615. var finalScatteringRange = Attribute.FinalScatteringRange;
  1616. if (Master != null)
  1617. {
  1618. startScatteringRange = Master.RoleState.CalcStartScattering(startScatteringRange);
  1619. finalScatteringRange = Master.RoleState.CalcFinalScattering(finalScatteringRange);
  1620. }
  1621. if (startScatteringRange <= finalScatteringRange)
  1622. {
  1623. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta,
  1624. startScatteringRange);
  1625. }
  1626. else
  1627. {
  1628. CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeBackSpeed * delta,
  1629. startScatteringRange);
  1630. }
  1631. }
  1632.  
  1633. //散射值添加处理
  1634. private void ScatteringRangeAddHandler()
  1635. {
  1636. var startScatteringRange = Attribute.StartScatteringRange;
  1637. var finalScatteringRange = Attribute.FinalScatteringRange;
  1638. if (Master != null)
  1639. {
  1640. startScatteringRange = Master.RoleState.CalcStartScattering(startScatteringRange);
  1641. finalScatteringRange = Master.RoleState.CalcFinalScattering(finalScatteringRange);
  1642. }
  1643. if (startScatteringRange <= finalScatteringRange)
  1644. {
  1645. CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue,
  1646. finalScatteringRange);
  1647. }
  1648. else
  1649. {
  1650. CurrScatteringRange = Mathf.Min(CurrScatteringRange - Attribute.ScatteringRangeAddValue,
  1651. finalScatteringRange);
  1652. }
  1653. }
  1654.  
  1655. //射速增加处理
  1656. private void FiringSpeedAddHandler(float delta)
  1657. {
  1658. if (Attribute.ContinuousShoot)
  1659. {
  1660. CurrentFiringSpeed = Mathf.MoveToward(CurrentFiringSpeed, Attribute.FinalFiringSpeed,
  1661. Attribute.FiringSpeedAddSpeed * delta);
  1662. }
  1663. else
  1664. {
  1665. CurrentFiringSpeed = Attribute.StartFiringSpeed;
  1666. }
  1667. }
  1668. //射速衰减处理
  1669. private void FiringSpeedBackHandler(float delta)
  1670. {
  1671. if (Attribute.ContinuousShoot)
  1672. {
  1673. CurrentFiringSpeed = Mathf.MoveToward(CurrentFiringSpeed, Attribute.StartFiringSpeed,
  1674. Attribute.FiringSpeedBackSpeed * delta);
  1675. }
  1676. else
  1677. {
  1678. CurrentFiringSpeed = Attribute.StartFiringSpeed;
  1679. }
  1680. }
  1681.  
  1682. /// <summary>
  1683. /// 换弹计时器时间到, 执行换弹操作
  1684. /// </summary>
  1685. private void ReloadSuccess()
  1686. {
  1687. if (Attribute.AloneReload) //单独装填
  1688. {
  1689. if (ResidueAmmo >= Attribute.AloneReloadCount) //剩余子弹充足
  1690. {
  1691. if (CurrAmmo + Attribute.AloneReloadCount <= Attribute.AmmoCapacity)
  1692. {
  1693. ResidueAmmo -= Attribute.AloneReloadCount;
  1694. CurrAmmo += Attribute.AloneReloadCount;
  1695. }
  1696. else //子弹满了
  1697. {
  1698. var num = Attribute.AmmoCapacity - CurrAmmo;
  1699. CurrAmmo = Attribute.AmmoCapacity;
  1700. ResidueAmmo -= num;
  1701. }
  1702. }
  1703. else if (ResidueAmmo != 0) //剩余子弹不足
  1704. {
  1705. if (ResidueAmmo + CurrAmmo <= Attribute.AmmoCapacity)
  1706. {
  1707. CurrAmmo += ResidueAmmo;
  1708. ResidueAmmo = 0;
  1709. }
  1710. else //子弹满了
  1711. {
  1712. var num = Attribute.AmmoCapacity - CurrAmmo;
  1713. CurrAmmo = Attribute.AmmoCapacity;
  1714. ResidueAmmo -= num;
  1715. }
  1716. }
  1717.  
  1718. if (!_aloneReloadStop && ResidueAmmo != 0 && CurrAmmo != Attribute.AmmoCapacity) //继续装弹
  1719. {
  1720. ReloadHandler();
  1721. }
  1722. }
  1723. else //换弹结束
  1724. {
  1725. if (CurrAmmo + ResidueAmmo >= Attribute.AmmoCapacity)
  1726. {
  1727. ResidueAmmo -= Attribute.AmmoCapacity - CurrAmmo;
  1728. CurrAmmo = Attribute.AmmoCapacity;
  1729. }
  1730. else
  1731. {
  1732. CurrAmmo += ResidueAmmo;
  1733. ResidueAmmo = 0;
  1734. }
  1735.  
  1736. StopReload();
  1737. ReloadFinishHandler();
  1738. }
  1739. }
  1740.  
  1741. //播放动画
  1742. private void PlayAnimationPlayer(string name)
  1743. {
  1744. if (AnimationPlayer != null && AnimationPlayer.HasAnimation(name))
  1745. {
  1746. AnimationPlayer.Play(name);
  1747. }
  1748. }
  1749.  
  1750. //帧动画播放结束
  1751. private void OnAnimatedSpriteFinished()
  1752. {
  1753. // Debug.Log("帧动画播放结束...");
  1754. AnimatedSprite.Play(AnimatorNames.Default);
  1755. }
  1756.  
  1757. //动画播放器播放结束
  1758. private void OnAnimationPlayerFinished(StringName name)
  1759. {
  1760. if (Master != null && !IsActive)
  1761. {
  1762. Master.OnPutBackMount(this, PackageIndex);
  1763. }
  1764. }
  1765.  
  1766. public override CheckInteractiveResult CheckInteractive(ActivityObject master)
  1767. {
  1768. var result = new CheckInteractiveResult(this);
  1769.  
  1770. if (master is Role roleMaster) //碰到角色
  1771. {
  1772. if (Master == null)
  1773. {
  1774. if (roleMaster.WeaponPack.Capacity == 0)
  1775. {
  1776. //容量为0
  1777. return result;
  1778. }
  1779. var masterWeapon = roleMaster.WeaponPack.ActiveItem;
  1780. //查找是否有同类型武器
  1781. var index = roleMaster.WeaponPack.FindIndex(ActivityBase.Id);
  1782. if (index != -1) //如果有这个武器
  1783. {
  1784. if (CurrAmmo + ResidueAmmo != 0) //子弹不为空
  1785. {
  1786. var targetWeapon = roleMaster.WeaponPack.GetItem(index);
  1787. if (!targetWeapon.IsAmmoFull()) //背包里面的武器子弹未满
  1788. {
  1789. //可以互动拾起弹药
  1790. result.CanInteractive = true;
  1791. result.Type = CheckInteractiveResult.InteractiveType.Bullet;
  1792. return result;
  1793. }
  1794. }
  1795. }
  1796. else //没有武器
  1797. {
  1798. if (roleMaster.WeaponPack.HasVacancy()) //有空位, 能拾起武器
  1799. {
  1800. //可以互动, 拾起武器
  1801. result.CanInteractive = true;
  1802. result.Type = CheckInteractiveResult.InteractiveType.PickUp;
  1803. return result;
  1804. }
  1805. else if (masterWeapon != null) //替换武器 // && masterWeapon.Attribute.WeightType == Attribute.WeightType)
  1806. {
  1807. //可以互动, 切换武器
  1808. result.CanInteractive = true;
  1809. result.Type = CheckInteractiveResult.InteractiveType.Replace;
  1810. return result;
  1811. }
  1812. }
  1813. }
  1814. }
  1815.  
  1816. return result;
  1817. }
  1818.  
  1819. public override void Interactive(ActivityObject master)
  1820. {
  1821. if (master is Role roleMaster) //与role互动
  1822. {
  1823. if (roleMaster.WeaponPack.Capacity == 0)
  1824. {
  1825. //容量为0
  1826. return;
  1827. }
  1828. var holster = roleMaster.WeaponPack;
  1829. //查找是否有同类型武器
  1830. var index = holster.FindIndex(ActivityBase.Id);
  1831. if (index != -1) //如果有这个武器
  1832. {
  1833. if (CurrAmmo + ResidueAmmo == 0) //没有子弹了
  1834. {
  1835. return;
  1836. }
  1837.  
  1838. var weapon = holster.GetItem(index);
  1839. //子弹上限
  1840. var maxCount = Attribute.MaxAmmoCapacity;
  1841. //是否捡到子弹
  1842. var flag = false;
  1843. if (ResidueAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount)
  1844. {
  1845. var count = weapon.PickUpAmmo(ResidueAmmo);
  1846. if (count != ResidueAmmo)
  1847. {
  1848. ResidueAmmo = count;
  1849. flag = true;
  1850. }
  1851. }
  1852.  
  1853. if (CurrAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount)
  1854. {
  1855. var count = weapon.PickUpAmmo(CurrAmmo);
  1856. if (count != CurrAmmo)
  1857. {
  1858. CurrAmmo = count;
  1859. flag = true;
  1860. }
  1861. }
  1862.  
  1863. //播放互动效果
  1864. if (flag)
  1865. {
  1866. Throw(GlobalPosition, 0, Utils.Random.RandomRangeInt(20, 50), Vector2.Zero, Utils.Random.RandomRangeInt(-180, 180));
  1867. //没有子弹了, 停止播放泛白效果
  1868. if (IsTotalAmmoEmpty())
  1869. {
  1870. //停止动画
  1871. AnimationPlayer.Stop();
  1872. //清除泛白效果
  1873. SetBlendSchedule(0);
  1874. }
  1875. }
  1876. }
  1877. else //没有武器
  1878. {
  1879. if (!holster.HasVacancy()) //没有空位置, 扔掉当前武器
  1880. {
  1881. //替换武器
  1882. roleMaster.ThrowWeapon();
  1883. }
  1884. roleMaster.PickUpWeapon(this);
  1885. }
  1886. }
  1887. }
  1888.  
  1889. /// <summary>
  1890. /// 获取当前武器真实的旋转角度(弧度制), 由于武器旋转时加入了旋转吸附, 所以需要通过该函数来来知道当前武器的真实旋转角度
  1891. /// </summary>
  1892. public float GetRealGlobalRotation()
  1893. {
  1894. return Mathf.DegToRad(Master.MountPoint.RealRotationDegrees) + Rotation;
  1895. }
  1896.  
  1897. /// <summary>
  1898. /// 触发扔掉武器时抛出的效果, 并不会管武器是否在武器背包中
  1899. /// </summary>
  1900. /// <param name="master">触发扔掉该武器的的角色</param>
  1901. public void ThrowWeapon(Role master)
  1902. {
  1903. ThrowWeapon(master, master.GlobalPosition);
  1904. }
  1905.  
  1906. /// <summary>
  1907. /// 触发扔掉武器时抛出的效果, 并不会管武器是否在武器背包中
  1908. /// </summary>
  1909. /// <param name="master">触发扔掉该武器的的角色</param>
  1910. /// <param name="startPosition">投抛起始位置</param>
  1911. public void ThrowWeapon(Role master, Vector2 startPosition)
  1912. {
  1913. //阴影偏移
  1914. ShadowOffset = new Vector2(0, 2);
  1915.  
  1916. if (master.Face == FaceDirection.Left)
  1917. {
  1918. Scale *= new Vector2(1, -1);
  1919. }
  1920.  
  1921. var rotation = master.MountPoint.GlobalRotation;
  1922. GlobalRotation = rotation;
  1923.  
  1924. if (master.Face == FaceDirection.Right)
  1925. {
  1926. startPosition += _gripPoint.Rotated(rotation);
  1927. }
  1928. else
  1929. {
  1930. startPosition += new Vector2(_gripPoint.X, -_gripPoint.Y).Rotated(rotation);
  1931. }
  1932.  
  1933. var startHeight = -master.MountPoint.Position.Y;
  1934. var velocity = new Vector2(20, 0).Rotated(rotation);
  1935. var yf = Utils.Random.RandomRangeInt(50, 70);
  1936. Throw(startPosition, startHeight, yf, velocity, 0);
  1937. //继承role的移动速度
  1938. InheritVelocity(master);
  1939. }
  1940.  
  1941. protected override void OnThrowStart()
  1942. {
  1943. //禁用碰撞
  1944. //Collision.Disabled = true;
  1945. //AnimationPlayer.Play(AnimatorNames.Floodlight);
  1946. }
  1947.  
  1948. protected override void OnThrowOver()
  1949. {
  1950. //启用碰撞
  1951. //Collision.Disabled = false;
  1952. //还有弹药, 播放泛白效果
  1953. if (!IsTotalAmmoEmpty())
  1954. {
  1955. AnimationPlayer.Play(AnimatorNames.Floodlight);
  1956. }
  1957. }
  1958.  
  1959. /// <summary>
  1960. /// 触发启用武器, 这个函数由 Holster 对象调用
  1961. /// </summary>
  1962. private void Active()
  1963. {
  1964. //调整阴影
  1965. //ShadowOffset = new Vector2(0, Master.GlobalPosition.Y - GlobalPosition.Y);
  1966. //ShadowOffset = new Vector2(0, -Master.MountPoint.Position.Y + 2);
  1967. ShadowOffset = new Vector2(0, -Master.MountPoint.Position.Y);
  1968. //枪口默认抬起角度
  1969. RotationDegrees = -Attribute.DefaultAngle;
  1970. ShowShadowSprite();
  1971. OnActive();
  1972. }
  1973.  
  1974. /// <summary>
  1975. /// 触发收起武器, 这个函数由 Holster 对象调用
  1976. /// </summary>
  1977. private void Conceal()
  1978. {
  1979. //停止换弹动画
  1980. if (AnimationPlayer.CurrentAnimation == AnimatorNames.Reloading && AnimationPlayer.IsPlaying())
  1981. {
  1982. AnimationPlayer.Play(AnimatorNames.Reset);
  1983. }
  1984. HideShadowSprite();
  1985. OnConceal();
  1986. }
  1987. public void OnRemoveItem()
  1988. {
  1989. //要重置部分重要属性属性
  1990. if (Master.IsAi)
  1991. {
  1992. _triggerTimer = 0;
  1993. }
  1994. GetParent().RemoveChild(this);
  1995. _triggerRoleFlag = false;
  1996. SetCurrentWeaponAttribute(_playerWeaponAttribute);
  1997. CollisionLayer = _tempLayer;
  1998.  
  1999. //精灵位置, 旋转中心点
  2000. AnimatedSprite.Position = Vector2.Zero;
  2001. AnimatedSprite.Offset = Vector2.Zero;
  2002. Collision.Position = _collPoint2;
  2003. //清除 Ai 拾起标记
  2004. RemoveSign(SignNames.AiFindWeaponSign);
  2005. //停止换弹
  2006. if (Reloading)
  2007. {
  2008. StopReload();
  2009. }
  2010. //停止换弹动画
  2011. if (AnimationPlayer.CurrentAnimation == AnimatorNames.Reloading && AnimationPlayer.IsPlaying())
  2012. {
  2013. AnimationPlayer.Play(AnimatorNames.Reset);
  2014. }
  2015. OnRemove(Master);
  2016. }
  2017.  
  2018. public void OnPickUpItem()
  2019. {
  2020. Pickup();
  2021. _triggerRoleFlag = true;
  2022. SetCurrentWeaponAttribute(Master.IsAi ? _aiWeaponAttribute : _playerWeaponAttribute);
  2023. //停止动画
  2024. AnimationPlayer.Stop();
  2025. //清除泛白效果
  2026. SetBlendSchedule(0);
  2027. ZIndex = 0;
  2028. //禁用碰撞
  2029. //Collision.Disabled = true;
  2030. AnimatedSprite.Position = _gripPoint;
  2031. AnimatedSprite.Offset = _gripOffset;
  2032. Collision.Position = _collPoint1;
  2033. //修改层级
  2034. _tempLayer = CollisionLayer;
  2035. CollisionLayer = PhysicsLayer.OnHand;
  2036. //清除 Ai 拾起标记
  2037. RemoveSign(SignNames.AiFindWeaponSign);
  2038. OnPickUp(Master);
  2039. }
  2040.  
  2041. public void OnActiveItem()
  2042. {
  2043. //更改父节点
  2044. var parent = GetParentOrNull<Node>();
  2045. if (parent == null)
  2046. {
  2047. Master.MountPoint.AddChild(this);
  2048. }
  2049. else if (parent != Master.MountPoint)
  2050. {
  2051. parent.RemoveChild(this);
  2052. Master.MountPoint.AddChild(this);
  2053. }
  2054.  
  2055. Position = Vector2.Zero;
  2056. Scale = Vector2.One;
  2057. RotationDegrees = 0;
  2058. Visible = true;
  2059. Active();
  2060. }
  2061.  
  2062. public void OnConcealItem()
  2063. {
  2064. var tempParent = GetParentOrNull<Node2D>();
  2065. if (tempParent != null)
  2066. {
  2067. tempParent.RemoveChild(this);
  2068. Master.BackMountPoint.AddChild(this);
  2069. Master.OnPutBackMount(this, PackageIndex);
  2070. Conceal();
  2071. }
  2072. }
  2073.  
  2074. public void OnOverflowItem()
  2075. {
  2076. Master.ThrowWeapon(PackageIndex);
  2077. }
  2078.  
  2079. /// <summary>
  2080. /// 获取相对于武器本地坐标的开火位置
  2081. /// </summary>
  2082. public Vector2 GetLocalFirePosition()
  2083. {
  2084. return AnimatedSprite.Position + FirePoint.Position;
  2085. }
  2086. /// <summary>
  2087. /// 获取相对于武器本地坐标的抛壳位置
  2088. /// </summary>
  2089. public Vector2 GetLocalShellPosition()
  2090. {
  2091. return AnimatedSprite.Position + ShellPoint.Position;
  2092. }
  2093.  
  2094. /// <summary>
  2095. /// 获取握把位置, 相当于武器的原点坐标
  2096. /// </summary>
  2097. public Vector2 GetGripPosition()
  2098. {
  2099. return _gripPoint + _gripOffset;
  2100. }
  2101.  
  2102. //设置当前使用的武器属性
  2103. private void SetCurrentWeaponAttribute(ExcelConfig.WeaponBase attr)
  2104. {
  2105. if (attr != _weaponAttribute)
  2106. {
  2107. _weaponAttribute = attr;
  2108. //重置开火速率
  2109. CurrentFiringSpeed = _weaponAttribute.StartFiringSpeed;
  2110. }
  2111. }
  2112.  
  2113. //-------------------------------- Ai相关 -----------------------------
  2114. /// <summary>
  2115. /// Ai调用, 触发扣动扳机, 并返回攻击状态
  2116. /// </summary>
  2117. public AiAttackEnum AiTriggerAttackState(AiAttackEnum prevState)
  2118. {
  2119. var chargeFinish = false;
  2120. if (prevState == AiAttackEnum.AttackCharge) //蓄力中
  2121. {
  2122. var enemy = (Enemy)Master;
  2123. if (!IsChargeFinish())
  2124. {
  2125. enemy.Attack();
  2126. return prevState;
  2127. }
  2128.  
  2129. chargeFinish = true;
  2130. enemy.LockingTime = 0;
  2131. }
  2132. AiAttackEnum flag;
  2133. if (IsTotalAmmoEmpty()) //当前武器弹药打空
  2134. {
  2135. //切换到有子弹的武器
  2136. var index = Master.WeaponPack.FindIndex((we, i) => !we.IsTotalAmmoEmpty());
  2137. if (index != -1)
  2138. {
  2139. flag = AiAttackEnum.ExchangeWeapon;
  2140. Master.WeaponPack.ExchangeByIndex(index);
  2141. }
  2142. else //所有子弹打光
  2143. {
  2144. flag = AiAttackEnum.NoAmmo;
  2145. }
  2146. }
  2147. else if (Reloading) //换弹中
  2148. {
  2149. flag = AiAttackEnum.TriggerReload;
  2150. }
  2151. else if (IsAmmoEmpty()) //弹夹已经打空
  2152. {
  2153. flag = AiAttackEnum.Reloading;
  2154. Reload();
  2155. }
  2156. else if (_beLoadedState == 0 || _beLoadedState == -1) //需要上膛
  2157. {
  2158. flag = AiAttackEnum.AttackInterval;
  2159. if (_attackTimer <= 0)
  2160. {
  2161. BeLoaded();
  2162. }
  2163. }
  2164. else if (_beLoadedState == 1) //上膛中
  2165. {
  2166. flag = AiAttackEnum.AttackInterval;
  2167. }
  2168. else if (_continuousCount >= 1 && (!chargeFinish || _continuousCount >= 2)) //连发中
  2169. {
  2170. flag = AiAttackEnum.Attack;
  2171. }
  2172. else if (IsAttackIntervalTime()) //开火间隙
  2173. {
  2174. flag = AiAttackEnum.AttackInterval;
  2175. }
  2176. else
  2177. {
  2178. var enemy = (Enemy)Master;
  2179. if (enemy.LockTargetTime >= Attribute.AiAttackAttr.LockingTime) //正常射击
  2180. {
  2181. if (GetDelayedAttackTime() > 0)
  2182. {
  2183. flag = AiAttackEnum.Attack;
  2184. enemy.Attack();
  2185. if (_attackFlag) //成功触发攻击
  2186. {
  2187. enemy.LockingTime = 0;
  2188. }
  2189. }
  2190. else
  2191. {
  2192. if (Attribute.ContinuousShoot) //连发
  2193. {
  2194. flag = AiAttackEnum.Attack;
  2195. enemy.Attack();
  2196. if (_attackFlag) //成功触发攻击
  2197. {
  2198. enemy.LockingTime = 0;
  2199. }
  2200. }
  2201. else //单发
  2202. {
  2203. if (Attribute.LooseShoot && Attribute.MinChargeTime > 0) //松发并蓄力攻击
  2204. {
  2205. flag = AiAttackEnum.AttackCharge;
  2206. enemy.Attack();
  2207. }
  2208. else
  2209. {
  2210. flag = AiAttackEnum.Attack;
  2211. enemy.Attack();
  2212. if (_attackFlag && _attackTimer > 0) //成功触发攻击
  2213. {
  2214. enemy.LockingTime = 0;
  2215. }
  2216. }
  2217. }
  2218. }
  2219. }
  2220. else //锁定时间没到
  2221. {
  2222. flag = AiAttackEnum.LockingTime;
  2223. }
  2224. }
  2225.  
  2226. return flag;
  2227. }
  2228.  
  2229. // /// <summary>
  2230. // /// 获取 Ai 对于该武器的评分, 评分越高, 代表 Ai 会越优先选择该武器, 如果为 -1, 则表示 Ai 不会使用该武器
  2231. // /// </summary>
  2232. // public float GetAiScore()
  2233. // {
  2234. // return 1;
  2235. // }
  2236. }