// Debug alert for mobile debugging
if (typeof debugAlert === 'function') {
debugAlert('object.js starting to load');
}
/**
* Open the game controller overlay
*/
function openGameController() {
const overlayContent = document.getElementById('overlayContent');
overlayContent.innerHTML = `
<div style="height: 100%; overflow: auto; padding: 10px;">
<div id="projectOverview"></div>
</div>
`;
renderProjectOverview();
}
/**
* Render the complete project overview in game controller
*/
function renderProjectOverview() {
const container = document.getElementById('projectOverview');
if (!container) return;
container.innerHTML = '';
// Tile Groups Section
const groupsSection = document.createElement('div');
groupsSection.style.cssText = 'margin-bottom: 20px; padding: 15px; background: #1a1a1a; border-radius: 8px;';
const groupsTitle = document.createElement('h3');
groupsTitle.textContent = 'Tile Groups';
groupsTitle.style.cssText = 'margin: 0 0 10px 0; color: #6cf; font-size: 18px;';
groupsSection.appendChild(groupsTitle);
if (typeof groups !== 'undefined' && groups && groups.length > 0) {
groups.forEach((group, index) => {
const groupDiv = document.createElement('div');
groupDiv.style.cssText = 'margin-bottom: 15px; padding: 10px; background: #2a2a2a; border-radius: 6px;';
// Group header
const header = document.createElement('div');
header.innerHTML = `
<strong style="color: #fff;">Group ${index + 1}</strong>
<span style="color: #888; margin-left: 10px;">${group.tiles ? group.tiles.length : 0} tiles</span>
`;
header.style.cssText = 'margin-bottom: 8px;';
groupDiv.appendChild(header);
// Group details
const details = document.createElement('div');
details.style.cssText = 'font-size: 12px; color: #ccc; margin-bottom: 10px;';
details.innerHTML = `
<div><strong>URL:</strong> ${group.url || 'None'}</div>
<div><strong>Group ID:</strong> ${group.id || index}</div>
${group.tiles && group.tiles.length > 0 ? `
<div><strong>Tile Size:</strong> ${group.tiles[0].size || 'Unknown'}px</div>
` : ''}
`;
groupDiv.appendChild(details);
// Tile previews with ID badges
if (group.tiles && group.tiles.length > 0) {
const previewDiv = document.createElement('div');
previewDiv.style.cssText = 'display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px;';
group.tiles.forEach(tile => {
const tileWrapper = document.createElement('div');
tileWrapper.style.cssText = 'position: relative; display: inline-block;';
const canvas = document.createElement('canvas');
canvas.width = 48;
canvas.height = 48;
canvas.style.cssText = 'border: 2px solid #666; border-radius: 4px; background: #000;';
const ctx = canvas.getContext('2d');
const tempCanvas = document.createElement('canvas');
tempCanvas.width = tile.size;
tempCanvas.height = tile.size;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.putImageData(tile.data, 0, 0);
ctx.drawImage(tempCanvas, 0, 0, tile.size, tile.size, 0, 0, 48, 48);
// Add ID badge
const idBadge = document.createElement('span');
idBadge.textContent = tile.uniqueId;
idBadge.style.cssText = `
position: absolute; bottom: -2px; right: -2px;
background: rgba(0,0,0,0.8); color: #fff;
font-size: 9px; padding: 1px 4px; border-radius: 3px;
border: 1px solid #6cf;
`;
tileWrapper.appendChild(canvas);
tileWrapper.appendChild(idBadge);
previewDiv.appendChild(tileWrapper);
});
groupDiv.appendChild(previewDiv);
}
groupsSection.appendChild(groupDiv);
});
} else {
const noGroups = document.createElement('div');
noGroups.textContent = 'No tile groups created yet. Use the Tile Picker to create groups.';
noGroups.style.cssText = 'color: #888; font-style: italic; padding: 10px;';
groupsSection.appendChild(noGroups);
}
container.appendChild(groupsSection);
// Tilemaps Section
const mapsSection = document.createElement('div');
mapsSection.style.cssText = 'margin-bottom: 20px; padding: 15px; background: #1a1a1a; border-radius: 8px;';
const mapsTitle = document.createElement('h3');
mapsTitle.textContent = 'Tilemaps';
mapsTitle.style.cssText = 'margin: 0 0 10px 0; color: #6cf; font-size: 18px;';
mapsSection.appendChild(mapsTitle);
if (typeof tilemaps !== 'undefined' && tilemaps && tilemaps.length > 0) {
tilemaps.forEach((tilemap, index) => {
const tilemapDiv = document.createElement('div');
tilemapDiv.style.cssText = 'margin-bottom: 20px; padding: 10px; background: #2a2a2a; border-radius: 6px;';
const totalTiles = tilemap.data ? tilemap.data.filter(t => t !== 0).length : 0;
const totalCells = tilemap.width * tilemap.height;
const fillPercent = ((totalTiles / totalCells) * 100).toFixed(1);
const isActive = typeof currentTilemapIndex !== 'undefined' && currentTilemapIndex === index;
// Tilemap header
const header = document.createElement('div');
header.innerHTML = `
<strong style="color: ${isActive ? '#6cf' : '#fff'};">${tilemap.name}</strong>
${isActive ? '<span style="color: #6cf; margin-left: 10px;">(Active)</span>' : ''}
`;
header.style.cssText = 'margin-bottom: 8px;';
tilemapDiv.appendChild(header);
// Tilemap details
const details = document.createElement('div');
details.style.cssText = 'font-size: 12px; color: #ccc; margin-bottom: 10px;';
details.innerHTML = `
<div><strong>Dimensions:</strong> ${tilemap.width} × ${tilemap.height} (${totalCells} cells)</div>
<div><strong>Tile Size:</strong> ${tilemap.tileSize}px</div>
<div><strong>Placed Tiles:</strong> ${totalTiles}</div>
<div><strong>Fill:</strong> ${fillPercent}%</div>
<div><strong>Map ID:</strong> ${tilemap.id}</div>
`;
tilemapDiv.appendChild(details);
// Phaser-style 2D array display
if (tilemap.data && tilemap.data.length > 0) {
const arrayTitle = document.createElement('div');
arrayTitle.textContent = 'Phaser 2D Array:';
arrayTitle.style.cssText = 'font-weight: bold; color: #6cf; margin-bottom: 5px; font-size: 12px;';
tilemapDiv.appendChild(arrayTitle);
const arrayContainer = document.createElement('div');
arrayContainer.style.cssText = `
background: #1a1a1a; padding: 10px; border-radius: 4px;
font-family: 'Courier New', monospace; font-size: 10px;
color: #ccc; overflow-x: auto; max-height: 200px; overflow-y: auto;
`;
// Convert 1D array to 2D array format
let arrayText = '[\n';
for (let y = 0; y < tilemap.height; y++) {
let row = ' [';
for (let x = 0; x < tilemap.width; x++) {
const index = y * tilemap.width + x;
const tileId = tilemap.data[index] || 0;
row += tileId.toString().padStart(3, ' ');
if (x < tilemap.width - 1) row += ',';
}
row += ']';
if (y < tilemap.height - 1) row += ',';
arrayText += row + '\n';
}
arrayText += ']';
// Format for display with proper line breaks
const formattedArray = arrayText.split('\n').map(line => {
return `<div style="line-height: 1.2;">${line}</div>`;
}).join('');
arrayContainer.innerHTML = formattedArray;
tilemapDiv.appendChild(arrayContainer);
// Copy button for the array
const copyBtn = document.createElement('button');
copyBtn.textContent = 'Copy Array';
copyBtn.style.cssText = `
margin-top: 5px; background: #444; color: white; border: none;
padding: 4px 8px; border-radius: 4px; cursor: pointer; font-size: 10px;
`;
copyBtn.addEventListener('click', () => {
navigator.clipboard.writeText(arrayText).then(() => {
copyBtn.textContent = 'Copied!';
setTimeout(() => copyBtn.textContent = 'Copy Array', 1000);
});
});
tilemapDiv.appendChild(copyBtn);
}
mapsSection.appendChild(tilemapDiv);
});
} else {
const noMaps = document.createElement('div');
noMaps.textContent = 'No tilemaps created yet. Use the Tilemap Editor to create maps.';
noMaps.style.cssText = 'color: #888; font-style: italic; padding: 10px;';
mapsSection.appendChild(noMaps);
}
container.appendChild(mapsSection);
// Project Stats Section
const statsSection = document.createElement('div');
statsSection.style.cssText = 'margin-bottom: 20px; padding: 15px; background: #1a1a1a; border-radius: 8px;';
const statsTitle = document.createElement('h3');
statsTitle.textContent = 'Project Statistics';
statsTitle.style.cssText = 'margin: 0 0 10px 0; color: #6cf; font-size: 18px;';
statsSection.appendChild(statsTitle);
// Calculate stats
let totalGroups = 0;
let totalTiles = 0;
let totalMaps = 0;
let totalPlacedTiles = 0;
if (typeof groups !== 'undefined' && groups) {
totalGroups = groups.length;
totalTiles = groups.reduce((sum, group) => sum + (group.tiles ? group.tiles.length : 0), 0);
}
if (typeof tilemaps !== 'undefined' && tilemaps) {
totalMaps = tilemaps.length;
totalPlacedTiles = tilemaps.reduce((sum, map) => {
return sum + (map.data ? map.data.filter(t => t !== 0).length : 0);
}, 0);
}
const statsDiv = document.createElement('div');
statsDiv.style.cssText = 'font-size: 14px; color: #ccc;';
statsDiv.innerHTML = `
<div style="margin-bottom: 8px;"><strong>Total Tile Groups:</strong> ${totalGroups}</div>
<div style="margin-bottom: 8px;"><strong>Total Unique Tiles:</strong> ${totalTiles}</div>
<div style="margin-bottom: 8px;"><strong>Total Tilemaps:</strong> ${totalMaps}</div>
<div style="margin-bottom: 8px;"><strong>Total Placed Tiles:</strong> ${totalPlacedTiles}</div>
`;
statsSection.appendChild(statsDiv);
container.appendChild(statsSection);
// Export section
const exportSection = document.createElement('div');
exportSection.style.cssText = 'padding: 15px; background: #1a1a1a; border-radius: 8px;';
const exportTitle = document.createElement('h3');
exportTitle.textContent = 'Export Project';
exportTitle.style.cssText = 'margin: 0 0 10px 0; color: #6cf; font-size: 18px;';
exportSection.appendChild(exportTitle);
const exportBtn = document.createElement('button');
exportBtn.textContent = 'Export Complete Project';
exportBtn.style.cssText = `
background: #4a4; color: white; border: none;
padding: 10px 20px; border-radius: 6px; cursor: pointer; font-size: 14px;
`;
exportBtn.addEventListener('click', exportCompleteProject);
exportSection.appendChild(exportBtn);
container.appendChild(exportSection);
}
/**
* Export complete project data
*/
function exportCompleteProject() {
const projectData = {
metadata: {
exportDate: new Date().toISOString(),
version: "1.0",
editor: "Tile Map Editor"
},
tileGroups: typeof groups !== 'undefined' ? groups : [],
tilemaps: typeof tilemaps !== 'undefined' ? tilemaps : [],
statistics: calculateProjectStats()
};
// Create downloadable JSON
const dataStr = JSON.stringify(projectData, null, 2);
const dataBlob = new Blob([dataStr], {type: 'application/json'});
const url = URL.createObjectURL(dataBlob);
// Create download link
const link = document.createElement('a');
link.href = url;
link.download = `tilemap-project-${new Date().toISOString().split('T')[0]}.json`;
// Trigger download
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
alert('Project data exported successfully!');
}
/**
* Calculate project statistics
*/
function calculateProjectStats() {
const stats = {
totalGroups: 0,
totalTiles: 0,
totalMaps: 0,
totalPlacedTiles: 0,
sourceImages: 0,
tileSizes: []
};
// Tile group stats
if (typeof groups !== 'undefined' && groups) {
stats.totalGroups = groups.length;
stats.totalTiles = groups.reduce((sum, group) => sum + (group.tiles ? group.tiles.length : 0), 0);
const uniqueUrls = new Set(groups.map(g => g.url).filter(url => url));
stats.sourceImages = uniqueUrls.size;
const sizes = new Set();
groups.forEach(group => {
if (group.tiles) {
group.tiles.forEach(tile => {
if (tile.size) sizes.add(tile.size);
});
}
});
stats.tileSizes = Array.from(sizes).sort((a, b) => a - b);
}
// Tilemap stats
if (typeof tilemaps !== 'undefined' && tilemaps) {
stats.totalMaps = tilemaps.length;
stats.totalPlacedTiles = tilemaps.reduce((sum, map) => {
return sum + (map.data ? map.data.filter(t => t !== 0).length : 0);
}, 0);
}
return stats;
}
// Debug alert for mobile debugging - success
if (typeof debugAlert === 'function') {
debugAlert('object.js loaded successfully');
}