import "@babylonjs/core/Debug/debugLayer";
import "@babylonjs/inspector";
import "@babylonjs/loaders/glTF";
import { Engine, Scene, Vector3, Mesh, Color3, Color4, ShadowGenerator, GlowLayer, PointLight, FreeCamera, CubeTexture, Sound, PostProcess, Effect, SceneLoader, Matrix, MeshBuilder, Quaternion, AssetsManager } from "@babylonjs/core";
import { AdvancedDynamicTexture, StackPanel, Button, TextBlock, Rectangle, Control, Image } from "@babylonjs/gui";
import {En1} from './environment/en1'
// 游戏状态枚举
enum State{Start=0,Game=1,Lose=2,Cutscene=3}
class App {
private _scene:Scene;
private _canvas:HTMLCanvasElement;
private _engine:Engine;
private _state:number=0;
private _transition:boolean=false
constructor() {
this._canvas=this._createCanvas()
this._engine = new Engine(this._canvas, true);
this._scene = new Scene(this._engine);
window.addEventListener("keydown", (ev) => {
// Shift+Ctrl+Alt+I
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
if (this._scene.debugLayer.isVisible()) {
this._scene.debugLayer.hide();
} else {
this._scene.debugLayer.show();
}
}
});
this._main()
}
private _createCanvas():HTMLCanvasElement{
document.documentElement.style['overflow']='hidden'
document.documentElement.style.overflow='hidden'
document.documentElement.style.width='100%'
document.documentElement.style.height='100%'
document.documentElement.style.margin='0'
document.documentElement.style.padding='0'
document.body.style.overflow='hidden'
document.body.style.width='100%'
document.body.style.height='100%'
document.body.style.margin='0'
document.body.style.padding='0'
this._canvas=document.createElement('canvas')
this._canvas.style.width="100%"
this._canvas.style.height="100%"
this._canvas.id="gameCanvas"
document.body.appendChild(this._canvas)
return this._canvas
}
private async _main():Promise<void>{
await this._gotoStart()
this._engine.runRenderLoop(()=>{
switch(this._state){
case State.Start:
this._scene.render()
case State.Cutscene:
this._scene.render()
case State.Game:
//if 240seconds/ 4mins have have passed, go to the lose state
// if (this._ui.time >= 240 && !this._player.win) {
// this._goToLose();
// this._ui.stopTimer();
// }
// if (this._ui.quit) {
// this._goToStart();
// this._ui.quit = false;
// }
this._scene.render();
break;
case State.Lose:
this._scene.render();
break;
default: break;
}
})
}
private async _gotoStart(){
// 登陆界面
this._scene.detachControl();
let scene = new Scene(this._engine);
scene.clearColor = new Color4(0, 0, 0, 1);
let camera = new FreeCamera("camera1", new Vector3(0, 0, 0), scene);
camera.setTarget(Vector3.Zero());
const start=new Sound('startSong','./source/sounds/copycat(revised).mp3',scene,function(){},{
volume:0.25,
loop:true,
autoplay:true
})
const sfx=new Sound('select','./source/sounds/vgmenuselect.wav',scene,function(){})
// GUI
const guiMenu = AdvancedDynamicTexture.CreateFullscreenUI("UI");
guiMenu.idealHeight = 720;
// backgroundImage
const imageRect=new Rectangle('titleContainer')
imageRect.width=0.8
imageRect.thickness=0
guiMenu.addControl(imageRect)
const startbg=new Image('startbg','../source/sprites/start.jpeg')
imageRect.addControl(startbg)
const title = new TextBlock("title", "SUMMER'S FESTIVAL");
title.resizeToFit = true;
title.fontFamily = "Ceviche One";
title.fontSize = "64px";
title.color = "white";
title.resizeToFit = true;
title.top = "14px";
title.width = 0.8;
title.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
imageRect.addControl(title);
const startBtn = Button.CreateSimpleButton("start", "PLAY");
startBtn.fontFamily = "Viga";
startBtn.width = 0.2
startBtn.height = "40px";
startBtn.color = "white";
startBtn.top = "-14px";
startBtn.thickness = 0;
startBtn.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
imageRect.addControl(startBtn);
Effect.RegisterShader("fade",
"precision highp float;" +
"varying vec2 vUV;" +
"uniform sampler2D textureSampler; " +
"uniform float fadeLevel; " +
"void main(void){" +
"vec4 baseColor = texture2D(textureSampler, vUV) * fadeLevel;" +
"baseColor.a = 1.0;" +
"gl_FragColor = baseColor;" +
"}");
let fadeLevel = 1.0;
this._transition = false;
scene.registerBeforeRender(() => {
if (this._transition) {
fadeLevel -= .05;
if(fadeLevel <= 0){
this._gotoCutScene();
this._transition = false;
}
}
})
startBtn.onPointerClickObservable.add(()=>{
const postProcess = new PostProcess("Fade", "fade", ["fadeLevel"], null, 1.0, camera);
postProcess.onApply=(effect)=>{
effect.setFloat("fadeLevel", fadeLevel);
}
this._transition=true
sfx.play()
scene.detachControl()
})
await scene.whenReadyAsync()
this._engine.hideLoadingUI()
this._scene.dispose()
// 这里一开始错了
this._scene=scene
this._state=State.Start
}
private async _gotoCutScene(){
// 主要是展示过场动画
// this._engine.displayLoadingUI();
this._scene.detachControl();
let cutScene = new Scene(this._engine);
let camera = new FreeCamera("camera1", new Vector3(0, 0, 0), cutScene);
camera.setTarget(Vector3.Zero());
cutScene.clearColor = new Color4(0, 0, 0, 1);
const cutSceneUI = AdvancedDynamicTexture.CreateFullscreenUI("cutscene");
let transition = 0;
let canplay = false;
let finished_anim = false;
let anims_loaded = 0;
let animTimer:any;
let anim2Timer:any;
let anim = 1;
const beginning_anim=new Image('sparkLife','../source/sprites/beginning_anim.png')
beginning_anim.stretch = Image.STRETCH_UNIFORM;
beginning_anim.cellId = 0;
beginning_anim.cellHeight = 480;
beginning_anim.cellWidth = 480;
beginning_anim.sourceWidth = 480;
beginning_anim.sourceHeight = 480;
cutSceneUI.addControl(beginning_anim);
beginning_anim.onImageLoadedObservable.add(() => {
anims_loaded++;
console.log(anims_loaded)
})
const working_anim = new Image("sparkLife", "../source/sprites/working_anim.png");
working_anim.stretch = Image.STRETCH_UNIFORM;
working_anim.cellId = 0;
working_anim.cellHeight = 480;
working_anim.cellWidth = 480;
working_anim.sourceWidth = 480;
working_anim.sourceHeight = 480;
working_anim.isVisible = false;
cutSceneUI.addControl(working_anim);
working_anim.onImageLoadedObservable.add(() => {
anims_loaded++;
})
const dropoff_anim = new Image("sparkLife", "../source/sprites/dropoff_anim.png");
dropoff_anim.stretch = Image.STRETCH_UNIFORM;
dropoff_anim.cellId = 0;
dropoff_anim.cellHeight = 480;
dropoff_anim.cellWidth = 480;
dropoff_anim.sourceWidth = 480;
dropoff_anim.sourceHeight = 480;
dropoff_anim.isVisible = false;
cutSceneUI.addControl(dropoff_anim);
dropoff_anim.onImageLoadedObservable.add(() => {
anims_loaded++;
})
const leaving_anim = new Image("sparkLife", "../source/sprites/leaving_anim.png");
leaving_anim.stretch = Image.STRETCH_UNIFORM;
leaving_anim.cellId = 0;
leaving_anim.cellHeight = 480;
leaving_anim.cellWidth = 480;
leaving_anim.sourceWidth = 480;
leaving_anim.sourceHeight = 480;
leaving_anim.isVisible = false;
cutSceneUI.addControl(leaving_anim);
leaving_anim.onImageLoadedObservable.add(() => {
anims_loaded++;
})
const watermelon_anim = new Image("sparkLife", "../source/sprites/watermelon_anim.png");
watermelon_anim.stretch = Image.STRETCH_UNIFORM;
watermelon_anim.cellId = 0;
watermelon_anim.cellHeight = 480;
watermelon_anim.cellWidth = 480;
watermelon_anim.sourceWidth = 480;
watermelon_anim.sourceHeight = 480;
watermelon_anim.isVisible = false;
cutSceneUI.addControl(watermelon_anim);
watermelon_anim.onImageLoadedObservable.add(() => {
anims_loaded++;
})
const reading_anim = new Image("sparkLife", "../source/sprites/reading_anim.png");
reading_anim.stretch = Image.STRETCH_UNIFORM;
reading_anim.cellId = 0;
reading_anim.cellHeight = 480;
reading_anim.cellWidth = 480;
reading_anim.sourceWidth = 480;
reading_anim.sourceHeight = 480;
reading_anim.isVisible = false;
cutSceneUI.addControl(reading_anim);
reading_anim.onImageLoadedObservable.add(() => {
anims_loaded++;
})
//Dialogue animations
const dialogueBg = new Image("sparkLife", "../source/sprites/bg_anim_text_dialogue.png");
dialogueBg.stretch = Image.STRETCH_UNIFORM;
dialogueBg.cellId = 0;
dialogueBg.cellHeight = 480;
dialogueBg.cellWidth = 480;
dialogueBg.sourceWidth = 480;
dialogueBg.sourceHeight = 480;
dialogueBg.horizontalAlignment = 0;
dialogueBg.verticalAlignment = 0;
dialogueBg.isVisible = false;
cutSceneUI.addControl(dialogueBg);
dialogueBg.onImageLoadedObservable.add(() => {
anims_loaded++;
})
const dialogue = new Image("sparkLife", "../source/sprites/text_dialogue.png");
dialogue.stretch = Image.STRETCH_UNIFORM;
dialogue.cellId = 0;
dialogue.cellHeight = 480;
dialogue.cellWidth = 480;
dialogue.sourceWidth = 480;
dialogue.sourceHeight = 480;
dialogue.horizontalAlignment = 0;
dialogue.verticalAlignment = 0;
dialogue.isVisible = false;
cutSceneUI.addControl(dialogue);
dialogue.onImageLoadedObservable.add(() => {
anims_loaded++;
})
// 加载了全部的过场动画
let dialogueTimer = setInterval(() => {
if(finished_anim && dialogueBg.cellId < 3){
dialogueBg.cellId++;
} else {
dialogueBg.cellId = 0;
}
}, 250);
// 对话的标志位
const skipBtn = Button.CreateSimpleButton("skip", "SKIP");
skipBtn.fontFamily = "Viga";
skipBtn.width = "45px";
skipBtn.left = "-14px";
skipBtn.height = "40px";
skipBtn.color = "white";
skipBtn.top = "14px";
skipBtn.thickness = 0;
skipBtn.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
skipBtn.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT;
cutSceneUI.addControl(skipBtn);
skipBtn.onPointerDownObservable.add(()=> {
cutScene.detachControl();
clearInterval(animTimer);
clearInterval(anim2Timer);
clearInterval(dialogueTimer);
this._engine.displayLoadingUI();
canplay = true;
});
// 跳过剧情动画的操作
const next = Button.CreateImageOnlyButton("next", "../source/sprites/arrowBtn.png");
next.rotation = Math.PI / 2;
next.thickness = 0;
next.verticalAlignment = Control.VERTICAL_ALIGNMENT_BOTTOM;
next.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT;
next.width = "64px";
next.height = "64px";
next.top = "-3%";
next.left = "-12%";
next.isVisible = false;
cutSceneUI.addControl(next);
next.onPointerUpObservable.add(() => {
if (transition == 8) {
cutScene.detachControl();
this._engine.displayLoadingUI();
transition = 0;
canplay = true;
} else if(transition < 8){
transition++;
dialogue.cellId++;
}
})
// 下一步操作
// 自动处理动画的逻辑
cutScene.onBeforeRenderObservable.add(()=>{
if(anims_loaded==8){
this._engine.hideLoadingUI()
anims_loaded=0;
animTimer=setInterval(()=>{
switch(anim) {
case 1:
if(beginning_anim.cellId == 9){ //each animation could have a different number of frames
anim++;
beginning_anim.isVisible = false; // current animation hidden
working_anim.isVisible = true; // show the next animation
} else {
beginning_anim.cellId++;
}
break;
case 2:
if(working_anim.cellId == 11){
anim++;
working_anim.isVisible = false;
dropoff_anim.isVisible = true;
} else {
working_anim.cellId++;
}
break;
case 3:
if(dropoff_anim.cellId == 11){
anim++;
dropoff_anim.isVisible = false;
leaving_anim.isVisible = true;
} else {
dropoff_anim.cellId++;
}
break;
case 4:
if(leaving_anim.cellId == 9){
anim++;
leaving_anim.isVisible = false;
watermelon_anim.isVisible = true;
} else {
leaving_anim.cellId++;
}
break;
default:
break;
}
},250)
anim2Timer=setInterval(()=>{
switch(anim) {
case 5:
if(watermelon_anim.cellId == 8){
anim++;
watermelon_anim.isVisible = false;
reading_anim.isVisible = true;
} else {
watermelon_anim.cellId++;
}
break;
case 6:
if(reading_anim.cellId == 11){
reading_anim.isVisible = false;
finished_anim = true;
dialogueBg.isVisible = true;
dialogue.isVisible = true;
next.isVisible = true;
} else {
reading_anim.cellId++;
}
break;
}
},750)
}
if(finishedLoading&&canplay){
canplay=true
this._goToGame()
}
})
// 最后的处理
await cutScene.whenReadyAsync();
this._scene.dispose();
this._state = State.Cutscene;
this._scene = cutScene;
var finishedLoading=false
await this._setUpGame().then((res)=>{
finishedLoading=true
})
}
private async _goToLose():Promise<void>{
this._engine.displayLoadingUI();
//--SCENE SETUP--
this._scene.detachControl();
let scene = new Scene(this._engine);
scene.clearColor = new Color4(0, 0, 0, 1);
let camera = new FreeCamera("camera1", new Vector3(0, 0, 0), scene);
camera.setTarget(Vector3.Zero());
//--GUI--
const guiMenu = AdvancedDynamicTexture.CreateFullscreenUI("UI");
const mainBtn = Button.CreateSimpleButton("mainmenu", "MAIN MENU");
mainBtn.width = 0.2;
mainBtn.height = "40px";
mainBtn.color = "white";
guiMenu.addControl(mainBtn);
mainBtn.onPointerUpObservable.add(() => {
this._gotoStart();
});
//--SCENE FINISHED LOADING--
await scene.whenReadyAsync();
this._engine.hideLoadingUI();
this._scene.dispose();
this._scene = scene;
this._state = State.Lose;
}
private async _goToGame():Promise<void>{
}
private async _setUpGame(){
let scene=new Scene(this._engine)
const environment = new En1(scene);
// this._environment = environment; //class variable for App
await environment.load();
}
}
new App();
网友评论