Update gameplay mechanics, asteroid model, and star base physics
All checks were successful
Build / build (push) Successful in 1m18s
All checks were successful
Build / build (push) Successful in 1m18s
- Switch to asteroid4.glb model with updated material handling - Adjust difficulty parameters: increased spawn distances (220-450m range), updated force multipliers, varied asteroid sizes - Fix scoreboard timer display (was showing frames instead of actual seconds) - Refactor star base to use asset container with mesh merging for better performance - Change star base physics from STATIC to ANIMATED with collision detection enabled - Add directional lighting in level deserializer for improved scene lighting - Clean up commented code and optimize debug logging - Update base.glb 3D model 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
3e36662031
commit
37128d8fbd
BIN
public/asteroid4.glb
Normal file
BIN
public/asteroid4.glb
Normal file
Binary file not shown.
BIN
public/base.glb
BIN
public/base.glb
Binary file not shown.
@ -1,20 +1,18 @@
|
||||
import {DefaultScene} from "./defaultScene";
|
||||
import type {AudioEngineV2} from "@babylonjs/core";
|
||||
import {
|
||||
AbstractMesh,
|
||||
Color3, DistanceConstraint, Engine, InstancedMesh, LinesMesh, Mesh,
|
||||
Color3,
|
||||
DistanceConstraint,
|
||||
MeshBuilder,
|
||||
Observable,
|
||||
ParticleHelper,
|
||||
PhysicsAggregate,
|
||||
PhysicsMotionType,
|
||||
PhysicsShapeType, PointsCloudSystem,
|
||||
StandardMaterial, TransformNode,
|
||||
PhysicsShapeType,
|
||||
StandardMaterial,
|
||||
Vector3
|
||||
} from "@babylonjs/core";
|
||||
import type {AudioEngineV2} from "@babylonjs/core";
|
||||
import {Ship} from "./ship";
|
||||
|
||||
import {RockFactory} from "./rockFactory";
|
||||
import Level from "./level";
|
||||
import {Scoreboard} from "./scoreboard";
|
||||
import setLoadingMessage from "./setLoadingMessage";
|
||||
@ -55,12 +53,7 @@ export class Level1 implements Level {
|
||||
this._ship.addController(controller);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//console.log('Controller observable registered, observer:', !!observer);
|
||||
|
||||
this.initialize();
|
||||
|
||||
}
|
||||
|
||||
getReadyObservable(): Observable<Level> {
|
||||
@ -94,6 +87,7 @@ export class Level1 implements Level {
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this._startBase.dispose();
|
||||
this._endBase.dispose();
|
||||
@ -101,6 +95,7 @@ export class Level1 implements Level {
|
||||
this._backgroundStars.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
debugLog('Initializing level from config:', this._levelConfig.difficulty);
|
||||
if (this._initialized) {
|
||||
@ -133,6 +128,7 @@ export class Level1 implements Level {
|
||||
// Calculate distance from start base
|
||||
const dist = Vector3.Distance(asteroidMesh.position, this._startBase.position);
|
||||
const constraint = new DistanceConstraint(dist, DefaultScene.MainScene);
|
||||
// constraint.isCollisionsEnabled = true;
|
||||
this._startBase.physicsBody.addConstraint(asteroidMesh.physicsBody, constraint);
|
||||
}
|
||||
}
|
||||
@ -155,6 +151,7 @@ export class Level1 implements Level {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this._initialized = true;
|
||||
|
||||
// Notify that initialization is complete
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {
|
||||
AbstractMesh,
|
||||
Color3,
|
||||
Color3, DirectionalLight,
|
||||
GlowLayer,
|
||||
MeshBuilder,
|
||||
Observable,
|
||||
@ -66,6 +66,10 @@ export class LevelDeserializer {
|
||||
const planets = this.createPlanets();
|
||||
const asteroids = await this.createAsteroids(scoreObservable);
|
||||
|
||||
const dir = new Vector3(-1,-2,-1)
|
||||
const light = new DirectionalLight("dirLight", dir, DefaultScene.MainScene);
|
||||
const light2 = new DirectionalLight("dirLight2", dir.negate(), DefaultScene.MainScene);
|
||||
light2.intensity = .5;
|
||||
return {
|
||||
startBase,
|
||||
sun,
|
||||
|
||||
@ -214,29 +214,29 @@ export class LevelGenerator {
|
||||
case 'recruit':
|
||||
return {
|
||||
rockCount: 5,
|
||||
forceMultiplier: .5,
|
||||
forceMultiplier: .8,
|
||||
rockSizeMin: 10,
|
||||
rockSizeMax: 15,
|
||||
distanceMin: 80,
|
||||
distanceMax: 100
|
||||
distanceMin: 220,
|
||||
distanceMax: 250
|
||||
};
|
||||
case 'pilot':
|
||||
return {
|
||||
rockCount: 10,
|
||||
forceMultiplier: 1,
|
||||
rockSizeMin: 8,
|
||||
rockSizeMax: 12,
|
||||
distanceMin: 80,
|
||||
distanceMax: 150
|
||||
rockSizeMax: 20,
|
||||
distanceMin: 225,
|
||||
distanceMax: 300
|
||||
};
|
||||
case 'captain':
|
||||
return {
|
||||
rockCount: 20,
|
||||
forceMultiplier: 1.2,
|
||||
rockSizeMin: 2,
|
||||
rockSizeMax: 7,
|
||||
distanceMin: 100,
|
||||
distanceMax: 250
|
||||
rockSizeMin: 5,
|
||||
rockSizeMax: 40,
|
||||
distanceMin: 230,
|
||||
distanceMax: 450
|
||||
};
|
||||
case 'commander':
|
||||
return {
|
||||
|
||||
@ -4,7 +4,7 @@ import {
|
||||
CreateAudioEngineAsync,
|
||||
DirectionalLight,
|
||||
Engine,
|
||||
HavokPlugin,
|
||||
HavokPlugin, HemisphericLight,
|
||||
ParticleHelper,
|
||||
Scene,
|
||||
ScenePerformancePriority,
|
||||
@ -255,7 +255,12 @@ export class Main {
|
||||
const havok = await HavokPhysics();
|
||||
const havokPlugin = new HavokPlugin(true, havok);
|
||||
//DefaultScene.MainScene.ambientColor = new Color3(.1, .1, .1);
|
||||
const light = new DirectionalLight("dirLight", new Vector3(-1, -2, -1), DefaultScene.MainScene);
|
||||
|
||||
//const light = new HemisphericLight("mainlight", new Vector3(-1, -1, 0), DefaultScene.MainScene);
|
||||
//light.diffuse = new Color3(.4, .4, .3);
|
||||
//light.groundColor = new Color3(.2, .2, .1);
|
||||
//light.intensity = .5;
|
||||
//light.specular = new Color3(0,0,0);
|
||||
DefaultScene.MainScene.enablePhysics(new Vector3(0, 0, 0), havokPlugin);
|
||||
DefaultScene.MainScene.getPhysicsEngine().setTimeStep(1/60);
|
||||
DefaultScene.MainScene.getPhysicsEngine().setSubTimeStep(5);
|
||||
|
||||
@ -52,7 +52,7 @@ export class RockFactory {
|
||||
}
|
||||
private static async loadMesh() {
|
||||
debugLog('loading mesh');
|
||||
const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "asteroid3.glb", DefaultScene.MainScene);
|
||||
const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "asteroid4.glb", DefaultScene.MainScene);
|
||||
this._rockMesh = importMesh.meshes[1].clone("asteroid", null, false);
|
||||
this._rockMesh.setParent(null);
|
||||
this._rockMesh.setEnabled(false);
|
||||
@ -62,16 +62,17 @@ export class RockFactory {
|
||||
if (!this._rockMaterial) {
|
||||
// Clone the original material from GLB to preserve all textures
|
||||
this._originalMaterial = this._rockMesh.material.clone("asteroid-original") as PBRMaterial;
|
||||
this._rockMaterial = this._rockMesh.material.clone("asteroid-original") as PBRMaterial;
|
||||
debugLog('Cloned original material from GLB:', this._originalMaterial);
|
||||
|
||||
// Create material using GameConfig texture level
|
||||
const config = GameConfig.getInstance();
|
||||
/*const config = GameConfig.getInstance();
|
||||
this._rockMaterial = MaterialFactory.createAsteroidMaterial(
|
||||
'asteroid-material',
|
||||
config.asteroidTextureLevel,
|
||||
DefaultScene.MainScene,
|
||||
this._originalMaterial
|
||||
) as PBRMaterial;
|
||||
) as PBRMaterial;*/
|
||||
this._rockMaterial.freeze();
|
||||
|
||||
this._rockMesh.material = this._rockMaterial;
|
||||
@ -113,12 +114,13 @@ export class RockFactory {
|
||||
body.setLinearDamping(0)
|
||||
body.setMotionType(PhysicsMotionType.DYNAMIC);
|
||||
body.setCollisionCallbackEnabled(true);
|
||||
|
||||
body.getCollisionObservable().add((eventData) => {
|
||||
if (eventData.type == 'COLLISION_STARTED') {
|
||||
debugLog('[RockFactory] Collision detected:', {
|
||||
/*debugLog('[RockFactory] Collision detected:', {
|
||||
collidedWith: eventData.collidedAgainst.transformNode.id,
|
||||
asteroidName: eventData.collider.transformNode.name
|
||||
});
|
||||
});*/
|
||||
|
||||
if ( eventData.collidedAgainst.transformNode.id == 'ammo') {
|
||||
debugLog('[RockFactory] ASTEROID HIT! Triggering explosion...');
|
||||
@ -147,8 +149,15 @@ export class RockFactory {
|
||||
eventData.collidedAgainst.dispose();
|
||||
debugLog('[RockFactory] Disposal complete');
|
||||
}
|
||||
} else {
|
||||
/*debugLog('[RockFactory] Collision ended between:', {
|
||||
collider: eventData.collider.transformNode.id,
|
||||
collidedWith: eventData.collidedAgainst.transformNode.id
|
||||
});*/
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//body.setAngularVelocity(new Vector3(Math.random(), Math.random(), Math.random()));
|
||||
// body.setLinearVelocity(Vector3.Random(-10, 10));
|
||||
}
|
||||
|
||||
@ -82,8 +82,8 @@ export class Scoreboard {
|
||||
scoreText.text = `Score: ${this.calculateScore()}`;
|
||||
remainingText.text = `Remaining: ${this._remaining}`;
|
||||
const elapsed = Date.now() - this._startTime;
|
||||
if (this._active && i++%40 == 0) {
|
||||
timeRemainingText.text = `Time: ${Math.floor(elapsed/60).toString().padStart(2,"0")}:${(elapsed%60).toString().padStart(2,"0")}`;
|
||||
if (this._active && i++%30 == 0) {
|
||||
timeRemainingText.text = `Time: ${Math.floor(elapsed/60000).toString().padStart(2,"0")}:${(Math.floor(elapsed/1000)%60).toString().padStart(2,"0")}`;
|
||||
fpsText.text = `FPS: ${Math.floor(scene.getEngine().getFps())}`;
|
||||
}
|
||||
});
|
||||
|
||||
@ -231,16 +231,16 @@ export class Ship {
|
||||
//shipMesh.position.y = 1;
|
||||
shipMesh.position.z = -1;
|
||||
// shipMesh.renderingGroupId = 3;
|
||||
const light = new PointLight("ship.light", new Vector3(0, .5, .1), DefaultScene.MainScene);
|
||||
light.intensity = 4;
|
||||
light.includedOnlyMeshes = [shipMesh];
|
||||
//const light = new PointLight("ship.light", new Vector3(0, .5, .1), DefaultScene.MainScene);
|
||||
//light.intensity = 4;
|
||||
/*light.includedOnlyMeshes = [shipMesh];
|
||||
for (const mesh of shipMesh.getChildMeshes()) {
|
||||
// mesh.renderingGroupId = 3;
|
||||
if (mesh.material.id.indexOf('glass') === -1) {
|
||||
light.includedOnlyMeshes.push(mesh);
|
||||
}
|
||||
}
|
||||
light.parent = this._ship;
|
||||
light.parent = this._ship;*/
|
||||
//DefaultScene.MainScene.getMaterialById('glass_mat.002').alpha = .4;
|
||||
}
|
||||
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
import {
|
||||
AbstractMesh,
|
||||
AbstractMesh, LoadAssetContainerAsync, Mesh,
|
||||
PhysicsAggregate,
|
||||
PhysicsMotionType,
|
||||
PhysicsShapeType,
|
||||
SceneLoader,
|
||||
PhysicsShapeType, Scene,
|
||||
Vector3
|
||||
} from "@babylonjs/core";
|
||||
import {DefaultScene} from "./defaultScene";
|
||||
import {GameConfig} from "./gameConfig";
|
||||
import {debug} from "openai/core";
|
||||
import debugLog from "./debug";
|
||||
|
||||
/**
|
||||
@ -20,21 +18,33 @@ export default async function buildStarBase(position: Vector3): Promise<Abstract
|
||||
const scene = DefaultScene.MainScene;
|
||||
|
||||
// Load the base model
|
||||
const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "base.glb", scene);
|
||||
const baseMesh = importMesh.meshes[0].getChildMeshes()[0];
|
||||
debugLog('Star base mesh loaded:', baseMesh);
|
||||
baseMesh.id = "starBase";
|
||||
baseMesh.name = "starBase";
|
||||
baseMesh.position = position;
|
||||
debugLog('Ship Bounds radius', baseMesh.getBoundingInfo().boundingSphere.radiusWorld);
|
||||
// Create physics if enabled
|
||||
const importMesh = await LoadAssetContainerAsync('/base.glb', DefaultScene.MainScene,
|
||||
{
|
||||
pluginOptions: {
|
||||
gltf: {
|
||||
enabled: true,
|
||||
}
|
||||
}
|
||||
});
|
||||
importMesh.addAllToScene();
|
||||
const starBase = Mesh.MergeMeshes(importMesh.rootNodes[0].getChildMeshes(false), true, false, null, false, true);
|
||||
starBase.id = 'starBase';
|
||||
starBase.name = 'starBase';
|
||||
DefaultScene.MainScene.addMesh(starBase);
|
||||
debugLog('imported base mesh', importMesh.meshes[0]);
|
||||
|
||||
starBase.position = position;
|
||||
const config = GameConfig.getInstance();
|
||||
if (config.physicsEnabled) {
|
||||
const agg = new PhysicsAggregate(baseMesh, PhysicsShapeType.MESH, {
|
||||
mass: 0
|
||||
const agg = new PhysicsAggregate(starBase, PhysicsShapeType.MESH, {
|
||||
mass: 10000
|
||||
}, scene);
|
||||
agg.body.setMotionType(PhysicsMotionType.STATIC);
|
||||
agg.body.setMotionType(PhysicsMotionType.ANIMATED);
|
||||
agg.body.setCollisionCallbackEnabled(true);
|
||||
agg.body.getCollisionObservable().add((collidedBody) => {
|
||||
debugLog('collidedBody', collidedBody);
|
||||
})
|
||||
}
|
||||
|
||||
return baseMesh;
|
||||
importMesh.rootNodes[0].dispose();
|
||||
return starBase;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user