import { Scene } from 'phaser';
import Player from './Player';
import ScoreText from "./ScoreText";
export default class MainScene extends Scene {
private player!: Phaser.Physics.Arcade.Sprite;
private platforms!: Phaser.Physics.Arcade.StaticGroup;
private joystick: any;
private rexVirtualJoystick: any;
private stars!: Phaser.Physics.Arcade.Group;
private hitSound!: Phaser.Sound.BaseSound;
private score: number = 0;
private timeLeft: number =30; // 制限時間(30秒)
private scoreText!: Phaser.GameObjects.Text;
private timerText!: Phaser.GameObjects.Text;
private timerEvent!: Phaser.Time.TimerEvent;
constructor() {
super('MainScene');
}
preload() {
this.load.image('sky', 'assets/sky.png');
this.load.image('ground', 'assets/platform.png');
this.load.spritesheet('player', 'assets/player3.png', {
frameWidth: 116, frameHeight: 168
});
this.load.image('star', 'assets/star.png');
this.load.image('bomb', 'assets/bomb.png');
this.load.audio('coinSound', 'assets/coin.mp3');
}
create() {
this.add.image(950 / 2, 550 / 2, 'sky').setScale(1.5).setAlpha(0.9);
this.scoreText = this.add.text(16, 16, 'Stars: 0 / 10',
{ fontSize: '32px', color: '#fff' });
this.timerText = this.add.text(16, 50, `Time: ${this.timeLeft}`,
{ fontSize: '32px', color: '#ff0000' });
this.hitSound = this.sound.add('coinSound', {volume: 0.7, delay: 0});
this.platforms = this.physics.add.staticGroup();
this.platforms.create(400, 548, 'ground').setScale(2).refreshBody();
this.platforms.create(640, 350, 'ground');
this.platforms.create(50, 200, 'ground');
this.platforms.create(750, 180, 'ground');
this.stars = this.physics.add.group({
key: 'star',
repeat: 11,
setXY: {x: 12, y: 0, stepX: 70},
});
this.physics.add.collider(this.stars, this.platforms);
(this.stars.getChildren() as Phaser.Physics.Arcade.Sprite[]).forEach(star => {
star.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});
this.player = new Player(this, 400, 360, 'player');
this.player.setBounce(0.2).setScale(0.5);
this.physics.add.existing(this.player);
this.player.setCollideWorldBounds(true);
this.physics.add.collider(this.player, this.platforms);
this.joystick = this.rexVirtualJoystick.add(this, {
x: 100,
y: 400,
radius: 100,
base: this.add.circle(0, 0, 100, 0x888888),
thumb: this.add.circle(0, 0, 50, 0xcccccc),
dir: '8dir', // 8方向入力
forceMin: 16,
fixed: false, // ここをfalseに設定
enable: true
}).setVisible(false); // 最初は非表示にしておく
this.input.on('pointerdown', (pointer: Phaser.Input.Pointer) => {
this.joystick.x = pointer.x;
this.joystick.y = pointer.y;
this.joystick.setVisible(true); // タッチした場所で表示
this.joystick.base.depth = 100; // 必要に応じて重なり順を調整
this.joystick.thumb.depth = 101;
});
// 指を離した時に非表示にする場合
this.input.on('pointerup', () => {
this.joystick.setVisible(false);
});
this.physics.add.collider( this.player, this.stars, (player,star, ) =>
{
//(star as Phaser.Physics.Arcade.Sprite).disableBody(true, true);
const en = star as Phaser.Physics.Arcade.Sprite;
en.disableBody(true, true);
//this.scoreText.addScore(5);
this.score += 1;
this.scoreText.setText(`Stars: ${this.score} / 10`);
// 10個集めたらクリア処理へ
if (this.score >= 10) {
this.winGame();
this.input.once('pointerdown', () => {
//this.updateEnemyBehavior();
this.score = 0;
this.timerEvent.destroy();
this.timeLeft = 30;
this.scene.restart();
});
}
this.hitSound.play();
if (this.stars.countActive(true) === 0) {
this.spawnNewStars(5);
}
});
this.timerEvent = this.time.addEvent({
delay: 1000,
callback: this.updateTimer,
callbackScope: this,
loop: true
});
}
// 星を生成する関数
spawnStars() {
for (let i = 0; i < 12; i++) {
const star = this.stars.create(i * 70, 0, 'star');
star.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
}
}
private updateTimer() {
this.timeLeft -= 1;
this.timerText.setText(`Time: ${this.timeLeft}`);
// 時間切れになったらゲームオーバー
if (this.timeLeft <= 0) {
this.gameOver();
this.input.once('pointerdown', () => {
// this.updateEnemyBehavior();
this.score = 0;
this.timerEvent.destroy();
this.timeLeft = 30;
this.scene.restart();
});
}
}
private gameOver() {
this.timerEvent.remove(); // タイマー停止
//this.timerEvent.destroy(); // タイマー停止
this.physics.pause(); // 物理演算停止
this.add.text(400, 300, 'GAME OVER',
{ fontSize: '64px', color: '#f00' }).setOrigin(0.5);
}
private winGame() {
this.timerEvent.remove();
this.add.text(400, 300, 'YOU WIN!',
{ fontSize: '64px', color: '#0f0' }).setOrigin(0.5);
}
private spawnNewStars(count: number) {
//count分だけ星を再活性化、または新規作成
for (let i = 0; i < count; i++) {
// 画面内のランダムな位置に配置
const x = Phaser.Math.Between(20, 900);
const y = Phaser.Math.Between(10, 0);
// 既存の非アクティブなオブジェクトを再利用
const star = this.stars.get(x, y, 'star');
if (star) {
star.setActive(true);
star.setVisible(true);
star.body.enable = true;
// 必要に応じてバウンド設定などを再適用
star.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
}
}
}
update() {
// 3. 毎フレーム、ジョイスティックの状態をプレイヤーに渡す
if (this.player) {
this.player.update(this.joystick);
}
}
}