space-game/src/scoreboard.ts
Michael Mainguy 03f170e150
Some checks failed
Build / build (push) Failing after 18s
Create mesh-based physics for ship and optimize planet geometry
- Update Ship class to use CONVEX_HULL physics from ship1.glb
  - Find geometry mesh from loaded GLB and create physics from it
  - Move physics creation to initialize() after mesh loads
  - Add fallback to BOX shape if mesh not found

- Fix ship position setter for async initialization
  - Add null check for physics body
  - Set transform position directly if body doesn't exist yet
  - Prevents crash when position set before mesh loads

- Optimize planet vertex count for performance
  - Reduce sphere segments from 32 to 12
  - ~144 vertices vs ~1024 vertices per planet
  - Planets are background objects, lower poly acceptable

- Update ship1.glb model

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 08:22:21 -05:00

123 lines
4.2 KiB
TypeScript

import {AdvancedDynamicTexture, Control, StackPanel, TextBlock} from "@babylonjs/gui";
import {DefaultScene} from "./defaultScene";
import {
Angle,
MeshBuilder,
Observable, StandardMaterial,
Vector3,
} from "@babylonjs/core";
export type ScoreEvent = {
score: number,
message: string,
remaining: number,
timeRemaining? : number
}
export class Scoreboard {
private _score: number = 0;
private _remaining: number = 0;
private _timeRemaining: number = 61;
private _lastMessage: string = null;
private _active = false;
private _done = false;
public readonly onScoreObservable: Observable<ScoreEvent> = new Observable<ScoreEvent>();
constructor() {
this.initialize();
}
public get done() {
return this._done;
}
public set done(value: boolean) {
this._done = value;
}
public setRemainingCount(count: number) {
this._remaining = count;
}
private initialize() {
const scene = DefaultScene.MainScene;
const parent = scene.getNodeById('ship');
console.log('Scoreboard parent:', parent);
console.log('Initializing scoreboard');
const scoreboard = MeshBuilder.CreatePlane("scoreboard", {width: 1, height: 1}, scene);
scoreboard.renderingGroupId = 3;
const material = new StandardMaterial("scoreboard", scene);
scoreboard.parent =parent;
scoreboard.position.y = 1.05;
scoreboard.position.z = 2.1;
scoreboard.visibility = .5;
scoreboard.scaling = new Vector3(.4, .4, .4);
const advancedTexture = AdvancedDynamicTexture.CreateForMesh(scoreboard, 512, 512);
advancedTexture.background = "black";
advancedTexture.hasAlpha = false;
const scoreText = this.createText();
const fpsText = this.createText();
fpsText.text = "FPS: 60";
const hullText = this.createText();
hullText.text = 'Hull: 100%';
const remainingText = this.createText();
remainingText.text = 'Remaining: 0';
const timeRemainingText = this.createText();
timeRemainingText.text = 'Time: 2:00';
const panel = new StackPanel();
panel.isVertical = true;
panel.height = 1;
panel.isVertical = true;
panel.addControl(scoreText);
panel.addControl(remainingText);
panel.addControl(fpsText);
panel.addControl(hullText);
panel.addControl(timeRemainingText);
advancedTexture.addControl(panel);
let i = 0;
let lastSecond: number = Date.now();
const afterRender = scene.onAfterRenderObservable.add(() => {
scoreText.text = `Score: ${this.calculateScore()}`;
remainingText.text = `Remaining: ${this._remaining}`;
const now = Date.now();
if (this._active && (Math.floor(lastSecond / 1000) < Math.floor(now/1000))) {
this._timeRemaining--;
if (this._timeRemaining <= 0) {
scene.onAfterRenderObservable.remove(afterRender);
}
lastSecond = now;
timeRemainingText.text = `Time: ${Math.floor(this._timeRemaining/60).toString().padStart(2,"0")}:${(this._timeRemaining%60).toString().padStart(2,"0")}`;
}
if (i++%60 == 0) {
fpsText.text = `FPS: ${Math.floor(scene.getEngine().getFps())}`;
}
});
this.onScoreObservable.add((score: ScoreEvent) => {
this._score += score.score * this._timeRemaining;
this._remaining += score.remaining;
this._lastMessage = score.message;
if (score.timeRemaining) {
this._timeRemaining = score.timeRemaining;
}
});
this._active = true;
}
private createText(): TextBlock {
const text1 = new TextBlock();
text1.color = "white";
text1.fontSize = "60px";
text1.height = "80px";
text1.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
text1.textVerticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
return text1;
}
private calculateScore() {
return Math.floor(this._score);
}
}