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