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; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var playerAsset = self.attachAsset('player', { width: BLOCK_SIZE * 0.8, height: BLOCK_SIZE * 0.9, color: 0xFFDAB9, shape: 'box', anchorX: 0.5, anchorY: 1 }); self.update = function () { // nothing for now }; 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 = []; // 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][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); function updatePlayerPos() { player.x = playerX * BLOCK_SIZE + BLOCK_SIZE / 2; player.y = playerY * BLOCK_SIZE + BLOCK_SIZE; } // Camera function updateCamera() { // Center on player, clamp to world cameraX = player.x - 2048 / 2; cameraY = player.y - 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 and player 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.x = playerX * BLOCK_SIZE + BLOCK_SIZE / 2 - cameraX; player.y = playerY * BLOCK_SIZE + BLOCK_SIZE - cameraY; } // 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; 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; } // If tap on block: mine if not air, else place if (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) { var nx = playerX + dx; var ny = playerY + dy; if (nx < 0 || nx >= WORLD_WIDTH || ny < 0 || ny >= WORLD_HEIGHT) return; // Only move if not blocked if (world[nx][ny] === BLOCK_AIR) { playerX = nx; playerY = ny; playerDir = dx > 0 ? 1 : -1; updatePlayerPos(); updateCamera(); } } // Gravity function applyGravity() { if (playerY + 1 < WORLD_HEIGHT && world[playerX][playerY + 1] === BLOCK_AIR) { playerY++; updatePlayerPos(); 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(); // Camera updateCamera(); // Day-night updateDayNight(); }; // Init generateWorld(); updatePlayerPos(); updateCamera(); setupGUI(); setupControls(); updateInventoryUI();
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,680 @@
-/****
+/****
+* 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;
+});
+// Player class
+var Player = Container.expand(function () {
+ var self = Container.call(this);
+ var playerAsset = self.attachAsset('player', {
+ width: BLOCK_SIZE * 0.8,
+ height: BLOCK_SIZE * 0.9,
+ color: 0xFFDAB9,
+ shape: 'box',
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ self.update = function () {
+ // nothing for now
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ 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 = [];
+// 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][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);
+function updatePlayerPos() {
+ player.x = playerX * BLOCK_SIZE + BLOCK_SIZE / 2;
+ player.y = playerY * BLOCK_SIZE + BLOCK_SIZE;
+}
+// Camera
+function updateCamera() {
+ // Center on player, clamp to world
+ cameraX = player.x - 2048 / 2;
+ cameraY = player.y - 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 and player
+ 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.x = playerX * BLOCK_SIZE + BLOCK_SIZE / 2 - cameraX;
+ player.y = playerY * BLOCK_SIZE + BLOCK_SIZE - cameraY;
+}
+// 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;
+ 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;
+ }
+ // If tap on block: mine if not air, else place
+ if (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) {
+ var nx = playerX + dx;
+ var ny = playerY + dy;
+ if (nx < 0 || nx >= WORLD_WIDTH || ny < 0 || ny >= WORLD_HEIGHT) return;
+ // Only move if not blocked
+ if (world[nx][ny] === BLOCK_AIR) {
+ playerX = nx;
+ playerY = ny;
+ playerDir = dx > 0 ? 1 : -1;
+ updatePlayerPos();
+ updateCamera();
+ }
+}
+// Gravity
+function applyGravity() {
+ if (playerY + 1 < WORLD_HEIGHT && world[playerX][playerY + 1] === BLOCK_AIR) {
+ playerY++;
+ updatePlayerPos();
+ 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();
+ // Camera
+ updateCamera();
+ // Day-night
+ updateDayNight();
+};
+// Init
+generateWorld();
+updatePlayerPos();
+updateCamera();
+setupGUI();
+setupControls();
+updateInventoryUI();
\ No newline at end of file