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();
});
}
}