MainScene


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