_demos/game-editor/demo.js import DataGridXL from __componentPath__;
import * as Phaser from 'https://cdn.jsdelivr.net/npm/phaser@3.85.2/dist/phaser.esm.js';
function debounce(fn, delay) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), delay);
};
}
let game;
let resizeObserver;
let debouncedHandleResize;
export function init(){
const gridMap = [
[20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 82, 29, 29, 29, 48, 48, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 48, 48, 29, 29, 48, 48, 48, 48, 29, 29, 29, 29, 29, 29, 82, 29, 29, 20],
[20, 48, 48, 48, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 48, 48, 48, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 82, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 48, 48, 48, 48, 48, 29, 29, 29, 29, 29, 29, 82, 29, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 48, 48, 48, 48, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 82, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 48, 48, 48, 20],
[20, 29, 29, 29, 29, 29, 29, 48, 48, 48, 48, 48, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 20],
[20, 48, 48, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 82, 29, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 48, 48, 48, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 20],
[20, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 82, 29, 29, 20],
[20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20]
];
const flatMap = gridMap.flat();
const inlineMap = {
"height":19,
"infinite":false,
"layers":[
{
"data": flatMap,
"height":19,
"id":3,
"name":"Level1",
"opacity":1,
"type":"tilelayer",
"visible":true,//false,
"width":25,
"x":0,
"y":0
},
{
"data": flatMap,
"height":19,
"id":4,
"name":"Level2",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":25,
"x":0,
"y":0
}
],
"nextlayerid":5,
"nextobjectid":1,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.2.2",
"tileheight":32,
"tilesets":[
{
"columns":14,
"firstgid":1,
"image":"/assets/phaser/gridtiles.png",
"imageheight":320,
"imagewidth":448,
"margin":0,
"name":"tiles",
"spacing":0,
"tilecount":140,
"tileheight":32,
"tilewidth":32
}
],
"tilewidth":32,
"type":"map",
"version":1.2,
"width":25
};
class Example extends Phaser.Scene
{
cursors;
pickups;
player;
layer;
tileset;
map;
constructor() {
super('Example'); // <--- DIT VOEG JE TOE
}
preload ()
{
this.load.image('tiles', '/assets/phaser/gridtiles.png');
this.load.image('player', '/assets/phaser/phaser-dude.png');
}
create ()
{
// Create a map using the data from inlineMap
// BUT change how we parse the layers
this.map = this.make.tilemap({
width: inlineMap.width,
height: inlineMap.height,
tileWidth: inlineMap.tilewidth,
tileHeight: inlineMap.tileheight
});
// Setup camera
this.cameras.main.setBounds(0, 0, inlineMap.width * inlineMap.tilewidth, inlineMap.height * inlineMap.tileheight);
//tileWidth: 32, tileHeight: 32,
// this.map = this.make.tilemap({ data: inlineMap, format: Phaser.Tilemaps.Formats.TILED_JSON });
// add the tileset
this.tileset = this.map.addTilesetImage('tiles');
// Instead of trying to access the layer by name, create a new layer and populate it
// Use the first layer data from inlineMap (Level1)
this.layer = this.map.createBlankLayer('gameLayer', this.tileset);
// Populate the layer with tile data from the first layer
const layerData = inlineMap.layers[0].data;
let tileIndex = 0;
for (let y = 0; y < inlineMap.height; y++) {
for (let x = 0; x < inlineMap.width; x++) {
const tileId = layerData[tileIndex];
if (tileId !== 0) {
this.map.putTileAt(tileId, x, y, false, this.layer);
}
tileIndex++;
}
}
// 👇 DEBUG: check welke layers beschikbaar zijn
// console.log("Tilemap layers:", this.map.layers.map(l => l.name));
//this.layer = this.map.createLayer('Level1', this.tileset);
this.map.setCollision([ 20, 48 ], true, true, this.layer);
//this.map.setCollision([ 20, 48 ]);
this.pickups = this.map.filterTiles(tile => tile.index === 82);
const playerStart = {
col: 2,
row: 2
};
const tileSize = 32;
this.player = this.add.rectangle(
playerStart.col * tileSize + tileSize / 2,
playerStart.row * tileSize + tileSize / 2,
tileSize,
tileSize,
0xffff00
);
this.physics.add.existing(this.player);
this.physics.add.collider(this.player, this.layer);
this.cursors = this.input.keyboard.createCursorKeys();
this.cursors.up.on('down', () =>
{
if (this.player.body.blocked.down)
{
this.player.body.setVelocityY(-360);
}
}, this);
// Make the camera follow the player
this.cameras.main.startFollow(this.player, true, 0.08, 0.08);
}
update ()
{
this.player.body.setVelocityX(0);
if (this.cursors.left.isDown)
{
this.player.body.setVelocityX(-200);
}
else if (this.cursors.right.isDown)
{
this.player.body.setVelocityX(200);
}
this.physics.world.overlapTiles(this.player, this.pickups, this.hitPickup, null, this);
}
hitPickup (player, tile)
{
this.map.removeTile(tile, 29, false);
this.pickups = this.map.filterTiles(tile => tile.index === 82);
}
}
const gameDiv = document.getElementById('game');
const { width, height } = gameDiv.getBoundingClientRect();
const config = {
type: Phaser.AUTO,
width,
height,
backgroundColor: '#2d2d2d',
parent: 'game',
scene: Example,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 600 }
}
} ,
pixelArt: true,
scale: {
mode: Phaser.Scale.NONE, // je kunt dit aanpassen
autoCenter: Phaser.Scale.CENTER_BOTH
}
};
game = new Phaser.Game(config);
const handleResize = () => {
game.scale.resize(gameDiv.clientWidth, gameDiv.clientHeight);
};
debouncedHandleResize = debounce(handleResize, 100);
resizeObserver = new ResizeObserver((entries) => {
// alleen reageren als #game zelf is veranderd
for (const entry of entries) {
if (entry.target === gameDiv) {
debouncedHandleResize();
}
}
});
resizeObserver.observe(gameDiv);
const gridSize = 30;
// create grid
const grid = new DataGridXL("grid", {
licenseKey: __licenseKey__,
data: gridMap,
columnSettings: {
width: gridSize,
align: 'center',
headerAlign: 'center',
styleFunction(cellRef){
return {
backgroundColor: Number(cellRef.value) == 20 ?
'#D3D3D3' : Number(cellRef.value == 29) ?
'#A7C7E7' : Number(cellRef.value == 48) ?
'#CBB4D4' : Number(cellRef.value == 82) ?
'#FFF4B1' : 'transparent'
};
},
validateFunction(cellRef){
if(isNaN(cellRef.value)) return false;
return true;
}
},
// theme: {
// "sheet_text": "#000000aa"
// },
colHeaderLabelType: 'numbers',
//colWidth: 30,
rowHeight: gridSize,
rowHeaderWidth: gridSize,
allowMoveRows: false,
allowInsertRows: false,
allowDeleteRows: false,
allowHideRows: false,
allowInsertCols: false,
allowDeleteCols: false,
allowMoveCols: false,
allowHideCols: false,
allowSort: false,
bottomBar: [],
// fill cells
fillCellsDirection: 'xy',
allowSort: false
});
grid.events.on('$setcellvaluesbatch', (gridEvent) => {
console.log('set cell values batch', gridEvent);
const currentScene = game.scene.getScene('Example');
if (!currentScene || !currentScene.map) return;
const { rowIds, colIds, values } = gridEvent;
for (let rowIdx = 0; rowIdx < rowIds.length; rowIdx++) {
for (let colIdx = 0; colIdx < colIds.length; colIdx++) {
const row = rowIds[rowIdx] - 1; // id to index
const col = colIds[colIdx] - 1; // id to index
const newValue = values[rowIdx][colIdx];
console.log('not a number?', row, col, isNaN(newValue));
if (isNaN(newValue)) continue;
// Pas de tile aan in de map
currentScene.map.putTileAt(newValue, col, row, false, currentScene.layer);
// 🟡 Flash effect op deze tile
const tileWorldX = col * currentScene.map.tileWidth;
const tileWorldY = row * currentScene.map.tileHeight;
const flash = currentScene.add.rectangle(
tileWorldX + currentScene.map.tileWidth / 2,
tileWorldY + currentScene.map.tileHeight / 2,
currentScene.map.tileWidth,
currentScene.map.tileHeight,
0xffff00,
0.4
);
currentScene.tweens.add({
targets: flash,
alpha: 0,
ease: 'Sine.easeOut',
duration: 400,
onComplete: () => flash.destroy()
});
}
}
// Update pickups (bijv. tiles met index 82)
currentScene.pickups = currentScene.map.filterTiles(tile => tile.index === 82);
});
}
export function destroy() {
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
}
if (game) {
game.destroy(true); // true = remove canvas from DOM
game = null;
}
}