User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'NaN')' in or related to this line: 'var type = world[x][y];' Line Number: 408
User prompt
i canet see player
User prompt
make player otto attak
User prompt
fix game pls
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'NaN')' in or related to this line: 'var type = world[x][y];' Line Number: 392
User prompt
Please fix the bug: 'ReferenceError: zombies is not defined' in or related to this line: 'for (var i = 0; i < zombies.length; i++) {' Line Number: 772
User prompt
Please fix the bug: 'Player is not defined' in or related to this line: 'var player = new Player();' Line Number: 218
User prompt
add enemys zombes
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '22.65000000000009')' in or related to this line: 'if (world[nx][ny] === BLOCK_AIR) {' Line Number: 83
User prompt
make mous controles
User prompt
Please fix the bug: 'updatePlayerPos is not defined' in or related to this line: 'updatePlayerPos();' Line Number: 795
User prompt
make proper player
Code edit (1 edits merged)
Please save this source code
User prompt
BlockCraft 2D
Initial prompt
make 2d minecraft
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// BlockSprite class
var BlockSprite = Container.expand(function () {
	var self = Container.call(this);
	self.blockType = BLOCK_AIR;
	self.xIndex = 0;
	self.yIndex = 0;
	self.asset = null;
	self.setBlock = function (type) {
		self.blockType = type;
		if (self.asset) {
			self.removeChild(self.asset);
			self.asset = null;
		}
		if (type !== BLOCK_AIR) {
			self.asset = self.attachAsset('block_' + type, {
				width: BLOCK_SIZE,
				height: BLOCK_SIZE,
				color: BLOCK_COLORS[type],
				shape: 'box',
				anchorX: 0,
				anchorY: 0
			});
		}
	};
	return self;
});
// Minimal Player class definition to fix 'Player is not defined'
var Player = Container.expand(function () {
	var self = Container.call(this);
	self.xIndex = playerX;
	self.yIndex = playerY;
	// Attach player asset
	self.asset = self.attachAsset('player', {
		width: BLOCK_SIZE,
		height: BLOCK_SIZE,
		anchorX: 0,
		anchorY: 0
	});
	// Dummy update method for compatibility
	self.update = function () {
		self.x = self.xIndex * BLOCK_SIZE - cameraX;
		self.y = self.yIndex * BLOCK_SIZE - cameraY;
	};
	// Dummy move method for compatibility
	self.move = function (dx, dy) {
		self.xIndex += dx;
		self.yIndex += dy;
	};
	// Dummy jump method for compatibility
	self.jump = function () {};
	// Dummy applyGravity method for compatibility
	self.applyGravity = function () {};
	// Attack method: damages any zombie adjacent to player
	self.attack = function () {
		// Player attacks all zombies in adjacent blocks (including diagonals)
		for (var i = zombies.length - 1; i >= 0; i--) {
			var z = zombies[i];
			var dx = Math.abs(z.xIndex - self.xIndex);
			var dy = Math.abs(z.yIndex - self.yIndex);
			if (dx <= 1 && dy <= 1) {
				// Remove zombie from game and array
				if (z.destroy) z.destroy();
				zombies.splice(i, 1);
			}
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x87ceeb // sky blue
});
/**** 
* Game Code
****/ 
// Block types
// Generate world
var BLOCK_AIR = 0;
var BLOCK_DIRT = 1;
var BLOCK_GRASS = 2;
var BLOCK_STONE = 3;
var BLOCK_WOOD = 4;
var BLOCK_LEAF = 5;
var BLOCK_CRAFTING = 6;
var BLOCK_CHEST = 7;
var BLOCK_SAND = 8;
// Block colors
var BLOCK_COLORS = {};
BLOCK_COLORS[BLOCK_AIR] = 0x000000; // invisible
BLOCK_COLORS[BLOCK_DIRT] = 0x8B5A2B;
BLOCK_COLORS[BLOCK_GRASS] = 0x4CAF50;
BLOCK_COLORS[BLOCK_STONE] = 0x888888;
BLOCK_COLORS[BLOCK_WOOD] = 0xA0522D;
BLOCK_COLORS[BLOCK_LEAF] = 0x228B22;
BLOCK_COLORS[BLOCK_CRAFTING] = 0xFFD700;
BLOCK_COLORS[BLOCK_CHEST] = 0xC2B280;
BLOCK_COLORS[BLOCK_SAND] = 0xF4E2B2;
// Block size
var BLOCK_SIZE = 100;
// World size (in blocks)
var WORLD_WIDTH = 20;
var WORLD_HEIGHT = 24;
// Inventory size
var INVENTORY_SIZE = 6;
// Simple recipes: [ [inputBlock, count], ... ] => [outputBlock, count]
var RECIPES = [{
	inputs: [[BLOCK_WOOD, 2]],
	output: [BLOCK_CRAFTING, 1]
}, {
	inputs: [[BLOCK_STONE, 3]],
	output: [BLOCK_CHEST, 1]
}, {
	inputs: [[BLOCK_SAND, 2]],
	output: [BLOCK_GLASS = 9, 1]
} // glass is not in world, but can be crafted
];
// Add glass to block colors
BLOCK_COLORS[BLOCK_GLASS] = 0xE0FFFF;
// Block names
var BLOCK_NAMES = {};
BLOCK_NAMES[BLOCK_AIR] = "Air";
BLOCK_NAMES[BLOCK_DIRT] = "Dirt";
BLOCK_NAMES[BLOCK_GRASS] = "Grass";
BLOCK_NAMES[BLOCK_STONE] = "Stone";
BLOCK_NAMES[BLOCK_WOOD] = "Wood";
BLOCK_NAMES[BLOCK_LEAF] = "Leaf";
BLOCK_NAMES[BLOCK_CRAFTING] = "Crafting Table";
BLOCK_NAMES[BLOCK_CHEST] = "Chest";
BLOCK_NAMES[BLOCK_SAND] = "Sand";
BLOCK_NAMES[BLOCK_GLASS] = "Glass";
// Block can be placed
var BLOCK_PLACEABLE = {};
BLOCK_PLACEABLE[BLOCK_DIRT] = true;
BLOCK_PLACEABLE[BLOCK_GRASS] = true;
BLOCK_PLACEABLE[BLOCK_STONE] = true;
BLOCK_PLACEABLE[BLOCK_WOOD] = true;
BLOCK_PLACEABLE[BLOCK_LEAF] = true;
BLOCK_PLACEABLE[BLOCK_CRAFTING] = true;
BLOCK_PLACEABLE[BLOCK_CHEST] = true;
BLOCK_PLACEABLE[BLOCK_SAND] = true;
BLOCK_PLACEABLE[BLOCK_GLASS] = true;
// Block can be mined
var BLOCK_MINEABLE = {};
BLOCK_MINEABLE[BLOCK_DIRT] = true;
BLOCK_MINEABLE[BLOCK_GRASS] = true;
BLOCK_MINEABLE[BLOCK_STONE] = true;
BLOCK_MINEABLE[BLOCK_WOOD] = true;
BLOCK_MINEABLE[BLOCK_LEAF] = true;
BLOCK_MINEABLE[BLOCK_CRAFTING] = true;
BLOCK_MINEABLE[BLOCK_CHEST] = true;
BLOCK_MINEABLE[BLOCK_SAND] = true;
BLOCK_MINEABLE[BLOCK_GLASS] = true;
// Block drops (what you get when you mine it)
var BLOCK_DROPS = {};
BLOCK_DROPS[BLOCK_GRASS] = BLOCK_DIRT;
BLOCK_DROPS[BLOCK_DIRT] = BLOCK_DIRT;
BLOCK_DROPS[BLOCK_STONE] = BLOCK_STONE;
BLOCK_DROPS[BLOCK_WOOD] = BLOCK_WOOD;
BLOCK_DROPS[BLOCK_LEAF] = BLOCK_LEAF;
BLOCK_DROPS[BLOCK_CRAFTING] = BLOCK_CRAFTING;
BLOCK_DROPS[BLOCK_CHEST] = BLOCK_CHEST;
BLOCK_DROPS[BLOCK_SAND] = BLOCK_SAND;
BLOCK_DROPS[BLOCK_GLASS] = BLOCK_GLASS;
// World data: 2D array [x][y] = block type
var world = [];
// Block sprites: 2D array [x][y] = BlockSprite
var blockSprites = [];
// Zombies array
var zombies = [];
// Inventory: array of {type, count}
var inventory = [];
for (var i = 0; i < INVENTORY_SIZE; i++) inventory.push({
	type: BLOCK_AIR,
	count: 0
});
// Selected inventory slot
var selectedSlot = 0;
// Player position (in block coordinates)
var playerX = Math.floor(WORLD_WIDTH / 2);
var playerY = 6;
// Player direction (1=right, -1=left)
var playerDir = 1;
// Is mining/placing
var isMining = false;
var isPlacing = false;
// Drag state
var dragStartX = null;
var dragStartY = null;
// Camera offset (in px)
var cameraX = 0;
var cameraY = 0;
// Day-night cycle
var dayTicks = 0;
var DAY_LENGTH = 1800; // 30 seconds
// UI elements
var inventoryNodes = [];
var selectedRect = null;
var blockNameText = null;
var craftingPanel = null;
var craftingButtons = [];
var showCrafting = false;
function generateWorld() {
	for (var x = 0; x < WORLD_WIDTH; x++) {
		world[x] = [];
		blockSprites[x] = [];
		for (var y = 0; y < WORLD_HEIGHT; y++) {
			var type = BLOCK_AIR;
			if (y > 18) {
				type = BLOCK_STONE;
			} else if (y > 14) {
				type = BLOCK_DIRT;
			} else if (y == 14) {
				type = BLOCK_GRASS;
			} else if (y == 13 && Math.random() < 0.2) {
				type = BLOCK_WOOD;
			} else if (y == 12 && world[x] &&
			// check world[x] is defined
			world[x][13] === BLOCK_WOOD && Math.random() < 0.7) {
				type = BLOCK_LEAF;
			} else if (y == 14 && Math.random() < 0.1) {
				type = BLOCK_SAND;
			}
			world[x][y] = type;
			var block = new BlockSprite();
			block.xIndex = x;
			block.yIndex = y;
			block.x = x * BLOCK_SIZE;
			block.y = y * BLOCK_SIZE;
			block.setBlock(type);
			blockSprites[x][y] = block;
			game.addChild(block);
		}
	}
}
// Place player
var player = new Player();
game.addChild(player);
// Camera
function updateCamera() {
	// Center on player, clamp to world
	cameraX = player.xIndex * BLOCK_SIZE + BLOCK_SIZE / 2 - 2048 / 2;
	cameraY = player.yIndex * BLOCK_SIZE + BLOCK_SIZE - 1200;
	if (cameraX < 0) cameraX = 0;
	if (cameraY < 0) cameraY = 0;
	var maxX = WORLD_WIDTH * BLOCK_SIZE - 2048;
	var maxY = WORLD_HEIGHT * BLOCK_SIZE - 2732;
	if (cameraX > maxX) cameraX = maxX;
	if (cameraY > maxY) cameraY = maxY;
	// Move all blocks
	for (var x = 0; x < WORLD_WIDTH; x++) {
		for (var y = 0; y < WORLD_HEIGHT; y++) {
			blockSprites[x][y].x = x * BLOCK_SIZE - cameraX;
			blockSprites[x][y].y = y * BLOCK_SIZE - cameraY;
		}
	}
	// Player's update will set its own position
	if (player && player.update) player.update();
}
// Inventory UI
function updateInventoryUI() {
	for (var i = 0; i < INVENTORY_SIZE; i++) {
		var node = inventoryNodes[i];
		var inv = inventory[i];
		if (inv.type !== BLOCK_AIR) {
			node.visible = true;
			node.asset.width = 90;
			node.asset.height = 90;
			node.asset.color = BLOCK_COLORS[inv.type];
			node.countText.setText(inv.count > 1 ? inv.count : "");
		} else {
			node.visible = false;
		}
		if (i === selectedSlot) {
			selectedRect.x = node.x - 5;
			selectedRect.y = node.y - 5;
			selectedRect.visible = true;
		}
	}
}
// Show block name
function showBlockName(type) {
	if (!blockNameText) return;
	blockNameText.setText(BLOCK_NAMES[type] || "");
	blockNameText.visible = true;
	LK.setTimeout(function () {
		blockNameText.visible = false;
	}, 1000);
}
// Crafting UI
function showCraftingPanel() {
	if (craftingPanel) craftingPanel.visible = true;
	showCrafting = true;
	// Update buttons
	for (var i = 0; i < RECIPES.length; i++) {
		var btn = craftingButtons[i];
		var canCraft = true;
		for (var j = 0; j < RECIPES[i].inputs.length; j++) {
			var input = RECIPES[i].inputs[j];
			var have = 0;
			for (var k = 0; k < INVENTORY_SIZE; k++) {
				if (inventory[k].type === input[0]) have += inventory[k].count;
			}
			if (have < input[1]) canCraft = false;
		}
		btn.alpha = canCraft ? 1 : 0.5;
		btn.interactive = canCraft;
	}
}
function hideCraftingPanel() {
	if (craftingPanel) craftingPanel.visible = false;
	showCrafting = false;
}
// Add to inventory
function addToInventory(type, count) {
	// Try to stack
	for (var i = 0; i < INVENTORY_SIZE; i++) {
		if (inventory[i].type === type && inventory[i].count < 99) {
			var add = Math.min(count, 99 - inventory[i].count);
			inventory[i].count += add;
			count -= add;
			if (count <= 0) return true;
		}
	}
	// Try to add to empty slot
	for (var i = 0; i < INVENTORY_SIZE; i++) {
		if (inventory[i].type === BLOCK_AIR) {
			inventory[i].type = type;
			inventory[i].count = count;
			return true;
		}
	}
	return false;
}
// Remove from inventory
function removeFromInventory(type, count) {
	for (var i = 0; i < INVENTORY_SIZE; i++) {
		if (inventory[i].type === type && inventory[i].count > 0) {
			var take = Math.min(count, inventory[i].count);
			inventory[i].count -= take;
			count -= take;
			if (inventory[i].count === 0) inventory[i].type = BLOCK_AIR;
			if (count <= 0) return true;
		}
	}
	return false;
}
// Mining/placing logic
function mineBlock(x, y) {
	if (x < 0 || x >= WORLD_WIDTH || y < 0 || y >= WORLD_HEIGHT) return;
	if (!world[x]) return;
	var type = world[x][y];
	if (type === BLOCK_AIR) return;
	if (!BLOCK_MINEABLE[type]) return;
	// Remove block
	world[x][y] = BLOCK_AIR;
	blockSprites[x][y].setBlock(BLOCK_AIR);
	// Drop item
	var drop = BLOCK_DROPS[type];
	if (drop) addToInventory(drop, 1);
	updateInventoryUI();
	showBlockName(type);
}
function placeBlock(x, y) {
	if (x < 0 || x >= WORLD_WIDTH || y < 0 || y >= WORLD_HEIGHT) return;
	if (world[x][y] !== BLOCK_AIR) return;
	var inv = inventory[selectedSlot];
	if (inv.type === BLOCK_AIR) return;
	if (!BLOCK_PLACEABLE[inv.type]) return;
	// Place block
	world[x][y] = inv.type;
	blockSprites[x][y].setBlock(inv.type);
	removeFromInventory(inv.type, 1);
	updateInventoryUI();
	showBlockName(inv.type);
}
// Touch/mouse events
game.down = function (x, y, obj) {
	if (showCrafting) return;
	dragStartX = x;
	dragStartY = y;
	// Convert to world block
	var wx = Math.floor((x + cameraX) / BLOCK_SIZE);
	var wy = Math.floor((y + cameraY) / BLOCK_SIZE);
	// If tap on player, open crafting if standing on crafting table
	if (wx === playerX && wy === playerY - 1 && world[playerX][playerY - 1] === BLOCK_CRAFTING) {
		showCraftingPanel();
		return;
	}
	// Mouse/touch controls for moving player: tap left/right block to move
	if (wx === player.xIndex - 1 && wy === player.yIndex) {
		movePlayer(-1, 0);
		return;
	}
	if (wx === player.xIndex + 1 && wy === player.yIndex) {
		movePlayer(1, 0);
		return;
	}
	if (wx === player.xIndex && wy === player.yIndex - 1) {
		movePlayer(0, -1);
		return;
	}
	// If tap on zombie: attack!
	var attackedZombie = false;
	for (var i = zombies.length - 1; i >= 0; i--) {
		var z = zombies[i];
		if (z.xIndex === wx && z.yIndex === wy) {
			if (player && player.attack) player.attack();
			attackedZombie = true;
			break;
		}
	}
	// If not attacking a zombie, mine/place as usual
	if (!attackedZombie && world[wx] && world[wx][wy] !== undefined) {
		if (world[wx][wy] !== BLOCK_AIR) {
			mineBlock(wx, wy);
			isMining = true;
		} else {
			placeBlock(wx, wy);
			isPlacing = true;
		}
	}
};
game.up = function (x, y, obj) {
	isMining = false;
	isPlacing = false;
	dragStartX = null;
	dragStartY = null;
};
game.move = function (x, y, obj) {
	if (showCrafting) return;
	if (dragStartX === null) return;
	var wx = Math.floor((x + cameraX) / BLOCK_SIZE);
	var wy = Math.floor((y + cameraY) / BLOCK_SIZE);
	if (isMining) {
		mineBlock(wx, wy);
	} else if (isPlacing) {
		placeBlock(wx, wy);
	}
};
// Inventory tap
function onInventoryTap(i) {
	selectedSlot = i;
	updateInventoryUI();
}
// Crafting tap
function onCraftingTap(i) {
	var recipe = RECIPES[i];
	// Remove inputs
	for (var j = 0; j < recipe.inputs.length; j++) {
		removeFromInventory(recipe.inputs[j][0], recipe.inputs[j][1]);
	}
	// Add output
	addToInventory(recipe.output[0], recipe.output[1]);
	updateInventoryUI();
	showCraftingPanel();
}
// Close crafting
function onCloseCrafting() {
	hideCraftingPanel();
}
// Move player left/right/jump
function movePlayer(dx, dy) {
	if (!player) return;
	if (dx !== 0) {
		player.move(dx, 0);
	}
	if (dy !== 0) {
		// Only allow jump if moving up
		if (dy < 0) player.jump();
	}
	updateCamera();
}
// Gravity
function applyGravity() {
	if (!player) return;
	player.applyGravity();
	updateCamera();
}
// Day-night cycle
function updateDayNight() {
	dayTicks++;
	if (dayTicks >= DAY_LENGTH) dayTicks = 0;
	// Fade to dark at night
	var t = dayTicks / DAY_LENGTH * 2 * Math.PI;
	var night = (Math.cos(t) + 1) / 2;
	var overlay = 0x000000;
	var alpha = 0.2 + 0.5 * night;
	if (!game.nightOverlay) {
		game.nightOverlay = LK.getAsset('nightOverlay', {
			width: 2048,
			height: 2732,
			color: overlay,
			shape: 'box',
			anchorX: 0,
			anchorY: 0
		});
		game.nightOverlay.alpha = alpha;
		game.addChild(game.nightOverlay);
	}
	game.nightOverlay.alpha = alpha;
	game.nightOverlay.zIndex = 9999;
}
// GUI
function setupGUI() {
	// Inventory bar
	for (var i = 0; i < INVENTORY_SIZE; i++) {
		var node = new Container();
		node.x = 300 + i * 130;
		node.y = 2632;
		node.asset = node.attachAsset('inv_' + i, {
			width: 90,
			height: 90,
			color: 0x222222,
			shape: 'box',
			anchorX: 0,
			anchorY: 0
		});
		node.countText = new Text2("", {
			size: 40,
			fill: "#fff"
		});
		node.countText.x = 60;
		node.countText.y = 50;
		node.addChild(node.countText);
		node.interactive = true;
		(function (idx) {
			node.down = function (x, y, obj) {
				onInventoryTap(idx);
			};
		})(i);
		LK.gui.bottom.addChild(node);
		inventoryNodes.push(node);
	}
	// Selected rect
	selectedRect = LK.getAsset('selectedRect', {
		width: 100,
		height: 100,
		color: 0xffff00,
		shape: 'box',
		anchorX: 0,
		anchorY: 0
	});
	selectedRect.alpha = 0.3;
	LK.gui.bottom.addChild(selectedRect);
	// Block name text
	blockNameText = new Text2("", {
		size: 60,
		fill: "#fff"
	});
	blockNameText.x = 1024;
	blockNameText.y = 100;
	blockNameText.anchor.set(0.5, 0);
	LK.gui.top.addChild(blockNameText);
	// Crafting panel
	craftingPanel = new Container();
	craftingPanel.x = 400;
	craftingPanel.y = 800;
	var panelBg = craftingPanel.attachAsset('craftingBg', {
		width: 1200,
		height: 900,
		color: 0x333333,
		shape: 'box',
		anchorX: 0,
		anchorY: 0
	});
	var title = new Text2("Crafting", {
		size: 80,
		fill: "#fff"
	});
	title.x = 600;
	title.y = 60;
	title.anchor.set(0.5, 0);
	craftingPanel.addChild(title);
	// Recipe buttons
	for (var i = 0; i < RECIPES.length; i++) {
		var btn = new Container();
		btn.x = 100;
		btn.y = 180 + i * 200;
		btn.bg = btn.attachAsset('craftBtn' + i, {
			width: 1000,
			height: 160,
			color: 0x555555,
			shape: 'box',
			anchorX: 0,
			anchorY: 0
		});
		var txt = new Text2("Craft " + BLOCK_NAMES[RECIPES[i].output[0]], {
			size: 50,
			fill: "#fff"
		});
		txt.x = 500;
		txt.y = 40;
		txt.anchor.set(0.5, 0);
		btn.addChild(txt);
		btn.interactive = true;
		(function (idx) {
			btn.down = function (x, y, obj) {
				onCraftingTap(idx);
			};
		})(i);
		craftingPanel.addChild(btn);
		craftingButtons.push(btn);
	}
	// Close button
	var closeBtn = new Container();
	closeBtn.x = 1050;
	closeBtn.y = 60;
	closeBtn.bg = closeBtn.attachAsset('closeBtn', {
		width: 100,
		height: 100,
		color: 0xaa2222,
		shape: 'box',
		anchorX: 0,
		anchorY: 0
	});
	var closeTxt = new Text2("X", {
		size: 70,
		fill: "#fff"
	});
	closeTxt.x = 50;
	closeTxt.y = 15;
	closeTxt.anchor.set(0.5, 0);
	closeBtn.addChild(closeTxt);
	closeBtn.interactive = true;
	closeBtn.down = function (x, y, obj) {
		onCloseCrafting();
	};
	craftingPanel.addChild(closeBtn);
	craftingPanel.visible = false;
	LK.gui.center.addChild(craftingPanel);
}
// Controls
function setupControls() {
	// Left button
	var leftBtn = new Container();
	leftBtn.x = 100;
	leftBtn.y = 2500;
	leftBtn.bg = leftBtn.attachAsset('leftBtn', {
		width: 120,
		height: 120,
		color: 0x444444,
		shape: 'box',
		anchorX: 0,
		anchorY: 0
	});
	var ltxt = new Text2("<", {
		size: 80,
		fill: "#fff"
	});
	ltxt.x = 60;
	ltxt.y = 20;
	ltxt.anchor.set(0.5, 0);
	leftBtn.addChild(ltxt);
	leftBtn.interactive = true;
	leftBtn.down = function (x, y, obj) {
		movePlayer(-1, 0);
	};
	LK.gui.bottomLeft.addChild(leftBtn);
	// Right button
	var rightBtn = new Container();
	rightBtn.x = 350;
	rightBtn.y = 2500;
	rightBtn.bg = rightBtn.attachAsset('rightBtn', {
		width: 120,
		height: 120,
		color: 0x444444,
		shape: 'box',
		anchorX: 0,
		anchorY: 0
	});
	var rtxt = new Text2(">", {
		size: 80,
		fill: "#fff"
	});
	rtxt.x = 60;
	rtxt.y = 20;
	rtxt.anchor.set(0.5, 0);
	rightBtn.addChild(rtxt);
	rightBtn.interactive = true;
	rightBtn.down = function (x, y, obj) {
		movePlayer(1, 0);
	};
	LK.gui.bottomLeft.addChild(rightBtn);
	// Jump button
	var jumpBtn = new Container();
	jumpBtn.x = 1800;
	jumpBtn.y = 2500;
	jumpBtn.bg = jumpBtn.attachAsset('jumpBtn', {
		width: 120,
		height: 120,
		color: 0x444444,
		shape: 'box',
		anchorX: 0,
		anchorY: 0
	});
	var jtxt = new Text2("^", {
		size: 80,
		fill: "#fff"
	});
	jtxt.x = 60;
	jtxt.y = 20;
	jtxt.anchor.set(0.5, 0);
	jumpBtn.addChild(jtxt);
	jumpBtn.interactive = true;
	jumpBtn.down = function (x, y, obj) {
		movePlayer(0, -1);
	};
	LK.gui.bottomRight.addChild(jumpBtn);
}
// Main update
game.update = function () {
	// Gravity
	applyGravity();
	// Zombies update
	for (var i = 0; i < zombies.length; i++) {
		var z = zombies[i];
		// Save last position for event logic
		z.lastXIndex = z.xIndex;
		z.lastYIndex = z.yIndex;
		var wasTouching = z.lastWasTouchingPlayer;
		// AI and gravity
		z.ai();
		z.applyGravity();
		if (z.update) z.update();
		// Check collision with player (only trigger on first frame of contact)
		var touching = z.isTouchingPlayer();
		if (!wasTouching && touching) {
			// Flash screen red and show game over
			LK.effects.flashScreen(0xff0000, 1000);
			LK.showGameOver();
		}
		z.lastWasTouchingPlayer = touching;
	}
	// Camera
	updateCamera();
	// Day-night
	updateDayNight();
};
// Init
generateWorld();
if (player && player.update) player.update();
updateCamera();
setupGUI();
setupControls();
updateInventoryUI(); ===================================================================
--- original.js
+++ change.js
@@ -359,8 +359,9 @@
 }
 // Mining/placing logic
 function mineBlock(x, y) {
 	if (x < 0 || x >= WORLD_WIDTH || y < 0 || y >= WORLD_HEIGHT) return;
+	if (!world[x]) return;
 	var type = world[x][y];
 	if (type === BLOCK_AIR) return;
 	if (!BLOCK_MINEABLE[type]) return;
 	// Remove block