type3games-engine
Version:
Modulární herní engine pro 2D hry v JavaScriptu
219 lines (200 loc) • 8.07 kB
JavaScript
import { Vector,Event } from "./coretools.js"
import {EventMovingBlock,EventBlock,Block,Player,Entity,Sprite,MovingBlock,Physic, Render, GameLoop} from "./engine.js"
class LevelLoader{
constructor({settings,pathPrefix,levelList}){
if (settings){
this.defaultSettings = settings
}
this.pathPrefix = pathPrefix || ""
this.xmax = 0
this.ymax = 0
this.levelList = levelList
Event.on("NextLevel",this.nextLevel.bind(this))
Event.on("End",(() => {this.GameLoop.destroy();}).bind(this))
}
loadLevel(level){
this.xmax = 0
this.ymax = 0
this.currentLevel = level.name || "unnamedLevel"
let settings
if(level.settings == "default" && this.defaultSettings){
settings = this.defaultSettings
}else{
settings = level.settings
}
for(let element in settings){
if(!settings[element].settings || !settings[element].settings.imageSrc){continue}
settings[element].settings.imageSrc = this.pathPrefix + settings[element].settings.imageSrc
}
this.physic = new Physic()
this.render = new Render(settings.render || {with: 200, height: 200, scale:1})
this.elementsLoaded = []
this.numOfElements = 0
this.grid
let positions = {}
let waitList = []
if (level.grid){
level.grid.forEach((array,i) => {
if (array.length > this.xmax){this.xmax = array.length}
if (i > this.ymax){this.ymax = i}
array.forEach((e,j) => {
if(e){
if (settings[e]){
let element = {...settings[e]}
element.settings.onLoadCallback = this.elementLoaded.bind(this)
element.settings.y = i*settings.grid.size
element.settings.x = j*settings.grid.size
this.addElement(element)
this.numOfElements++
}else if(Array.isArray(e)){
let element = {...settings[e[0]]}
waitList.push([element,[e[1],i,j]])
}else{
positions[e] = [i*settings.grid.size,j*settings.grid.size]
}
}
})
})
waitList.forEach((element) => {
element[0].settings.onLoadCallback = this.elementLoaded.bind(this)
element[0].settings.starty = element[1][1]*settings.grid.size
element[0].settings.startx = element[1][2]*settings.grid.size
element[0].settings.endy = positions[element[1][0]] ? positions[element[1][0]][0] : element[1][1]*settings.grid.size
element[0].settings.endx = positions[element[1][0]] ? positions[element[1][0]][1] : element[1][2]*settings.grid.size
this.addElement(element[0])
this.numOfElements++
})
}
this.render.setCameraBoundres(this.xmax * settings.grid.size,(this.ymax+1) * settings.grid.size)
Event.emit("LevelLoading",level)
this.waitToLoad(settings);
}
addElement(element){
this.addGame(element.settings);
switch (element.type) {
case "block":
new Block(element.settings);
break;
case "player":
let p = new Player(element.settings);
this.render.cameraFolow(p.position);
break;
case "entity":
new Entity(element.settings);
break;
case "sprite":
new Sprite(element.settings);
break;
case "movingBlock":
new MovingBlock(element.settings);
break;
case "eventBlock":
new EventBlock(element.settings);
break;
case "eventMovingBlock":
new EventMovingBlock(element.settings);
break;
default:
console.warn(`Unknown element type: ${element.type}`);
break;
}
}
elementLoaded(){
this.elementsLoaded.push(true)
}
parseJSON(json){
let obj = JSON.parse(json)
if (obj.settings == "default"){return obj}
for (let element in obj.settings){
if(!obj.settings[element].settings){continue}
for(let parameter in obj.settings[element].settings){
if(obj.settings[element].settings[parameter].x != undefined && obj.settings[element].settings[parameter].y != undefined){
obj.settings[element].settings[parameter] = new Vector(obj.settings[element].settings[parameter].x,obj.settings[element].settings[parameter].y)
}
}
}
return obj
}
loadJSON(url) {
const xhr = new XMLHttpRequest();
xhr.open('GET', this.pathPrefix + url, true);
let callback = () => {
if (xhr.status === 200) {
let level = this.parseJSON(xhr.response)
if (!level.name){
level.name = url.replace(/^.*[\\/]/, "")
level.name = level.name.split(".")[0]
}
this.loadLevel(level);
Event.emit("LevelJSONLoaded",url)
} else {
throw new Error(`Chyba ${xhr.status} při načítání ${url}`);
}
}
xhr.onload = callback.bind(this) ;
xhr.onerror = function () {
callback('Síťová chyba', null);
};
xhr.send();
}
loadDefaultFromJSON(url){
const xhr = new XMLHttpRequest();
xhr.open('GET', this.pathPrefix + url, true);
let callback = () => {
if (xhr.status === 200) {
this.defaultSettings = this.parseJSON(xhr.response).settings
Event.emit("DefaultSettingsJSONLoaded",url)
} else {
throw new Error(`Chyba ${xhr.status} při načítání ${url}`);
}
}
xhr.onload = callback.bind(this) ;
xhr.onerror = function () {
callback('Síťová chyba', null);
};
xhr.send();
}
addGame(settings){
settings.physic = this.physic
settings.render = this.render
return settings
}
waitToLoad(settings) {
if(this.numOfElements != this.elementsLoaded.length) {
window.setTimeout(this.waitToLoad.bind(this,settings), 100); /* this checks the flag every 100 milliseconds*/
} else {
/* do something*/
settings.GameLoop = this.addGame(settings.GameLoop || {fps:60,physic:{},render:{}})
this.GameLoop = new GameLoop(settings.GameLoop)
this.GameLoop.start()
}
}
nextLevel(){
if (!this.levelList || !Array.isArray(this.levelList) || this.levelList.length === 0) {
console.warn("Level list is missing or empty.");
Event.emit("LevelListMissing");
return;
}
if (!this.currentLevel || this.currentLevel === "unnamedLevel") {
console.warn("Current level is not set or is unnamed.");
Event.emit("CurrentLevelNotSet");
return;
}
const currentLevelIndex = this.levelList.indexOf(this.currentLevel);
if (currentLevelIndex === -1) {
console.warn(`Current level '${this.currentLevel}' not found in level list.`);
Event.emit("CurrentLevelNotFound", this.currentLevel);
return;
}
const nextLevelIndex = (currentLevelIndex + 1);
if (nextLevelIndex >= this.levelList.length) {
console.warn("No more levels available.");
Event.emit("NoMoreLevels");
return;
}
this.currentLevel = this.levelList[nextLevelIndex];
Event.emit("End");
this.loadJSON(this.pathPrefix + this.currentLevel+".json");
}
}
export default LevelLoader