User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'toGlobal')' in or related to this line: 'var localPos = block.toLocal(obj.parent.toGlobal(obj.position));' Line Number: 330
Code edit (1 edits merged)
Please save this source code
User prompt
Mine Escape
Initial prompt
💣 4. Mine Escape Concept: You’re trapped in a grid with hidden bombs. Click to reveal safe blocks. Goal: Clear all safe blocks without hitting bombs (like Minesweeper). Tools: Python (tkinter) Bonus idea: Add random power-ups or hint system.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var GridBlock = Container.expand(function (gridX, gridY, hasMine) {
var self = Container.call(this);
self.gridX = gridX;
self.gridY = gridY;
self.hasMine = hasMine;
self.isRevealed = false;
self.isFlagged = false;
self.adjacentMines = 0;
// Visual elements
self.hiddenGraphics = self.attachAsset('hiddenBlock', {
anchorX: 0.5,
anchorY: 0.5
});
self.revealedGraphics = self.attachAsset('revealedBlock', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.mineGraphics = self.attachAsset('mineBlock', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.flagGraphics = self.attachAsset('flaggedBlock', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Number text for adjacent mine count
self.numberText = new Text2('', {
size: 80,
fill: 0x000000
});
self.numberText.anchor.set(0.5, 0.5);
self.numberText.alpha = 0;
self.addChild(self.numberText);
self.reveal = function () {
if (self.isRevealed || self.isFlagged) return;
self.isRevealed = true;
LK.getSound('reveal').play();
// Hide hidden block
tween(self.hiddenGraphics, {
alpha: 0
}, {
duration: 200
});
if (self.hasMine) {
// Show mine
tween(self.mineGraphics, {
alpha: 1
}, {
duration: 200
});
LK.getSound('explode').play();
gameOver = true;
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
} else {
// Show revealed block
tween(self.revealedGraphics, {
alpha: 1
}, {
duration: 200
});
// Show number if adjacent mines > 0
if (self.adjacentMines > 0) {
self.numberText.setText(self.adjacentMines.toString());
self.numberText.fill = self.getNumberColor(self.adjacentMines);
tween(self.numberText, {
alpha: 1
}, {
duration: 200
});
}
}
};
self.toggleFlag = function () {
if (self.isRevealed) return;
self.isFlagged = !self.isFlagged;
LK.getSound('flag').play();
if (self.isFlagged) {
tween(self.flagGraphics, {
alpha: 1
}, {
duration: 200
});
tween(self.hiddenGraphics, {
alpha: 0.5
}, {
duration: 200
});
} else {
tween(self.flagGraphics, {
alpha: 0
}, {
duration: 200
});
tween(self.hiddenGraphics, {
alpha: 1
}, {
duration: 200
});
}
};
self.getNumberColor = function (num) {
var colors = ['#000000', '#0000ff', '#008000', '#ff0000', '#800080', '#800000', '#008080', '#000000', '#808080'];
return colors[num] || '#000000';
};
self.down = function (x, y, obj) {
if (gameOver) return;
// Simple tap reveals, long press flags (simulated with double tap)
if (self.lastTapTime && Date.now() - self.lastTapTime < 300) {
self.toggleFlag();
} else {
if (!self.isFlagged) {
self.reveal();
}
}
self.lastTapTime = Date.now();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c5530
});
/****
* Game Code
****/
var GRID_SIZE = 8;
var MINE_COUNT = 10;
var BLOCK_SIZE = 200;
var BLOCK_SPACING = 220;
var gameGrid = [];
var blocks = [];
var gameOver = false;
var revealedCount = 0;
var totalSafeBlocks = GRID_SIZE * GRID_SIZE - MINE_COUNT;
// UI Elements
var titleText = new Text2('Mine Escape', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
LK.gui.top.addChild(titleText);
var instructionText = new Text2('Tap to reveal • Double tap to flag', {
size: 60,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 1);
instructionText.y = -50;
LK.gui.bottom.addChild(instructionText);
var mineCountText = new Text2('Mines: ' + MINE_COUNT, {
size: 80,
fill: 0xFFFFFF
});
mineCountText.anchor.set(0, 0);
LK.gui.topLeft.addChild(mineCountText);
mineCountText.x = 120; // Avoid platform menu
function initializeGrid() {
// Create empty grid
for (var y = 0; y < GRID_SIZE; y++) {
gameGrid[y] = [];
for (var x = 0; x < GRID_SIZE; x++) {
gameGrid[y][x] = false; // false = no mine, true = mine
}
}
// Place mines randomly
var minesPlaced = 0;
while (minesPlaced < MINE_COUNT) {
var x = Math.floor(Math.random() * GRID_SIZE);
var y = Math.floor(Math.random() * GRID_SIZE);
if (!gameGrid[y][x]) {
gameGrid[y][x] = true;
minesPlaced++;
}
}
}
function createBlocks() {
var gridWidth = (GRID_SIZE - 1) * BLOCK_SPACING;
var gridHeight = (GRID_SIZE - 1) * BLOCK_SPACING;
var startX = (2048 - gridWidth) / 2;
var startY = (2732 - gridHeight) / 2;
for (var y = 0; y < GRID_SIZE; y++) {
blocks[y] = [];
for (var x = 0; x < GRID_SIZE; x++) {
var block = new GridBlock(x, y, gameGrid[y][x]);
block.x = startX + x * BLOCK_SPACING;
block.y = startY + y * BLOCK_SPACING;
blocks[y][x] = block;
game.addChild(block);
}
}
}
function calculateAdjacentMines() {
for (var y = 0; y < GRID_SIZE; y++) {
for (var x = 0; x < GRID_SIZE; x++) {
if (!blocks[y][x].hasMine) {
var count = 0;
for (var dy = -1; dy <= 1; dy++) {
for (var dx = -1; dx <= 1; dx++) {
if (dx === 0 && dy === 0) continue;
var nx = x + dx;
var ny = y + dy;
if (nx >= 0 && nx < GRID_SIZE && ny >= 0 && ny < GRID_SIZE) {
if (gameGrid[ny][nx]) count++;
}
}
}
blocks[y][x].adjacentMines = count;
}
}
}
}
function revealAdjacentEmpty(x, y) {
if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE) return;
var block = blocks[y][x];
if (block.isRevealed || block.hasMine || block.isFlagged) return;
block.isRevealed = true;
revealedCount++;
// Animate reveal
tween(block.hiddenGraphics, {
alpha: 0
}, {
duration: 200
});
tween(block.revealedGraphics, {
alpha: 1
}, {
duration: 200
});
if (block.adjacentMines > 0) {
block.numberText.setText(block.adjacentMines.toString());
block.numberText.fill = block.getNumberColor(block.adjacentMines);
tween(block.numberText, {
alpha: 1
}, {
duration: 200
});
} else {
// If no adjacent mines, reveal surrounding blocks
LK.setTimeout(function () {
for (var dy = -1; dy <= 1; dy++) {
for (var dx = -1; dx <= 1; dx++) {
if (dx === 0 && dy === 0) continue;
revealAdjacentEmpty(x + dx, y + dy);
}
}
}, 100);
}
}
function checkWinCondition() {
if (revealedCount === totalSafeBlocks) {
LK.setTimeout(function () {
LK.showYouWin();
}, 500);
}
}
// Initialize the game
initializeGrid();
createBlocks();
calculateAdjacentMines();
// Override block reveal to handle flood fill and win condition
game.update = function () {
if (gameOver) return;
// Count revealed safe blocks
var currentRevealed = 0;
for (var y = 0; y < GRID_SIZE; y++) {
for (var x = 0; x < GRID_SIZE; x++) {
var block = blocks[y][x];
if (block.isRevealed && !block.hasMine) {
currentRevealed++;
}
}
}
revealedCount = currentRevealed;
checkWinCondition();
};
// Handle block reveals with flood fill for empty areas
game.down = function (x, y, obj) {
if (gameOver) return;
// Find which block was clicked using direct distance calculation
for (var by = 0; by < GRID_SIZE; by++) {
for (var bx = 0; bx < GRID_SIZE; bx++) {
var block = blocks[by][bx];
// Check if click is within block bounds using direct coordinate comparison
var distX = Math.abs(x - block.x);
var distY = Math.abs(y - block.y);
if (distX < BLOCK_SIZE / 2 && distY < BLOCK_SIZE / 2) {
if (!block.isRevealed && !block.isFlagged) {
if (block.hasMine) {
block.reveal();
} else {
// Use flood fill for empty areas
revealAdjacentEmpty(bx, by);
}
}
return;
}
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -291,14 +291,16 @@
};
// Handle block reveals with flood fill for empty areas
game.down = function (x, y, obj) {
if (gameOver) return;
- // Find which block was clicked
+ // Find which block was clicked using direct distance calculation
for (var by = 0; by < GRID_SIZE; by++) {
for (var bx = 0; bx < GRID_SIZE; bx++) {
var block = blocks[by][bx];
- var localPos = block.toLocal(obj.parent.toGlobal(obj.position));
- if (Math.abs(localPos.x) < BLOCK_SIZE / 2 && Math.abs(localPos.y) < BLOCK_SIZE / 2) {
+ // Check if click is within block bounds using direct coordinate comparison
+ var distX = Math.abs(x - block.x);
+ var distY = Math.abs(y - block.y);
+ if (distX < BLOCK_SIZE / 2 && distY < BLOCK_SIZE / 2) {
if (!block.isRevealed && !block.isFlagged) {
if (block.hasMine) {
block.reveal();
} else {