Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / props / weapon / Weapon.cs
@小李xl 小李xl on 24 Aug 2022 22 KB 架构调整
  1. using Godot;
  2. using System;
  3.  
  4. /// <summary>
  5. /// 武器的基类
  6. /// </summary>
  7. public abstract class Weapon : Node2D, IProp
  8. {
  9.  
  10. /// <summary>
  11. /// 武器的唯一id
  12. /// </summary>
  13. public string Id { get; }
  14.  
  15. /// <summary>
  16. /// 开火回调事件
  17. /// </summary>
  18. public event Action<Weapon> FireEvent;
  19.  
  20. /// <summary>
  21. /// 属性数据
  22. /// </summary>
  23. public WeaponAttribute Attribute { get; private set; }
  24.  
  25. /// <summary>
  26. /// 武器的图片
  27. /// </summary>
  28. public Sprite WeaponSprite { get; private set; }
  29.  
  30. /// <summary>
  31. /// 动画播放器
  32. /// </summary>
  33. /// <value></value>
  34. public AnimationPlayer AnimationPlayer { get; private set; }
  35.  
  36. /// <summary>
  37. /// 武器攻击的目标阵营
  38. /// </summary>
  39. public CampEnum TargetCamp { get; set; }
  40.  
  41. /// <summary>
  42. /// 该武器的拥有者
  43. /// </summary>
  44. public Role Master { get; private set; }
  45.  
  46. /// <summary>
  47. /// 当前弹夹弹药剩余量
  48. /// </summary>
  49. public int CurrAmmo { get; private set; }
  50. /// <summary>
  51. /// 剩余弹药量
  52. /// </summary>
  53. public int ResidueAmmo { get; private set; }
  54.  
  55. /// <summary>
  56. /// 武器管的开火点
  57. /// </summary>
  58. public Position2D FirePoint { get; private set; }
  59. /// <summary>
  60. /// 武器管的原点
  61. /// </summary>
  62. public Position2D OriginPoint { get; private set; }
  63. /// <summary>
  64. /// 弹壳抛出的点
  65. /// </summary>
  66. public Position2D ShellPoint { get; private set; }
  67. /// <summary>
  68. /// 碰撞器节点
  69. /// </summary>
  70. /// <value></value>
  71. public CollisionShape2D CollisionShape2D { get; private set; }
  72. /// <summary>
  73. /// 武器的当前散射半径
  74. /// </summary>
  75. public float CurrScatteringRange { get; private set; } = 0;
  76. /// <summary>
  77. /// 是否在换弹中
  78. /// </summary>
  79. /// <value></value>
  80. public bool Reloading { get; private set; } = false;
  81. /// <summary>
  82. /// 换弹计时器
  83. /// </summary>
  84. public float ReloadTimer { get; private set; } = 0;
  85. /// <summary>
  86. /// 换弹进度 (0 - 1)
  87. /// </summary>
  88. public float ReloadProgress
  89. {
  90. get
  91. {
  92. if (Attribute.AloneReload)
  93. {
  94. var num = 1f / Attribute.AmmoCapacity;
  95. return num * (Attribute.AmmoCapacity - CurrAmmo - 1) + num * (ReloadTimer / Attribute.ReloadTime);
  96. }
  97. return ReloadTimer / Attribute.ReloadTime;
  98. }
  99. }
  100.  
  101. //是否按下
  102. private bool triggerFlag = false;
  103. //扳机计时器
  104. private float triggerTimer = 0;
  105. //开火前延时时间
  106. private float delayedTime = 0;
  107. //开火间隙时间
  108. private float fireInterval = 0;
  109. //开火武器口角度
  110. private float fireAngle = 0;
  111. //攻击冷却计时
  112. private float attackTimer = 0;
  113. //攻击状态
  114. private bool attackFlag = false;
  115. //按下的时间
  116. private float downTimer = 0;
  117. //松开的时间
  118. private float upTimer = 0;
  119. //连发次数
  120. private float continuousCount = 0;
  121. //连发状态记录
  122. private bool continuousShootFlag = false;
  123.  
  124. /// <summary>
  125. /// 根据属性创建一把武器
  126. /// </summary>
  127. /// <param name="id">武器唯一id</param>
  128. /// <param name="attribute">属性</param>
  129. public Weapon(string id, WeaponAttribute attribute)
  130. {
  131. Id = id;
  132. Attribute = attribute;
  133. //加载预制体
  134. var tempPrefab = ResourceManager.Load<PackedScene>(Attribute.WeaponPrefab);
  135. if (tempPrefab == null)
  136. {
  137. throw new Exception("WeaponAttribute中未设置'WeaponPrefab'属性!");
  138. }
  139. var tempNode = tempPrefab.Instance();
  140. var body = tempNode.GetChild(0);
  141. tempNode.RemoveChild(body);
  142. AddChild(body);
  143.  
  144. WeaponSprite = GetNode<Sprite>("WeaponBody/WeaponSprite");
  145. FirePoint = GetNode<Position2D>("WeaponBody/FirePoint");
  146. OriginPoint = GetNode<Position2D>("WeaponBody/OriginPoint");
  147. ShellPoint = GetNode<Position2D>("WeaponBody/ShellPoint");
  148. AnimationPlayer = GetNode<AnimationPlayer>("WeaponBody/AnimationPlayer");
  149. CollisionShape2D = GetNode<CollisionShape2D>("WeaponBody/Collision");
  150.  
  151. //更新图片
  152. WeaponSprite.Texture = ResourceLoader.Load<Texture>(Attribute.Sprite);
  153. WeaponSprite.Position = Attribute.CenterPosition;
  154. //开火位置
  155. FirePoint.Position = new Vector2(Attribute.FirePosition.x, -Attribute.FirePosition.y);
  156. OriginPoint.Position = new Vector2(0, -Attribute.FirePosition.y);
  157.  
  158. //弹药量
  159. CurrAmmo = Attribute.AmmoCapacity;
  160. //剩余弹药量
  161. ResidueAmmo = Attribute.MaxAmmoCapacity - Attribute.AmmoCapacity;
  162. }
  163.  
  164. /// <summary>
  165. /// 当按下扳机时调用
  166. /// </summary>
  167. protected abstract void OnDownTrigger();
  168.  
  169. /// <summary>
  170. /// 当松开扳机时调用
  171. /// </summary>
  172. protected abstract void OnUpTrigger();
  173.  
  174. /// <summary>
  175. /// 单次开火时调用的函数
  176. /// </summary>
  177. protected abstract void OnFire();
  178.  
  179. /// <summary>
  180. /// 发射子弹时调用的函数, 每发射一枚子弹调用一次,
  181. /// 如果做霰弹武器效果, 一次开火发射5枚子弹, 则该函数调用5次
  182. /// </summary>
  183. protected abstract void OnShoot();
  184.  
  185. /// <summary>
  186. /// 当开始换弹时调用
  187. /// </summary>
  188. protected abstract void OnReload();
  189.  
  190. /// <summary>
  191. /// 当换弹完成时调用
  192. /// </summary>
  193. protected abstract void OnReloadFinish();
  194.  
  195. /// <summary>
  196. /// 当武器被拾起时调用
  197. /// </summary>
  198. /// <param name="master">拾起该武器的角色</param>
  199. protected abstract void OnPickUp(Role master);
  200.  
  201. /// <summary>
  202. /// 当武器从武器袋中扔掉时调用
  203. /// </summary>
  204. protected abstract void OnThrowOut();
  205.  
  206. /// <summary>
  207. /// 当武器被激活时调用, 也就是使用当武器是调用
  208. /// </summary>
  209. protected abstract void OnActive();
  210.  
  211. /// <summary>
  212. /// 当武器被收起时调用
  213. /// </summary>
  214. protected abstract void OnConceal();
  215.  
  216. public override void _Process(float delta)
  217. {
  218. if (Master == null) //这把武器被扔在地上
  219. {
  220. Reloading = false;
  221. ReloadTimer = 0;
  222. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  223. triggerFlag = false;
  224. attackFlag = false;
  225. attackTimer = attackTimer > 0 ? attackTimer - delta : 0;
  226. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
  227. continuousCount = 0;
  228. delayedTime = 0;
  229. }
  230. else if (Master.Holster.ActiveWeapon != this) //当前武器没有被使用
  231. {
  232. Reloading = false;
  233. ReloadTimer = 0;
  234. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  235. triggerFlag = false;
  236. attackFlag = false;
  237. attackTimer = attackTimer > 0 ? attackTimer - delta : 0;
  238. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
  239. continuousCount = 0;
  240. delayedTime = 0;
  241. }
  242. else //正在使用中
  243. {
  244.  
  245. //换弹
  246. if (Reloading)
  247. {
  248. ReloadTimer -= delta;
  249. if (ReloadTimer <= 0)
  250. {
  251. ReloadSuccess();
  252. }
  253. }
  254.  
  255. if (triggerFlag)
  256. {
  257. if (upTimer > 0) //第一帧按下扳机
  258. {
  259. upTimer = 0;
  260. DownTrigger();
  261. }
  262. downTimer += delta;
  263. }
  264. else
  265. {
  266. if (downTimer > 0) //第一帧松开扳机
  267. {
  268. downTimer = 0;
  269. UpTriggern();
  270. }
  271. upTimer += delta;
  272. }
  273.  
  274. // 攻击的计时器
  275. if (attackTimer > 0)
  276. {
  277. attackTimer -= delta;
  278. if (attackTimer < 0)
  279. {
  280. delayedTime += attackTimer;
  281. attackTimer = 0;
  282. }
  283. }
  284. else if (delayedTime > 0) //攻击延时
  285. {
  286. delayedTime -= delta;
  287. if (attackTimer < 0)
  288. {
  289. delayedTime = 0;
  290. }
  291. }
  292.  
  293. //连发判断
  294. if (continuousCount > 0 && delayedTime <= 0 && attackTimer <= 0)
  295. {
  296. //开火
  297. TriggernFire();
  298. }
  299.  
  300. if (!attackFlag && attackTimer <= 0)
  301. {
  302. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
  303. }
  304. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  305. triggerFlag = false;
  306. attackFlag = false;
  307.  
  308. //武器身回归
  309. Position = Position.MoveToward(Vector2.Zero, 35 * delta);
  310. if (fireInterval == 0)
  311. {
  312. RotationDegrees = 0;
  313. }
  314. else
  315. {
  316. RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval);
  317. }
  318. }
  319. }
  320.  
  321. /// <summary>
  322. /// 扳机函数, 调用即视为扣动扳机
  323. /// </summary>
  324. public void Trigger()
  325. {
  326. //是否第一帧按下
  327. var justDown = downTimer == 0;
  328. //是否能发射
  329. var flag = false;
  330. if (continuousCount <= 0) //不能处于连发状态下
  331. {
  332. if (Attribute.ContinuousShoot) //自动射击
  333. {
  334. if (triggerTimer > 0)
  335. {
  336. if (continuousShootFlag)
  337. {
  338. flag = true;
  339. }
  340. }
  341. else
  342. {
  343. flag = true;
  344. if (delayedTime <= 0 && attackTimer <= 0)
  345. {
  346. continuousShootFlag = true;
  347. }
  348. }
  349. }
  350. else //半自动
  351. {
  352. if (justDown && triggerTimer <= 0)
  353. {
  354. flag = true;
  355. }
  356. }
  357. }
  358.  
  359. if (flag)
  360. {
  361. var fireFlag = true; //是否能开火
  362. if (Reloading) //换弹中
  363. {
  364. if (CurrAmmo > 0 && Attribute.AloneReload && Attribute.AloneReloadCanShoot) //立即停止换弹
  365. {
  366. Reloading = false;
  367. ReloadTimer = 0;
  368. }
  369. else
  370. {
  371. fireFlag = false;
  372. }
  373. }
  374. else if (CurrAmmo <= 0)
  375. {
  376. fireFlag = false;
  377. //子弹不够
  378. _Reload();
  379. }
  380.  
  381. if (fireFlag)
  382. {
  383. if (justDown)
  384. {
  385. //开火前延时
  386. delayedTime = Attribute.DelayedTime;
  387. //扳机按下间隔
  388. triggerTimer = Attribute.TriggerInterval;
  389. //连发数量
  390. if (!Attribute.ContinuousShoot)
  391. {
  392. continuousCount = MathUtils.RandRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount);
  393. }
  394. }
  395. if (delayedTime <= 0 && attackTimer <= 0)
  396. {
  397. TriggernFire();
  398. }
  399. attackFlag = true;
  400. }
  401.  
  402. }
  403. triggerFlag = true;
  404. }
  405.  
  406. /// <summary>
  407. /// 刚按下扳机
  408. /// </summary>
  409. private void DownTrigger()
  410. {
  411. OnDownTrigger();
  412. }
  413.  
  414. /// <summary>
  415. /// 刚松开扳机
  416. /// </summary>
  417. private void UpTriggern()
  418. {
  419. continuousShootFlag = false;
  420. if (delayedTime > 0)
  421. {
  422. continuousCount = 0;
  423. }
  424. OnUpTrigger();
  425. }
  426.  
  427. /// <summary>
  428. /// 触发开火
  429. /// </summary>
  430. private void TriggernFire()
  431. {
  432. continuousCount = continuousCount > 0 ? continuousCount - 1 : 0;
  433.  
  434. //减子弹数量
  435. CurrAmmo--;
  436. //开火间隙
  437. fireInterval = 60 / Attribute.StartFiringSpeed;
  438. //攻击冷却
  439. attackTimer += fireInterval;
  440.  
  441. //触发开火函数
  442. OnFire();
  443.  
  444. //开火发射的子弹数量
  445. var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount);
  446. //武器口角度
  447. var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();
  448.  
  449. //创建子弹
  450. for (int i = 0; i < bulletCount; i++)
  451. {
  452. //先算武器口方向
  453. Rotation = (float)GD.RandRange(-angle, angle);
  454. //发射子弹
  455. OnShoot();
  456. }
  457.  
  458. //当前的散射半径
  459. CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange);
  460. //武器的旋转角度
  461. RotationDegrees -= Attribute.UpliftAngle;
  462. fireAngle = RotationDegrees;
  463. //武器身位置
  464. Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y);
  465.  
  466. if (FireEvent != null)
  467. {
  468. FireEvent(this);
  469. }
  470. }
  471.  
  472. /// <summary>
  473. /// 返回弹药是否到达上限
  474. /// </summary>
  475. public bool IsFullAmmo()
  476. {
  477. return CurrAmmo + ResidueAmmo >= Attribute.MaxAmmoCapacity;
  478. }
  479.  
  480. /// <summary>
  481. /// 返回是否弹药耗尽
  482. /// </summary>
  483. public bool IsEmptyAmmo()
  484. {
  485. return CurrAmmo + ResidueAmmo == 0;
  486. }
  487.  
  488. /// <summary>
  489. /// 拾起的弹药数量, 如果到达容量上限, 则返回拾取完毕后剩余的弹药数量
  490. /// </summary>
  491. /// <param name="count">弹药数量</param>
  492. public int PickUpAmmo(int count)
  493. {
  494. var num = ResidueAmmo;
  495. ResidueAmmo = Mathf.Min(ResidueAmmo + count, Attribute.MaxAmmoCapacity - CurrAmmo);
  496. return count - ResidueAmmo + num;
  497. }
  498.  
  499. /// <summary>
  500. /// 触发换弹
  501. /// </summary>
  502. public void _Reload()
  503. {
  504. if (CurrAmmo < Attribute.AmmoCapacity && ResidueAmmo > 0 && !Reloading)
  505. {
  506. Reloading = true;
  507. ReloadTimer = Attribute.ReloadTime;
  508. OnReload();
  509. }
  510. }
  511.  
  512. /// <summary>
  513. /// 换弹计时器时间到, 执行换弹操作
  514. /// </summary>
  515. private void ReloadSuccess()
  516. {
  517. if (Attribute.AloneReload) //单独装填
  518. {
  519. if (ResidueAmmo >= Attribute.AloneReloadCount) //剩余子弹充足
  520. {
  521. if (CurrAmmo + Attribute.AloneReloadCount <= Attribute.AmmoCapacity)
  522. {
  523. ResidueAmmo -= Attribute.AloneReloadCount;
  524. CurrAmmo += Attribute.AloneReloadCount;
  525. }
  526. else //子弹满了
  527. {
  528. var num = Attribute.AmmoCapacity - CurrAmmo;
  529. CurrAmmo = Attribute.AmmoCapacity;
  530. ResidueAmmo -= num;
  531. }
  532. }
  533. else if (ResidueAmmo != 0) //剩余子弹不足
  534. {
  535. if (ResidueAmmo + CurrAmmo <= Attribute.AmmoCapacity)
  536. {
  537. CurrAmmo += ResidueAmmo;
  538. ResidueAmmo = 0;
  539. }
  540. else //子弹满了
  541. {
  542. var num = Attribute.AmmoCapacity - CurrAmmo;
  543. CurrAmmo = Attribute.AmmoCapacity;
  544. ResidueAmmo -= num;
  545. }
  546. }
  547. if (ResidueAmmo == 0 || CurrAmmo == Attribute.AmmoCapacity) //换弹结束
  548. {
  549. Reloading = false;
  550. ReloadTimer = 0;
  551. OnReloadFinish();
  552. }
  553. else
  554. {
  555. ReloadTimer = Attribute.ReloadTime;
  556. OnReload();
  557. }
  558. }
  559. else //换弹结束
  560. {
  561. if (ResidueAmmo >= Attribute.AmmoCapacity)
  562. {
  563. ResidueAmmo -= Attribute.AmmoCapacity - CurrAmmo;
  564. CurrAmmo = Attribute.AmmoCapacity;
  565. }
  566. else
  567. {
  568. CurrAmmo = ResidueAmmo;
  569. ResidueAmmo = 0;
  570. }
  571. Reloading = false;
  572. ReloadTimer = 0;
  573. OnReloadFinish();
  574. }
  575. }
  576.  
  577. public CheckInteractiveResult CheckInteractive(Role master)
  578. {
  579. var result = new CheckInteractiveResult(this);
  580. if (Master == null)
  581. {
  582. var masterWeapon = master.Holster.ActiveWeapon;
  583. //查找是否有同类型武器
  584. var index = master.Holster.FindWeapon(Id);
  585. if (index != -1) //如果有这个武器
  586. {
  587. if (CurrAmmo + ResidueAmmo != 0) //子弹不为空
  588. {
  589. var targetWeapon = master.Holster.GetWeapon(index);
  590. if (!targetWeapon.IsFullAmmo()) //背包里面的武器子弹未满
  591. {
  592. //可以互动拾起弹药
  593. result.CanInteractive = true;
  594. result.Message = Attribute.Name;
  595. result.ShowIcon = "res://resource/sprite/ui/icon/icon_bullet.png";
  596. return result;
  597. }
  598. }
  599. }
  600. else //没有武器
  601. {
  602. if (master.Holster.CanPickupWeapon(this)) //能拾起武器
  603. {
  604. //可以互动, 拾起武器
  605. result.CanInteractive = true;
  606. result.Message = Attribute.Name;
  607. result.ShowIcon = "res://resource/sprite/ui/icon/icon_pickup.png";
  608. return result;
  609. }
  610. else if (masterWeapon != null && masterWeapon.Attribute.WeightType == Attribute.WeightType) //替换武器
  611. {
  612. //可以互动, 切换武器
  613. result.CanInteractive = true;
  614. result.Message = Attribute.Name;
  615. result.ShowIcon = "res://resource/sprite/ui/icon/icon_replace.png";
  616. return result;
  617. }
  618. }
  619. }
  620. return result;
  621. }
  622.  
  623. public void Interactive(Role master)
  624. {
  625. //查找是否有同类型武器
  626. var index = master.Holster.FindWeapon(Id);
  627. if (index != -1) //如果有这个武器
  628. {
  629. if (CurrAmmo + ResidueAmmo == 0) //没有子弹了
  630. {
  631. return;
  632. }
  633. var weapon = master.Holster.GetWeapon(index);
  634. //子弹上限
  635. var maxCount = Attribute.MaxAmmoCapacity;
  636. //是否捡到子弹
  637. var flag = false;
  638. if (ResidueAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount)
  639. {
  640. var count = weapon.PickUpAmmo(ResidueAmmo);
  641. if (count != ResidueAmmo)
  642. {
  643. ResidueAmmo = count;
  644. flag = true;
  645. }
  646. }
  647. if (CurrAmmo > 0 && weapon.CurrAmmo + weapon.ResidueAmmo < maxCount)
  648. {
  649. var count = weapon.PickUpAmmo(CurrAmmo);
  650. if (count != CurrAmmo)
  651. {
  652. CurrAmmo = count;
  653. flag = true;
  654. }
  655. }
  656. //播放互动效果
  657. if (flag)
  658. {
  659. this.StartThrow<ThrowWeapon>(new Vector2(20, 20), GlobalPosition, 0, 0,
  660. MathUtils.RandRangeInt(-20, 20), MathUtils.RandRangeInt(20, 50),
  661. MathUtils.RandRangeInt(-180, 180), WeaponSprite);
  662. }
  663. }
  664. else //没有武器
  665. {
  666. if (master.Holster.PickupWeapon(this) == -1)
  667. {
  668. var slot = master.Holster.SlotList[master.Holster.ActiveIndex];
  669. if (slot.Type == Attribute.WeightType)
  670. {
  671. var weapon = master.Holster.RmoveWeapon(master.Holster.ActiveIndex);
  672. weapon.StartThrowWeapon(master);
  673. master.PickUpWeapon(this);
  674. }
  675. }
  676. }
  677. }
  678.  
  679. public Vector2 GetItemPosition()
  680. {
  681. return GlobalPosition;
  682. }
  683.  
  684. /// <summary>
  685. /// 触发落到地面
  686. /// </summary>
  687. public void _FallToGround()
  688. {
  689. //启用碰撞
  690. CollisionShape2D.Disabled = false;
  691. }
  692.  
  693. /// <summary>
  694. /// 触发拾起
  695. /// </summary>
  696. public void _PickUpWeapon(Role master)
  697. {
  698. Master = master;
  699. //握把位置
  700. WeaponSprite.Position = Attribute.HoldPosition;
  701. //清除泛白效果
  702. ShaderMaterial sm = WeaponSprite.Material as ShaderMaterial;
  703. sm.SetShaderParam("schedule", 0);
  704. //停止动画
  705. AnimationPlayer.Stop();
  706. ZIndex = 0;
  707. //禁用碰撞
  708. CollisionShape2D.Disabled = true;
  709. OnPickUp(master);
  710. }
  711.  
  712. /// <summary>
  713. /// 触发抛出
  714. /// </summary>a
  715. public void _ThrowOutWeapon()
  716. {
  717. Master = null;
  718. WeaponSprite.Position = Attribute.CenterPosition;
  719. AnimationPlayer.Play("Floodlight");
  720. OnThrowOut();
  721. }
  722.  
  723. /// <summary>
  724. /// 触发启用武器
  725. /// </summary>
  726. public void _Active()
  727. {
  728. OnActive();
  729. }
  730.  
  731. /// <summary>
  732. /// 触发收起武器
  733. /// </summary>
  734. public void _Conceal()
  735. {
  736. OnConceal();
  737. }
  738.  
  739. /// <summary>
  740. /// 实例化并返回子弹对象
  741. /// </summary>
  742. /// <param name="bulletPack">子弹的预制体</param>
  743. protected T CreateBullet<T>(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null) where T : Node2D, IBullet
  744. {
  745. return (T)CreateBullet(bulletPack, globalPostion, globalRotation, parent);
  746. }
  747.  
  748. /// <summary>
  749. /// 实例化并返回子弹对象
  750. /// </summary>
  751. /// <param name="bulletPack">子弹的预制体</param>
  752. protected IBullet CreateBullet(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null)
  753. {
  754. // 实例化子弹
  755. Node2D bullet = bulletPack.Instance<Node2D>();
  756. // 设置坐标
  757. bullet.GlobalPosition = globalPostion;
  758. // 旋转角度
  759. bullet.GlobalRotation = globalRotation;
  760. if (parent == null)
  761. {
  762. RoomManager.Current.SortRoot.AddChild(bullet);
  763. }
  764. else
  765. {
  766. parent.AddChild(bullet);
  767. }
  768. // 调用初始化
  769. IBullet result = (IBullet)bullet;
  770. result.Init(TargetCamp, this, null);
  771. return result;
  772. }
  773. }