Refactor scoreboard to use GLB mesh and improve ship mechanics
All checks were successful
Build / build (push) Successful in 1m19s
All checks were successful
Build / build (push) Successful in 1m19s
- Move scoreboard ownership from Level1 to Ship class for better encapsulation - Refactor scoreboard.initialize() to accept GLB submesh (Screen material mesh) - Dispose original material when applying AdvancedDynamicTexture to mesh - Change scoreboard background to green for visibility testing - Increase ship velocities: MAX_LINEAR_VELOCITY to 200, LINEAR_FORCE_MULTIPLIER to 1200 - Adjust ammo spawn position (y: 0.5, z: 7.1) and velocity (200000) - Update sight reticle position to match new ammo spawn point (y: 0.5) - Fix sight circle rotation and rendering group assignment - Update ship2.glb, ship1.glb, and base.glb models - Comment out ship position override in level initialization 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
37128d8fbd
commit
f11005fdb6
BIN
public/base.glb
BIN
public/base.glb
Binary file not shown.
BIN
public/ship1.glb
BIN
public/ship1.glb
Binary file not shown.
BIN
public/ship2.glb
BIN
public/ship2.glb
Binary file not shown.
@ -27,7 +27,6 @@ export class Level1 implements Level {
|
|||||||
private _initialized: boolean = false;
|
private _initialized: boolean = false;
|
||||||
private _startBase: AbstractMesh;
|
private _startBase: AbstractMesh;
|
||||||
private _endBase: AbstractMesh;
|
private _endBase: AbstractMesh;
|
||||||
private _scoreboard: Scoreboard;
|
|
||||||
private _levelConfig: LevelConfig;
|
private _levelConfig: LevelConfig;
|
||||||
private _audioEngine: AudioEngineV2;
|
private _audioEngine: AudioEngineV2;
|
||||||
private _deserializer: LevelDeserializer;
|
private _deserializer: LevelDeserializer;
|
||||||
@ -38,7 +37,7 @@ export class Level1 implements Level {
|
|||||||
this._audioEngine = audioEngine;
|
this._audioEngine = audioEngine;
|
||||||
this._deserializer = new LevelDeserializer(levelConfig);
|
this._deserializer = new LevelDeserializer(levelConfig);
|
||||||
this._ship = new Ship(audioEngine);
|
this._ship = new Ship(audioEngine);
|
||||||
this._scoreboard = new Scoreboard();
|
|
||||||
const xr = DefaultScene.XR;
|
const xr = DefaultScene.XR;
|
||||||
|
|
||||||
debugLog('Level1 constructor - Setting up XR observables');
|
debugLog('Level1 constructor - Setting up XR observables');
|
||||||
@ -105,18 +104,18 @@ export class Level1 implements Level {
|
|||||||
setLoadingMessage("Loading level from configuration...");
|
setLoadingMessage("Loading level from configuration...");
|
||||||
|
|
||||||
// Use deserializer to create all entities from config
|
// Use deserializer to create all entities from config
|
||||||
const entities = await this._deserializer.deserialize(this._scoreboard.onScoreObservable);
|
const entities = await this._deserializer.deserialize(this._ship.scoreboard.onScoreObservable);
|
||||||
|
|
||||||
this._startBase = entities.startBase;
|
this._startBase = entities.startBase;
|
||||||
// sun and planets are already created by deserializer
|
// sun and planets are already created by deserializer
|
||||||
|
|
||||||
// Initialize scoreboard with total asteroid count
|
// Initialize scoreboard with total asteroid count
|
||||||
this._scoreboard.setRemainingCount(entities.asteroids.length);
|
this._ship.scoreboard.setRemainingCount(entities.asteroids.length);
|
||||||
debugLog(`Initialized scoreboard with ${entities.asteroids.length} asteroids`);
|
debugLog(`Initialized scoreboard with ${entities.asteroids.length} asteroids`);
|
||||||
|
|
||||||
// Position ship from config
|
// Position ship from config
|
||||||
const shipConfig = this._deserializer.getShipConfig();
|
const shipConfig = this._deserializer.getShipConfig();
|
||||||
this._ship.position = new Vector3(shipConfig.position[0], shipConfig.position[1], shipConfig.position[2]);
|
//this._ship.position = new Vector3(shipConfig.position[0], shipConfig.position[1], shipConfig.position[2]);
|
||||||
|
|
||||||
// Add distance constraints to asteroids (if physics enabled)
|
// Add distance constraints to asteroids (if physics enabled)
|
||||||
setLoadingMessage("Configuring physics constraints...");
|
setLoadingMessage("Configuring physics constraints...");
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import {AdvancedDynamicTexture, Control, StackPanel, TextBlock} from "@babylonjs/gui";
|
import {AdvancedDynamicTexture, Control, StackPanel, TextBlock} from "@babylonjs/gui";
|
||||||
import {DefaultScene} from "./defaultScene";
|
import {DefaultScene} from "./defaultScene";
|
||||||
import {
|
import {
|
||||||
|
AbstractMesh, Mesh,
|
||||||
MeshBuilder,
|
MeshBuilder,
|
||||||
Observable, StandardMaterial,
|
Observable, StandardMaterial,
|
||||||
Vector3,
|
Vector3,
|
||||||
@ -21,7 +22,7 @@ export class Scoreboard {
|
|||||||
private _done = false;
|
private _done = false;
|
||||||
public readonly onScoreObservable: Observable<ScoreEvent> = new Observable<ScoreEvent>();
|
public readonly onScoreObservable: Observable<ScoreEvent> = new Observable<ScoreEvent>();
|
||||||
constructor() {
|
constructor() {
|
||||||
this.initialize();
|
|
||||||
}
|
}
|
||||||
public get done() {
|
public get done() {
|
||||||
return this._done;
|
return this._done;
|
||||||
@ -32,26 +33,40 @@ export class Scoreboard {
|
|||||||
public setRemainingCount(count: number) {
|
public setRemainingCount(count: number) {
|
||||||
this._remaining = count;
|
this._remaining = count;
|
||||||
}
|
}
|
||||||
private initialize() {
|
public initialize(baseMesh: Mesh) {
|
||||||
const scene = DefaultScene.MainScene;
|
const scene = DefaultScene.MainScene;
|
||||||
|
|
||||||
const parent = scene.getNodeById('ship');
|
const parent = scene.getNodeById('ship');
|
||||||
debugLog('Scoreboard parent:', parent);
|
debugLog('Scoreboard parent:', parent);
|
||||||
debugLog('Initializing scoreboard');
|
debugLog('Initializing scoreboard');
|
||||||
const scoreboard = MeshBuilder.CreatePlane("scoreboard", {width: 1, height: 1}, scene);
|
let scoreboard = null;
|
||||||
// scoreboard.renderingGroupId = 3;
|
|
||||||
const material = new StandardMaterial("scoreboard", scene);
|
|
||||||
|
|
||||||
|
if (baseMesh) {
|
||||||
|
scoreboard = baseMesh;
|
||||||
|
|
||||||
|
scoreboard.material.dispose();
|
||||||
|
//scoreboard.material = new StandardMaterial("scoreboard", scene);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
scoreboard = MeshBuilder.CreatePlane("scoreboard", {width: 1, height: 1}, scene);
|
||||||
scoreboard.parent =parent;
|
scoreboard.parent =parent;
|
||||||
|
|
||||||
scoreboard.position.y = 1.05;
|
scoreboard.position.y = 1.05;
|
||||||
scoreboard.position.z = 2.1;
|
scoreboard.position.z = 2.1;
|
||||||
scoreboard.visibility = .5;
|
scoreboard.visibility = .5;
|
||||||
|
|
||||||
scoreboard.scaling = new Vector3(.4, .4, .4);
|
scoreboard.scaling = new Vector3(.4, .4, .4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// scoreboard.renderingGroupId = 3;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const advancedTexture = AdvancedDynamicTexture.CreateForMesh(scoreboard, 512, 512);
|
const advancedTexture = AdvancedDynamicTexture.CreateForMesh(scoreboard, 512, 512);
|
||||||
advancedTexture.background = "black";
|
advancedTexture.background = "green";
|
||||||
advancedTexture.hasAlpha = false;
|
advancedTexture.hasAlpha = false;
|
||||||
const scoreText = this.createText();
|
const scoreText = this.createText();
|
||||||
|
|
||||||
@ -69,8 +84,8 @@ export class Scoreboard {
|
|||||||
|
|
||||||
const panel = new StackPanel();
|
const panel = new StackPanel();
|
||||||
panel.isVertical = true;
|
panel.isVertical = true;
|
||||||
panel.height = 1;
|
//panel.height = .5;
|
||||||
panel.isVertical = true;
|
//panel.isVertical = true;
|
||||||
panel.addControl(scoreText);
|
panel.addControl(scoreText);
|
||||||
panel.addControl(remainingText);
|
panel.addControl(remainingText);
|
||||||
panel.addControl(fpsText);
|
panel.addControl(fpsText);
|
||||||
@ -92,6 +107,7 @@ export class Scoreboard {
|
|||||||
this._score += score.score;
|
this._score += score.score;
|
||||||
this._remaining += score.remaining;
|
this._remaining += score.remaining;
|
||||||
});
|
});
|
||||||
|
|
||||||
this._active = true;
|
this._active = true;
|
||||||
}
|
}
|
||||||
private createText(): TextBlock {
|
private createText(): TextBlock {
|
||||||
|
|||||||
27
src/ship.ts
27
src/ship.ts
@ -22,9 +22,10 @@ import {DefaultScene} from "./defaultScene";
|
|||||||
import { GameConfig } from "./gameConfig";
|
import { GameConfig } from "./gameConfig";
|
||||||
import { Sight } from "./sight";
|
import { Sight } from "./sight";
|
||||||
import debugLog from './debug';
|
import debugLog from './debug';
|
||||||
const MAX_LINEAR_VELOCITY = 80;
|
import {Scoreboard} from "./scoreboard";
|
||||||
|
const MAX_LINEAR_VELOCITY = 200;
|
||||||
const MAX_ANGULAR_VELOCITY = 1.8;
|
const MAX_ANGULAR_VELOCITY = 1.8;
|
||||||
const LINEAR_FORCE_MULTIPLIER = 800;
|
const LINEAR_FORCE_MULTIPLIER = 1200;
|
||||||
const ANGULAR_FORCE_MULTIPLIER = 20;
|
const ANGULAR_FORCE_MULTIPLIER = 20;
|
||||||
|
|
||||||
const controllerComponents = [
|
const controllerComponents = [
|
||||||
@ -52,6 +53,7 @@ type ControllerEvent = {
|
|||||||
|
|
||||||
export class Ship {
|
export class Ship {
|
||||||
private _ship: TransformNode;
|
private _ship: TransformNode;
|
||||||
|
private _scoreboard: Scoreboard;
|
||||||
private _controllerObservable: Observable<ControllerEvent> = new Observable<ControllerEvent>();
|
private _controllerObservable: Observable<ControllerEvent> = new Observable<ControllerEvent>();
|
||||||
private _ammoMaterial: StandardMaterial;
|
private _ammoMaterial: StandardMaterial;
|
||||||
private _primaryThrustVectorSound: StaticSound;
|
private _primaryThrustVectorSound: StaticSound;
|
||||||
@ -87,7 +89,9 @@ export class Ship {
|
|||||||
volume: 0.5
|
volume: 0.5
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
public get scoreboard(): Scoreboard {
|
||||||
|
return this._scoreboard;
|
||||||
|
}
|
||||||
private shoot() {
|
private shoot() {
|
||||||
// Only allow shooting if physics is enabled
|
// Only allow shooting if physics is enabled
|
||||||
const config = GameConfig.getInstance();
|
const config = GameConfig.getInstance();
|
||||||
@ -98,8 +102,9 @@ export class Ship {
|
|||||||
this._shot?.play();
|
this._shot?.play();
|
||||||
const ammo = new InstancedMesh("ammo", this._ammoBaseMesh as Mesh);
|
const ammo = new InstancedMesh("ammo", this._ammoBaseMesh as Mesh);
|
||||||
ammo.parent = this._ship;
|
ammo.parent = this._ship;
|
||||||
ammo.position.y = 2;
|
ammo.position.y = .5;
|
||||||
ammo.rotation.x = Math.PI / 2;
|
ammo.position.z = 7.1;
|
||||||
|
//ammo.rotation.x = Math.PI / 2;
|
||||||
ammo.setParent(null);
|
ammo.setParent(null);
|
||||||
const ammoAggregate = new PhysicsAggregate(ammo, PhysicsShapeType.SPHERE, {
|
const ammoAggregate = new PhysicsAggregate(ammo, PhysicsShapeType.SPHERE, {
|
||||||
mass: 1000,
|
mass: 1000,
|
||||||
@ -110,7 +115,7 @@ export class Ship {
|
|||||||
|
|
||||||
ammoAggregate.body.setMotionType(PhysicsMotionType.DYNAMIC);
|
ammoAggregate.body.setMotionType(PhysicsMotionType.DYNAMIC);
|
||||||
|
|
||||||
ammoAggregate.body.setLinearVelocity(this._ship.forward.scale(100000))
|
ammoAggregate.body.setLinearVelocity(this._ship.forward.scale(200000))
|
||||||
//.add(this._ship.physicsBody.getLinearVelocity()));
|
//.add(this._ship.physicsBody.getLinearVelocity()));
|
||||||
|
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
@ -170,7 +175,7 @@ export class Ship {
|
|||||||
|
|
||||||
// Create sight reticle
|
// Create sight reticle
|
||||||
this._sight = new Sight(DefaultScene.MainScene, this._ship, {
|
this._sight = new Sight(DefaultScene.MainScene, this._ship, {
|
||||||
position: new Vector3(0, 2, 125),
|
position: new Vector3(0, .5, 125),
|
||||||
circleRadius: 2,
|
circleRadius: 2,
|
||||||
crosshairLength: 1.5,
|
crosshairLength: 1.5,
|
||||||
lineThickness: 0.1,
|
lineThickness: 0.1,
|
||||||
@ -183,11 +188,16 @@ export class Ship {
|
|||||||
|
|
||||||
|
|
||||||
private async initialize() {
|
private async initialize() {
|
||||||
|
this._scoreboard = new Scoreboard();
|
||||||
|
|
||||||
const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "ship2.glb", DefaultScene.MainScene);
|
const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "ship2.glb", DefaultScene.MainScene);
|
||||||
|
|
||||||
const shipMesh = importMesh.meshes[0];
|
const shipMesh = importMesh.meshes[0];
|
||||||
shipMesh.id = "shipMesh";
|
shipMesh.id = "shipMesh";
|
||||||
shipMesh.name = "shipMesh";
|
shipMesh.name = "shipMesh";
|
||||||
|
debugLog(shipMesh.position);
|
||||||
shipMesh.parent = this._ship;
|
shipMesh.parent = this._ship;
|
||||||
|
debugLog(shipMesh.position);
|
||||||
|
|
||||||
// Create physics aggregate based on the loaded mesh (if physics enabled)
|
// Create physics aggregate based on the loaded mesh (if physics enabled)
|
||||||
const config = GameConfig.getInstance();
|
const config = GameConfig.getInstance();
|
||||||
@ -242,6 +252,9 @@ export class Ship {
|
|||||||
}
|
}
|
||||||
light.parent = this._ship;*/
|
light.parent = this._ship;*/
|
||||||
//DefaultScene.MainScene.getMaterialById('glass_mat.002').alpha = .4;
|
//DefaultScene.MainScene.getMaterialById('glass_mat.002').alpha = .4;
|
||||||
|
const screenMesh = DefaultScene.MainScene.getMaterialById('Screen')?.getBindedMeshes()[0];
|
||||||
|
this._scoreboard.initialize(screenMesh as Mesh);
|
||||||
|
//this._scoreboard.initialize(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -78,8 +78,9 @@ export class Sight {
|
|||||||
tessellation: 64
|
tessellation: 64
|
||||||
}, this.scene);
|
}, this.scene);
|
||||||
this.circle.parent = this.reticleGroup;
|
this.circle.parent = this.reticleGroup;
|
||||||
|
this.circle.rotation.x = -Math.PI / 2;
|
||||||
this.circle.material = material;
|
this.circle.material = material;
|
||||||
// this.circle.renderingGroupId = this.config.renderingGroupId;
|
this.circle.renderingGroupId = this.config.renderingGroupId;
|
||||||
|
|
||||||
// Create crosshair lines (4 lines extending from center gap)
|
// Create crosshair lines (4 lines extending from center gap)
|
||||||
this.createCrosshairLines(material);
|
this.createCrosshairLines(material);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user