From c9d03e832d76801a9d88f82570a2862e7e646981 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Thu, 20 Feb 2025 19:11:46 -0600 Subject: [PATCH] changed game dynamics. --- src/level1.ts | 48 +++++++++++---- src/main.ts | 30 +++++++++- src/scoreboard.ts | 98 ++++++++++++++++++++---------- src/ship.ts | 148 ++++++++++++++++++++++------------------------ src/starfield.ts | 90 ++++++++++++++++++---------- 5 files changed, 258 insertions(+), 156 deletions(-) diff --git a/src/level1.ts b/src/level1.ts index d384e09..d869045 100644 --- a/src/level1.ts +++ b/src/level1.ts @@ -1,20 +1,21 @@ import {DefaultScene} from "./defaultScene"; import { AbstractMesh, - Color3, DistanceConstraint, Engine, InstancedMesh, Mesh, + Color3, DistanceConstraint, Engine, InstancedMesh, LinesMesh, Mesh, MeshBuilder, Observable, ParticleHelper, PhysicsAggregate, PhysicsMotionType, - PhysicsShapeType, Sound, + PhysicsShapeType, PointsCloudSystem, Sound, StandardMaterial, TransformNode, Vector3 } from "@babylonjs/core"; import {Ship} from "./ship"; -import {ScoreEvent} from "./scoreEvent"; + import {RockFactory} from "./starfield"; import Level from "./level"; +import {Scoreboard} from "./scoreboard"; export class Level1 implements Level { private _ship: Ship; @@ -22,10 +23,11 @@ export class Level1 implements Level { private _initialized: boolean = false; private _startBase: AbstractMesh; private _endBase: AbstractMesh; - public onScoreObservable: Observable = new Observable(); + private _scoreboard: Scoreboard; constructor() { this._ship = new Ship(); + this._scoreboard = new Scoreboard(); const xr = DefaultScene.XR; xr.baseExperience.onInitialXRPoseSetObservable.add(() => { xr.baseExperience.camera.parent = this._ship.transformNode; @@ -35,7 +37,6 @@ export class Level1 implements Level { this._ship.addController(controller); }); this.createStartBase(); - this.initialize(); } @@ -55,6 +56,7 @@ export class Level1 implements Level { this._endBase.dispose(); } public async initialize() { + console.log('initialize'); if (this._initialized) { return; } @@ -62,17 +64,37 @@ export class Level1 implements Level { ParticleHelper.BaseAssetsUrl = window.location.href; this._ship.position = new Vector3(0, 1, 0); await RockFactory.init(); - const baseTransform = new TransformNode("baseTransform", DefaultScene.MainScene); - baseTransform.position = this._startBase.getAbsolutePosition(); - for (let i = 0; i < 50; i++) { - const dist = (Math.random() * 200) + 190; - const rock = await RockFactory.createRock(i, new Vector3(Math.random() * 200 +50 * Math.sign(Math.random() -.5),200,200), Vector3.Random(1, 5)) + for (let i = 0; i < 5; i++) { + const dist = (Math.random() * 50) + 190; + const size = Vector3.Random(1,1.3).scale(Math.random() * 5 + 5) + + const rock = await RockFactory.createRock(i, new Vector3(Math.random() * 200 +50 * Math.sign(Math.random() -.5),200,200), + size, + this._scoreboard.onScoreObservable); const constraint = new DistanceConstraint(dist, DefaultScene.MainScene); - //rock.physicsBody.addConstraint(this._endBase.physicsBody, constraint); + + /* + const options: {updatable: boolean, points: Array, instance?: LinesMesh} = + {updatable: true, points: [rock.position, this._startBase.absolutePosition]} + + let line = MeshBuilder.CreateLines("line", options , DefaultScene.MainScene); + + line.color = new Color3(1, 0, 0); + DefaultScene.MainScene.onAfterRenderObservable.add(() => { + //const pos = rock.position; + options.points[0].copyFrom(rock.position); + options.instance = line; + line = MeshBuilder.CreateLines("lines", options); + }); + */ + this._scoreboard.onScoreObservable.notifyObservers({ + score: 0, + remaining: 1, + message: "Get Ready" + }); this._startBase.physicsBody.addConstraint(rock.physicsBody, constraint); - rock.physicsBody.applyForce(Vector3.Random(-1, 1).scale(50000000), rock.getAbsolutePosition()); - //rock.physicsBody.setAngularVelocity(Vector3.Random(-.5, .5)); + rock.physicsBody.applyForce(Vector3.Random(-1, 1).scale(5000000), rock.position); } } diff --git a/src/main.ts b/src/main.ts index 7fcf961..e423d98 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,13 @@ -import {Engine, HavokPlugin, PhotoDome, Scene, Vector3, WebGPUEngine, WebXRDefaultExperience} from "@babylonjs/core"; +import { + Color3, + Engine, + HavokPlugin, + PhotoDome, + Scene, StandardMaterial, + Vector3, + WebGPUEngine, + WebXRDefaultExperience +} from "@babylonjs/core"; import '@babylonjs/loaders'; import HavokPhysics from "@babylonjs/havok"; @@ -21,6 +30,10 @@ export class Main { private _gameState: GameState = GameState.DEMO; constructor() { this._loadingDiv = document.querySelector('#loadingDiv'); + if (!navigator.xr) { + this._loadingDiv.innerText = "This browser does not support WebXR"; + return; + } this.initialize(); document.querySelector('#startButton').addEventListener('click', () => { @@ -55,7 +68,18 @@ export class Main { this._currentLevel.getReadyObservable().add(() => { }); - const photoDome = new PhotoDome("testdome", '/8192.webp', {}, DefaultScene.MainScene); + + const photoDome1 = new PhotoDome("testdome", '/8192.webp', {size: 1000}, DefaultScene.MainScene); + photoDome1.material.diffuseTexture.hasAlpha = true; + photoDome1.material.alpha = .3; + + const photoDome2 = new PhotoDome("testdome", '/8192.webp', {size: 2000}, DefaultScene.MainScene); + photoDome2.rotation.y = Math.PI; + photoDome2.rotation.x = Math.PI/2; + DefaultScene.MainScene.onAfterRenderObservable.add(() => { + photoDome1.position = DefaultScene.MainScene.activeCamera.globalPosition; + photoDome2.position = DefaultScene.MainScene.activeCamera.globalPosition; + }); } private setLoadingMessage(message: string) { this._loadingDiv.innerText = message; @@ -75,6 +99,7 @@ export class Main { } DefaultScene.DemoScene = new Scene(engine); DefaultScene.MainScene = new Scene(engine); + DefaultScene.MainScene.ambientColor = new Color3(.2, .2, .2); this.setLoadingMessage("Initializing Physics Engine.."); await this.setupPhysics(); @@ -98,6 +123,7 @@ export class Main { const havok = await HavokPhysics(); const havokPlugin = new HavokPlugin(true, havok); DefaultScene.MainScene.enablePhysics(new Vector3(0, 0, 0), havokPlugin); + DefaultScene.MainScene.getPhysicsEngine().setSubTimeStep(5); DefaultScene.MainScene.collisionsEnabled = true; } diff --git a/src/scoreboard.ts b/src/scoreboard.ts index 9d29600..a403618 100644 --- a/src/scoreboard.ts +++ b/src/scoreboard.ts @@ -1,40 +1,46 @@ import {AdvancedDynamicTexture, Control, StackPanel, TextBlock} from "@babylonjs/gui"; import {DefaultScene} from "./defaultScene"; import { - AbstractMesh, - ActionManager, Angle, - ExecuteCodeAction, MeshBuilder, - Observable, - TransformNode, + Observable, StandardMaterial, Vector3, } from "@babylonjs/core"; -import {ScoreEvent} from "./scoreEvent"; - +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; - public onscoreObservable: Observable = new Observable(); + private _active = false; + private _done = false; + public readonly onScoreObservable: Observable = new Observable(); constructor() { DefaultScene.MainScene.onNewMeshAddedObservable.add((mesh) => { if (mesh.id == 'RightUpperDisplay') { - window.setTimeout(() => { - //mesh.material = null; - this.initialize(); - },1000); - + this.initialize(); } }); - //this.initialize(camera); + } + public get done() { + return this._done; + } + public set done(value: boolean) { + this._done = value; } private initialize() { const scene = DefaultScene.MainScene; const parent = scene.getMeshById('RightUpperDisplay'); const scoreboard = MeshBuilder.CreatePlane("scoreboard", {width: 1, height: 1}, scene); - scoreboard.parent =parent; + const material = new StandardMaterial("scoreboard", scene); + scoreboard.parent =parent; scoreboard.position.x = -.76; scoreboard.position.y = 4.19; scoreboard.position.z = .53; @@ -42,43 +48,71 @@ export class Scoreboard { scoreboard.rotation.z = Math.PI; scoreboard.scaling = new Vector3(.3, .3, .3); - const advancedTexture = AdvancedDynamicTexture.CreateForMesh(scoreboard); + const advancedTexture = AdvancedDynamicTexture.CreateForMesh(scoreboard, 512, 512); advancedTexture.background = "black"; + advancedTexture.hasAlpha = false; const scoreText = this.createText(); - advancedTexture.addControl(scoreText); + const fpsText = this.createText(); - fpsText.top = '120px'; + fpsText.text = "FPS: 60"; + const hullText = this.createText(); - //hullText.top = '240px'; 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; - advancedTexture.addControl(fpsText); - advancedTexture.addControl(scoreText); + panel.height = 1; + panel.isVertical = true; + panel.addControl(scoreText); + panel.addControl(remainingText); + panel.addControl(fpsText); + panel.addControl(hullText); + panel.addControl(timeRemainingText); + advancedTexture.addControl(panel); - scene.onAfterRenderObservable.add(() => { + let i = 0; + let lastSecond: number = Date.now(); + const afterRender = scene.onAfterRenderObservable.add(() => { scoreText.text = `Score: ${this.calculateScore()}`; - if (this._lastMessage != null) { - fpsText.text = this._lastMessage; - } else { - fpsText.text = ''; + 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) => { - this._score += score.score; + 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 = 90; + text1.fontSize = "60px"; + text1.height = "80px"; text1.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; - text1.textVerticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; + text1.textVerticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER; return text1; } private calculateScore() { diff --git a/src/ship.ts b/src/ship.ts index 4058851..5bb075e 100644 --- a/src/ship.ts +++ b/src/ship.ts @@ -2,9 +2,8 @@ import { AbstractMesh, Color3, DirectionalLight, - Engine, FreeCamera, - GlowLayer, + GlowLayer, InstancedMesh, Mesh, MeshBuilder, Observable, PhysicsAggregate, @@ -22,9 +21,7 @@ import { WebXRInputSource } from "@babylonjs/core"; import {DefaultScene} from "./defaultScene"; - -import {ShipEngine} from "./shipEngine"; -import {Level1} from "./level1"; +const MAX_FORWARD_THRUST = 40; const controllerComponents = [ 'a-button', @@ -49,6 +46,7 @@ type ControllerEvent = { } enum ControllerStickMode { + BEGINNER, ARCADE, REALISTIC } @@ -56,30 +54,31 @@ enum ControllerStickMode { export class Ship { private _ship: TransformNode; private _controllerObservable: Observable = new Observable(); - public onReadyObservable: Observable = new Observable(); - private _engine: ShipEngine; private _ammoMaterial: StandardMaterial; private _forwardNode: TransformNode; private _rotationNode: TransformNode; - private _onscore: Observable; - private _ammo: Array = []; private _glowLayer: GlowLayer; - private _thrust: Sound; - private _thrust2: Sound; + private _primaryThrustVectorSound: Sound; + private _secondaryThrustVectorSound: Sound; private _shot: Sound; private _shooting: boolean = false; private _camera: FreeCamera; - - constructor() { - + private _ammoBaseMesh: AbstractMesh; + private _controllerMode: ControllerStickMode; + private _active = false; + constructor(mode: ControllerStickMode = ControllerStickMode.BEGINNER) { + this._controllerMode = mode this.setup(); this.initialize(); } + public set controllerMode(mode: ControllerStickMode) { + this._controllerMode = mode; + } private shoot() { this._shot.play(); - const ammo = MeshBuilder.CreateCapsule("bullet", {radius: .1, height: 2.5}, DefaultScene.MainScene); - ammo.parent = this._ship + const ammo = new InstancedMesh("ammo", this._ammoBaseMesh as Mesh); + ammo.parent = this._ship; ammo.position.y = 2; ammo.rotation.x = Math.PI / 2; ammo.setParent(null); @@ -87,17 +86,18 @@ export class Ship { mass: 1000, restitution: 0 }, DefaultScene.MainScene); + ammoAggregate.body.setAngularDamping(1); - ammo.material = this._ammoMaterial; ammoAggregate.body.setMotionType(PhysicsMotionType.DYNAMIC); - ammoAggregate.body.setLinearVelocity(this._ship.forward.scale(200).add(this._ship.physicsBody.getLinearVelocity())); + ammoAggregate.body.setLinearVelocity(this._ship.forward.scale(10000)) + //.add(this._ship.physicsBody.getLinearVelocity())); window.setTimeout(() => { ammoAggregate.dispose(); ammo.dispose() - }, 1500) + }, 1500); } public set position(newPosition: Vector3) { @@ -113,11 +113,11 @@ export class Ship { this._ship = new TransformNode("ship", DefaultScene.MainScene); this._glowLayer = new GlowLayer('bullets', DefaultScene.MainScene); this._glowLayer.intensity = 1; - this._thrust = new Sound("thrust", "/thrust5.mp3", DefaultScene.MainScene, null, { + this._primaryThrustVectorSound = new Sound("thrust", "/thrust5.mp3", DefaultScene.MainScene, null, { loop: true, autoplay: false }); - this._thrust2 = new Sound("thrust2", "/thrust5.mp3", DefaultScene.MainScene, null, { + this._secondaryThrustVectorSound = new Sound("thrust2", "/thrust5.mp3", DefaultScene.MainScene, null, { loop: true, autoplay: false, volume: .5 @@ -126,6 +126,9 @@ export class Ship { {loop: false, autoplay: false, volume: .5}); this._ammoMaterial = new StandardMaterial("ammoMaterial", DefaultScene.MainScene); this._ammoMaterial.emissiveColor = new Color3(1, 1, 0); + this._ammoBaseMesh = MeshBuilder.CreateCapsule("bullet", {radius: .1, height: 2.5}, DefaultScene.MainScene); + this._ammoBaseMesh.material = this._ammoMaterial; + const light = new DirectionalLight("light", new Vector3(.1, -1, 0), DefaultScene.MainScene); const landingLight = new SpotLight("landingLight", new Vector3(0, 0, 0), new Vector3(0, -.5, .5), 1.5, .5, DefaultScene.MainScene); @@ -163,13 +166,17 @@ export class Ship { signtMaterial.emissiveColor = Color3.Yellow(); sight.material = signtMaterial; sight.position = new Vector3(0, 2, 125); - - window.setInterval(() => { - this.applyForce(); - }, 50); + let i = Date.now(); + DefaultScene.MainScene.onBeforeRenderObservable.add(() => { + if (Date.now() - i > 50 && this._active == true) { + this.applyForce(); + i = Date.now(); + } + }); + this._active = true; } private async initialize() { - const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "cockpit3.glb", DefaultScene.MainScene); + const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "cockpit2.glb", DefaultScene.MainScene); const shipMesh = importMesh.meshes[0]; shipMesh.id = "shipMesh"; shipMesh.name = "shipMesh"; @@ -177,7 +184,8 @@ export class Ship { shipMesh.rotation.y = Math.PI; shipMesh.position.y = 1; shipMesh.position.z = -1; - DefaultScene.MainScene.getMaterialById('glass_mat.002').alpha = .7; + + DefaultScene.MainScene.getMaterialById('glass_mat.002').alpha = .4; } @@ -190,65 +198,41 @@ export class Ship { private _mouseDown = false; private _mousePos = new Vector2(0, 0); - private scale(value: number) { - return value * .8; - } - - public get transformNode() { return this._ship; } - private adjust(value: number, increment: number = .8): number { - if (Math.abs(value) < .001) { - return 0; - } else { - return value * increment; - } - } private applyForce() { if (!this?._ship?.physicsBody) { return; } const body = this._ship.physicsBody; - if (Math.abs(this._forwardValue) > 40) { - this._forwardValue = Math.sign(this._forwardValue) * 40; + //If we're moving over MAX_FORWARD_THRUST, we can't add any more thrust, + //just continue at MAX_FORWARD_THRUST + if (Math.abs(this._forwardValue) > MAX_FORWARD_THRUST) { + this._forwardValue = Math.sign(this._forwardValue) * MAX_FORWARD_THRUST; } - if (Math.abs(this._forwardValue) <= 40) { + //if forward thrust is under 40 we can apply more thrust + if (Math.abs(this._forwardValue) <= MAX_FORWARD_THRUST) { if (Math.abs(this._leftStickVector.y) > .1) { - if (!this._thrust.isPlaying) { - this._thrust.play(); + if (!this._primaryThrustVectorSound.isPlaying) { + this._primaryThrustVectorSound.play(); } - this._thrust.setVolume(Math.abs(this._leftStickVector.y)); + this._primaryThrustVectorSound.setVolume(Math.abs(this._leftStickVector.y)); this._forwardValue += this._leftStickVector.y * .8; } else { - if (this._thrust.isPlaying) { - this._thrust.pause(); + if (this._primaryThrustVectorSound.isPlaying) { + this._primaryThrustVectorSound.pause(); } - this._forwardValue = this.adjust(this._forwardValue, .98); + this._forwardValue = decrementValue(this._forwardValue, .98); } } - if (Math.abs(this._leftStickVector.x) > .1) { - this._yawValue += this._leftStickVector.x * .03; - } else { - - this._yawValue = this.adjust(this._yawValue); - } - - if (Math.abs(this._rightStickVector.x) > .1) { - this._rollValue += this._rightStickVector.x * .03; - } else { - this._rollValue = this.adjust(this._rollValue); - } - - if (Math.abs(this._rightStickVector.y) > .1) { - this._pitchValue += this._rightStickVector.y * .03; - } else { - this._pitchValue = this.adjust(this._pitchValue); - } + this._yawValue = adjustStickValue(this._leftStickVector.x, this._yawValue); + this._rollValue = adjustStickValue(this._rightStickVector.x, this._rollValue); + this._pitchValue = adjustStickValue(this._rightStickVector.y, this._pitchValue); this._forwardNode.position.z = this._forwardValue; this._rotationNode.position.y = this._yawValue; @@ -260,20 +244,18 @@ export class Ship { Math.abs(this._leftStickVector.x); if (thrust2 > .01) { - if (!this._thrust2.isPlaying) { - this._thrust2.play(); + if (!this._secondaryThrustVectorSound.isPlaying) { + this._secondaryThrustVectorSound.play(); } - this._thrust2.setVolume(thrust2 * .4); + this._secondaryThrustVectorSound.setVolume(thrust2 * .4); } else { - if (this._thrust2.isPlaying) { - this._thrust2.pause(); + if (this._secondaryThrustVectorSound.isPlaying) { + this._secondaryThrustVectorSound.pause(); } } - body.setAngularVelocity(this._rotationNode.absolutePosition.subtract(this._ship.absolutePosition)); body.setLinearVelocity(this._forwardNode.absolutePosition.subtract(this._ship.absolutePosition).scale(-1)); - //this._engine.forwardback(this._forwardValue); } private controllerCallback = (controllerEvent: ControllerEvent) => { @@ -349,7 +331,6 @@ export class Ship { case '1': this._camera.position.x = 15; this._camera.rotation.y = -Math.PI / 2; - console.log(1); break; case ' ': this.shoot(); @@ -386,14 +367,12 @@ export class Ship { if (controller.inputSource.handedness == "left") { this._leftInputSource = controller; this._leftInputSource.onMotionControllerInitObservable.add((motionController) => { - console.log(motionController); this.mapMotionController(motionController); }); } if (controller.inputSource.handedness == "right") { this._rightInputSource = controller; this._rightInputSource.onMotionControllerInitObservable.add((motionController) => { - console.log(motionController); this.mapMotionController(motionController); }); } @@ -434,4 +413,19 @@ export class Ship { } }); } -} \ No newline at end of file +} +function decrementValue(value: number, increment: number = .8): number { + if (Math.abs(value) < .01) { + return 0; + } else { + return value * increment; + } +} + +function adjustStickValue(stickVector: number, thrustValue: number): number { + if (Math.abs(stickVector) > .03) { + return thrustValue + (Math.pow(stickVector, 3) * .1); + } else { + return decrementValue(thrustValue, .85); + } +} diff --git a/src/starfield.ts b/src/starfield.ts index e57f794..773248a 100644 --- a/src/starfield.ts +++ b/src/starfield.ts @@ -1,69 +1,95 @@ import { - AbstractMesh, Color3, ISceneLoaderAsyncResult, MeshBuilder, ParticleHelper, ParticleSystem, ParticleSystemSet, - PhysicsAggregate, + AbstractMesh, + Color3, InstancedMesh, + Mesh, + MeshBuilder, Observable, + ParticleHelper, + ParticleSystem, + ParticleSystemSet, + PBRMaterial, + PhysicsAggregate, PhysicsBody, PhysicsMotionType, PhysicsShapeType, - SceneLoader, StandardMaterial, + SceneLoader, Vector3 } from "@babylonjs/core"; import {DefaultScene} from "./defaultScene"; +import {ScoreEvent} from "./scoreboard"; let _particleData: any = null; - +export class Rock { + private _rockMesh: AbstractMesh; + constructor(mesh: AbstractMesh) { + this._rockMesh = mesh; + } + public get physicsBody(): PhysicsBody { + return this._rockMesh.physicsBody; + } + public get position(): Vector3 { + return this._rockMesh.getAbsolutePosition(); + } +} export class RockFactory { private static _rockMesh: AbstractMesh; - private static _rockMaterial: StandardMaterial; - + private static _rockMaterial: PBRMaterial; + private static _explosion: ParticleSystemSet; public static async init() { + + if (!this._explosion) { + const set = await ParticleHelper.CreateAsync("explosion", DefaultScene.MainScene); + this._explosion = set.serialize(true); + set.dispose(); + } if (!this._rockMesh) { console.log('loading mesh'); - const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "asteroid.glb", DefaultScene.MainScene); - this._rockMesh = importMesh.meshes[1].clone("asteroid", null, true); + const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "asteroid2.glb", DefaultScene.MainScene); + this._rockMesh = importMesh.meshes[1].clone("asteroid", null, false); this._rockMesh.setParent(null); this._rockMesh.setEnabled(false); //importMesh.meshes[1].dispose(); console.log(importMesh.meshes); if (!this._rockMaterial) { - this._rockMaterial = this._rockMesh.material.clone("asteroid") as StandardMaterial; + this._rockMaterial = this._rockMesh.material.clone("asteroid") as PBRMaterial; this._rockMaterial.name = 'asteroid-material'; this._rockMaterial.id = 'asteroid-material'; + const material = (this._rockMaterial as PBRMaterial) + //material.albedoTexture = null; + material.ambientColor = new Color3(.4, .4 ,.4); + //material.albedoColor = new Color3(1, 1, 1); + //material.emissiveColor = new Color3(1, 1, 1); + this._rockMesh.material = this._rockMaterial; importMesh.meshes[1].dispose(false, true); importMesh.meshes[0].dispose(); } } } - public static async createRock(i: number, position: Vector3, size: Vector3): Promise { - const explosion = await ParticleHelper.CreateAsync("explosion", DefaultScene.MainScene); + public static async createRock(i: number, position: Vector3, size: Vector3, + score: Observable): Promise { - const rock = this._rockMesh.clone("asteroid-" + i, null, true); + const rock = new InstancedMesh("asteroid-" +i, this._rockMesh as Mesh); - //rock.material.dispose(); - //rock.material = rockMaterial; rock.scaling = size; rock.position = position; - //rock.setParent(null); - + //rock.material = this._rockMaterial; rock.name = "asteroid-" + i; rock.id = "asteroid-" + i; rock.metadata = {type: 'asteroid'}; rock.setEnabled(true); - const agg = new PhysicsAggregate(rock, PhysicsShapeType.CONVEX_HULL, {mass: 10000, restitution: .0001}, DefaultScene.MainScene); + const agg = new PhysicsAggregate(rock, PhysicsShapeType.CONVEX_HULL, { + mass: 10000, + restitution: .5, + }, DefaultScene.MainScene); const body =agg.body; - body.setLinearDamping(.001); - //body.setAngularDamping(.00001); + body.setLinearDamping(0); body.setMotionType(PhysicsMotionType.DYNAMIC); body.setCollisionCallbackEnabled(true); - //rock.renderOutline = true; - //rock.outlineColor = Color3.Red(); - //rock.outlineWidth = .02; - //rock.showBoundingBox = true; - - //rock.renderOverlay = true; body.getCollisionObservable().add((eventData) => { if (eventData.type == 'COLLISION_STARTED') { - if ( eventData.collidedAgainst.transformNode.id == 'bullet') { + if ( eventData.collidedAgainst.transformNode.id == 'ammo') { + score.notifyObservers({score: 1, remaining: -1, message: "Asteroid Destroyed"}); + const explosion = ParticleSystemSet.Parse(this._explosion, DefaultScene.MainScene, false, 10); const position = eventData.point; // _explosion.emitterNode = position; @@ -77,11 +103,11 @@ export class RockFactory { const ball = MeshBuilder.CreateBox("ball", {size: .01}, DefaultScene.MainScene); - ball.scaling = new Vector3(.1, .1, .1); + ball.scaling = new Vector3(.4, .4, .4); ball.position = position; - const material = new StandardMaterial("ball-material", DefaultScene.MainScene); - material.emissiveColor = Color3.Yellow(); - ball.material = material; + //const material = new StandardMaterial("ball-material", DefaultScene.MainScene); + //material.emissiveColor = Color3.Yellow(); + //ball.material = material; explosion.start(ball); @@ -95,13 +121,13 @@ export class RockFactory { ball.dispose(false, true); } //ball.dispose(); - }, 2000); + }, 1500); } } }); //body.setAngularVelocity(new Vector3(Math.random(), Math.random(), Math.random())); // body.setLinearVelocity(Vector3.Random(-10, 10)); - return rock; + return new Rock(rock); } }