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