import * as Matter from "matter-js"; import BotBehavior from "../../../libs/class/bot-behavior"; import Generator from "../../../libs/class/generator"; import { Counter, netPosOpt, numberOpt } from "../../../libs/class/math"; import { byId } from "../../../libs/class/system"; import SpriteTextureComponent from "../../../libs/class/visual-methods/sprite-animation"; import TextComponent from "../../../libs/class/visual-methods/text"; import TextureComponent from "../../../libs/class/visual-methods/texture"; import { DEFAULT_GAMEPLAY_ROLES, DEFAULT_PLAYER_DATA, DEFAULT_RENDER_BOUNDS, } from "../../../libs/defaults"; import { worldElementType } from "../../../libs/interface/global"; import { IMultiplayer, BaseMultiPlayer, } from "../../../libs/interface/networking"; import Starter from "../../../libs/starter"; import { worldElement, worldElementParams } from "../../../libs/types/global"; import GameMap from "./map"; import Level1 from "./packs/level1"; import Platformer from "./platformer"; /** * @description Finally game start at here * @function level1 * @return void */ class GamePlay extends Platformer implements IMultiplayer { public multiPlayerRef: BaseMultiPlayer|any={ root: this, init(rtcEvent) { console.log("rtcEvent addNewPlayer: ", rtcEvent); this.root.addNetPlayer(this.root, rtcEvent); }, update(multiplayer) { multiplayer.data = JSON.parse(multiplayer.data) if(multiplayer.data.netPos) { Matter.Body.setPosition( this.root.netBodies["netObject_"+multiplayer.from.connectionId], { x: multiplayer.data.netPos.x, y: multiplayer.data.netPos.y } ); Matter.Body.setAngle( this.root.netBodies["netObject_"+multiplayer.from.connectionId], -Math.PI*0 ); if(multiplayer.data.netDir) { if(multiplayer.data.netDir==="left") { this.root.netBodies[ "netObject_"+multiplayer.from.connectionId ].render.visualComponent.setHorizontalFlip(true); } else if(multiplayer.data.netDir==="right") { this.root.netBodies[ "netObject_"+multiplayer.from.connectionId ].render.visualComponent.setHorizontalFlip(false); } } } else if(multiplayer.data.noMoreLives===true) { // What to do with gameplay ?! // Just hide or hard variand // server database politic make clear player is out of game // bis logic - Initator must have credibility // Not tested Soft this.root.netBodies[ "netObject_"+multiplayer.from.connectionId ].render.visible=false; console.log(" VISIBLE FALSE FOR ET OBJECT"); // Hard make exit if netPlayer is initator // Hard - exit game - if game logic } }, /** * If someone leaves all client actions is here * - remove from scene * - clear object from netObject_x */ preventDoubleLGP: {}, leaveGamePlay(rtcEvent) { console.info("rtcEvent LEAVE GAME: ", rtcEvent.connectionId); if(typeof this.preventDoubleLGP[rtcEvent.connectionId]==='undefined') { this.preventDoubleLGP[rtcEvent.connectionId]=true; this.root.starter.destroyBody(this.root.netBodies["netObject_"+rtcEvent.connectionId]); delete this.root.netBodies["netObject_"+rtcEvent.connectionId]; } }, }; private generatorOfCollecions: any; private generators: any=[]; private gamePlayWelcomeNote: string= "This application was created on visual-ts
\ Example: Real time multiplayer `Platformer` zlatnaspirala@gmail.com
\ General: MIT License
\ Copyright (c) 2019 Nikola Lukic zlatnaspirala@gmail.com Serbia Nis
\ Except: Folder src/libs with licence:
\ GPLV3 Copyright (c) 2019 maximumroulette.com"; /** * @description deadZoneForBottom Definition and Default value * - overrided from map or map2d(generated) by deadLines object * DeadLines object. In future Can be used for enemy static action; */ private deadZoneForBottom: number=DEFAULT_GAMEPLAY_ROLES.MAP_MARGIN_BOTTOM; private deadZoneForRight: number=DEFAULT_GAMEPLAY_ROLES.MAP_MARGIN_RIGHT; constructor (starter: Starter) { super(starter); if(this.starter.ioc.getConfig().getAutoStartGamePlay()) { // Implement to the multiplayer solution: // level feature. // Override this.deadZoneForBottom=2500; this.load(); } this.broadcaster=starter.ioc.get.Broadcaster; // MessageBox // this.starter.ioc.get.MessageBox.show(this.gamePlayWelcomeNote); } public attachAppEvents=() => { const myInstance=this; window.addEventListener("game-init", function(e) { console.info("game-init Player spawn. e => ", (e as any).detail); try { if((e as any).detail&&(e as any).detail.data.game==="undefined") { console.warn("Bad game-init attempt."); return; } else if((e as any).detail&&(e as any).detail.data.game===null) { console.info("game-init Player spawn. data.game === null"); myInstance.initSelectPlayer(); myInstance.selectPlayer("nidzica"); myInstance.playerSpawn(true); myInstance.broadcaster.activateDataStream(myInstance.multiPlayerRef); return; } myInstance.initSelectPlayer(); myInstance.selectPlayer("nidzica"); myInstance.load((e as any).detail.data.game); /** * @description * Real time connections works only for gameplay time. */ myInstance.broadcaster.activateDataStream(myInstance.multiPlayerRef); // myInstance.broadcaster console.info("Player spawn. game-init .startNewGame"); // Play music in background myInstance.starter.ioc.get.Sound.createAudio("./audios/sb_indreams.mp3", "bgMusic"); myInstance.starter.ioc.get.Sound.createAudio("./audios/collect-item.mp3", "collectItem"); myInstance.starter.ioc.get.Sound.createAudio("./audios/dead.mp3", "dead"); myInstance.starter.ioc.get.Sound.createAudio("./audios/jump.mp3", "jump"); // Correct bg Music myInstance.starter.ioc.get.Sound.audioBox.bgMusic.volume=0.3; sessionStorage.setItem('current-level', (e as any).detail.data.mapName) } catch(err) { console.error("Very bad #00001", err); } }); window.addEventListener("game-end", function(e) { try { if( (e as any).detail&& (e as any).detail.data.game!=="undefined"&& (e as any).detail.data.game!==null&& (e as any).detail.data.game===myInstance.gameName ) { myInstance.destroyGamePlayPlatformer(); (byId("playAgainBtn") as HTMLButtonElement).disabled=true; (byId("soundOptionDom") as HTMLButtonElement).disabled=true; (byId("openGamePlay") as HTMLButtonElement).disabled=false; (byId("out-of-game") as HTMLButtonElement).disabled=true; console.info("Game end. THIS ", this); console.info("Game end. ", myInstance.starter.ioc.get.Network.nameUI); myInstance.starter.ioc.get.Broadcaster.leaveRoomBtn.click(); // ??? check this later // myInstance.starter.ioc.get.Network.nameUI.disabled = (this as any).disabled = false; // myInstance.starter.ioc.get.Network.connectUI.disabled = (this as any).disabled = false; myInstance.starter.ioc.get.Network.connector.inGamePlay=false; myInstance.deattachMatterEvents(); // ENTER HERE NEW VER // Leave // myInstance.starter.ioc.get.Network.rtcMultiConnection.connection.leave(); // myInstance.starter.ioc.get.Network.rtcMultiConnection.connection.disconnect(); myInstance.netBodies={}; console.info( "game-end global event. Destroying game play. DISCONNECT" ); } } catch(err) { console.error("Very bad #1", err); } }); window.addEventListener('onStreamCreated', (e: any) => { console.log(" onStreamCreated ON STREAM CREATED [REMOTE]=>", e.detail); console.log(" onStreamCreated ON TEST THIS ]=>", this); this.multiPlayerRef.init(e.detail) }) window.addEventListener('connectionDestroyed', (e: any) => { console.log("connectionDestroyed =>", e.detail.connectionId); this.multiPlayerRef.leaveGamePlay(e.detail) }) }; private deattachMatterEvents() { Matter.Events.off(this.starter.getEngine(), undefined, undefined); } private overrideOnKeyDown=() => { const testRoot=this; if(typeof testRoot.player==="undefined"||testRoot.player===null) { return; } const vc=testRoot.player.render.visualComponent; if(vc.assets.SeqFrame.getValue()===0) { return; } testRoot.selectedPlayer.setCurrentTile("run"); testRoot.player.render.visualComponent.setNewShema(testRoot.selectedPlayer); testRoot.player.render.visualComponent.assets.SeqFrame.setNewValue(0); testRoot.player.render.visualComponent.seqFrameX.setDelay(8); }; private overrideOnKeyUp=() => { const testRoot=this; if(typeof testRoot.player==="undefined"||testRoot.player===null) { return; } const vc=testRoot.player.render.visualComponent; if(vc.assets.SeqFrame.getValue()===2) { return; } testRoot.selectedPlayer.setCurrentTile("idle"); testRoot.player.render.visualComponent.setNewShema(testRoot.selectedPlayer); vc.assets.SeqFrame.setNewValue(2); vc.seqFrameX.setDelay(8); }; private attachMatterEvents() { const root=this; const globalEvent=this.starter.ioc.get.GlobalEvent; globalEvent.providers.onkeydown=this.overrideOnKeyDown; globalEvent.providers.onkeyup=this.overrideOnKeyUp; const playerSpeed=DEFAULT_PLAYER_DATA.SPEED_AMP; root.starter.setRenderView( DEFAULT_RENDER_BOUNDS.WIDTH, DEFAULT_RENDER_BOUNDS.HEIGHT ); this.enemys.forEach(function(item) { const test=new BotBehavior(item); test.patrol(); }); Matter.Events.on( this.starter.getEngine(), "beforeUpdate", function(event) { if(!root.player) { return; } if(root.player&&root.player.position.y>root.deadZoneForBottom) { root.playerDie(root.player); } if(root.player) { Matter.Body.setAngle(root.player, -Math.PI*0); // Matter.Body.setAngle(root.enemys[0] as Matter.Body, -Math.PI * 0); Matter.Bounds.shift(root.starter.getRender().bounds, { x: root.player.position.x- root.starter.getRender().options.width/1.5, y: root.player.position.y- root.starter.getRender().options.height/1.5, }); if( root.player.velocity.x<0.1&& numberOpt(root.player.velocity.y)===0&& root.player.currentDir==="idle" ) { // empty // console.info("IDLE STOPS", root.player.currentDir) } else { if (root.broadcaster.connection) root.broadcaster.connection.send({ netPos: netPosOpt(root.player.position), netDir: root.player.currentDir, }); } } root.generatorOfCollecions.counter.getValue(); } ); const limit=0.3; // at the start of a colision for player Matter.Events.on( this.starter.getEngine(), "collisionStart", function(event) { root.collisionCheck(event, true); } ); // ongoing checks for collisions for player Matter.Events.on( this.starter.getEngine(), "collisionActive", function(event) { root.collisionCheck(event, true); } ); // at the end of a colision for player set ground to false Matter.Events.on( this.starter.getEngine(), "collisionEnd", function(event) { root.collisionCheck(event, false); } ); Matter.Events.on(this.starter.getEngine(), "afterTick", function(event) { if(!root.player) { return; } // jump if(globalEvent.activeKey[38]&&root.player.ground) { const s=root.player.jumpAmp*playerSpeed; root.player.ground=false; root.player.force={ x: 0, y: -s, }; Matter.Body.setVelocity(root.player, { x: 0, y: -s }); // this.player.currentDir = "jump"; root.starter.ioc.get.Sound.playById('jump'); } else if( globalEvent.activeKey[37]&& root.player.angularVelocity>-limit ) { root.player.render.visualComponent.setHorizontalFlip(true); root.player.force={ x: -playerSpeed, y: 0, }; Matter.Body.applyForce( root.player, { x: root.player.position.x, y: root.player.position.y }, root.player.force ); root.player.currentDir="left"; } else if( globalEvent.activeKey[39]&& root.player.angularVelocity { const newStaticElement: worldElement=Matter.Bodies.rectangle( item.x, item.y, item.w, item.h, { isStatic: true, isSleeping: false, label: "background", render: { visualComponent: new TextureComponent("wall", item.tex), sprite: { olala: true, }, } as any|Matter.IBodyRenderOptions, } ); newStaticElement.collisionFilter.group=-1; this.grounds.push(newStaticElement); ((this.grounds[this.grounds.length-1] as Matter.Body) .render as any).visualComponent .setVerticalTiles(item.tiles.tilesY) .setHorizontalTiles(item.tiles.tilesX); }); gameMap.getStaticGrounds().forEach(item => { const newStaticElement: worldElement=Matter.Bodies.rectangle( item.x, item.y, item.w, item.h, { isStatic: true, isSleeping: false, label: "ground", collisionFilter: { group: this.staticCategory, } as any, render: { visualComponent: new TextureComponent("imgGround", item.tex), sprite: { olala: true, }, } as any|Matter.IBodyRenderOptions, } ); this.grounds.push(newStaticElement); ((this.grounds[this.grounds.length-1] as Matter.Body) .render as any).visualComponent .setVerticalTiles(item.tiles.tilesX) .setHorizontalTiles(item.tiles.tilesY); }); gameMap.getCollectItems().forEach(item => { const newStaticElement: worldElement=Matter.Bodies.rectangle( item.x, item.y, item.w, item.h, { isStatic: true, label: item.colectionLabel, collisionFilter: { group: this.staticCategory, mask: this.playerCategory, } as any, render: { visualComponent: new TextureComponent("imgCollectItem1", item.tex), sprite: { olala: true, xScale: 1, yScale: 1, }, } as any|Matter.IBodyRenderOptions, } ); (newStaticElement.render as any).visualComponent .setVerticalTiles(item.tiles.tilesY) .setHorizontalTiles(item.tiles.tilesX); this.grounds.push(newStaticElement); }); gameMap.getEnemys().forEach(item => { let enemySprite; if(item.enemyLabel==="crapmunch") { enemySprite=new SpriteTextureComponent("enemy", item.tex, { byX: 10, byY: 1, }); } else if(item.enemyLabel==="chopper") { enemySprite=new SpriteTextureComponent("enemy", item.tex, { byX: 5, byY: 1, }); } const newStaticElement: worldElement=Matter.Bodies.rectangle( item.x, item.y, item.w, item.h, { isStatic: false, label: item.enemyLabel, density: 0.0005, friction: 0.01, frictionAir: 0.06, restitution: 0.3, collisionFilter: { group: this.staticCategory, mask: this.playerCategory, } as any, render: { visualComponent: enemySprite, sprite: { olala: true, xScale: 1, yScale: 1, }, } as any|Matter.IBodyRenderOptions, } ); (newStaticElement.render as any).visualComponent.keepAspectRatio=true; (newStaticElement.render as any).visualComponent.setHorizontalFlip(true); this.enemys.push(newStaticElement); }); gameMap.getDeadLines().forEach(item => { let enemySprite; root.deadZoneForBottom=item.y; enemySprite=new SpriteTextureComponent("deadline", item.tex, { byX: item.tiles.tilesX, byY: item.tiles.tilesY, }); const newStaticElement: worldElement=Matter.Bodies.rectangle( item.x, item.y, item.w, item.h, { isStatic: true, label: item.enemyLabel, density: 0.0005, friction: 0.01, frictionAir: 0.06, restitution: 0.3, collisionFilter: { group: -1, mask: this.playerCategory, } as any, render: { visualComponent: enemySprite, sprite: { olala: true, xScale: 1, yScale: 1, }, } as any|Matter.IBodyRenderOptions, } ); (newStaticElement.render as any).visualComponent.keepAspectRatio=true; (newStaticElement.render as any).visualComponent.setHorizontalFlip(true); this.deadLines.push(newStaticElement); }); gameMap.getStaticBanners().forEach(item => { const newStaticElement: worldElement=Matter.Bodies.rectangle( item.x, item.y, item.w, item.h, { isStatic: true, label: "Label Text", render: { visualComponent: new TextComponent(item.text, item.options!), sprite: { olala: true, }, } as any|Matter.IBodyRenderOptions, } ); newStaticElement.collisionFilter.group=-1; this.labels.push(newStaticElement); }); this.starter.AddNewBodies(this.grounds as worldElement); this.starter.AddNewBodies(this.enemys as worldElement); this.starter.AddNewBodies(this.deadLines as worldElement); this.starter.AddNewBodies(this.player as worldElement); this.starter.AddNewBodies(this.labels as worldElement); /** * @description * Test Generator */ // Create text and sprite let textureGenerator=require("../imgs/collect-items/tileYellow_09.png"); let enemyTex=new TextureComponent("gen", textureGenerator); const newParamsElement: worldElementParams|any={ x: 300, y: 300, w: 30, h: 30, playerRadius: 30, arg2: { isStatic: false, label: "enemy", density: 0.0005, friction: 0.01, frictionAir: 0.06, restitution: 0.3, collisionFilter: { group: 0x0002, mask: 0x0004, } as any, render: { visualComponent: enemyTex, sprite: { xScale: 1, yScale: 1, }, } as any|Matter.IBodyRenderOptions, }, }; // Force initial this.generatorOfCollecions=new Generator({ genType: worldElementType.RECT, emit: [ { force: { x: 0.02, y: -0.01 } }, { force: { x: -0.02, y: -0.01 } }, { force: { x: 0.02, y: -0.01 } }, { force: { x: -0.01, y: -0.02 } }, { force: { x: 0.01, y: -0.02 } }, { force: { x: -0.01, y: -0.02 } } ], delayForce: [ { delta: 500, force: { x: -0.02, y: -0.01 } }, { delta: 1500, force: { x: 0.02, y: -0.02 } }, { delta: 2000, force: { x: -0.02, y: -0.01 } }, { delta: 500, force: { x: -0.03, y: -0.01 } }, { delta: 1500, force: { x: 0.03, y: -0.02 } }, { delta: 2000, force: { x: -0.03, y: -0.01 } } ], counter: new Counter(0, 1, 1, "REPEAT"), newParamsElement: newParamsElement, starter: this.starter, destroyAfter: 3000 }); this.attachMatterEvents(); } } export default GamePlay;