Create mesh-based physics for ship and optimize planet geometry
Some checks failed
Build / build (push) Failing after 18s
Some checks failed
Build / build (push) Failing after 18s
- 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>
This commit is contained in:
parent
a9054c2389
commit
03f170e150
BIN
public/ship1.glb
BIN
public/ship1.glb
Binary file not shown.
@ -138,9 +138,11 @@ export class LevelDeserializer {
|
|||||||
const sunPosition = this.arrayToVector3(this.config.sun.position);
|
const sunPosition = this.arrayToVector3(this.config.sun.position);
|
||||||
|
|
||||||
for (const planetConfig of this.config.planets) {
|
for (const planetConfig of this.config.planets) {
|
||||||
|
// Use fewer segments for better performance - planets are background objects
|
||||||
|
// 16 segments = ~256 vertices vs 32 segments = ~1024 vertices
|
||||||
const planet = MeshBuilder.CreateSphere(planetConfig.name, {
|
const planet = MeshBuilder.CreateSphere(planetConfig.name, {
|
||||||
diameter: planetConfig.diameter,
|
diameter: planetConfig.diameter,
|
||||||
segments: 32
|
segments: 12 // Reduced from 32 for performance
|
||||||
}, this.scene);
|
}, this.scene);
|
||||||
|
|
||||||
const planetPosition = this.arrayToVector3(planetConfig.position);
|
const planetPosition = this.arrayToVector3(planetConfig.position);
|
||||||
@ -156,7 +158,7 @@ export class LevelDeserializer {
|
|||||||
// Create lightmap with bright light pointing toward sun
|
// Create lightmap with bright light pointing toward sun
|
||||||
const lightmap = createSphereLightmap(
|
const lightmap = createSphereLightmap(
|
||||||
planetConfig.name + "-lightmap",
|
planetConfig.name + "-lightmap",
|
||||||
512, // texture size
|
256, // texture size
|
||||||
DefaultScene.MainScene,
|
DefaultScene.MainScene,
|
||||||
toSun, // bright light from sun direction
|
toSun, // bright light from sun direction
|
||||||
1, // bright intensity
|
1, // bright intensity
|
||||||
|
|||||||
@ -21,11 +21,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() {
|
||||||
DefaultScene.MainScene.onNewMeshAddedObservable.add((mesh) => {
|
this.initialize();
|
||||||
if (mesh.id == 'RightUpperDisplay') {
|
|
||||||
this.initialize();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
public get done() {
|
public get done() {
|
||||||
return this._done;
|
return this._done;
|
||||||
@ -39,18 +35,20 @@ export class Scoreboard {
|
|||||||
private initialize() {
|
private initialize() {
|
||||||
const scene = DefaultScene.MainScene;
|
const scene = DefaultScene.MainScene;
|
||||||
|
|
||||||
const parent = scene.getMeshById('RightUpperDisplay');
|
const parent = scene.getNodeById('ship');
|
||||||
|
console.log('Scoreboard parent:', parent);
|
||||||
|
console.log('Initializing scoreboard');
|
||||||
const scoreboard = MeshBuilder.CreatePlane("scoreboard", {width: 1, height: 1}, scene);
|
const scoreboard = MeshBuilder.CreatePlane("scoreboard", {width: 1, height: 1}, scene);
|
||||||
scoreboard.renderingGroupId = 3;
|
scoreboard.renderingGroupId = 3;
|
||||||
const material = new StandardMaterial("scoreboard", scene);
|
const material = new StandardMaterial("scoreboard", scene);
|
||||||
|
|
||||||
scoreboard.parent =parent;
|
scoreboard.parent =parent;
|
||||||
scoreboard.position.x = -.76;
|
|
||||||
scoreboard.position.y = 4.19;
|
scoreboard.position.y = 1.05;
|
||||||
scoreboard.position.z = .53;
|
scoreboard.position.z = 2.1;
|
||||||
scoreboard.rotation.x = Angle.FromDegrees(104).radians();
|
scoreboard.visibility = .5;
|
||||||
scoreboard.rotation.z = Math.PI;
|
|
||||||
scoreboard.scaling = new Vector3(.3, .3, .3);
|
scoreboard.scaling = new Vector3(.4, .4, .4);
|
||||||
|
|
||||||
const advancedTexture = AdvancedDynamicTexture.CreateForMesh(scoreboard, 512, 512);
|
const advancedTexture = AdvancedDynamicTexture.CreateForMesh(scoreboard, 512, 512);
|
||||||
advancedTexture.background = "black";
|
advancedTexture.background = "black";
|
||||||
|
|||||||
54
src/ship.ts
54
src/ship.ts
@ -123,6 +123,14 @@ export class Ship {
|
|||||||
|
|
||||||
public set position(newPosition: Vector3) {
|
public set position(newPosition: Vector3) {
|
||||||
const body = this._ship.physicsBody;
|
const body = this._ship.physicsBody;
|
||||||
|
|
||||||
|
// Physics body might not exist yet if called before initialize() completes
|
||||||
|
if (!body) {
|
||||||
|
// Just set position directly on transform node
|
||||||
|
this._ship.position.copyFrom(newPosition);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
body.disablePreStep = false;
|
body.disablePreStep = false;
|
||||||
body.transformNode.position.copyFrom(newPosition);
|
body.transformNode.position.copyFrom(newPosition);
|
||||||
DefaultScene.MainScene.onAfterRenderObservable.addOnce(() => {
|
DefaultScene.MainScene.onAfterRenderObservable.addOnce(() => {
|
||||||
@ -150,17 +158,9 @@ export class Ship {
|
|||||||
//const landingLight = new SpotLight("landingLight", new Vector3(0, 0, 0), new Vector3(0, -.5, .5), 1.5, .5, DefaultScene.MainScene);
|
//const landingLight = new SpotLight("landingLight", new Vector3(0, 0, 0), new Vector3(0, -.5, .5), 1.5, .5, DefaultScene.MainScene);
|
||||||
// landingLight.parent = this._ship;
|
// landingLight.parent = this._ship;
|
||||||
// landingLight.position.z = 5;
|
// landingLight.position.z = 5;
|
||||||
const agg = new PhysicsAggregate(this._ship, PhysicsShapeType.BOX, {
|
|
||||||
mass: 100,
|
|
||||||
extents: new Vector3(4, 4, 7.4),
|
|
||||||
center: new Vector3(0, 1, 1.8)
|
|
||||||
}, DefaultScene.MainScene);
|
|
||||||
|
|
||||||
agg.body.setMotionType(PhysicsMotionType.DYNAMIC);
|
// Physics will be set up after mesh loads in initialize()
|
||||||
agg.body.setLinearDamping(.1);
|
|
||||||
agg.body.setAngularDamping(.2);
|
|
||||||
agg.body.setAngularVelocity(new Vector3(0, 0, 0));
|
|
||||||
agg.body.setCollisionCallbackEnabled(true);
|
|
||||||
this.setupKeyboard();
|
this.setupKeyboard();
|
||||||
this.setupMouse();
|
this.setupMouse();
|
||||||
this._controllerObservable.add(this.controllerCallback);
|
this._controllerObservable.add(this.controllerCallback);
|
||||||
@ -201,6 +201,40 @@ export class Ship {
|
|||||||
shipMesh.id = "shipMesh";
|
shipMesh.id = "shipMesh";
|
||||||
shipMesh.name = "shipMesh";
|
shipMesh.name = "shipMesh";
|
||||||
shipMesh.parent = this._ship;
|
shipMesh.parent = this._ship;
|
||||||
|
|
||||||
|
// Create physics aggregate based on the loaded mesh
|
||||||
|
// Find the actual geometry mesh (usually meshes[1] or a child)
|
||||||
|
//const geometryMesh = importMesh.meshes.find(m => m instanceof Mesh && m.getTotalVertices() > 0) as Mesh;
|
||||||
|
const geo = shipMesh.getChildMeshes()[0]
|
||||||
|
if (geo) {
|
||||||
|
|
||||||
|
|
||||||
|
// Create physics aggregate on the ship TransformNode using the mesh shape
|
||||||
|
const agg = new PhysicsAggregate(this._ship, PhysicsShapeType.CONVEX_HULL, {
|
||||||
|
mass: 100,
|
||||||
|
mesh: (geo as Mesh) // Use the actual ship geometry
|
||||||
|
}, DefaultScene.MainScene);
|
||||||
|
|
||||||
|
agg.body.setMotionType(PhysicsMotionType.DYNAMIC);
|
||||||
|
agg.body.setLinearDamping(.1);
|
||||||
|
agg.body.setAngularDamping(.2);
|
||||||
|
agg.body.setAngularVelocity(new Vector3(0, 0, 0));
|
||||||
|
agg.body.setCollisionCallbackEnabled(true);
|
||||||
|
} else {
|
||||||
|
console.warn("No geometry mesh found in ship1.glb, falling back to box shape");
|
||||||
|
// Fallback to box shape if mesh not found
|
||||||
|
const agg = new PhysicsAggregate(this._ship, PhysicsShapeType.BOX, {
|
||||||
|
mass: 100,
|
||||||
|
extents: new Vector3(4, 4, 7.4),
|
||||||
|
center: new Vector3(0, 1, 1.8)
|
||||||
|
}, DefaultScene.MainScene);
|
||||||
|
|
||||||
|
agg.body.setMotionType(PhysicsMotionType.DYNAMIC);
|
||||||
|
agg.body.setLinearDamping(.1);
|
||||||
|
agg.body.setAngularDamping(.2);
|
||||||
|
agg.body.setAngularVelocity(new Vector3(0, 0, 0));
|
||||||
|
agg.body.setCollisionCallbackEnabled(true);
|
||||||
|
}
|
||||||
//shipMesh.rotation.y = Angle.FromDegrees(90).radians();
|
//shipMesh.rotation.y = Angle.FromDegrees(90).radians();
|
||||||
//shipMesh.rotation.y = Math.PI;
|
//shipMesh.rotation.y = Math.PI;
|
||||||
//shipMesh.position.y = 1;
|
//shipMesh.position.y = 1;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user