immersive2/src/tutorial/introduction.ts

181 lines
6.4 KiB
TypeScript

import {
AbstractMesh,
Color3,
DynamicTexture,
MeshBuilder,
PhysicsAggregate,
PhysicsHelper,
PhysicsShapeType,
Scene,
StandardMaterial,
Vector3,
VideoTexture
} from "@babylonjs/core";
import {Button3D, GUI3DManager, TextBlock} from "@babylonjs/gui";
import {DiaSounds} from "../util/diaSounds";
import {AppConfig} from "../util/appConfig";
import Hls from "hls.js";
export class Introduction {
private readonly scene: Scene;
private manager: GUI3DManager;
private physicsHelper: PhysicsHelper;
private current: AbstractMesh[] = [];
private step: number = 0;
private items: AbstractMesh[] = [];
private advance: Button3D;
private sounds: DiaSounds;
private config: AppConfig;
constructor(scene: Scene, config: AppConfig) {
this.sounds = new DiaSounds(scene);
this.scene = scene;
this.config = config;
this.manager = new GUI3DManager(scene);
this.physicsHelper = new PhysicsHelper(scene);
}
public start() {
this.scene.physicsEnabled = true;
this.advance = new Button3D("advance");
const text = new TextBlock("advance", "Click Me");
text.fontSize = "48px";
text.color = "#ffffff";
text.alpha = 1;
this.advance.content = text;
this.advance.onPointerClickObservable.add(() => {
this.takeStep();
}, -1, false, this, false);
this.manager.addControl(this.advance);
this.advance.isVisible = false;
this.advance.position.y = 0;
this.advance.position.x = 2;
this.scene.onReadyObservable.add(() => {
this.advance.isVisible = true;
});
}
buildVideo(src: string, size: number, position: Vector3): AbstractMesh {
const vid = document.createElement("video");
vid.setAttribute('autoplay', 'true');
vid.setAttribute('playsinline', 'true');
vid.setAttribute('src', src);
const texture = new VideoTexture("video", vid, this.scene, true);
const mesh = this.makeObject("video", position, size, 16 / 9);
const material = new StandardMaterial("video_material", this.scene);
material.diffuseTexture = texture;
material.diffuseColor = new Color3(1, 1, 1);
material.emissiveColor = new Color3(1, 1, 1);
mesh.material = material;
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(src);
hls.attachMedia(vid);
hls.on(Hls.Events.MANIFEST_PARSED, function () {
vid.play();
});
} else if (vid.canPlayType('application/vnd.apple.mpegurl')) {
vid.src = src;
vid.addEventListener('loadedmetadata', function () {
vid.play();
});
}
return mesh;
}
makeObject(text: string, position: Vector3, size: number, ratio: number = 2): AbstractMesh {
const welcome = MeshBuilder.CreateTiledBox(text + "_box", {width: 1, height: 1, depth: 1}, this.scene);
welcome.position = position;
welcome.scaling = new Vector3(size, size / ratio, size);
const aggregate = new PhysicsAggregate(welcome, PhysicsShapeType.BOX, {
friction: 1,
mass: 1,
restitution: .1
}, this.scene);
aggregate.body.getCollisionObservable().add((collider) => {
if (collider.impulse < .5) {
return;
}
let volume = 0;
const sound = this.sounds.bounce;
if (collider.impulse > 1 && collider.impulse < 10) {
volume = collider.impulse / 10;
}
if (volume > 0) {
sound.attachToMesh(aggregate.body.transformNode);
sound.updateOptions({offset: 0, volume: volume, length: .990});
sound.play();
}
});
aggregate.body.setCollisionCallbackEnabled(true);
return welcome;
}
buildText(text: string, size: number, textureSize: number, position: Vector3): AbstractMesh {
const mesh = this.makeObject(text, position, size);
const texture = new DynamicTexture("dynamic texture", {
width: textureSize,
height: textureSize / 2
}, this.scene, true);
texture.drawText(text, null, null, "bold 128px Arial", "white", "#00f", true, true);
mesh.material = new StandardMaterial(text + "_material", this.scene);
mesh.material.alpha = 1;
(mesh.material as StandardMaterial).diffuseTexture = texture;
texture.update();
return mesh;
}
private takeStep() {
this.current.forEach((mesh) => {
const pos = mesh.physicsBody.transformNode.absolutePosition.clone();
pos.x = pos.x - .1;
mesh.physicsBody.applyImpulse(new Vector3(0, 8, 12), pos);
});
switch (this.step) {
case 0:
this.items.push(this.buildText("Welcome To", 3, 1024, new Vector3(0, 15, 5)));
this.items.push(this.buildText("Deep Diagram", 5, 1024, new Vector3(0, 10, 5)));
this.current = this.items.slice(-2);
break;
case 1:
this.items.push(this.buildText("Let us show you", 3, 1024, new Vector3(-1.5, 16, 5)));
this.items.push(this.buildText("what you can build", 4, 1200, new Vector3(2, 12, 5)));
this.current = this.items.slice(-2);
break;
case 2:
this.items.push(this.buildText("A quick video", 5, 1024, new Vector3(0, 15, 5)));
this.current = this.items.slice(-1);
break;
case 3:
const src = 'https://customer-l4pyjzbav11fzy04.cloudflarestream.com/8b906146c75bb5d81e03d199707ed0e9/manifest/video.m3u8'
this.items.push(this.buildVideo(src, 7, new Vector3(0, 15, 6)));
this.current = this.items.slice(-1);
break;
case 4:
this.items.forEach((mesh) => {
mesh.physicsBody.dispose();
mesh.dispose();
});
this.advance.dispose();
this.manager.dispose();
const config = this.config.current;
config.demoCompleted = true;
this.config.current = config;
this.items = [];
}
this.step++;
}
}