import Matter=require("matter-js"); import Broadcaster from "../../../libs/class/networking2/app.js"; import { byId, createAppEvent, htmlHeader } from "../../../libs/class/system"; import SpriteTextureComponent from "../../../libs/class/visual-methods/sprite-animation"; import { DEFAULT_GAMEPLAY_ROLES, DEFAULT_PLAYER_DATA } from "../../../libs/defaults"; import { IGamePlayModel, IPoint, ISelectedPlayer } from "../../../libs/interface/global"; import Starter from "../../../libs/starter"; import { UniVector, worldElement } from "../../../libs/types/global"; require("../audios/player/dead.mp3"); // import "../audios/player/collect-item.mp3"; import Level1 from "./packs/level1"; import Level2 from "./packs/level2"; import Level3 from "./packs/level3"; import Level4 from "./packs/level4"; import Level5 from "./packs/level5"; import Level6 from "./packs/level6"; // import { DEFAULT_PLAYER_DATA } from "../../../libs/defaults"; /** * @author Nikola Lukic * @class Platformer Multiplayer Solution. * @param Starter * @description This is game logic part * we stil use class based methodology. * About resource we use requir */ class Platformer implements IGamePlayModel { public gameName: string="platformer"; public version: number=0.3; public playerCategory=0x0002; public staticCategory=0x0004; public starter: Starter; public grounds: worldElement[]=[]; public enemys: worldElement[]=[]; public deadLines: worldElement[]=[]; public labels: worldElement[]=[]; public v: any; public player: Matter.Body|any=undefined; // move to maps 'labes text' public hudLives: Matter.Body|any=null; public netBodies: UniVector={}; public broadcaster: Broadcaster; public selectedPlayer: ISelectedPlayer; private selectPlayerArray: ISelectedPlayer[]=[]; private lives: number=DEFAULT_PLAYER_DATA.INITIAL_LIVES; private preventDoubleExecution: boolean=false; private playerStartPositions: IPoint[]=[{ x: 120, y: 200 }]; private playerDeadPauseInterval: number=550; private UIPlayerBoard: HTMLDivElement; private UIPlayAgainBtn: HTMLDivElement; private UISoundOptionDom: HTMLDivElement; private levelMaps: any={ generatedMap: Level1, Level1, Level2, Level3, Level4, Level5, Level6, }; constructor (starter: Starter) { this.starter=starter; this.broadcaster=this.starter.ioc.get.Broadcaster; // this.starter.getEngine().enableSleeping = true; this.initSelectPlayer(); this.addUIPlayerBoard(); this.showPlayerBoardUI(); this.attachUpdateLives(); // fix mobile if(this.starter.ioc.get.Browser.isLandscape()) { console.log('LANSCAPE MOBILE') } } /** * Network works. */ public addNetPlayer=(myInstance, rtcEvent?) => { this.preventDoubleExecution=false; const sptTexCom=new SpriteTextureComponent( "playerImage", (this.selectedPlayer.resource as any), ({ byX: 5, byY: 1 } as any), ); console.log("New netPlayer: TEST THIS ", this); const playerRadius=50; const netPlayer: worldElement=Matter.Bodies.circle( this.playerStartPositions[0].x, this.playerStartPositions[0].y, playerRadius, { netId: 1000, label: rtcEvent.connectionId, density: 0.0005, friction: 0.01, frictionAir: 0.06, restitution: 0.3, ground: true, jumpCD: 0, portal: -1, collisionFilter: { category: this.playerCategory, } as any, render: { visualComponent: sptTexCom, fillStyle: "blue", sprite: { xScale: 1, yScale: 1, }, } as any, } as Matter.IBodyDefinition); netPlayer.collisionFilter.group=-1; (netPlayer.render as any).visualComponent.assets.SeqFrame.setNewSeqFrameRegimeType("CONST"); (netPlayer.render as any).visualComponent.keepAspectRatio=true; (netPlayer.render as any).visualComponent.setHorizontalFlip(true); const addToScene=true; if(addToScene) { // this.netPlayer.id = 2; // Sometime networking make double join session receive signal console.log("myInstance.netBodies[netObject_ + rtcEvent.conn id]>>", myInstance.netBodies["netObject_"+rtcEvent.connectionId]); if(myInstance.netBodies["netObject_"+rtcEvent.connectionId]) { console.log("ALREADY EXIST"); return; } this.starter.AddNewBodies(netPlayer as worldElement); console.info("Net Player body created."); myInstance.netBodies["netObject_"+rtcEvent.connectionId]=netPlayer; } } public initSelectPlayer() { // Create UI for basic select player features. // Register /* this.selectPlayerArray.push({ labelName: "robot", poster: require("../imgs/players/robot/poster.png"), resource: [ require("../imgs/players/robot/1.png"), require("../imgs/players/robot/2.png"), require("../imgs/players/robot/3.png"), require("../imgs/players/robot/4.png"), require("../imgs/players/robot/5.png"), require("../imgs/players/robot/6.png"), require("../imgs/players/robot/7.png"), require("../imgs/players/robot/8.png"), ], type: "frameByFrame" }); */ this.selectPlayerArray.push({ labelName: "nidzica", poster: require("../imgs/players/nidzica/posterNidzica.png"), resource: [ require("../imgs/players/nidzica/nidzica-running.png"), require("../imgs/explosion/explosion.png"), require("../imgs/players/nidzica/nidzica-idle.png"), ], type: "sprite", spriteTile: { run: { byX: 5, byY: 1 }, idle: { byX: 3, byY: 1 } }, spriteTileCurrent: "run", setCurrentTile(key: string) { this.spriteTileCurrent=key; }, }); this.selectPlayerArray.push({ labelName: "smartGirl", poster: require("../imgs/players/smart-girl/poster.png"), resource: [ require("../imgs/players/smart-girl/smart-girl.png"), require("../imgs/explosion/explosion.png"), require("../imgs/players/smart-girl/smart-girl-idle.png"), ], type: "sprite", spriteTile: { run: { byX: 5, byY: 1 }, idle: { byX: 5, byY: 1 } }, spriteTileCurrent: "idle", setCurrentTile(key: string) { this.spriteTileCurrent=key; }, }); } public createPlayer(addToScene: boolean) { const sptTexCom=new SpriteTextureComponent( "playerImage", (this.selectedPlayer.resource as any), ({ byX: 5, byY: 1 } as any), ); this.preventDoubleExecution=false; const playerRadius=50; this.player=Matter.Bodies.circle( this.playerStartPositions[0].x, this.playerStartPositions[0].y, playerRadius, { label: "player", jumpAmp: 80, density: 0.0005, friction: 0.01, frictionAir: 0.06, restitution: 0.3, ground: true, jumpCD: 0, portal: -1, collisionFilter: { category: this.playerCategory, } as any, render: { visualComponent: sptTexCom, fillStyle: "blue", sprite: { xScale: 1, yScale: 1, }, } as any, } as Matter.IBodyDefinition); this.player.collisionFilter.group=-1; if(this.player.render.visualComponent instanceof SpriteTextureComponent) { this.player.render.visualComponent.assets.SeqFrame.setNewSeqFrameRegimeType("CONST"); this.player.render.visualComponent.keepAspectRatio=true; } else { this.player.render.visualComponent.keepAspectRatio=true; // hardcode for now this.player.render.sprite.xScale=0.2; this.player.render.sprite.yScale=0.2; } this.player.render.visualComponent.setHorizontalFlip(false); if(addToScene) { this.player.id=2; this.starter.AddNewBodies(this.player as worldElement); console.info("Player body created from 'dead'."); } } public playerSpawn(recreatePlayer: boolean) { if(this.player===null||this.player===undefined) { this.createPlayer(recreatePlayer); } else if(this.player.type==="body") { // empty for now } } public collisionCheck(event, ground: boolean) { const myInstance=this; const pairs=event.pairs; for(let i=0, j=pairs.length; i!==j; ++i) { const pair=pairs[i]; if(pair.activeContacts) { // collectItemPoint used , this is next type : // nextLevelItem or teleport // Destroy world , player create next game play // or change position in current map. if(pair.bodyA.label==="player"&&pair.bodyB.label.indexOf("Level")!==-1) { const nextLevelItem=pair.bodyB.label; myInstance.nextLevel(nextLevelItem); } if(pair.bodyA.label==="player"&&pair.bodyB.label==="crapmunch") { const collectitem=pair.bodyA; this.playerDie(collectitem); } else if(pair.bodyB.label==="player"&&pair.bodyA.label==="crapmunch") { const collectitem=pair.bodyB; this.playerDie(collectitem); } if(pair.bodyA.label==="player"&&pair.bodyB.label==="collectItemPoint") { const collectitem2=pair.bodyB; this.starter.destroyBody(collectitem2); } pair.activeContacts.forEach((element) => { if(element.vertex.body.label==="player"&& element.vertex.index>5&&element.vertex.index<8&& this.player!==null) { (this.player as any).ground=ground; } else if(element.vertex.body.label==="player") { if(this.player===null) { return; } (this.player as any).ground=false; } }); } } } public showPlayerBoardUI=() => { const myInstance=this; fetch("./templates/ui/player-board.html", { headers: htmlHeader, }). then(function(res) { return res.text(); }).then(function(html) { myInstance.UIPlayerBoard=byId("UIPlayerBoard") as HTMLDivElement; myInstance.UIPlayerBoard.innerHTML=html; myInstance.UIPlayerBoard.style.display="block"; myInstance.UIPlayAgainBtn=byId("playAgainBtn") as HTMLDivElement; myInstance.UISoundOptionDom=byId("soundOptionDom") as HTMLDivElement; myInstance.showSelectPlayerUI() console.log('TEST !showSelectPlayerUI!!!!!!') /** * @description In gameplay Enable od disable sounds. * New aproach `()=>` next migration. */ myInstance.UISoundOptionDom.addEventListener("click", function(e) { if((e.currentTarget as HTMLElement).innerHTML=="Sound: Off") { myInstance.starter.ioc.get.Sound.audioBox.bgMusic.pause(); myInstance.starter.ioc.get.Sound.audioBox.noSound=true; (e.currentTarget as HTMLElement).innerText="Sound: On"; } else { myInstance.starter.ioc.get.Sound.audioBox.noSound=false; myInstance.starter.ioc.get.Sound.playById('bgMusic'); (e.currentTarget as HTMLElement).innerText="Sound: Off"; } }); /** * @description Running game-play right here */ myInstance.UIPlayAgainBtn.addEventListener("click", function() { const appStartGamePlay=createAppEvent("game-init", { mapName: "Level1", game: myInstance.levelMaps.Level1, }); (window as any).dispatchEvent(appStartGamePlay); myInstance.player.render.visualComponent.assets.SeqFrame.setNewValue(0); myInstance.selectedPlayer.spriteTileCurrent="run"; myInstance.player.render.visualComponent.setNewShema(myInstance.selectedPlayer); myInstance.player.render.visualComponent.seqFrameX.setDelay(8); }, false); }); } protected showSelectPlayerUI() { const myInstance=this; // Select Player feature - Load UI fetch("./templates/ui/select-player.html", { headers: htmlHeader, }). then(function(res) { return res.text(); }).then(function(html) { const popup=byId("popup") as HTMLDivElement; popup.innerHTML=html; popup.style.display="block"; myInstance.selectPlayerArray.forEach(function(itemPlayer) { const local=document.createElement("div"); local.id=""+itemPlayer.labelName; local.className="bounceIn selectPlayerBox"; // local.setAttribute("style", "width:30%;display:inline-block;cursor:pointer;text-align:center;padding: 9px;"); local.innerHTML=" Name:"+ itemPlayer.labelName+ " "; local.addEventListener("click", function() { myInstance.selectPlayer(itemPlayer.labelName); const appStartGamePlay=createAppEvent( "game-init", { mapName: "Level1", game: myInstance.levelMaps.Level1, }, ); (window as any).dispatchEvent(appStartGamePlay); popup.innerHTML=""; document.body.removeChild(popup); }, false); byId("listOfPlayers").appendChild(local); // popup.appendChild(local); }); }); } protected playerDie(collectitem) { if(!this.preventDoubleExecution) { const root=this; this.preventDoubleExecution=true; // Hard dead // this.starter.destroyBody(collectitem); this.player.render.visualComponent.shema={ byX: 4, byY: 4 }; this.player.render.visualComponent.assets.SeqFrame.setNewValue(1); this.lives=this.lives-1; (this.UIPlayerBoard.getElementsByClassName("UIPlayerLives")[0] as HTMLSpanElement).innerText=this.lives.toString(); this.starter.ioc.get.Sound.playById('dead'); if(this.lives===0||this.lives<0) { this.starter.destroyBody(collectitem); this.player=null; this.broadcaster.connection.send({ noMoreLives: true, }); if((byId("playAgainBtn") as HTMLButtonElement)) { (byId("playAgainBtn") as HTMLButtonElement).disabled=false; } /* Re born from hard dead hard dead - body removed from scene setTimeout(function () { root.playerSpawn(); }, this.playerDeadPauseInterval); */ return; } setTimeout(function() { root.player.render.visualComponent.assets.SeqFrame.setNewValue(0); root.selectedPlayer.spriteTileCurrent="run"; // create general method ! root.player.render.visualComponent.setNewShema(root.selectedPlayer); // Soft dead for now Matter.Body.setPosition(root.player, root.playerStartPositions[0]); root.playerSpawn(false); root.preventDoubleExecution=false; }, this.playerDeadPauseInterval); } } protected destroyGamePlayPlatformer() { this.starter.destroyGamePlay(); this.starter.deattachMatterEvents(); this.grounds=[]; this.enemys=[]; this.deadLines=[]; this.labels=[]; } protected selectPlayer(labelName: string="nidzica") { const root=this; this.selectPlayerArray.forEach((element) => { if(element.labelName===labelName) { root.selectedPlayer=element; } }); } private attachUpdateLives=() => { const root=this; window.addEventListener("update-lives", function(e) { root.lives=(e as any).detail.data.lives; }); } private addUIPlayerBoard=() => { this.UIPlayerBoard=document.createElement("div"); this.UIPlayerBoard.id="UIPlayerBoard"; this.UIPlayerBoard.className="leftPanelUni"; document.getElementsByTagName("body")[0].appendChild(this.UIPlayerBoard); } /** * @description Jump intro new wourld. * @param data * @type Void * root.broadcaster.connection.send({ * netPos: netPosOpt(root.player.position), * netDir: root.player.currentDir, */ private nextLevel(data: string): void { const root=this; console.log('NEXT LEVEL ', data) if(data.indexOf("Level")!==-1) { // sessionStorage.setItem('current-level', (e as any).detail.data.mapName) const appEndGamePlay=createAppEvent("game-end", { game: root.gameName, level: sessionStorage.getItem('current-level') }); (window as any).dispatchEvent(appEndGamePlay); // this.player = null; root.player.render.visualComponent.assets.SeqFrame.setNewValue(0); root.selectedPlayer.spriteTileCurrent="run"; root.player.render.visualComponent.setNewShema(root.selectedPlayer); root.player.render.visualComponent.seqFrameX.setDelay(8); Matter.Body.setPosition(root.player, root.playerStartPositions[0]); setTimeout(function() { const appStartGamePlay=createAppEvent("game-init", { mapName: data, game: root.levelMaps[data], }); (window as any).dispatchEvent(appStartGamePlay); }, DEFAULT_GAMEPLAY_ROLES.RESPAWN_INTERVAL); } } } export default Platformer;