📜
object_copy7.js
Back
📝 Javascript ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
// Debug alert for mobile debugging if (typeof debugAlert === 'function') { debugAlert('object.js loaded'); } // Simple game object let gameObject = { id: 'game_001', name: 'My Tile Game', version: '1.0.0' }; // Attributes will be loaded from attributes.json let gameAttributes = null; let tileGroupAttributes = null; let tileMapAttributes = null; function openGameController() { const overlayContent = document.getElementById('overlayContent'); overlayContent.innerHTML = ` <div style="height: 100%; overflow: auto; padding: 10px;"> <div id="gameController"></div> </div> `; // Load attributes first, then render loadAttributesAndRender(); } function loadAttributesAndRender() { fetch('attributes.json') .then(response => { if (!response.ok) { throw new Error('Failed to load attributes.json'); } return response.json(); }) .then(data => { gameAttributes = data.game; tileGroupAttributes = data.tileGroup; tileMapAttributes = data.tileMap; if (typeof debugAlert === 'function') { debugAlert('Attributes loaded successfully'); } renderGameController(); }) .catch(error => { if (typeof debugAlert === 'function') { debugAlert('Failed to load attributes.json: ' + error.message); } // Fallback to basic view if attributes.json fails to load renderBasicGameController(); }); } function renderBasicGameController() { const container = document.getElementById('gameController'); container.innerHTML = ` <div style="padding: 15px; background: #1a1a1a; border-radius: 8px; margin-bottom: 20px;"> <h3 style="color: #6cf; margin: 0 0 15px 0;">Game Object</h3> <div style="color: #f44; padding: 10px;"> Could not load attributes.json. Using basic view. </div> <div style="margin: 8px 0; padding: 10px; background: #333; border-radius: 4px; color: #ccc; font-size: 12px;"> <div>ID: ${gameObject.id}</div> <div>Name: ${gameObject.name}</div> <div>Version: ${gameObject.version}</div> <div>Groups: ${typeof groups !== 'undefined' ? groups.length : 0}</div> <div>Tilemaps: ${typeof tilemaps !== 'undefined' ? tilemaps.length : 0}</div> </div> </div> `; } function renderGameController() { const container = document.getElementById('gameController'); if (!gameAttributes || !tileGroupAttributes || !tileMapAttributes) { container.innerHTML = ` <div style="padding: 15px; background: #1a1a1a; border-radius: 8px;"> <h3 style="color: #6cf;">Loading attributes...</h3> <div style="color: #888;">Please wait while attributes.json loads.</div> </div> `; return; } container.innerHTML = ` <div style="padding: 15px; background: #1a1a1a; border-radius: 8px; margin-bottom: 20px;"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;"> <h3 style="color: #6cf; margin: 0;">Game Object</h3> <button onclick="copyGameObjectJSON()" style="background: #4a4; color: white; border: none; padding: 4px 8px; border-radius: 4px; cursor: pointer; font-size: 10px;">Copy JSON</button> </div> <div style="margin-bottom: 15px;"> <strong style="color: #f44;">Mandatory:</strong> <div style="margin: 8px 0; padding: 10px; background: #333; border-radius: 4px; color: #ccc; font-size: 12px;"> <div>ID: ${gameObject.id}</div> <div>Name: ${gameObject.name}</div> <div>Version: ${gameObject.version}</div> </div> </div> <div id="gameChangeable" style="margin-bottom: 15px;"> <strong style="color: #4a4;">Changeable:</strong> <div style="margin: 8px 0; padding: 10px; background: #333; border-radius: 4px; font-size: 11px;"></div> </div> <div id="gameOptional"> <strong style="color: #888;">Optional:</strong> <div style="margin: 8px 0; padding: 10px; background: #333; border-radius: 4px; font-size: 11px;"></div> </div> </div> <div id="tileGroupsContainer"></div> <div id="tilemapsContainer"></div> `; // Add attributes using DOM manipulation addGameAttributes(); addTileGroupsSection(); addTilemapsSection(); } function copyGameObjectJSON() { try { // Collect current attribute values from dropdowns const gameChangeable = {}; const gameOptional = {}; // Get game attributes from the interface const gameSelects = document.querySelectorAll('#gameChangeable select, #gameOptional select'); gameSelects.forEach(select => { const onchange = select.getAttribute('onchange'); if (onchange && onchange.includes('game')) { const keyMatch = onchange.match(/'([^']+)'/g); if (keyMatch && keyMatch.length >= 3) { const key = keyMatch[2].replace(/'/g, ''); let value = select.value; // Convert types if (value === 'null') value = null; else if (value === 'true') value = true; else if (value === 'false') value = false; else if (!isNaN(value) && value !== '') value = Number(value); if (onchange.includes('changeable')) { gameChangeable[key] = value; } else { gameOptional[key] = value; } } } }); const completeGameObject = { metadata: { id: gameObject.id, name: gameObject.name, version: gameObject.version, exportDate: new Date().toISOString(), editor: "Tile Game Editor" }, // Actual game configuration gameObject: { changeable: gameChangeable, optional: gameOptional }, // Complete tile groups data tileGroups: typeof groups !== 'undefined' ? groups.map(group => ({ name: group.name, url: group.url, tileCount: group.tiles ? group.tiles.length : 0, tileSize: group.tiles && group.tiles[0] ? group.tiles[0].size : null, tiles: group.tiles ? group.tiles.map(tile => ({ uniqueId: tile.uniqueId, sourceX: tile.sourceX, sourceY: tile.sourceY, size: tile.size, linearIndex: Math.floor(tile.sourceY / tile.size) * 8 + Math.floor(tile.sourceX / tile.size) })) : [] })) : [], // Complete tilemaps data tilemaps: typeof tilemaps !== 'undefined' ? tilemaps.map(tilemap => ({ id: tilemap.id, name: tilemap.name, width: tilemap.width, height: tilemap.height, tileSize: tilemap.tileSize, data: tilemap.data, fillPercentage: tilemap.width && tilemap.height ? ((tilemap.data ? tilemap.data.filter(t => t !== 0).length : 0) / (tilemap.width * tilemap.height) * 100).toFixed(1) : 0 })) : [], // Project statistics statistics: { totalTileGroups: typeof groups !== 'undefined' ? groups.length : 0, totalTiles: typeof groups !== 'undefined' ? groups.reduce((sum, group) => sum + (group.tiles ? group.tiles.length : 0), 0) : 0, totalTilemaps: typeof tilemaps !== 'undefined' ? tilemaps.length : 0, totalPlacedTiles: typeof tilemaps !== 'undefined' ? tilemaps.reduce((sum, map) => sum + (map.data ? map.data.filter(t => t !== 0).length : 0), 0) : 0, uniqueSourceImages: typeof groups !== 'undefined' ? new Set(groups.map(g => g.url).filter(url => url)).size : 0 } }; const jsonString = JSON.stringify(completeGameObject, null, 2); navigator.clipboard.writeText(jsonString).then(() => { if (typeof debugAlert === 'function') { debugAlert('Complete game data copied! ' + Math.round(jsonString.length / 1024) + 'KB'); } }).catch(() => { if (typeof debugAlert === 'function') { debugAlert('Game data: ' + jsonString.substring(0, 200) + '...'); } }); } catch (error) { if (typeof debugAlert === 'function') { debugAlert('Copy failed: ' + error.message); } } } function addGameAttributes() { // Add changeable attributes const changeableContainer = document.querySelector('#gameChangeable > div'); addAttributesToContainer(changeableContainer, gameAttributes.changeable, 'game', 'changeable'); // Add optional attributes const optionalContainer = document.querySelector('#gameOptional > div'); addAttributesToContainer(optionalContainer, gameAttributes.optional, 'game', 'optional'); } function addAttributesToContainer(container, attributes, section, type) { for (const categoryKey in attributes) { const category = attributes[categoryKey]; if (category.value !== undefined) { // Single attribute addSingleAttribute(container, categoryKey, category, section, type); } else { // Category with sub-attributes const categoryLabel = document.createElement('div'); categoryLabel.textContent = categoryKey + ':'; categoryLabel.style.cssText = 'font-weight: bold; margin: 8px 0 4px 0; color: #fff;'; container.appendChild(categoryLabel); for (const attrKey in category) { const attr = category[attrKey]; addSingleAttribute(container, categoryKey + '.' + attrKey, attr, section, type); } } } } function addSingleAttribute(container, key, attr, section, type) { const attrDiv = document.createElement('div'); attrDiv.style.cssText = 'margin: 4px 0; display: flex; align-items: center; gap: 10px;'; const label = document.createElement('span'); label.textContent = key + ':'; label.style.cssText = 'min-width: 100px; color: #ccc;'; attrDiv.appendChild(label); const select = document.createElement('select'); select.style.cssText = 'background: #222; color: #fff; border: 1px solid #555; padding: 2px 4px; border-radius: 2px; font-size: 11px;'; attr.options.forEach(option => { const optionElement = document.createElement('option'); optionElement.value = option; optionElement.textContent = option === null ? 'null' : option; optionElement.selected = option === attr.value; select.appendChild(optionElement); }); select.onchange = function() { updateAttribute(section, type, key, this.value); }; attrDiv.appendChild(select); container.appendChild(attrDiv); } function updateAttribute(section, type, key, value) { let convertedValue = value; if (value === 'null') convertedValue = null; else if (value === 'true') convertedValue = true; else if (value === 'false') convertedValue = false; else if (!isNaN(value) && value !== '') convertedValue = Number(value); if (typeof debugAlert === 'function') { debugAlert('Updated ' + section + '.' + key + ' = ' + convertedValue); } } function addTileGroupsSection() { const container = document.getElementById('tileGroupsContainer'); if (!container) return; const section = document.createElement('div'); section.style.cssText = 'padding: 15px; background: #1a1a1a; border-radius: 8px; margin-bottom: 20px;'; const title = document.createElement('h3'); title.textContent = 'Tile Groups'; title.style.cssText = 'color: #6cf; margin: 0 0 15px 0;'; section.appendChild(title); if (typeof groups === 'undefined' || !groups || groups.length === 0) { 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;'; section.appendChild(noGroups); } else { groups.forEach((group, index) => { const groupDiv = document.createElement('div'); groupDiv.style.cssText = 'margin-bottom: 20px; padding: 15px; background: #2a2a2a; border-radius: 6px; border-left: 4px solid #6cf;'; const groupTitle = document.createElement('h4'); groupTitle.textContent = 'Group ' + (index + 1) + ': ' + (group.name || 'Unnamed'); groupTitle.style.cssText = 'margin: 0 0 10px 0; color: #fff;'; groupDiv.appendChild(groupTitle); // Mandatory info const mandatoryDiv = document.createElement('div'); mandatoryDiv.style.cssText = 'margin-bottom: 10px;'; const mandatoryLabel = document.createElement('strong'); mandatoryLabel.textContent = 'Mandatory:'; mandatoryLabel.style.cssText = 'color: #f44;'; mandatoryDiv.appendChild(mandatoryLabel); const mandatoryInfo = document.createElement('div'); mandatoryInfo.style.cssText = 'margin: 8px 0; padding: 8px; background: #333; border-radius: 4px; font-size: 11px; color: #ccc;'; mandatoryInfo.innerHTML = 'ID: group_' + (index + 1) + '<br>' + 'Atlas Key: ' + (group.url ? group.url.split('/').pop() : 'none') + '<br>' + 'Tile Size: ' + (group.tiles && group.tiles[0] ? group.tiles[0].size : 32) + 'px<br>' + 'Members: ' + (group.tiles ? group.tiles.length : 0) + ' tiles'; mandatoryDiv.appendChild(mandatoryInfo); groupDiv.appendChild(mandatoryDiv); // Changeable attributes const changeableDiv = document.createElement('div'); changeableDiv.style.cssText = 'margin-bottom: 10px;'; const changeableLabel = document.createElement('strong'); changeableLabel.textContent = 'Changeable:'; changeableLabel.style.cssText = 'color: #4a4;'; changeableDiv.appendChild(changeableLabel); const changeableContainer = document.createElement('div'); changeableContainer.style.cssText = 'margin: 8px 0; padding: 8px; background: #333; border-radius: 4px; font-size: 11px;'; addAttributesToContainer(changeableContainer, tileGroupAttributes.changeable, 'tileGroup', 'changeable'); changeableDiv.appendChild(changeableContainer); groupDiv.appendChild(changeableDiv); // Optional attributes const optionalDiv = document.createElement('div'); optionalDiv.style.cssText = 'margin-bottom: 10px;'; const optionalLabel = document.createElement('strong'); optionalLabel.textContent = 'Optional:'; optionalLabel.style.cssText = 'color: #888;'; optionalDiv.appendChild(optionalLabel); const optionalContainer = document.createElement('div'); optionalContainer.style.cssText = 'margin: 8px 0; padding: 8px; background: #333; border-radius: 4px; font-size: 11px;'; addAttributesToContainer(optionalContainer, tileGroupAttributes.optional, 'tileGroup', 'optional'); optionalDiv.appendChild(optionalContainer); groupDiv.appendChild(optionalDiv); // Add tile previews if tiles exist if (group.tiles && group.tiles.length > 0) { addTilePreviewsToGroup(groupDiv, group); } section.appendChild(groupDiv); }); } container.appendChild(section); } function addTilePreviewsToGroup(groupDiv, group) { const previewContainer = document.createElement('div'); previewContainer.style.cssText = 'display: flex; gap: 5px; flex-wrap: wrap; margin-top: 10px;'; group.tiles.forEach(tile => { const tileWrapper = document.createElement('div'); tileWrapper.style.cssText = 'position: relative; display: inline-block;'; // Create canvas for tile display const canvas = document.createElement('canvas'); canvas.width = 32; canvas.height = 32; canvas.style.cssText = 'border: 2px solid #666; border-radius: 4px; background: #000;'; // Draw the tile 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); // Scale to 32x32 for preview ctx.drawImage(tempCanvas, 0, 0, tile.size, tile.size, 0, 0, 32, 32); // Create ID badge (bottom-right) 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: 8px; padding: 1px 3px; border-radius: 2px; border: 1px solid #6cf;'; // Create linear index badge (top-left) const tileX = Math.floor(tile.sourceX / tile.size); const tileY = Math.floor(tile.sourceY / tile.size); const tilesPerRow = 8; // Default assumption const linearIndex = tileY * tilesPerRow + tileX; const indexBadge = document.createElement('span'); indexBadge.textContent = linearIndex.toString(); indexBadge.style.cssText = 'position: absolute; top: -2px; left: -2px; background: rgba(0,0,0,0.8); color: #fff; font-size: 7px; padding: 1px 2px; border-radius: 2px; border: 1px solid #4a4;'; // Assemble the tile preview tileWrapper.appendChild(canvas); tileWrapper.appendChild(idBadge); tileWrapper.appendChild(indexBadge); previewContainer.appendChild(tileWrapper); }); groupDiv.appendChild(previewContainer); } function addTilemapsSection() { const container = document.getElementById('tilemapsContainer'); if (!container) return; const section = document.createElement('div'); section.style.cssText = 'padding: 15px; background: #1a1a1a; border-radius: 8px; margin-bottom: 20px;'; const title = document.createElement('h3'); title.textContent = 'Tile Maps'; title.style.cssText = 'color: #6cf; margin: 0 0 15px 0;'; section.appendChild(title); if (typeof tilemaps === 'undefined' || !tilemaps || tilemaps.length === 0) { 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;'; section.appendChild(noMaps); } else { tilemaps.forEach((tilemap, index) => { const isActive = typeof currentTilemapIndex !== 'undefined' && currentTilemapIndex === index; const totalTiles = tilemap.data ? tilemap.data.filter(t => t !== 0).length : 0; const fillPercent = tilemap.width && tilemap.height ? ((totalTiles / (tilemap.width * tilemap.height)) * 100).toFixed(1) : '0.0'; const mapDiv = document.createElement('div'); mapDiv.style.cssText = 'margin-bottom: 20px; padding: 15px; background: #2a2a2a; border-radius: 6px; border-left: 4px solid #6cf;'; const mapTitle = document.createElement('h4'); mapTitle.textContent = tilemap.name + (isActive ? ' (Active)' : ''); mapTitle.style.cssText = 'margin: 0 0 10px 0; color: ' + (isActive ? '#6cf' : '#fff') + ';'; mapDiv.appendChild(mapTitle); // Mandatory info const mandatoryDiv = document.createElement('div'); mandatoryDiv.style.cssText = 'margin-bottom: 10px;'; const mandatoryLabel = document.createElement('strong'); mandatoryLabel.textContent = 'Mandatory:'; mandatoryLabel.style.cssText = 'color: #f44;'; mandatoryDiv.appendChild(mandatoryLabel); const mandatoryInfo = document.createElement('div'); mandatoryInfo.style.cssText = 'margin: 8px 0; padding: 8px; background: #333; border-radius: 4px; font-size: 11px; color: #ccc;'; mandatoryInfo.innerHTML = 'ID: map_' + tilemap.id + '<br>' + 'Dimensions: ' + tilemap.width + ' x ' + tilemap.height + '<br>' + 'Fill: ' + fillPercent + '% (' + totalTiles + ' tiles)'; mandatoryDiv.appendChild(mandatoryInfo); mapDiv.appendChild(mandatoryDiv); // Changeable attributes const changeableDiv = document.createElement('div'); changeableDiv.style.cssText = 'margin-bottom: 10px;'; const changeableLabel = document.createElement('strong'); changeableLabel.textContent = 'Changeable:'; changeableLabel.style.cssText = 'color: #4a4;'; changeableDiv.appendChild(changeableLabel); const changeableContainer = document.createElement('div'); changeableContainer.style.cssText = 'margin: 8px 0; padding: 8px; background: #333; border-radius: 4px; font-size: 11px;'; addAttributesToContainer(changeableContainer, tileMapAttributes.changeable, 'tileMap', 'changeable'); changeableDiv.appendChild(changeableContainer); mapDiv.appendChild(changeableDiv); // Optional attributes const optionalDiv = document.createElement('div'); optionalDiv.style.cssText = 'margin-bottom: 10px;'; const optionalLabel = document.createElement('strong'); optionalLabel.textContent = 'Optional:'; optionalLabel.style.cssText = 'color: #888;'; optionalDiv.appendChild(optionalLabel); const optionalContainer = document.createElement('div'); optionalContainer.style.cssText = 'margin: 8px 0; padding: 8px; background: #333; border-radius: 4px; font-size: 11px;'; addAttributesToContainer(optionalContainer, tileMapAttributes.optional, 'tileMap', 'optional'); optionalDiv.appendChild(optionalContainer); mapDiv.appendChild(optionalDiv); // Add Phaser array if data exists if (tilemap.data && tilemap.data.length > 0) { addPhaserArrayToMap(mapDiv, tilemap, index); } section.appendChild(mapDiv); }); } container.appendChild(section); } function addPhaserArrayToMap(mapDiv, tilemap, mapIndex) { const arrayContainer = document.createElement('div'); const arrayLabel = document.createElement('strong'); arrayLabel.textContent = 'Phaser 2D Array:'; arrayLabel.style.cssText = 'color: #6cf;'; arrayContainer.appendChild(arrayLabel); const arrayDisplay = document.createElement('div'); arrayDisplay.style.cssText = 'background: #1a1a1a; padding: 10px; border-radius: 4px; margin-top: 5px; font-family: "Courier New", monospace; font-size: 10px; color: #ccc; overflow-x: auto; max-height: 150px; overflow-y: auto;'; // Build the array text let arrayText = '[\n'; for (let y = 0; y < tilemap.height; y++) { let row = ' ['; for (let x = 0; x < tilemap.width; x++) { const dataIndex = y * tilemap.width + x; const tileId = tilemap.data[dataIndex] || 0; row += tileId.toString().padStart(3, ' '); if (x < tilemap.width - 1) row += ','; } row += ']'; if (y < tilemap.height - 1) row += ','; arrayText += row + '\n'; } arrayText += ']'; // Display the formatted array const lines = arrayText.split('\n'); lines.forEach(line => { const lineDiv = document.createElement('div'); lineDiv.textContent = line; lineDiv.style.cssText = 'line-height: 1.2;'; arrayDisplay.appendChild(lineDiv); }); arrayContainer.appendChild(arrayDisplay); // Add copy button 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.onclick = function() { copyTilemapArray(arrayText, mapIndex); }; arrayContainer.appendChild(copyBtn); mapDiv.appendChild(arrayContainer); } function copyTilemapArray(arrayText, mapIndex) { try { navigator.clipboard.writeText(arrayText).then(function() { if (typeof debugAlert === 'function') { debugAlert('Array copied to clipboard!'); } }).catch(function() { if (typeof debugAlert === 'function') { debugAlert('Array preview: ' + arrayText.substring(0, 50) + '...'); } }); } catch (error) { if (typeof debugAlert === 'function') { debugAlert('Copy failed: ' + error.message); } } } if (typeof debugAlert === 'function') { debugAlert('object.js loaded successfully'); }