{"id":129,"date":"2026-04-26T15:54:54","date_gmt":"2026-04-26T06:54:54","guid":{"rendered":"https:\/\/tate.stars.ne.jp\/wpa\/?p=129"},"modified":"2026-04-26T16:00:28","modified_gmt":"2026-04-26T07:00:28","slug":"invader","status":"publish","type":"post","link":"https:\/\/tate.stars.ne.jp\/wpa\/invader.html","title":{"rendered":"Invader"},"content":{"rendered":"<pre><code class=\"swift\">\nMainScene\nimport { Scene } from 'phaser';\nexport default class MainScene extends Scene {\n private sprite1: any;\n private sprite2: any;\n private sprite3: any;\n private container!: Phaser.GameObjects.Container;\n private bullets!: Phaser.Physics.Arcade.Group;\n private player!: Phaser.Physics.Arcade.Sprite & { body: Phaser.Physics.Arcade.Body };\n private scoreText!: Phaser.GameObjects.Text;\n private joystick: any;\n private rexVirtualJoystick: any;\n private score = 0;\n private cursors?: Phaser.Types.Input.Keyboard.CursorKeys;\n private joystickArea!: Phaser.Geom.Rectangle;\n private enemies!: Phaser.Physics.Arcade.Group;\n private enemyBullets!: Phaser.Physics.Arcade.Group;\n private bunkers!: Phaser.Physics.Arcade.StaticGroup;\n private maxHealth = 10;\n private hearts: Phaser.GameObjects.Image[] = [];\n private currentHealth = 10;\n private playerLife = 10;\n private bunkerGroup!: Phaser.Physics.Arcade.StaticGroup;\n private myship!: Phaser.Types.Physics.Arcade.ImageWithDynamicBody;\n private ufoBullets!: Phaser.Physics.Arcade.Group;\n constructor() {\n     super('MainScene');\n }\npreload() {\n this.load.spritesheet('invader', 'assets\/spaceinvaders2.png',\n  {frameWidth: 52, frameHeight: 36});\n this.load.image('player', 'assets\/yousai2.png');\n this.load.image('jump', 'assets\/jump.png');\n this.load.image(\"bullet\", \"assets\/bullet.png\");\n this.load.image(\"bullet2\", \"assets\/laser2.png\");\n this.load.image('heart', 'assets\/heart.png');\n this.load.image('myship', 'assets\/ship.png');\n this.load.image(\"bulletufo\", \"assets\/ufo.png\");\n }\ncreate() {\n this.anims.create({\n   key: 'invader1',\n  frames: this.anims.generateFrameNumbers('invader', { start: 0, end: 1 }),\n  frameRate: 2,\n  repeat: -1\n  });\n  this.anims.create({\n   key: 'invader2',\n    frames: this.anims.generateFrameNumbers('invader', { start: 2, end: 3 }),\n   frameRate: 2,\n   repeat: -1\n  });\n  this.anims.create({\n   key: 'invader3',\n   frames: this.anims.generateFrameNumbers('invader', { start: 4, end: 5 }),\n    frameRate: 2,\n    repeat: -1\n});\n \/\/ \u30cf\u30fc\u30c8\u753b\u50cf\u3092\u914d\u7f6e\n for (let i = 0; i < this.maxHealth; i++) {\n    const heart = this.add.image(186 + i * 25, 19, 'heart').setScale(0.08).setScrollFactor(0);\n    this.hearts.push(heart);\n}\n this.myship = this.physics.add.image(800*0.2, 50, 'myship');\n  this.myship.setTint(0xFF0000);\n  \/\/ this.ship.depth = 2;\n  this.myship.setDepth(2);\n  this.myship.setCollideWorldBounds(true);\n  this.myship.setBounce(1).setScale(1.2);\n  this.myship.setVelocityX(200);\n  this.myship.setDepth(1);\/\/ \u53f3\u65b9\u5411\u306b\u79fb\u52d5\u958b\u59cb\n  this.ufoBullets = this.physics.add.group();\n \/\/ 2\u79d2\uff082000ms\uff09\u3054\u3068\u306b\u767a\u5c04\u5224\u5b9a\u3092\u884c\u3046\u30bf\u30a4\u30de\u30fc\n this.time.addEvent({\n  delay: 500,\n  callback: this.shootUfoBullet,\n  callbackScope: this,\n    loop: true\n });\n this.enemies = this.physics.add.group();\n this.enemyBullets = this.physics.add.group();\n  this.time.addEvent({\n    delay: 500,                \/\/ 1000\u30df\u30ea\u79d2\uff081\u79d2\uff09\u3054\u3068\u306b\u5b9f\u884c\n    callback: this.enemyShoot,  \/\/ \u5b9f\u884c\u3059\u308b\u30e1\u30bd\u30c3\u30c9\n    callbackScope: this,\n    loop: true                  \/\/ \u7e70\u308a\u8fd4\u3059\n});\n for (let y = 0; y < 2; y++) {\n  for (let x = 0; x < 10; x++) {\n  this.sprite1 = this.enemies.create(40 + x * 56, 100+ y * 40, 'invader');\n  this.sprite1.play('invader1');\n  this.sprite1.setTint(0x0000FF);\n  this.sprite2 = this.enemies.create(40 + x * 56, 180+ y * 40, 'invader');\n  this.sprite2.play('invader2');\n  this.sprite2.setTint(0x8B008B);\n  this.sprite3 = this.enemies.create(40 + x * 56, 260+ y * 40, 'invader');\n  this.sprite3.play('invader3');\n  this.sprite3.setTint(0x4B0082);\n  this.container = this.add.container(800*0.01-10, 600*0.04-40, [ this.sprite1, this.sprite2, this.sprite3 ]);\n  this.tweens.add({\n  targets: this.container,\n    x: 180,\n     duration: 3000,\n     yoyo: true,\n     repeat: -1\n });\n }\n }\n\nthis.bullets = this.physics.add.group({\n defaultKey: \"bullet\",\n allowGravity: false,\n maxSize: 100\n});\nthis.player = this.physics.add.sprite(800\/2, 600 - 110, 'player').setDepth(1).setScale(0.9);\nthis.player.setInteractive();\n  this.player.setTint(0xffffff);\n  this.player.body.allowGravity = false;\n  this.player.setCollideWorldBounds(true);\n  this.player.setImmovable(true);\n  this.scoreText = this.add.text(14, 14, 'score: 0', { fontSize: '25px' });\n  this.scoreText.setScrollFactor(0);\n   if (this.input.keyboard) {\n      this.cursors = this.input.keyboard.createCursorKeys();\n   }\n this.joystickArea = new Phaser.Geom.Rectangle(0, 200, 800, 280);\n   const graphics = this.add.graphics();\n   graphics.lineStyle(2, 0x00ff00);\n   graphics.strokeRectShape(this.joystickArea);\n    this.joystick = this.rexVirtualJoystick.add(this, {\n    x: 100,\n    y: 400,\n    radius: 100,\n    base: this.add.circle(0, 0, 100, 0x888888).setAlpha(0.1),\n    thumb: this.add.circle(0, 0, 50, 0xaaaaaa),\n    dir:'left&#038;right',\n    forceMin: 16,\n    fixed: false,  \/\/ \u3053\u3053\u3092false\u306b\u8a2d\u5b9a\n    enable: true\n  }).setVisible(false); \/\/ \u6700\u521d\u306f\u975e\u8868\u793a\u306b\u3057\u3066\u304a\u304f\nthis.input.on('pointerdown', (pointer: Phaser.Input.Pointer) => {\n  if (this.joystickArea.contains(pointer.x, pointer.y)) {\n   this.joystick.setPosition(pointer.x, pointer.y);\n   this.joystick.setVisible(true);\n  this.joystick.base.depth = 100; \/\/ \u5fc5\u8981\u306b\u5fdc\u3058\u3066\u91cd\u306a\u308a\u9806\u3092\u8abf\u6574\n   this.joystick.thumb.depth = 101;\n  }\n});\n\/\/ \u6307\u3092\u96e2\u3057\u305f\u6642\u306b\u975e\u8868\u793a\u306b\u3059\u308b\u5834\u5408\n this.input.on('pointerup', () => {\n   this.joystick.setVisible(false);\n});\n  this.input.addPointer(2);\n  const jumpButton =  this.add.image(800\/1.2, 600 - 62, 'jump').setScale(0.4).setInteractive();\n  jumpButton.on(\"pointerdown\", () => {\n   this.shoot();\n });\n jumpButton.on(\"pointerup\", () => {\n   this.shoot();\n  });\n  \nthis.physics.add.collider( this.enemies, this.bullets,(alien, bullet)=>{\n  const en = bullet as Phaser.Physics.Arcade.Sprite;\n  const aln = alien as Phaser.Physics.Arcade.Sprite;\n  en.disableBody(true, true);\n   \/\/ en.disableBody(true, true);\n   \/\/  aliens.setActive(false);\n  aln.disableBody(true, true);\n  this.score += 5;\n  this.scoreText.setText('Score: ' + this.score);\n  if (this.enemies.countActive(true) === 0) {\n    this.gameWin();\n }\n  this.time.delayedCall(500, () => {\n   en.setActive(false);\n    en.alpha = 0;\n  });\n });\n  this.physics.add.collider(this.player, [this.enemyBullets,this.ufoBullets], (myplayer, myenemy) =>\n  {\n const tar =myplayer as Phaser.Physics.Arcade.Sprite;\n const myeny =myenemy as Phaser.Physics.Arcade.Sprite;\n myeny.disableBody(true, true);\n this.time.delayedCall(500, () => {\n  if (myeny.active) {\n    \/\/ myeny.destroy();\n    myeny.setAlpha(0);\n     }\n  });\n \/\/  targetPlayer.disableBody(true, true);\n  this.playerLife -= 1;\n  this.damage();\n \/\/ const tar = myplayer as Phaser.Physics.Arcade.Sprite;\n tar.setTint(0xff0000);\n this.time.addEvent({\n  delay: 200,\n  callback: () => {\n    tar.setTint(0xffffff);\n }\n });\n \/\/ \u30e9\u30a4\u30d5\u304c0\u306b\u306a\u3063\u305f\u3089\u30b2\u30fc\u30e0\u30aa\u30fc\u30d0\u30fc\nif (this.playerLife <= 0) {\n  this.physics.pause(); \/\/ \u7269\u7406\u30a8\u30f3\u30b8\u30f3\u3092\u505c\u6b62\n this.add.text(400, 250, 'GAME OVER', { fontSize: '84px', color: '#ff0000' }).setOrigin(0.5).setScrollFactor(0);\n  this.time.delayedCall(3000, () => {\n  tar.clearTint();\n  this.scene.start('MainScene');\n  this.playerLife = 10;\n  this.currentHealth = 10;\n  });\n }\n });\n\nthis.bunkerGroup = this.physics.add.staticGroup().setDepth(1);\n  const bunkerLocations = [150, 400, 650];\n  bunkerLocations.forEach(x => {\n   this.createBunker(x, 400);\n });\nthis.physics.add.overlap([this.enemyBullets,this.ufoBullets], this.bunkerGroup, (bullet, block) => {\n (bullet as Phaser.Physics.Arcade.Sprite).destroy(); \n \/\/ \u5f3e\u3092\u6d88\u3059\/\/ block.destroy();\n (block as Phaser.Physics.Arcade.Sprite).destroy();\n  });\nthis.physics.add.overlap(this.bullets, this.myship, (bullet, ship) => {\n (bullet as Phaser.Physics.Arcade.Sprite).destroy(); \/\/ \u5f3e\u3092\u6d88\u3059\n\/\/ block.destroy();\n(ship as Phaser.Physics.Arcade.Sprite).destroy();\n this.gameWin();\n});\n}\n\nprivate gameWin() {\n  this.physics.pause();\n  this.add.text(400, 300, 'YOU WIN!\\nClick to Restart',\n  { fontSize: '54px', color: '#002aff' }).setOrigin(0.5).setAlign('center');\n   this.input.once('pointerdown', () => {\n   this.scene.restart();\n   });\n}\n private shootUfoBullet() {\n const bullet = this.ufoBullets.get(this.myship.x, this.myship.y, \"bulletufo\");\n  if (bullet) {\n   bullet.setScale(0.08);\n   bullet.setActive(true).setVisible(true);\n   bullet.body.allowGravity = false;\n   \/\/  bullet.setVelocityY(500); \/\/ \u4e0b\u65b9\u5411\u306b\u767a\u5c04\n   bullet.body.velocity.y = 600;\n  }\n }\n createBunker( x: number, y: number) {\n \/\/ \u30d0\u30f3\u30ab\u30fc\u306e\u5f62\u3092\u30d3\u30c3\u30c8\u30de\u30c3\u30d7\u5f62\u5f0f\u306e\u914d\u5217\u3067\u5b9a\u7fa9 (1\u304c\u30d6\u30ed\u30c3\u30af\u30010\u304c\u7a7a\u767d)\n  const layout = [\n    [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],\n    [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],\n    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n    [1, 1, 1, 0, 0, 0, 0, 1, 1, 1],\n    [1, 1, 0, 0, 0, 0, 0, 0, 1, 1]\n   ];\n const blockSize = 8; \/\/ 1\u3064\u306e\u30d6\u30ed\u30c3\u30af\u306e\u30b5\u30a4\u30ba(px)\n const color = 0x20ff20; \/\/ \u30a4\u30f3\u30d9\u30fc\u30c0\u30fc\u98a8\u306e\u7dd1\u8272\n layout.forEach((row, rowIndex) => {\n   row.forEach((value, colIndex) => {\n    if (value === 1) {\n    \/\/ \u5404\u30c9\u30c3\u30c8\u3092\u77e9\u5f62(Rectangle)\u3068\u3057\u3066\u4f5c\u6210\n    const block = this.add.rectangle(\n      x + colIndex * blockSize,\n      y + rowIndex * blockSize,\n      blockSize,\n      blockSize,\n      color\n   );\n\/\/ \u7269\u7406\u30dc\u30c7\u30a3\u3092\u6709\u52b9\u5316\n this.bunkerGroup.add(block);\n  }\n   });\n });\n return this.bunkerGroup;\n }\n damage() {\nif (this.currentHealth > 0) {\n  this.currentHealth -= 1;\n   \/\/ \u914d\u5217\u306e\u6700\u5f8c\u306e\u30cf\u30fc\u30c8\u3092\u7a7a\u306e\u30cf\u30fc\u30c8\u306b\u5207\u308a\u66ff\u3048\u308b\u304b\u3001\u7834\u68c4\u3059\u308b\n   const heartToRemove = this.hearts.pop();\n   if (heartToRemove) {\n    heartToRemove.destroy(); \/\/ \u753b\u50cf\u3092\u7834\u68c4\n }\n if (this.currentHealth === 0) {\n  this.player.setVisible(false);\n  }\n }\n}\nprivate enemyShoot() {\n   \/\/ \u751f\u304d\u6b8b\u3063\u3066\u3044\u308b\u6575\u3092\u3059\u3079\u3066\u53d6\u5f97\n  const livingEnemies = this.enemies.getChildren() as Phaser.Physics.Arcade.Sprite[];\n if (livingEnemies.length > 0) {\n  \/\/\u30e9\u30f3\u30c0\u30e0\u306b1\u4f53\u9078\u3076\n   const shooter = Phaser.Utils.Array.GetRandom(livingEnemies);\n   const randomInt = Phaser.Math.Between(2, 58);\n  \/\/ \u5f3e\u3092\u767a\u5c04\nconst bullet = this.enemyBullets.get(shooter.x+randomInt, shooter.y, 'bullet2');\n if (bullet) {\n  bullet.setScale(0.3);\n  bullet.setActive(true);\n  bullet.setVisible(true);\n   bullet.body.velocity.y = 500; \/\/ \u4e0b\u65b9\u5411\u306b\u767a\u5c04\n  }\n }\n }\nshoot() {\n  let bullet = this.bullets.get(this.player.x, this.player.y + 5);\n   if (bullet) {\n    bullet.setActive(true);\n    bullet.setVisible(true);\n    bullet.body.velocity.y = -500;\n \/\/ 2000\u30df\u30ea\u79d2\uff082\u79d2\uff09\u5f8c\u306b\u5f3e\u3092\u6d88\u6ec5\u3055\u305b\u308b\n  this.time.delayedCall(2000, () => {\n   if (bullet.active) {\n   bullet.destroy(); \/\/ \u307e\u305f\u306f bullet.disableBody(true, true);\n  }\n });\n }\n}\nupdate() {\nif (this.cursors?.left.isDown || this.joystick.left) {\n  this.player.setVelocityX(-200);\n  }\n else if (this.cursors?.right.isDown || this.joystick.right) {\n   this.player.setVelocityX(200);\n}\n else {\n this.player.setVelocityX(0);\n \/\/  this.player.setVelocityY(0);\n}\n }\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>MainScene import { Scene } fro&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,3],"tags":[],"class_list":["post-129","post","type-post","status-publish","format-standard","hentry","category-phaser4","category-typescript"],"_links":{"self":[{"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/posts\/129","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/comments?post=129"}],"version-history":[{"count":1,"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/posts\/129\/revisions"}],"predecessor-version":[{"id":130,"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/posts\/129\/revisions\/130"}],"wp:attachment":[{"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/media?parent=129"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/categories?post=129"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tate.stars.ne.jp\/wpa\/wp-json\/wp\/v2\/tags?post=129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}