sparkletown/sparkle

View on GitHub
src/components/templates/AnimateMap/game/map/systems/DebugSystem.ts

Summary

Maintainability
D
2 days
Test Coverage
import { Engine, NodeList, System } from "@ash.ts/ash";
import { Container, DisplayObject, Graphics, Sprite } from "pixi.js";
import { Viewport } from "pixi-viewport";

import { Point } from "types/utility";

import { GameConfig } from "components/templates/AnimateMap/configs/GameConfig";

import { RoomPointNode } from "../../../bridges/DataProvider/Structures/RoomsModel";
import { EventType } from "../../../bridges/EventProvider/EventProvider";
import { GameInstance } from "../../GameInstance";
import EntityFactory from "../entities/EntityFactory";
import { BotNode } from "../nodes/BotNode";
import { PlayerNode } from "../nodes/PlayerNode";
import { VenueNode } from "../nodes/VenueNode";
import { ViewportNode } from "../nodes/ViewportNode";

export class DebugSystem extends System {
  private container: Container;

  private venues?: NodeList<VenueNode>;
  private bots?: NodeList<BotNode>;
  private viewportNodes?: NodeList<ViewportNode>;
  private player?: NodeList<PlayerNode>;

  private zoomUpdated = true;
  private currentZoom = 0;

  constructor(
    container: Container,
    private creator: EntityFactory,
    private viewport: Viewport
  ) {
    super();
    this.container = container;
  }

  addToEngine(engine: Engine) {
    this.viewportNodes = engine.getNodeList(ViewportNode);
    this.viewportNodes.nodeAdded.add(this.handleViewprotAdded);
    if (this.viewportNodes.head) {
      this.currentZoom = this.viewportNodes.head.viewport.zoomLevel;
    }

    this.bots = engine.getNodeList(BotNode);

    this.player = engine.getNodeList(PlayerNode);

    // this.drawVenuesOuterCircle();
    // this.drawPlayaBorderCircle();
    // this.drawVenuesInnerCircle();

    this.venues = engine.getNodeList(VenueNode);
    this.venues.nodeAdded.add(this.venueAdded);
    this.venues.nodeRemoved.add(this.venueRemoved);

    GameInstance.instance.eventProvider.on(
      EventType.ON_ROOMS_CHANGED,
      this.handleRooms
    );
  }

  removeFromEngine(engine: Engine) {
    this.container?.removeChildren();

    this.venues?.nodeAdded.remove(this.venueAdded);
    this.venues?.nodeRemoved.remove(this.venueRemoved);
    this.venues = undefined;

    this.viewportNodes?.nodeAdded.remove(this.handleViewprotAdded);
    this.viewportNodes = undefined;

    this.bots = undefined;
    this.player = undefined;

    GameInstance.instance.eventProvider.off(
      EventType.ON_ROOMS_CHANGED,
      this.handleRooms
    );
  }

  update(time: number) {
    this.updateLineOfSight(time);

    const showDebug = false;
    if (showDebug) {
      this.updateBubbling();
      this.drawVenuesInnerCircle();
      this.drawVenuesOuterCircle();
      this.drawPlayaBorderCircle();
    }
  }

  private handleRooms = (points: RoomPointNode[]) => {
    const name = "roomPoint";
    if (this.container) {
      this.container.children.forEach((display) => {
        if (display.name.indexOf(name) > -1 && display.parent) {
          display.parent.removeChild(display);
        }
      });

      const set: Set<string> = new Set();
      points.forEach((item) => item.data.forEach((rect) => set.add(rect)));
      console.log(set);
      let count = 0;
      set.forEach((rect) => {
        const rectPoints = points.filter((items) => items.data.includes(rect));

        let min = { x: rectPoints[0].x, y: rectPoints[0].y };
        let max = { x: rectPoints[0].x, y: rectPoints[0].y };

        rectPoints.forEach((point) => {
          if (point.x < min.x && point.y < min.y) min = point;
          if (point.x > max.x && point.y > max.y) max = point;
        });

        const g: Graphics = new Graphics();
        g.name = `${name}${++count}`;
        g.lineStyle(4, 0x6108e6);
        g.drawRect(0, 0, max.x - min.x, max.y - min.y);
        g.position.set(min.x, min.y);
        this.container?.addChild(g);
      });
    }
  };

  private halo = {
    duration: 100,
    time: 0,
    direction: 1,
    getValue: (x: number) => {
      return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
    },
  };

  private updateLineOfSight(time: number) {
    const name = "visionOfSightRadius";
    const config: GameConfig = GameInstance.instance.getConfig();
    const currentZoomLevel = config.zoomViewportToLevel(this.viewport.scale.y);
    if (this.player && this.player.head) {
      const center: Point = this.player?.head
        ? { x: this.player.head.position.x, y: this.player.head.position.y }
        : this.viewport.center;
      const lineOfSight = config.getAvatarLineOfSightByZoomLevel(1);
      const visionOfSightRadius =
        this.player.head.position.scaleX * lineOfSight;

      let s = this.container?.getChildByName(name) as Sprite;
      if (!s) {
        s = new Sprite();
        s.name = name;

        const g: Graphics = new Graphics();
        g.alpha = 0.2;
        s.addChild(g);
        this.container?.addChild(s);
      }
      s.position.set(center.x, center.y);

      const lineThikness =
        currentZoomLevel === GameConfig.ZOOM_LEVEL_WALKING ? 2 : 4;

      const dayTime = Math.floor(
        GameInstance.instance.getConfig().getCurUTCTime() % 24
      );
      const backgroundColor = dayTime > 5 && dayTime < 18 ? 0x5e07ca : 0xffffff;
      const borderColor = dayTime > 5 && dayTime < 18 ? 0x6108e6 : 0xffffff;

      const g: Graphics = s.getChildAt(0) as Graphics;
      g.clear();
      g.beginFill(backgroundColor, 0.15);
      g.drawCircle(0, 0, visionOfSightRadius);
      g.endFill();
      g.lineStyle(lineThikness, borderColor);
      g.drawCircle(0, 0, visionOfSightRadius);

      this.halo.time +=
        time * (this.halo.direction === 1 ? 1 : 0.7) * this.halo.direction;
      if (this.halo.time <= 0) {
        this.halo.time = 0;
        this.halo.direction = 1;
      } else if (this.halo.time >= this.halo.duration) {
        this.halo.time = this.halo.duration;
        this.halo.direction = -1;
      }
      const value = this.halo.getValue(this.halo.time / this.halo.duration) / 3;

      s.scale.set(1 + value);
    } else {
      const s: Sprite | undefined = this.container?.getChildByName(
        name
      ) as Sprite;
      if (s) {
        this.container?.removeChild(s);
      }
    }
  }

  private updateBubbling() {
    if (Math.random() > 0.05) {
      return;
    }

    for (
      let node: BotNode | null | undefined = this.bots?.head;
      node;
      node = node?.next
    ) {
      if (Math.random() < 0.01) {
        this.creator.createBubble(node.bot.data.data.id, "Hello from debug!!!");
        return;
      }
    }
  }

  private handleViewprotAdded = (node: ViewportNode) => {
    if (node.viewport.zoomLevel !== this.currentZoom) {
      this.zoomUpdated = true;
    }
  };

  private drawVenuesInnerCircle() {
    const config = GameInstance.instance.getConfig();
    const center: Point = config.worldCenter;
    const radius = config.worldWidth * 0.073;

    const g: Graphics = new Graphics();
    g.beginFill(0x00ff00);
    g.drawCircle(center.x, center.y, radius);
    g.endFill();
    g.alpha = 0.1;
    this.container?.addChild(g);
  }

  private drawVenuesOuterCircle() {
    const config = GameInstance.instance.getConfig();
    const center: Point = config.worldCenter;
    const radius = config.worldWidth * 0.1713;

    const g: Graphics = new Graphics();
    g.beginFill(0x00ff00);
    g.drawCircle(center.x, center.y, radius);
    g.endFill();
    g.alpha = 0.1;
    this.container?.addChild(g);
  }

  private drawPlayaBorderCircle() {
    const config = GameInstance.instance.getConfig();
    const center: Point = config.worldCenter;
    const radius = config.worldWidth * 0.4;

    const g: Graphics = new Graphics();
    g.beginFill(0x00ff00);
    g.drawCircle(center.x, center.y, radius);
    g.endFill();
    g.alpha = 0.1;
    this.container?.addChild(g);
  }

  private venueAdded = (node: VenueNode) => {
    const g: Graphics = new Graphics();
    g.position.set(node.position.x, node.position.y);
    g.name = node.venue.model.data.url;
    g.beginFill(0x0000ff);
    g.drawCircle(0, 0, node.collision.radius);
    g.endFill();
    g.alpha = 0.1;
    // this.container?.addChild(g);
  };

  private venueRemoved = (node: VenueNode) => {
    const displayObject:
      | DisplayObject
      | null
      | undefined = this.container?.getChildByName(node.venue.model.data.url);
    if (displayObject) {
      this.container?.removeChild();
    }
  };
}