jsgam
Version:
JavaScript Graphic Adventure Maker
593 lines (473 loc) • 15.3 kB
JavaScript
import * as PIXI from 'pixi.js';
window.PIXI=PIXI; //Solution to use pixi-layers with PIXI v5
require("pixi-layers");
import { gsap } from "gsap";
import { PixiPlugin } from "gsap/PixiPlugin";
import { MotionPathPlugin } from "gsap/MotionPathPlugin";
// register the plugin
gsap.registerPlugin(PixiPlugin,MotionPathPlugin);
// give the plugin a reference to the PIXI object
PixiPlugin.registerPIXI(PIXI);
import GameLoader from './loader.js';
import Storage from './storage.js';
import Sound from './sound.js';
import Title from './class/title.js';
import GameScene from './class/gamescene.js';
import CutScene from './class/cutscene.js';
import GameObject from './class/gameobject.js';
import Inventory from './class/inventory.js';
import Puzzle from './class/puzzle.js';
import {TextField} from './class/text.js';
import Player from './class/player.js';
import NPC from './class/npc.js';
import Dialogue from './class/dialogue.js';
import Logo from './class/logo.js';
import Options from './class/options.js';
import ProgressBar from './class/progressbar.js';
class Game {
constructor(config){
this.settings={};
this.data={
scenes:[],
cutscenes:[],
objects:[],
dialogues:[],
puzzles:[],
texts:[],
music:[],
npc:[],
voices:[],
sounds:[]
};
this.width=config.width;
this.height=config.height;
this.gameContainer=document.getElementById(config.container);
this.holdTime=500;
this.playSounds = true;
//Setup the application
this.app = new PIXI.Application(
config.width,config.height,{
antialias: true,
autoResize: true,
resolution: devicePixelRatio
});
this.app.stage = new PIXI.display.Stage();
//Change game size when window size changes
if(config.autoResize!==undefined) this.app.renderer.autoResize=config.autoResize;
else window.addEventListener('resize', this.resize.bind(this));
if(config.fitToContainer!==undefined) this.fitToContainer();
//Disable contextmenu for mouse interaction
document.addEventListener('contextmenu', e => {
e.preventDefault();
});
//Append it to a HTML element
this.gameContainer.appendChild(this.app.view)
if(config.muteSound) this.playSounds = false;
//Load config files
this.preload(config.files);
}
//Read JSON configuration files
preload(files){
//Loading bar
this.progressBar=new ProgressBar(this);
this.loadingTxt=new PIXI.Text("Loading...", {fill: 'white',"fontSize": 50});
this.loadingTxt.anchor.set(0.5);
this.loadingTxt.x=this.width/2;
this.loadingTxt.y=this.height/2;
this.progressBar.container.y=this.loadingTxt.y+this.loadingTxt.height;
this.progressBar.container.x=this.width/2-this.progressBar.container.width/2;
this.app.stage.addChild(this.loadingTxt);
this.app.stage.addChild(this.progressBar.container);
this.resize();
this.jsons=new GameLoader();
this.jsons.game=this;
this.jsons.addJSON(files);
this.jsons.load(this.load.bind(this)); //When all config files are loaded, load the game resources.
}
//Load game resources (images,sounds,vids...)
load(){
this.files=new GameLoader();
this.files.game=this;
this.files.addFiles(Object.values(this.jsons.resources));
this.files.load(this.setup.bind(this));
}
setup(){
this.app.stage.removeChild(this.loadingTxt);
this.app.stage.removeChild(this.progressBar.container);
//Z-Order
this.addZOrder();
//Adjust to window size
this.resize();
this.tween=null;
this.logo=null;
this.options=null;
this.scenes={};
this.cutscenes={};
this.objects={};
this.npcs={};
this.dialogues={};
this.puzzles={};
this.music={};
this.sounds={};
this.voices={};
this.activeLanguage=0;
this.activeScene=null;
this.activeObject=null;
this.activeNPC=null;
this.activePuzzle=null;
this.activeDialogue=null;
this.activeCutscene=null;
this.activeVoice=null;
this.activeState=null;
this.finished=false;
this.storage=new Storage(this);
if(this.settings.Logos!==undefined) this.logo=new Logo(this);
this.titleLabel="Title";
if(this.settings.HoldTime!==undefined) this.holdTime=this.settings.HoldTime*1000;
if(this.settings.dialogueChoices!==undefined) this.dialogueChoices=this.settings.dialogueChoices;
else this.dialogueChoices=3;
//Setup title screen
this.addScene(this.titleLabel,new Title(),this.settings.TitleScreen);
//Add sounds,music and voices
let i;
let length=this.data.music.length;
for(i=0;i<length;i++)
{
this.addMusic(this.data.music[i].Name,new Sound(),this.data.music[i]);
}
length=this.data.sounds.length;
for(i=0;i<length;i++)
{
this.addSound(this.data.sounds[i].Name,new Sound(),this.data.sounds[i]);
}
length=this.data.voices.length;
for(i=0;i<length;i++)
{
this.addVoice(this.data.voices[i].Name,new Sound(),this.data.voices[i]);
}
//Add game objects
length=this.data.objects.length;
for(i=0;i<length;i++)
{
this.addObject(this.data.objects[i].Name,new GameObject(),this.data.objects[i]);
}
//Non-playable characters
length=this.data.npc.length;
for(i=0;i<length;i++)
{
this.addNPC(this.data.npc[i].Name,new NPC(),this.data.npc[i]);
}
//Dialogues
length=this.data.dialogues.length;
for(i=0;i<length;i++)
{
this.addDialogue(this.data.dialogues[i].Name,new Dialogue(),this.data.dialogues[i]);
}
//Add game scenes
length=this.data.scenes.length;
for(i=0;i<length;i++)
{
this.addScene(this.data.scenes[i].Name,new GameScene(),this.data.scenes[i]);
}
//Add cutscenes
length=this.data.cutscenes.length;
for(i=0;i<length;i++)
{
this.addCutscene(this.data.cutscenes[i].Name,new CutScene(),this.data.cutscenes[i]);
}
//Puzzles
length=this.data.puzzles.length;
for(i=0;i<length;i++)
{
this.addPuzzle(this.data.puzzles[i].Name,new Puzzle(),this.data.puzzles[i]);
}
//Add Inventory
this.addInventory();
//Add text field
this.addTextField();
//Add player
this.addPlayer();
//Add Options if they are defined
if(this.settings.Options!==undefined) this.addOptions();
//Check if there is a saved game
this.storage.check();
this.addBlackScreen();
//Game's loop
this.app.ticker.add(this.loop.bind(this));
if(this.settings.Logos!==undefined) this.logo.show();
else{
//Set Title as the first scene to show
this.setScene(this.titleLabel);
this.fadeIn();
if(this.options!==null){
this.app.stage.addChild(this.options.icon);
this.app.stage.addChild(this.options.container);
}
}
}
loop(dt){
// update current state
if (this.activeState != null) {
this.activeState.update(dt);
}
}
addMusic(name, music, config) {
this.music[name] = music;
//Music parameters
music.config=config;
//Set game so music can access it
music.game = this;
music.source=this.files.resources[name].sound;
}
addSound(name, sound, config) {
this.sounds[name] = sound;
//Music parameters
sound.config=config;
//Set game so music can access it
sound.game = this;
sound.source=this.files.resources[name].sound;
if(config.Sprites){
let audioSprite = Object.assign({}, ...config.Sprites.map(object => ({[object.key]: object.value})));
sound.source._sprite=audioSprite;
}
}
addVoice(name, voice, config) {
this.voices[name] = voice;
//Music parameters
voice.config=config;
//Set game so music can access it
voice.game = this;
voice.source=this.files.resources[name].sound;
voice.source._sprite=config.Sprites;
}
addObject(name, object, config) {
this.objects[name] = object;
//Config the object
object.config=config;
//Set game so object can access it
object.game = this;
//Build object
object.build();
}
addScene(name, scene, config) {
this.scenes[name] = scene;
//Config the scene
scene.setup(config);
//Set game so scene can access it
scene.game = this;
//Build scene
scene.build();
}
addCutscene(name, cutscene, config) {
this.cutscenes[name] = cutscene;
//Config the scene
cutscene.config=config;
//Set game so scene can access it
cutscene.game = this;
//Build scene
cutscene.build();
}
addPuzzle(name, puzzle, config) {
this.puzzles[name] = puzzle;
//Puzzle's config
puzzle.config=config;
//Set game so puzzle can access it
puzzle.game = this;
}
addZOrder(){
this.BottomGroup= new PIXI.display.Group(0,false);
this.sortGroup= new PIXI.display.Group(1, true);
this.sortGroup.on('sort', function (sprite) {
sprite.zOrder = sprite.y;
});
this.TopGroup = new PIXI.display.Group(2,false);
this.UIGroup = new PIXI.display.Group(3,false);
this.BlackGroup = new PIXI.display.Group(4,false);
this.layerBottom=new PIXI.display.Layer(this.BottomGroup);
this.layer=new PIXI.display.Layer(this.sortGroup);
this.layerTop=new PIXI.display.Layer(this.TopGroup);
this.layerUI=new PIXI.display.Layer(this.UIGroup);
this.app.stage.group.enableSort = true;
this.app.stage.addChild(this.layerBottom);//Z-order
this.app.stage.addChild(this.layer);//Z-order
this.app.stage.addChild(this.layerTop);//Z-order
this.app.stage.addChild(this.layerUI);//Z-order
}
addInventory(){
this.inventory=new Inventory();
this.inventory.game=this;
this.inventory.build();
}
addOptions(){
this.options=new Options();
this.options.game=this;
this.options.build();
}
addPlayer(){
this.player=new Player();
this.player.game=this;
this.data.player.Name="player";
this.player.setup(this.data.player);
}
addNPC(name, char, config){
this.npcs[name] = char;
char.game = this;
char.setup(config);
char.build();
}
addDialogue(name, dialogue, config){
this.dialogues[name] = dialogue;
dialogue.game = this;
dialogue.setup(config);
}
addTextField(){
this.textField=new TextField();
this.textField.game=this;
this.textField.build();
}
//Used for fade between screens
addBlackScreen(){
this.blackScreen=new PIXI.Sprite(PIXI.Texture.WHITE);
this.blackScreen.width=this.width;
this.blackScreen.height=this.height;
this.blackScreen.tint=0x000000;
this.blackScreen.parentLayer = this.layerUI;
}
//Adjust game screen to the window
resize() {
var w = window.innerWidth;// * window.devicePixelRatio;
var h = window.innerHeight;// * window.devicePixelRatio;
var ratio = Math.min( w/this.width, h/this.height);
this.app.renderer.resize(this.width*ratio,this.height*ratio);
this.app.stage.scale.set(ratio);
}
//Adjust game screen to container
fitToContainer() {
let canvas=this.app.view;
canvas.style.width='100%';
canvas.style.height='100%';
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
}
fullscreen(){
if (this.gameContainer.requestFullscreen) {
this.gameContainer.requestFullscreen();
} else if (this.gameContainer.mozRequestFullScreen) { /* Firefox */
this.gameContainer.mozRequestFullScreen();
} else if (this.gameContainer.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
this.gameContainer.webkitRequestFullscreen();
} else if (this.gameContainer.msRequestFullscreen) { /* IE/Edge */
this.gameContainer.msRequestFullscreen();
}
if(!this.app.renderer.autoResize) this.resize();
}
//The magic begins
start(){
//Show Inventory
this.app.stage.addChild(this.inventory.container);
this.app.stage.addChild(this.inventory.icon);
//Show Player
this.app.stage.addChild(this.player.sprite);
//Add Text Field
this.app.stage.addChild(this.textField.container);
}
pause(){
this.activeScene.hide();
this.inventory.hide();
this.inventory.hideIcon();
if(this.options!==null){
this.options.hide();
this.options.hideIcon();
}
this.player.hide();
if(this.activeScene.music!==undefined){
this.music[this.activeScene.music].stop();
}
}
resume(){
this.inventory.showIcon();
if(this.options!==null){
this.options.showIcon();
}
this.player.show();
this.activeScene.show();
this.fadeIn();
}
end(){
this.finished=true;
}
home(){
location.reload();
}
setScene(name,playerCoords) {
//Remove current container
if (this.activeScene !== null) {
this.app.stage.removeChild(this.activeScene.container);
}
//Set current container
this.activeScene = this.scenes[name];
//Player parameters
if(playerCoords!==undefined){
this.player.sprite.x=playerCoords[0];
this.player.sprite.y=playerCoords[1];
}
if(this.activeScene.config.Player!==undefined){
if(this.activeScene.config.Player.Position!==undefined){
this.player.position(this.activeScene.config.Player.Position);
}
if(this.activeScene.config.Player.Size!==undefined){
this.player.size=this.activeScene.config.Player.Size;
this.player.scale();
}
}
//Save game progress
if(this.activeScene!==this.scenes[this.titleLabel])
this.storage.save();
}
changeScene(name,playerCoords){
//Stop the current music playing
if(this.activeScene.music!==undefined){
this.music[this.activeScene.music].stop();
}
this.app.stage.addChild(this.blackScreen);
if(this.tween) this.tween.kill();
this.tween=gsap.set(this.blackScreen, {alpha:0});
this.tween=gsap.fromTo(this.blackScreen,
{alpha:0},
{duration:1,alpha:1, onComplete:this.fadeOutEnd.bind(this),
onCompleteParams:[name,playerCoords]});
}
fadeIn(){
//Add our new container
this.app.stage.addChild(this.activeScene.container);
this.app.stage.addChild(this.blackScreen);
if(this.tween) this.tween.kill();
this.tween=gsap.set(this.blackScreen, {alpha:1});
this.tween=gsap.fromTo(this.blackScreen,
{alpha:1},
{duration:1,alpha:0, onComplete:this.fadeInEnd.bind(this)}
);
}
fadeInEnd(){
this.app.stage.removeChild(this.blackScreen);
//Play music if there is one to play
if(this.activeScene.music!==undefined){
this.music[this.activeScene.music].play(true);
}
}
fadeOutEnd(name,playerCoords){
this.setScene(name,playerCoords);
//Check Cutscenes
if(this.activeScene.config.CutScene!==undefined &&
!this.cutscenes[this.activeScene.config.CutScene].played){
this.activeCutscene=this.cutscenes[this.activeScene.config.CutScene];
this.pause();
this.activeCutscene.show();
}else{
this.resume();
}
this.player.scale();
this.app.stage.removeChild(this.blackScreen);
}
}
export default Game;