import * as Matter from "matter-js";
import BotBehavior from "../../../libs/class/bot-behavior";
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 Starter from "../../../libs/starter";
import { worldElement } from "../../../libs/types/global";
import GameMap from "./map";
import Level1 from "./packs/level1";
import Platformer from "./Platformer";
/**
* @description Finally game start at here.
* Manage Level's here, Level1 will be default map.
* @function Init start class and begin with matter.js scene rendering.
* @return void
*/
class GamePlay extends Platformer {
private gamePlayWelcomeNote: string = "This application was created on visual-ts
\
Example: Single player `Platformer` zlatnaspirala@gmail.com
\
General: MIT License
\
Copyright (c) 2020 Nikola Lukic zlatnaspirala@gmail.com Serbia Nis
\
Except: Folder src/libs with licence:
\
GNU LESSER GENERAL PUBLIC LICENSE Version 3
\
Copyright (c) 2020 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);
// Implement to the multiplayer solution:
// level feature.
// Override
this.deadZoneForBottom = 2500;
// depend on config DISABLED
if (this.starter.ioc.getConfig().getAutoStartGamePlay()) {
// this.load();
}
// Load in anyway
// this.load();
// MessageBox
this.starter.ioc.get.MessageBox.show(this.gamePlayWelcomeNote);
}
public attachAppEvents = () => {
const myInstance = this;
window.addEventListener("game-init", function (e) {
try {
if ((e as any).detail &&
((e as any).detail.data.game !== "undefined" &&
( e as any).detail.data.game !== null &&
typeof ( e as any).detail.data.game.label !== "undefined" &&
( e as any).detail.data.game.label === "player")) {
console.warn("Bad #2 game-init attempt.");
return;
} else if ((e as any).detail &&
(e as any).detail.data.game === null ) {
console.info("game-init Player spawn. Player are not destroyed at this moment...");
myInstance.playerSpawn(true);
myInstance.initSelectPlayer();
myInstance.selectPlayer("nidzica");
return;
}
myInstance.load((e as any).detail.data.game);
console.info("Player spawn on game-init");
} catch (err) { console.error("Very bad in game-init #1", 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) {
myInstance.destroyGamePlayPlatformer();
(byId("playAgainBtn") as HTMLButtonElement).disabled = false;
console.info("game-end");
}
} catch (err) { console.error("Very bad #00003 ", err); }
});
}
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(): void {
const root = this;
const globalEvent = this.starter.ioc.get.GlobalEvent;
globalEvent.providers.onkeydown = this.overrideOnKeyDown;
globalEvent.providers.onkeyup = this.overrideOnKeyUp;
// globalEvent.injectDependency("platformerInstance", root);
root.starter.setRenderView(DEFAULT_RENDER_BOUNDS.WIDTH, DEFAULT_RENDER_BOUNDS.HEIGHT);
const playerSpeed = DEFAULT_PLAYER_DATA.SPEED_AMP;
this.enemys.forEach(function (item) {
const test = new BotBehavior(item);
test.patrol();
});
Matter.Events.on(this.starter.getEngine(), "beforeUpdate", function () {
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.00001 && root.player.velocity.y === 0 &&
root.player.currentDir === "idle" ) {
// empty
}
}
});
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 () {
if (!root.player) { return; }
// jump
if (globalEvent.activeKey[38] && root.player.ground) {
const s = (root.player.jumpAmp);
root.player.ground = false;
root.player.force = {
x: 0,
y: -(s),
};
Matter.Body.setVelocity(root.player, { x: 0, y: -s });
root.starter.ioc.get.Sound.playById('jump');
// this.player.currentDir = "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 < limit) {
root.player.render.visualComponent.setHorizontalFlip(false);
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 = "right";
} else {
root.player.currentDir = "idle";
}
});
globalEvent.activateKeyDetection();
}
private load(mapPack?): void {
const root = this;
if (typeof mapPack === "undefined") {
mapPack = Level1;
}
// HARDCODE Test
// mapPack = Level6;
const gameMap: GameMap = new GameMap(mapPack);
/**
* @description Override data from starter.
*/
this.starter.setWorldBounds(
DEFAULT_GAMEPLAY_ROLES.MAP_MARGIN_LEFT,
DEFAULT_GAMEPLAY_ROLES.MAP_MARGIN_TOP,
root.deadZoneForRight,
root.deadZoneForBottom);
this.playerSpawn(false);
gameMap.getStaticBackgrounds().forEach((item) => {
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);
this.attachMatterEvents();
}
}
export default GamePlay;