Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / item / weapon / Weapon.cs
  1. using Godot;
  2. using System;
  3. using System.Collections.Generic;
  4.  
  5. /// <summary>
  6. /// 武器的基类
  7. /// </summary>
  8. public abstract partial class Weapon : ActivityObject
  9. {
  10. /// <summary>
  11. /// 开火回调事件
  12. /// </summary>
  13. public event Action<Weapon> FireEvent;
  14.  
  15. /// <summary>
  16. /// 武器属性数据
  17. /// </summary>
  18. public WeaponAttribute Attribute => _weaponAttribute;
  19.  
  20. private WeaponAttribute _weaponAttribute;
  21. private WeaponAttribute _originWeaponAttribute;
  22.  
  23. /// <summary>
  24. /// 武器攻击的目标阵营
  25. /// </summary>
  26. public CampEnum TargetCamp { get; set; }
  27.  
  28. /// <summary>
  29. /// 该武器的拥有者
  30. /// </summary>
  31. public Role Master { get; private set; }
  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.  
  43. /// <summary>
  44. /// 武器管的开火点
  45. /// </summary>
  46. public Marker2D FirePoint { get; private set; }
  47.  
  48. /// <summary>
  49. /// 武器管的原点
  50. /// </summary>
  51. public Marker2D OriginPoint { get; private set; }
  52.  
  53. /// <summary>
  54. /// 弹壳抛出的点
  55. /// </summary>
  56. public Marker2D ShellPoint { get; private set; }
  57.  
  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. /// 换弹计时器
  71. /// </summary>
  72. public float ReloadTimer { get; private set; } = 0;
  73.  
  74. /// <summary>
  75. /// 换弹进度 (0 - 1)
  76. /// </summary>
  77. public float ReloadProgress
  78. {
  79. get
  80. {
  81. if (Attribute.AloneReload)
  82. {
  83. var num = 1f / Attribute.AmmoCapacity;
  84. return num * (Attribute.AmmoCapacity - CurrAmmo - 1) + num * (ReloadTimer / Attribute.ReloadTime);
  85. }
  86.  
  87. return ReloadTimer / Attribute.ReloadTime;
  88. }
  89. }
  90.  
  91. /// <summary>
  92. /// 返回是否在蓄力中,
  93. /// 注意, 属性仅在 Attribute.LooseShoot == false 时有正确的返回值, 否则返回 false
  94. /// </summary>
  95. public bool IsCharging => _looseShootFlag;
  96.  
  97. /// <summary>
  98. /// 返回武器是否在武器袋中
  99. /// </summary>
  100. public bool IsInHolster => Master != null;
  101.  
  102. /// <summary>
  103. /// 返回是否真正使用该武器
  104. /// </summary>
  105. public bool IsActive => Master != null && Master.Holster.ActiveWeapon == this;
  106. /// <summary>
  107. /// 动画播放器
  108. /// </summary>
  109. public AnimationPlayer AnimationPlayer { get; private set; }
  110.  
  111.  
  112. //--------------------------------------------------------------------------------------------
  113. //是否按下
  114. private bool _triggerFlag = false;
  115.  
  116. //扳机计时器
  117. private float _triggerTimer = 0;
  118.  
  119. //开火前延时时间
  120. private float _delayedTime = 0;
  121.  
  122. //开火间隙时间
  123. private float _fireInterval = 0;
  124.  
  125. //开火武器口角度
  126. private float _fireAngle = 0;
  127.  
  128. //攻击冷却计时
  129. private float _attackTimer = 0;
  130.  
  131. //攻击状态
  132. private bool _attackFlag = false;
  133.  
  134. //按下的时间
  135. private float _downTimer = 0;
  136.  
  137. //松开的时间
  138. private float _upTimer = 0;
  139.  
  140. //连发次数
  141. private float _continuousCount = 0;
  142.  
  143. //连发状态记录
  144. private bool _continuousShootFlag = false;
  145.  
  146. //松开扳机是否开火
  147. private bool _looseShootFlag = false;
  148.  
  149. //蓄力攻击时长
  150. private float _chargeTime = 0;
  151.  
  152. //是否需要重置武器数据
  153. private bool _dirtyFlag = false;
  154.  
  155. //当前后坐力导致的偏移长度
  156. private float _currBacklashLength = 0;
  157. // ----------------------------------------------
  158. private uint _tempLayer;
  159.  
  160. /// <summary>
  161. /// 初始化武器属性
  162. /// </summary>
  163. public void InitWeapon(WeaponAttribute attribute)
  164. {
  165. _originWeaponAttribute = attribute;
  166. _weaponAttribute = attribute;
  167.  
  168. AnimationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
  169. FirePoint = GetNode<Marker2D>("FirePoint");
  170. OriginPoint = GetNode<Marker2D>("OriginPoint");
  171. ShellPoint = GetNode<Marker2D>("ShellPoint");
  172.  
  173. //图标
  174. SetDefaultTexture(ResourceLoader.Load<Texture2D>(Attribute.Sprite2D));
  175. AnimatedSprite.Position = Attribute.CenterPosition;
  176.  
  177. //开火位置
  178. FirePoint.Position = new Vector2(Attribute.FirePosition.X, -Attribute.FirePosition.Y);
  179. OriginPoint.Position = new Vector2(0, -Attribute.FirePosition.Y);
  180.  
  181. if (Attribute.AmmoCapacity > Attribute.MaxAmmoCapacity)
  182. {
  183. Attribute.AmmoCapacity = Attribute.MaxAmmoCapacity;
  184. GD.PrintErr("弹夹的容量不能超过弹药上限, 武器id: " + ItemId);
  185. }
  186. //弹药量
  187. CurrAmmo = Attribute.AmmoCapacity;
  188. //剩余弹药量
  189. ResidueAmmo = Mathf.Min(Attribute.StandbyAmmoCapacity + CurrAmmo, Attribute.MaxAmmoCapacity) - CurrAmmo;
  190. ThrowCollisionSize = new Vector2(20, 15);
  191. }
  192.  
  193. /// <summary>
  194. /// 单次开火时调用的函数
  195. /// </summary>
  196. protected abstract void OnFire();
  197.  
  198. /// <summary>
  199. /// 发射子弹时调用的函数, 每发射一枚子弹调用一次,
  200. /// 如果做霰弹武器效果, 一次开火发射5枚子弹, 则该函数调用5次
  201. /// </summary>
  202. /// <param name="fireRotation">开火时枪口旋转角度</param>
  203. protected abstract void OnShoot(float fireRotation);
  204. /// <summary>
  205. /// 当按下扳机时调用
  206. /// </summary>
  207. protected virtual void OnDownTrigger()
  208. {
  209. }
  210.  
  211. /// <summary>
  212. /// 当松开扳机时调用
  213. /// </summary>
  214. protected virtual void OnUpTrigger()
  215. {
  216. }
  217.  
  218. /// <summary>
  219. /// 开始蓄力时调用,
  220. /// 注意, 该函数仅在 Attribute.LooseShoot == false 时才能被调用
  221. /// </summary>
  222. protected virtual void OnStartCharge()
  223. {
  224. }
  225.  
  226. /// <summary>
  227. /// 当开始换弹时调用
  228. /// </summary>
  229. protected virtual void OnReload()
  230. {
  231. }
  232.  
  233. /// <summary>
  234. /// 当换弹完成时调用
  235. /// </summary>
  236. protected virtual void OnReloadFinish()
  237. {
  238. }
  239.  
  240. /// <summary>
  241. /// 当武器被拾起时调用
  242. /// </summary>
  243. /// <param name="master">拾起该武器的角色</param>
  244. protected virtual void OnPickUp(Role master)
  245. {
  246. }
  247.  
  248. /// <summary>
  249. /// 当武器从武器袋中移除时调用
  250. /// </summary>
  251. protected virtual void OnRemove()
  252. {
  253. }
  254.  
  255. /// <summary>
  256. /// 当武器被激活时调用, 也就是使用当武器时调用
  257. /// </summary>
  258. protected virtual void OnActive()
  259. {
  260. }
  261.  
  262. /// <summary>
  263. /// 当武器被收起时调用
  264. /// </summary>
  265. protected virtual void OnConceal()
  266. {
  267. }
  268.  
  269. /// <summary>
  270. /// 射击时调用, 返回消耗弹药数量, 默认为1, 如果返回为 0, 则不消耗弹药
  271. /// </summary>
  272. protected virtual int UseAmmoCount()
  273. {
  274. return 1;
  275. }
  276.  
  277. public override void _EnterTree()
  278. {
  279. base._EnterTree();
  280.  
  281. //收集落在地上的武器
  282. if (IsInGround())
  283. {
  284. World.Weapon_UnclaimedWeapons.Add(this);
  285. }
  286. }
  287.  
  288. public override void _ExitTree()
  289. {
  290. base._ExitTree();
  291. World.Weapon_UnclaimedWeapons.Remove(this);
  292. }
  293.  
  294. protected override void Process(float delta)
  295. {
  296. //这把武器被扔在地上, 或者当前武器没有被使用
  297. if (Master == null || Master.Holster.ActiveWeapon != this)
  298. {
  299. //_triggerTimer
  300. _triggerTimer = _triggerTimer > 0 ? _triggerTimer - delta : 0;
  301. //攻击冷却计时
  302. _attackTimer = _attackTimer > 0 ? _attackTimer - delta : 0;
  303. //武器的当前散射半径
  304. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta,
  305. Attribute.StartScatteringRange);
  306. //松开扳机
  307. if (_triggerFlag || _downTimer > 0)
  308. {
  309. UpTrigger();
  310. _downTimer = 0;
  311. }
  312. _triggerFlag = false;
  313.  
  314. //重置数据
  315. if (_dirtyFlag)
  316. {
  317. _dirtyFlag = false;
  318. Reloading = false;
  319. ReloadTimer = 0;
  320. _attackFlag = false;
  321. _continuousCount = 0;
  322. _delayedTime = 0;
  323. _upTimer = 0;
  324. _looseShootFlag = false;
  325. _chargeTime = 0;
  326. }
  327. }
  328. else //正在使用中
  329. {
  330. _dirtyFlag = true;
  331. //换弹
  332. if (Reloading)
  333. {
  334. ReloadTimer -= delta;
  335. if (ReloadTimer <= 0)
  336. {
  337. ReloadSuccess();
  338. }
  339. }
  340.  
  341. // 攻击的计时器
  342. if (_attackTimer > 0)
  343. {
  344. _attackTimer -= delta;
  345. if (_attackTimer < 0)
  346. {
  347. _delayedTime += _attackTimer;
  348. _attackTimer = 0;
  349. //枪口默认角度
  350. RotationDegrees = -Attribute.DefaultAngle;
  351. }
  352. }
  353. else if (_delayedTime > 0) //攻击延时
  354. {
  355. _delayedTime -= delta;
  356. if (_attackTimer < 0)
  357. {
  358. _delayedTime = 0;
  359. }
  360. }
  361. //扳机判定
  362. if (_triggerFlag)
  363. {
  364. if (_looseShootFlag) //蓄力时长
  365. {
  366. _chargeTime += delta;
  367. }
  368.  
  369. _downTimer += delta;
  370. if (_upTimer > 0) //第一帧按下扳机
  371. {
  372. DownTrigger();
  373. _upTimer = 0;
  374. }
  375. }
  376. else
  377. {
  378. _upTimer += delta;
  379. if (_downTimer > 0) //第一帧松开扳机
  380. {
  381. UpTrigger();
  382. _downTimer = 0;
  383. }
  384. }
  385.  
  386. //连发判断
  387. if (!_looseShootFlag && _continuousCount > 0 && _delayedTime <= 0 && _attackTimer <= 0)
  388. {
  389. //连发开火
  390. TriggerFire();
  391. }
  392.  
  393. if (!_attackFlag && _attackTimer <= 0)
  394. {
  395. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta,
  396. Attribute.StartScatteringRange);
  397. }
  398.  
  399. _triggerTimer = _triggerTimer > 0 ? _triggerTimer - delta : 0;
  400. _triggerFlag = false;
  401. _attackFlag = false;
  402. //武器身回归
  403. //Position = Position.MoveToward(Vector2.Zero, Attribute.BacklashRegressionSpeed * delta).Rotated(Rotation);
  404. _currBacklashLength = Mathf.MoveToward(_currBacklashLength, 0, Attribute.BacklashRegressionSpeed * delta);
  405. Position = new Vector2(_currBacklashLength, 0).Rotated(Rotation);
  406. if (_attackTimer > 0)
  407. {
  408. RotationDegrees = Mathf.Lerp(
  409. _fireAngle, -Attribute.DefaultAngle,
  410. Mathf.Clamp((_fireInterval - _attackTimer) * Attribute.UpliftAngleRestore / _fireInterval, 0, 1)
  411. );
  412. }
  413. }
  414. }
  415.  
  416. /// <summary>
  417. /// 返回武器是否在地上
  418. /// </summary>
  419. /// <returns></returns>
  420. public bool IsInGround()
  421. {
  422. return Master == null && GetParent() == GameApplication.Instance.World.NormalLayer;
  423. }
  424. /// <summary>
  425. /// 扳机函数, 调用即视为按下扳机
  426. /// </summary>
  427. public void Trigger()
  428. {
  429. //这一帧已经按过了, 不需要再按下
  430. if (_triggerFlag) return;
  431. //是否第一帧按下
  432. var justDown = _downTimer == 0;
  433. //是否能发射
  434. var flag = false;
  435. if (_continuousCount <= 0) //不能处于连发状态下
  436. {
  437. if (Attribute.ContinuousShoot) //自动射击
  438. {
  439. if (_triggerTimer > 0)
  440. {
  441. if (_continuousShootFlag)
  442. {
  443. flag = true;
  444. }
  445. }
  446. else
  447. {
  448. flag = true;
  449. if (_delayedTime <= 0 && _attackTimer <= 0)
  450. {
  451. _continuousShootFlag = true;
  452. }
  453. }
  454. }
  455. else //半自动
  456. {
  457. if (justDown && _triggerTimer <= 0 && _attackTimer <= 0)
  458. {
  459. flag = true;
  460. }
  461. }
  462. }
  463.  
  464. if (flag)
  465. {
  466. var fireFlag = true; //是否能开火
  467. if (Reloading) //换弹中
  468. {
  469. if (CurrAmmo > 0 && Attribute.AloneReload && Attribute.AloneReloadCanShoot) //立即停止换弹
  470. {
  471. Reloading = false;
  472. ReloadTimer = 0;
  473. }
  474. else
  475. {
  476. fireFlag = false;
  477. }
  478. }
  479. else if (CurrAmmo <= 0) //子弹不够
  480. {
  481. fireFlag = false;
  482. if (justDown)
  483. {
  484. //第一帧按下, 触发换弹
  485. Reload();
  486. }
  487. }
  488.  
  489. if (fireFlag)
  490. {
  491. if (justDown)
  492. {
  493. //开火前延时
  494. _delayedTime = Attribute.DelayedTime;
  495. //扳机按下间隔
  496. _triggerTimer = Attribute.TriggerInterval;
  497. //连发数量
  498. if (!Attribute.ContinuousShoot)
  499. {
  500. _continuousCount =
  501. Utils.RandomRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount);
  502. }
  503. }
  504.  
  505. if (_delayedTime <= 0 && _attackTimer <= 0)
  506. {
  507. if (Attribute.LooseShoot) //松发开火
  508. {
  509. _looseShootFlag = true;
  510. OnStartCharge();
  511. }
  512. else
  513. {
  514. //开火
  515. TriggerFire();
  516. }
  517. }
  518.  
  519. _attackFlag = true;
  520. }
  521.  
  522. }
  523.  
  524. _triggerFlag = true;
  525. }
  526.  
  527. /// <summary>
  528. /// 返回是否按下扳机
  529. /// </summary>
  530. public bool IsPressTrigger()
  531. {
  532. return _triggerFlag;
  533. }
  534. /// <summary>
  535. /// 获取本次扳机按下的时长, 单位: 秒
  536. /// </summary>
  537. public float GetTriggerDownTime()
  538. {
  539. return _downTimer;
  540. }
  541.  
  542. /// <summary>
  543. /// 获取扳机蓄力时长, 计算按下扳机后从可以开火到当前一共经过了多长时间, 可用于计算蓄力攻击
  544. /// 注意, 该函数仅在 Attribute.LooseShoot == false 时有正确的返回值, 否则返回 0
  545. /// </summary>
  546. public float GetTriggerChargeTime()
  547. {
  548. return _chargeTime;
  549. }
  550. /// <summary>
  551. /// 获取延时射击倒计时, 单位: 秒
  552. /// </summary>
  553. public float GetDelayedAttackTime()
  554. {
  555. return _delayedTime;
  556. }
  557. /// <summary>
  558. /// 刚按下扳机
  559. /// </summary>
  560. private void DownTrigger()
  561. {
  562. OnDownTrigger();
  563. }
  564.  
  565. /// <summary>
  566. /// 刚松开扳机
  567. /// </summary>
  568. private void UpTrigger()
  569. {
  570. _continuousShootFlag = false;
  571. if (_delayedTime > 0)
  572. {
  573. _continuousCount = 0;
  574. }
  575.  
  576. //松发开火执行
  577. if (_looseShootFlag)
  578. {
  579. _looseShootFlag = false;
  580. if (_chargeTime >= Attribute.MinChargeTime) //判断蓄力是否够了
  581. {
  582. TriggerFire();
  583. }
  584. else //不能攻击
  585. {
  586. _continuousCount = 0;
  587. }
  588. _chargeTime = 0;
  589. }
  590.  
  591. OnUpTrigger();
  592. }
  593.  
  594. /// <summary>
  595. /// 触发开火
  596. /// </summary>
  597. private void TriggerFire()
  598. {
  599. _continuousCount = _continuousCount > 0 ? _continuousCount - 1 : 0;
  600.  
  601. //减子弹数量
  602. if (_originWeaponAttribute != _weaponAttribute) //Ai使用该武器, 有一定概率不消耗弹药
  603. {
  604. if (Utils.RandomRangeFloat(0, 1) < _weaponAttribute.AiAmmoConsumptionProbability) //触发消耗弹药
  605. {
  606. CurrAmmo -= UseAmmoCount();
  607. }
  608. }
  609. else
  610. {
  611. CurrAmmo -= UseAmmoCount();
  612. }
  613.  
  614. //开火间隙
  615. _fireInterval = 60 / Attribute.StartFiringSpeed;
  616. //攻击冷却
  617. _attackTimer += _fireInterval;
  618.  
  619. //触发开火函数
  620. OnFire();
  621.  
  622. //开火发射的子弹数量
  623. var bulletCount = Utils.RandomRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount);
  624. //武器口角度
  625. var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();
  626.  
  627. //先算武器口方向
  628. var tempRotation = Utils.RandomRangeFloat(-angle, angle);
  629. var tempAngle = Mathf.RadToDeg(tempRotation);
  630.  
  631. //开火时枪口角度
  632. var fireRotation = Mathf.DegToRad(Master.MountPoint.RealAngle) + tempRotation;
  633. //创建子弹
  634. for (int i = 0; i < bulletCount; i++)
  635. {
  636. //发射子弹
  637. OnShoot(fireRotation);
  638. }
  639.  
  640. //当前的散射半径
  641. CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue,
  642. Attribute.FinalScatteringRange);
  643. //武器的旋转角度
  644. tempAngle -= Attribute.UpliftAngle;
  645. RotationDegrees = tempAngle;
  646. _fireAngle = tempAngle;
  647. //武器身位置
  648. var max = Mathf.Abs(Mathf.Max(Attribute.MaxBacklash, Attribute.MinBacklash));
  649. _currBacklashLength = Mathf.Clamp(
  650. _currBacklashLength - Utils.RandomRangeFloat(Attribute.MinBacklash, Attribute.MaxBacklash),
  651. -max, max
  652. );
  653. Position = new Vector2(_currBacklashLength, 0).Rotated(Rotation);
  654.  
  655. if (FireEvent != null)
  656. {
  657. FireEvent(this);
  658. }
  659. }
  660.  
  661. /// <summary>
  662. /// 获取武器攻击的目标层级
  663. /// </summary>
  664. /// <returns></returns>
  665. public uint GetAttackLayer()
  666. {
  667. return Master != null ? Master.AttackLayer : Role.DefaultAttackLayer;
  668. }
  669. /// <summary>
  670. /// 返回弹药是否到达上限
  671. /// </summary>
  672. public bool IsAmmoFull()
  673. {
  674. return CurrAmmo + ResidueAmmo >= Attribute.MaxAmmoCapacity;
  675. }
  676.  
  677. /// <summary>
  678. /// 返回弹夹是否打空
  679. /// </summary>
  680. public bool IsAmmoEmpty()
  681. {
  682. return CurrAmmo == 0;
  683. }
  684. /// <summary>
  685. /// 返回是否弹药耗尽
  686. /// </summary>
  687. public bool IsTotalAmmoEmpty()
  688. {
  689. return CurrAmmo + ResidueAmmo == 0;
  690. }
  691.  
  692. /// <summary>
  693. /// 强制修改当前弹夹弹药量
  694. /// </summary>
  695. public void SetCurrAmmo(int count)
  696. {
  697. CurrAmmo = Mathf.Clamp(count, 0, Attribute.AmmoCapacity);
  698. }
  699.  
  700. /// <summary>
  701. /// 强制修改备用弹药量
  702. /// </summary>
  703. public void SetResidueAmmo(int count)
  704. {
  705. ResidueAmmo = Mathf.Clamp(count, 0, Attribute.MaxAmmoCapacity - CurrAmmo);
  706. }
  707. /// <summary>
  708. /// 强制修改弹药量, 优先改动备用弹药
  709. /// </summary>
  710. public void SetTotalAmmo(int total)
  711. {
  712. if (total < 0)
  713. {
  714. return;
  715. }
  716. var totalAmmo = CurrAmmo + ResidueAmmo;
  717. if (totalAmmo == total)
  718. {
  719. return;
  720. }
  721. if (total > totalAmmo) //弹药增加
  722. {
  723. ResidueAmmo = Mathf.Min(total - CurrAmmo, Attribute.MaxAmmoCapacity - CurrAmmo);
  724. }
  725. else //弹药减少
  726. {
  727. if (CurrAmmo < total)
  728. {
  729. ResidueAmmo = total - CurrAmmo;
  730. }
  731. else
  732. {
  733. CurrAmmo = total;
  734. ResidueAmmo = 0;
  735. }
  736. }
  737. }
  738.  
  739. /// <summary>
  740. /// 拾起的弹药数量, 如果到达容量上限, 则返回拾取完毕后剩余的弹药数量
  741. /// </summary>
  742. /// <param name="count">弹药数量</param>
  743. private int PickUpAmmo(int count)
  744. {
  745. var num = ResidueAmmo;
  746. ResidueAmmo = Mathf.Min(ResidueAmmo + count, Attribute.MaxAmmoCapacity - CurrAmmo);
  747. return count - ResidueAmmo + num;
  748. }
  749.  
  750. /// <summary>
  751. /// 触发换弹
  752. /// </summary>
  753. public void Reload()
  754. {
  755. if (CurrAmmo < Attribute.AmmoCapacity && ResidueAmmo > 0 && !Reloading)
  756. {
  757. Reloading = true;
  758. ReloadTimer = Attribute.ReloadTime;
  759. OnReload();
  760. }
  761. }
  762.  
  763. /// <summary>
  764. /// 换弹计时器时间到, 执行换弹操作
  765. /// </summary>
  766. private void ReloadSuccess()
  767. {
  768. if (Attribute.AloneReload) //单独装填
  769. {
  770. if (ResidueAmmo >= Attribute.AloneReloadCount) //剩余子弹充足
  771. {
  772. if (CurrAmmo + Attribute.AloneReloadCount <= Attribute.AmmoCapacity)
  773. {
  774. ResidueAmmo -= Attribute.AloneReloadCount;
  775. CurrAmmo += Attribute.AloneReloadCount;
  776. }
  777. else //子弹满了
  778. {
  779. var num = Attribute.AmmoCapacity - CurrAmmo;
  780. CurrAmmo = Attribute.AmmoCapacity;
  781. ResidueAmmo -= num;
  782. }
  783. }
  784. else if (ResidueAmmo != 0) //剩余子弹不足
  785. {
  786. if (ResidueAmmo + CurrAmmo <= Attribute.AmmoCapacity)
  787. {
  788. CurrAmmo += ResidueAmmo;
  789. ResidueAmmo = 0;
  790. }
  791. else //子弹满了
  792. {
  793. var num = Attribute.AmmoCapacity - CurrAmmo;
  794. CurrAmmo = Attribute.AmmoCapacity;
  795. ResidueAmmo -= num;
  796. }
  797. }
  798.  
  799. if (ResidueAmmo == 0 || CurrAmmo == Attribute.AmmoCapacity) //换弹结束
  800. {
  801. Reloading = false;
  802. ReloadTimer = 0;
  803. OnReloadFinish();
  804. }
  805. else
  806. {
  807. ReloadTimer = Attribute.ReloadTime;
  808. OnReload();
  809. }
  810. }
  811. else //换弹结束
  812. {
  813. if (CurrAmmo + ResidueAmmo >= Attribute.AmmoCapacity)
  814. {
  815. ResidueAmmo -= Attribute.AmmoCapacity - CurrAmmo;
  816. CurrAmmo = Attribute.AmmoCapacity;
  817. }
  818. else
  819. {
  820. CurrAmmo += ResidueAmmo;
  821. ResidueAmmo = 0;
  822. }
  823.  
  824. Reloading = false;
  825. ReloadTimer = 0;
  826. OnReloadFinish();
  827. }
  828. }
  829.  
  830. public override CheckInteractiveResult CheckInteractive(ActivityObject master)
  831. {
  832. var result = new CheckInteractiveResult(this);
  833.  
  834. if (master is Role roleMaster) //碰到角色
  835. {
  836. if (Master == null)
  837. {
  838. var masterWeapon = roleMaster.Holster.ActiveWeapon;
  839. //查找是否有同类型武器
  840. var index = roleMaster.Holster.FindWeapon(ItemId);
  841. if (index != -1) //如果有这个武器
  842. {
  843. if (CurrAmmo + ResidueAmmo != 0) //子弹不为空
  844. {
  845. var targetWeapon = roleMaster.Holster.GetWeapon(index);
  846. if (!targetWeapon.IsAmmoFull()) //背包里面的武器子弹未满
  847. {
  848. //可以互动拾起弹药
  849. result.CanInteractive = true;
  850. result.Message = Attribute.Name;
  851. result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_bullet_png;
  852. return result;
  853. }
  854. }
  855. }
  856. else //没有武器
  857. {
  858. if (roleMaster.Holster.CanPickupWeapon(this)) //能拾起武器
  859. {
  860. //可以互动, 拾起武器
  861. result.CanInteractive = true;
  862. result.Message = Attribute.Name;
  863. result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_pickup_png;
  864. return result;
  865. }
  866. else if (masterWeapon != null && masterWeapon.Attribute.WeightType == Attribute.WeightType) //替换武器
  867. {
  868. //可以互动, 切换武器
  869. result.CanInteractive = true;
  870. result.Message = Attribute.Name;
  871. result.ShowIcon = ResourcePath.resource_sprite_ui_icon_icon_replace_png;
  872. return result;
  873. }
  874. }
  875. }
  876. }
  877.  
  878. return result;
  879. }
  880.  
  881. public override void Interactive(ActivityObject master)
  882. {
  883. if (master is Role roleMaster) //与role互动
  884. {
  885. var holster = roleMaster.Holster;
  886. //查找是否有同类型武器
  887. var index = holster.FindWeapon(ItemId);
  888. if (index != -1) //如果有这个武器
  889. {
  890. if (CurrAmmo + ResidueAmmo == 0) //没有子弹了
  891. {
  892. return;
  893. }
  894.  
  895. var weapon = holster.GetWeapon(index);
  896. //子弹上限
  897. var maxCount = Attribute.MaxAmmoCapacity;
  898. //是否捡到子弹
  899. var flag = false;
  900. if (ResidueAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount)
  901. {
  902. var count = weapon.PickUpAmmo(ResidueAmmo);
  903. if (count != ResidueAmmo)
  904. {
  905. ResidueAmmo = count;
  906. flag = true;
  907. }
  908. }
  909.  
  910. if (CurrAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount)
  911. {
  912. var count = weapon.PickUpAmmo(CurrAmmo);
  913. if (count != CurrAmmo)
  914. {
  915. CurrAmmo = count;
  916. flag = true;
  917. }
  918. }
  919.  
  920. //播放互动效果
  921. if (flag)
  922. {
  923. Throw(GlobalPosition, 0, Utils.RandomRangeInt(20, 50), Vector2.Zero, Utils.RandomRangeInt(-180, 180));
  924. }
  925. }
  926. else //没有武器
  927. {
  928. if (holster.PickupWeapon(this) == -1)
  929. {
  930. //替换武器
  931. roleMaster.ThrowWeapon();
  932. roleMaster.PickUpWeapon(this);
  933. }
  934. }
  935. }
  936. }
  937.  
  938. /// <summary>
  939. /// 获取当前武器真实的旋转角度(弧度制), 由于武器旋转时加入了旋转吸附, 所以需要通过该函数来来知道当前武器的真实旋转角度
  940. /// </summary>
  941. public float GetRealGlobalRotation()
  942. {
  943. return Mathf.DegToRad(Master.MountPoint.RealAngle) + Rotation;
  944. }
  945.  
  946. /// <summary>
  947. /// 触发扔掉武器抛出的效果, 并不会管武器是否在武器袋中
  948. /// </summary>
  949. /// <param name="master">触发扔掉该武器的的角色</param>
  950. public void ThrowWeapon(Role master)
  951. {
  952. ThrowWeapon(master, master.GlobalPosition);
  953. }
  954.  
  955. /// <summary>
  956. /// 触发扔掉武器抛出的效果, 并不会管武器是否在武器袋中
  957. /// </summary>
  958. /// <param name="master">触发扔掉该武器的的角色</param>
  959. /// <param name="startPosition">投抛起始位置</param>
  960. public void ThrowWeapon(Role master, Vector2 startPosition)
  961. {
  962. //阴影偏移
  963. ShadowOffset = new Vector2(0, 2);
  964.  
  965. if (master.Face == FaceDirection.Left)
  966. {
  967. Scale *= new Vector2(1, -1);
  968. }
  969.  
  970. var angle = master.MountPoint.GlobalRotationDegrees;
  971. GlobalRotationDegrees = angle;
  972. //继承role的移动速度
  973. InheritVelocity(master);
  974.  
  975. var startHeight = 6;
  976. var direction = angle + Utils.RandomRangeInt(-20, 20);
  977. var velocity = new Vector2(20, 0).Rotated(direction * Mathf.Pi / 180);
  978. var yf = Utils.RandomRangeInt(50, 70);
  979. var rotate = Utils.RandomRangeInt(-90, 90);
  980. Throw(startPosition, startHeight, yf, velocity, rotate);
  981. }
  982.  
  983. protected override void OnThrowStart()
  984. {
  985. //禁用碰撞
  986. //Collision.Disabled = true;
  987. AnimationPlayer.Play(AnimatorNames.Floodlight);
  988. }
  989.  
  990. protected override void OnThrowOver()
  991. {
  992. //启用碰撞
  993. //Collision.Disabled = false;
  994. AnimationPlayer.Play(AnimatorNames.Floodlight);
  995. }
  996.  
  997. /// <summary>
  998. /// 触发拾起到 Holster, 这个函数由 Holster 对象调用
  999. /// </summary>
  1000. public void PickUpWeapon(Role master)
  1001. {
  1002. Master = master;
  1003. if (master.IsAi && _originWeaponAttribute.AiUseAttribute != null)
  1004. {
  1005. _weaponAttribute = _originWeaponAttribute.AiUseAttribute;
  1006. }
  1007. else
  1008. {
  1009. _weaponAttribute = _originWeaponAttribute;
  1010. }
  1011. //握把位置
  1012. AnimatedSprite.Position = Attribute.HoldPosition;
  1013. //停止动画
  1014. AnimationPlayer.Stop();
  1015. //清除泛白效果
  1016. SetBlendSchedule(0);
  1017. ZIndex = 0;
  1018. //禁用碰撞
  1019. //Collision.Disabled = true;
  1020. //修改层级
  1021. _tempLayer = CollisionLayer;
  1022. CollisionLayer = PhysicsLayer.InHand;
  1023. //清除 Ai 拾起标记
  1024. RemoveSign(SignNames.AiFindWeaponSign);
  1025. OnPickUp(master);
  1026. }
  1027.  
  1028. /// <summary>
  1029. /// 触发从 Holster 中移除, 这个函数由 Holster 对象调用
  1030. /// </summary>
  1031. public void RemoveAt()
  1032. {
  1033. Master = null;
  1034. CollisionLayer = _tempLayer;
  1035. _weaponAttribute = _originWeaponAttribute;
  1036. AnimatedSprite.Position = Attribute.CenterPosition;
  1037. //清除 Ai 拾起标记
  1038. RemoveSign(SignNames.AiFindWeaponSign);
  1039. OnRemove();
  1040. }
  1041.  
  1042. /// <summary>
  1043. /// 触发启用武器
  1044. /// </summary>
  1045. public void Active()
  1046. {
  1047. //调整阴影
  1048. ShadowOffset = new Vector2(0, Master.GlobalPosition.Y - GlobalPosition.Y);
  1049. //枪口默认抬起角度
  1050. RotationDegrees = -Attribute.DefaultAngle;
  1051. ShowShadowSprite();
  1052. OnActive();
  1053. }
  1054.  
  1055. /// <summary>
  1056. /// 触发收起武器
  1057. /// </summary>
  1058. public void Conceal()
  1059. {
  1060. HideShadowSprite();
  1061. OnConceal();
  1062. }
  1063.  
  1064. //-------------------------------- Ai相关 -----------------------------
  1065.  
  1066. /// <summary>
  1067. /// 获取 Ai 对于该武器的评分, 评分越高, 代表 Ai 会越优先选择该武器, 如果为 -1, 则表示 Ai 不会使用该武器
  1068. /// </summary>
  1069. public float GetAiScore()
  1070. {
  1071. return 1;
  1072. }
  1073. }