WeaponRandomSpawner.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { _decorator, Component, Node, Sprite, SpriteFrame, resources, Prefab, instantiate, UITransform, Vec2, Vec3, RigidBody2D, macro } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. @ccclass('WeaponRandomSpawner')
  4. export class WeaponRandomSpawner extends Component {
  5. /**
  6. * Pellet prefab used as bullet. Drag the Pellet.prefab into this slot in the editor.
  7. */
  8. @property({ type: Prefab })
  9. public pelletPrefab: Prefab | null = null;
  10. /**
  11. * Time interval (seconds) between two shots.
  12. */
  13. @property
  14. public fireInterval: number = 1.0;
  15. /** Cached weapon sprite component (WeaponBlock/B1/Weapon) */
  16. private _weaponSprite: Sprite | null = null;
  17. /** The sprite frame chosen randomly at scene start */
  18. private _selectedFrame: SpriteFrame | null = null;
  19. onLoad() {
  20. // Locate the Weapon sprite component inside the prefab hierarchy
  21. const b1Node: Node | null = this.node.getChildByName('B1');
  22. if (!b1Node) {
  23. console.error('[WeaponRandomSpawner] Cannot find child node "B1"');
  24. return;
  25. }
  26. const weaponNode: Node | null = b1Node.getChildByName('Weapon');
  27. if (!weaponNode) {
  28. console.error('[WeaponRandomSpawner] Cannot find grand-child node "Weapon" under B1');
  29. return;
  30. }
  31. this._weaponSprite = weaponNode.getComponent(Sprite);
  32. if (!this._weaponSprite) {
  33. console.error('[WeaponRandomSpawner] Sprite component missing on Weapon node');
  34. return;
  35. }
  36. // Load all sprite frames under resources/images/PlantsSprite at runtime
  37. resources.loadDir('images/PlantsSprite', SpriteFrame, (err, assets) => {
  38. if (err) {
  39. console.error('[WeaponRandomSpawner] Failed to load PlantsSprite resources:', err);
  40. return;
  41. }
  42. if (!assets || assets.length === 0) {
  43. console.warn('[WeaponRandomSpawner] No sprite frames found in images/PlantsSprite');
  44. return;
  45. }
  46. // Pick one sprite frame randomly and apply to weapon
  47. this._selectedFrame = assets[Math.floor(Math.random() * assets.length)];
  48. // Add null safety check before setting spriteFrame
  49. if (this._weaponSprite && this._weaponSprite.isValid && this._weaponSprite.node && this._weaponSprite.node.isValid) {
  50. this._weaponSprite.spriteFrame = this._selectedFrame;
  51. }
  52. });
  53. }
  54. start() {
  55. // Start auto-fire schedule
  56. this.schedule(this._fire.bind(this), this.fireInterval);
  57. }
  58. onDestroy() {
  59. // Clear references to prevent operations on destroyed components
  60. this._weaponSprite = null;
  61. this._selectedFrame = null;
  62. }
  63. /**
  64. * Instantiate a bullet prefab, copy the weapon sprite frame to it (scaled to half size)
  65. * and give it an upward velocity.
  66. */
  67. private _fire() {
  68. if (!this.pelletPrefab || !this._selectedFrame) {
  69. return; // Not ready yet
  70. }
  71. const bullet: Node = instantiate(this.pelletPrefab);
  72. // Add to the same scene, at world position of the weapon muzzle (current node)
  73. this.node.scene?.addChild(bullet);
  74. bullet.setWorldPosition(this.node.worldPosition);
  75. // Set bullet sprite frame with null safety checks
  76. const bulletSprite = bullet.getComponent(Sprite);
  77. if (bulletSprite && bulletSprite.isValid && bullet && bullet.isValid) {
  78. bulletSprite.spriteFrame = this._selectedFrame;
  79. }
  80. // Match bullet size to half of weapon sprite size
  81. const weaponUi = this._weaponSprite?.node.getComponent(UITransform);
  82. const bulletUi = bullet.getComponent(UITransform);
  83. if (weaponUi && bulletUi) {
  84. const size = weaponUi.contentSize;
  85. bulletUi.setContentSize(size.width * 0.5, size.height * 0.5);
  86. } else {
  87. // Fallback: scale the whole node
  88. bullet.setScale(this.node.scale.x * 0.5, this.node.scale.y * 0.5, 1);
  89. }
  90. // Give the bullet an upward velocity if it has a RigidBody2D component
  91. const rb = bullet.getComponent(RigidBody2D);
  92. if (rb) {
  93. rb.linearVelocity = new Vec2(0, 600);
  94. }
  95. }
  96. }