93 lines
3.3 KiB
TypeScript
93 lines
3.3 KiB
TypeScript
import { Vector3 } from "three";
|
|
import { CameraC_internal, UpdateController } from "@hitplay/playable_template";
|
|
import { ThreeC } from "./ThreeC";
|
|
import { resourceCounterBgSrc } from "../resources/images/images";
|
|
import { projectScreenPointToWorldRay } from "../utils/screenWorldProjection";
|
|
|
|
// See HudC's identical constant — same reasoning, this is a second instance
|
|
// of the same anchor technique for a second counter.
|
|
const ANCHOR_DISTANCE = 2.5;
|
|
|
|
// Second resource counter, stacked directly below HudC's own wood counter
|
|
// (see .resource-hud--pistol in ui.css). The zombie-part chunks dropped by
|
|
// kills (see ZombiePartC, spent on the pistol's own progression — see
|
|
// PistolLevelC / its Pay Zone) get the exact same fly-to-a-HUD-counter
|
|
// treatment wood does, just their own plate and their own live balance.
|
|
//
|
|
// Reuses HudC's plate art rather than shipping a second bespoke asset — a
|
|
// CSS hue-rotate on the plate (see ui.css) is what reads it as a different
|
|
// currency.
|
|
export class PistolResourceHudC {
|
|
private static initialized = false;
|
|
private static plateEl: HTMLElement;
|
|
private static countTextEl: HTMLElement;
|
|
private static lastDisplayedCount = -1;
|
|
private static balanceGetter: (() => number) | null = null;
|
|
|
|
static init() {
|
|
if (this.initialized) return;
|
|
this.initialized = true;
|
|
|
|
this.buildDom();
|
|
|
|
UpdateController.Instance.onUpdate.addDelegate(() => this.update());
|
|
}
|
|
|
|
// Same technique as HudC.getWorldAnchorPosition — see its own comment.
|
|
static getWorldAnchorPosition(): Vector3 {
|
|
const canvasRect = ThreeC.renderer.domElement.getBoundingClientRect();
|
|
const plateRect = this.plateEl.getBoundingClientRect();
|
|
|
|
const screenX = plateRect.right;
|
|
const screenY = plateRect.top + plateRect.height / 2;
|
|
|
|
const camera = CameraC_internal.getCamera();
|
|
const { origin, direction } = projectScreenPointToWorldRay(camera, canvasRect, screenX, screenY);
|
|
return origin.addScaledVector(direction, ANCHOR_DISTANCE);
|
|
}
|
|
|
|
// Injected rather than importing ZombiePartC/PayZoneC directly, matching
|
|
// HudC.setBalanceGetter.
|
|
static setBalanceGetter(getBalance: () => number) {
|
|
this.balanceGetter = getBalance;
|
|
}
|
|
|
|
private static buildDom() {
|
|
const holder = document.createElement("div");
|
|
holder.className = "resource-hud resource-hud--pistol";
|
|
|
|
const plate = document.createElement("div");
|
|
plate.className = "resource-hud__plate";
|
|
plate.style.backgroundImage = `url(${resourceCounterBgSrc})`;
|
|
|
|
const count = document.createElement("span");
|
|
count.className = "resource-hud__count";
|
|
|
|
const countText = document.createElement("span");
|
|
countText.className = "gamefont-x";
|
|
countText.textContent = "0";
|
|
count.appendChild(countText);
|
|
|
|
plate.appendChild(count);
|
|
holder.appendChild(plate);
|
|
|
|
const uiRoot = document.getElementById("ui-safe-area") ?? document.body;
|
|
uiRoot.appendChild(holder);
|
|
|
|
this.plateEl = plate;
|
|
this.countTextEl = countText;
|
|
}
|
|
|
|
private static update() {
|
|
if (!this.balanceGetter) return;
|
|
const count = this.balanceGetter();
|
|
if (count === this.lastDisplayedCount) return;
|
|
this.lastDisplayedCount = count;
|
|
this.countTextEl.textContent = String(count);
|
|
|
|
this.plateEl.classList.remove("is-bumping");
|
|
void this.plateEl.offsetWidth;
|
|
this.plateEl.classList.add("is-bumping");
|
|
}
|
|
}
|