Newer
Older
PixelPaintWar / apps / client / src / scenes / game / application / GameLoop.ts
import { Application, Container, Ticker } from "pixi.js";
import { config } from "@repo/shared";
import { socketManager } from "@client/network/SocketManager";
import { LocalPlayerController, RemotePlayerController } from "../entities/player/PlayerController";
import type { GamePlayers } from "./game.types";

type GameLoopOptions = {
  app: Application;
  worldContainer: Container;
  players: GamePlayers;
  myId: string;
  getJoystickInput: () => { x: number; y: number };
};

export class GameLoop {
  private app: Application;
  private worldContainer: Container;
  private players: GamePlayers;
  private myId: string;
  private getJoystickInput: () => { x: number; y: number };
  private lastPositionSentTime = 0;
  private wasMoving = false;

  constructor({ app, worldContainer, players, myId, getJoystickInput }: GameLoopOptions) {
    this.app = app;
    this.worldContainer = worldContainer;
    this.players = players;
    this.myId = myId;
    this.getJoystickInput = getJoystickInput;
  }

  public tick = (ticker: Ticker) => {
    const me = this.players[this.myId];
    if (!me || !(me instanceof LocalPlayerController)) return;

    const deltaSeconds = ticker.deltaMS / 1000;

    const { x: dx, y: dy } = this.getJoystickInput();
    const isMoving = dx !== 0 || dy !== 0;

    if (isMoving) {
      me.applyLocalInput({ axisX: dx, axisY: dy, deltaTime: deltaSeconds });
      me.tick();

      const now = performance.now();
      if (now - this.lastPositionSentTime >= config.GAME_CONFIG.PLAYER_POSITION_UPDATE_MS) {
        const position = me.getPosition();
        socketManager.game.sendMove(position.x, position.y);
        this.lastPositionSentTime = now;
      }
    } else if (this.wasMoving) {
      me.tick();
      const position = me.getPosition();
      socketManager.game.sendMove(position.x, position.y);
    } else {
      me.tick();
    }
    this.wasMoving = isMoving;

    Object.values(this.players).forEach((player) => {
      if (player instanceof RemotePlayerController) {
        player.tick(deltaSeconds);
      }
    });

    const meDisplay = me.getDisplayObject();
    this.worldContainer.position.set(-(meDisplay.x - this.app.screen.width / 2), -(meDisplay.y - this.app.screen.height / 2));
  };
}