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