Breakout


MainScene
import { Scene } from 'phaser';
import ScoreText from "./ScoreText";
export default class MainScene extends Scene {
 private paddle!: Phaser.Types.Physics.Arcade.ImageWithDynamicBody;
 private ball!: Phaser.Types.Physics.Arcade.ImageWithDynamicBody;
 private bricks!: Phaser.Physics.Arcade.StaticGroup;
 private scoreText!: ScoreText;
 private hitSound!: Phaser.Sound.BaseSound;
 constructor() {
     super('GameScene');
   }
 preload() {
 this.load.image('paddle', 'assets/paddle.png');
 this.load.image('ball', 'assets/ball2.png');
 this.load.image('brick', 'assets/brick.png');
 this.load.spritesheet('explosion', 'assets/explosion.png', {
   frameWidth: 64,
   frameHeight: 64,
   endFrame: 23
  });
 this.load.audio('coinSound', 'assets/se.mp3');
 }
create() {
        // 物理エンジンの設定
 this.physics.world.checkCollision.down = false;
 const style: Phaser.Types.GameObjects.Text.TextStyle = {
  fontSize: '22px',
  color: '#fff',
  fontFamily: 'Courier'
 };
 this.scoreText = new ScoreText(this, 14, 14, style);
 // パドルの作成
 this.paddle = this.physics.add.image(400, 550, 'paddle').setImmovable();
 this.paddle.body.setCollideWorldBounds(true);
 this.hitSound = this.sound.add('coinSound', {volume: 0.7, delay: 0});
 // ボールの作成
 this.ball = this.physics.add.image(400, 500, 'ball');
 this.ball.body.setCollideWorldBounds(true);
 this.ball.body.setBounce(1);
  this.anims.create({
   key: 'explode', // アニメーションの識別キー
   frames: this.anims.generateFrameNumbers('explosion', {
    start: 0, // 開始フレーム番号
    end: 23   // 終了フレーム番号
   }),
   frameRate: 20, // 1秒あたりのフレーム数
   repeat: 0,     // 繰り返し回数 (0で1回のみ再生、-1で無限ループ)
   hideOnComplete: true // アニメーション完了時に非表示にする
});
// ブロックの生成
  this.bricks = this.physics.add.staticGroup();
  for (let y = 0; y < 5; y++) {
   for (let x = 0; x < 12; x++) {
   this.bricks.create(70 + x * 60, 50 + y * 30, 'brick');
  }
 }
this.physics.add.collider(this.ball, this.paddle);
 this.physics.add.collider( this.ball, this.bricks, (ball,brick, ) =>
  {
//  (star as Phaser.Physics.Arcade.Sprite).disableBody(true, true);
const en = brick as Phaser.Physics.Arcade.Sprite;
en.disableBody(true, true);
this.scoreText.addScore(5);
 this.hitSound.play();
 this.createExplosion(en.x-5, en.y+2);
//   this.createExplosion(5,5);
 if (this.bricks.countActive(true) === 0) {
  //   this.gameClearText.setText('YOU WIN!\nClick to Restart');
   this.gameWin();
   }
 });
this.input.once('pointerdown', () => {
 this.startBall();
 });
}
private createExplosion(x: number, y: number) {
 const explosion = this.add.sprite(x, y,'explosion');
 explosion.play('explode');
 explosion.on('animationcomplete', () => {
 explosion.destroy(); // アニメが終わったら消す
  });
 }
startBall() {
  this.ball.body.setVelocity(250, -230);
}
private gameWin() {
  this.physics.pause();
  this.add.text(400, 300, 'YOU WIN!\nClick to Restart',
  { fontSize: '54px', color: '#009dff' }).setOrigin(0.5).setAlign('center');
  this.input.once('pointerdown', () => {
   this.scene.restart();
  });
 }

update() {
 const pointer = this.input.activePointer;
 this.paddle.x = Phaser.Math.Clamp(pointer.x, 50, 750);
 // ゲームオーバー判定
 if (this.ball.y > 600) {
 //  this.scene.restart();
 this.gameOver();
   }
}

private gameOver() {
 this.physics.pause(); // 物理演算を停止
 this.ball.setTint(0xff0000); // ボールを赤くする
 const gameOverText = this.add.text(400, 300, 'GAME OVER', {
   fontSize: '64px',
   color: '#ff0000'
 }).setOrigin(0.5);
 // 画面クリックで再開
 this.input.once('pointerdown', () => {
   this.scene.restart();
   });
 }
}