1. **중앙 네트워크/흐름 컨트롤러

MultiFlowController.ts**

설명

코드

ts
static initializeSocketListeners() {
  // (생략) ... 소켓 연결, join-room 등
  window.socket.on("game-event", (message: any) => {
    const { type, payload, roomId: incomingRoomId } = message;
    // ... roomId 체크
    switch (type) {
      case "spawn-mole":
      case "hit-mole":
      case "score-update":
        cc.director.emit(type, payload); // → 아래에서 각 컨트롤러가 on()으로 받음
        break;
      case "move-scene":
        cc.director.loadScene(payload.sceneName);
        break;
      // ... 기타
    }
  });
}
static endGame(sceneInstance: {isGameOver:boolean, unscheduleAllCallbacks:()=>void, score:number}) {
  if (sceneInstance.isGameOver) return;
  sceneInstance.isGameOver = true;
  sceneInstance.unscheduleAllCallbacks?.();

  const roomId = GameState.createdRoomId || GameState.incomingRoomId;
  window.socket.emit("game-event", {
    type: "game-end",
    roomId,
    payload: {
      score: sceneInstance.score,
      nickname: GameState.nickname,
      character: GameState.character,
      isHost: GameState.isHost
    }
  });
}


2. **게임 씬 통합 컨트롤러

MultiplayerMoleGameController.ts**

설명

코드

ts
start() {
  this.myGameCtrl = this.myGameArea.getComponent(PlayerMoleGameScene);
  this.opponentView = this.opponentGameArea.getComponent(OpponentMoleViewer);
  **// 이게 무조건 이 위치에 있어야함** 
  **MultiGameFlowController.initializeSocketListeners();**

  cc.director.on("spawn-mole", (data) => this.opponentView.spawnMoleFromData(data));
  cc.director.on("hit-mole", (data) => this.opponentView.hitMoleAnimation(data.index, data.moleType));
  cc.director.on("score-update", (data) => {
    if ((GameState.isHost && data.player === "guest") || (!GameState.isHost && data.player === "host")) {
      this.opponentView.setScore(data.score);
    }
  });
  cc.director.on("multi-game-start", () => this.myGameCtrl?.startGame());
}

3. **내 실제 게임 로직

PlayerMoleGameScene.ts**