/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { worldData: undefined, inventory: { dirt: 0, stone: 0, wood: 0, special: 0 } }); /**** * Classes ****/ var Block = Container.expand(function (type, solid) { var self = Container.call(this); self.type = type || 'dirt'; self.solid = solid !== undefined ? solid : true; var colors = { 'dirt': 0x8B4513, 'stone': 0x777777, 'wood': 0x8B5A2B, 'special': 0x00BFFF }; // Create block graphic var blockGraphic = self.attachAsset(self.type + 'Block', { anchorX: 0.5, anchorY: 0.5 }); // Make block interactive for mining self.interactive = true; self.down = function (x, y, obj) { if (self.solid && currentTool === 'mine') { // Mine the block LK.getSound('mine').play(); // Add to inventory storage.inventory[self.type]++; updateInventoryDisplay(); // Remove block from world var gridPos = worldToGrid(self.x, self.y); worldGrid[gridPos.y][gridPos.x] = null; self.destroy(); // Check surrounding blocks for physics updates checkPhysics(gridPos.x, gridPos.y - 1); } }; return self; }); var InventorySlot = Container.expand(function (index, type) { var self = Container.call(this); self.index = index; self.type = type; // Create background slot var slotGraphic = self.attachAsset('inventorySlot', { anchorX: 0.5, anchorY: 0.5 }); // Create block preview if this slot has a block type if (type) { var blockPreview = self.attachAsset(type + 'Block', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); } // Create count text self.countText = new Text2('0', { size: 30, fill: 0xFFFFFF }); self.countText.anchor.set(1, 1); self.countText.x = 40; self.countText.y = 40; self.addChild(self.countText); self.updateCount = function (count) { self.countText.setText(count.toString()); }; self.setSelected = function (selected) { if (selected) { slotGraphic.tint = 0xFFFFFF; tween(slotGraphic, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200 }); } else { slotGraphic.tint = 0xAAAAAA; tween(slotGraphic, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }; // Make slot interactive self.interactive = true; self.down = function (x, y, obj) { selectInventorySlot(self.index); }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphic = self.attachAsset('playerShape', { anchorX: 0.5, anchorY: 0.5 }); self.velocity = { x: 0, y: 0 }; self.grounded = false; self.speed = 8; self.gravity = 0.5; self.jumpStrength = 12; self.update = function () { // Apply gravity if (!self.grounded) { self.velocity.y += self.gravity; } else { self.velocity.y = 0; } // Apply movement self.x += self.velocity.x; self.y += self.velocity.y; // Check for collisions checkPlayerCollisions(); // Keep player in bounds if (self.x < 50) { self.x = 50; } if (self.x > worldWidth * blockSize - 50) { self.x = worldWidth * blockSize - 50; } if (self.y < 50) { self.y = 50; } if (self.y > worldHeight * blockSize - 50) { self.y = worldHeight * blockSize - 50; } // Update camera to follow player updateCamera(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Constants var blockSize = 100; var worldWidth = 50; var worldHeight = 30; var gravity = 0.5; var jumpStrength = 12; // Game state var worldGrid = []; var player = null; var camera = { x: 0, y: 0 }; var currentTool = 'mine'; // 'mine' or 'place' var selectedBlockType = null; var selectedInventorySlot = 0; var inventorySlots = []; var worldContainer = null; var uiContainer = null; var currentlyDragging = false; var dragStartX = 0; var dragStartY = 0; // Initialize world function initWorld() { // If we have saved world data, use it if (storage.worldData) { worldGrid = storage.worldData; } else { // Generate new world generateWorld(); } // Create a container for all world elements worldContainer = new Container(); game.addChild(worldContainer); // Create blocks based on world grid for (var y = 0; y < worldHeight; y++) { for (var x = 0; x < worldWidth; x++) { if (worldGrid[y][x]) { var block = new Block(worldGrid[y][x], true); block.x = x * blockSize + blockSize / 2; block.y = y * blockSize + blockSize / 2; worldContainer.addChild(block); } } } // Create player player = new Player(); player.x = worldWidth * blockSize / 2; player.y = 500; worldContainer.addChild(player); // Initialize UI initUI(); // Apply initial camera position updateCamera(); // Start music LK.playMusic('gameMusic'); } function generateWorld() { // Initialize empty grid for (var y = 0; y < worldHeight; y++) { worldGrid[y] = []; for (var x = 0; x < worldWidth; x++) { worldGrid[y][x] = null; } } // Generate ground var groundHeight = Math.floor(worldHeight * 0.7); for (var x = 0; x < worldWidth; x++) { // Surface layer worldGrid[groundHeight][x] = 'dirt'; // Dirt layer (3 blocks) for (var d = 1; d < 4; d++) { if (groundHeight + d < worldHeight) { worldGrid[groundHeight + d][x] = 'dirt'; } } // Stone layer (below dirt) for (var s = 4; s < worldHeight - groundHeight; s++) { if (groundHeight + s < worldHeight) { worldGrid[groundHeight + s][x] = 'stone'; } } } // Generate some trees generateTrees(groundHeight); // Generate some special blocks generateSpecialBlocks(groundHeight); } function generateTrees(groundHeight) { var treePositions = []; var treeCount = Math.floor(worldWidth / 10); // Generate random tree positions for (var i = 0; i < treeCount; i++) { var treeX = Math.floor(Math.random() * (worldWidth - 4)) + 2; treePositions.push(treeX); } // Create trees for (var t = 0; t < treePositions.length; t++) { var x = treePositions[t]; var treeHeight = Math.floor(Math.random() * 3) + 3; // Tree trunk for (var h = 1; h <= treeHeight; h++) { worldGrid[groundHeight - h][x] = 'wood'; } // Tree leaves worldGrid[groundHeight - treeHeight - 1][x] = 'wood'; if (x > 0) { worldGrid[groundHeight - treeHeight][x - 1] = 'wood'; } if (x < worldWidth - 1) { worldGrid[groundHeight - treeHeight][x + 1] = 'wood'; } } } function generateSpecialBlocks(groundHeight) { var specialCount = Math.floor(worldWidth / 15); for (var i = 0; i < specialCount; i++) { var x = Math.floor(Math.random() * worldWidth); var y = Math.floor(Math.random() * (worldHeight - groundHeight - 5)) + groundHeight + 3; worldGrid[y][x] = 'special'; } } function initUI() { // Create UI container uiContainer = new Container(); game.addChild(uiContainer); // Create inventory bar var inventoryBar = LK.getAsset('inventoryBar', { anchorX: 0.5, anchorY: 0.5 }); inventoryBar.x = 2048 / 2; inventoryBar.y = 2732 - 70; uiContainer.addChild(inventoryBar); // Create inventory slots var slotTypes = ['dirt', 'stone', 'wood', 'special']; for (var i = 0; i < 4; i++) { var slot = new InventorySlot(i, slotTypes[i]); slot.x = 2048 / 2 - 300 + i * 200; slot.y = 2732 - 70; inventorySlots.push(slot); uiContainer.addChild(slot); } // Create tool toggle button var toolButton = new Text2("MINE", { size: 50, fill: 0xFFFFFF }); toolButton.anchor.set(0.5, 0.5); toolButton.x = 2048 - 150; toolButton.y = 2732 - 70; toolButton.interactive = true; toolButton.down = function (x, y, obj) { if (currentTool === 'mine') { currentTool = 'place'; toolButton.setText("PLACE"); } else { currentTool = 'mine'; toolButton.setText("MINE"); } }; uiContainer.addChild(toolButton); // Select the first inventory slot by default selectInventorySlot(0); // Update inventory display updateInventoryDisplay(); } function updateInventoryDisplay() { var slotTypes = ['dirt', 'stone', 'wood', 'special']; for (var i = 0; i < inventorySlots.length; i++) { inventorySlots[i].updateCount(storage.inventory[slotTypes[i]]); } } function selectInventorySlot(index) { // Deselect previous slot if (selectedInventorySlot !== null) { inventorySlots[selectedInventorySlot].setSelected(false); } // Select new slot selectedInventorySlot = index; inventorySlots[selectedInventorySlot].setSelected(true); // Set selected block type var slotTypes = ['dirt', 'stone', 'wood', 'special']; selectedBlockType = slotTypes[selectedInventorySlot]; } function worldToGrid(worldX, worldY) { return { x: Math.floor(worldX / blockSize), y: Math.floor(worldY / blockSize) }; } function gridToWorld(gridX, gridY) { return { x: gridX * blockSize + blockSize / 2, y: gridY * blockSize + blockSize / 2 }; } function checkPlayerCollisions() { // Get player bounds var playerWidth = 80; var playerHeight = 180; var playerLeft = player.x - playerWidth / 2; var playerRight = player.x + playerWidth / 2; var playerTop = player.y - playerHeight / 2; var playerBottom = player.y + playerHeight / 2; // Get surrounding grid cells var gridX = Math.floor(player.x / blockSize); var gridY = Math.floor(player.y / blockSize); // Check each surrounding cell player.grounded = false; for (var y = Math.max(0, gridY - 2); y <= Math.min(worldHeight - 1, gridY + 2); y++) { for (var x = Math.max(0, gridX - 2); x <= Math.min(worldWidth - 1, gridX + 2); x++) { // Skip empty cells if (!worldGrid[y][x]) { continue; } // Calculate block bounds var blockLeft = x * blockSize; var blockRight = blockLeft + blockSize; var blockTop = y * blockSize; var blockBottom = blockTop + blockSize; // Check for collision if (playerRight > blockLeft && playerLeft < blockRight && playerBottom > blockTop && playerTop < blockBottom) { // Calculate overlap var overlapLeft = playerRight - blockLeft; var overlapRight = blockRight - playerLeft; var overlapTop = playerBottom - blockTop; var overlapBottom = blockBottom - playerTop; // Find smallest overlap var minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom); // Resolve collision if (minOverlap === overlapTop) { player.y -= overlapTop; player.velocity.y = 0; player.grounded = true; } else if (minOverlap === overlapBottom) { player.y += overlapBottom; player.velocity.y = 0; } else if (minOverlap === overlapLeft) { player.x -= overlapLeft; player.velocity.x = 0; } else if (minOverlap === overlapRight) { player.x += overlapRight; player.velocity.x = 0; } } } } } function updateCamera() { // Calculate target camera position (centered on player) var targetX = player.x - 2048 / 2; var targetY = player.y - 2732 / 2; // Apply camera constraints targetX = Math.max(0, Math.min(targetX, worldWidth * blockSize - 2048)); targetY = Math.max(0, Math.min(targetY, worldHeight * blockSize - 2732)); // Smooth camera movement camera.x = targetX; camera.y = targetY; // Apply camera position to world container worldContainer.x = -camera.x; worldContainer.y = -camera.y; } function checkPhysics(x, y) { // Skip if out of bounds if (x < 0 || x >= worldWidth || y < 0 || y >= worldHeight) { return; } // Skip if empty if (!worldGrid[y][x]) { return; } // Skip if supported if (y + 1 < worldHeight && worldGrid[y + 1][x]) { return; } // Block is unsupported, apply gravity applyGravityToBlock(x, y); } function applyGravityToBlock(x, y) { // Skip special blocks (they don't fall) if (worldGrid[y][x] === 'special') { return; } // Find all world objects at this position var blockToMove = null; for (var i = 0; i < worldContainer.children.length; i++) { var child = worldContainer.children[i]; if (child instanceof Block) { var gridPos = worldToGrid(child.x, child.y); if (gridPos.x === x && gridPos.y === y) { blockToMove = child; break; } } } if (!blockToMove) { return; } // Remove from current position worldGrid[y][x] = null; // Find landing position var newY = y; while (newY + 1 < worldHeight && !worldGrid[newY + 1][x]) { newY++; } // Update grid worldGrid[newY][x] = blockToMove.type; // Animate block falling tween(blockToMove, { y: newY * blockSize + blockSize / 2 }, { duration: (newY - y) * 100, easing: tween.easeIn, onFinish: function onFinish() { // Check surrounding blocks for more physics updates checkPhysics(x, newY - 1); checkPhysics(x - 1, newY); checkPhysics(x + 1, newY); } }); } // Handle player movement and game interaction var leftPressed = false; var rightPressed = false; var moveTimer = null; function handleGameClick(x, y, obj) { // Convert screen position to world position var worldX = x + camera.x; var worldY = y + camera.y; // Convert to grid position var gridPos = worldToGrid(worldX, worldY); // Check if position is within grid bounds if (gridPos.x < 0 || gridPos.x >= worldWidth || gridPos.y < 0 || gridPos.y >= worldHeight) { return; } if (currentTool === 'place' && selectedBlockType) { // Check if we have blocks of this type in inventory if (storage.inventory[selectedBlockType] > 0) { // Check if position is empty if (!worldGrid[gridPos.y][gridPos.x]) { // Check if position is within reach of player var playerGridPos = worldToGrid(player.x, player.y); var distance = Math.sqrt(Math.pow(playerGridPos.x - gridPos.x, 2) + Math.pow(playerGridPos.y - gridPos.y, 2)); if (distance <= 5) { // Place block worldGrid[gridPos.y][gridPos.x] = selectedBlockType; // Create block var block = new Block(selectedBlockType, true); block.x = gridPos.x * blockSize + blockSize / 2; block.y = gridPos.y * blockSize + blockSize / 2; worldContainer.addChild(block); // Remove from inventory storage.inventory[selectedBlockType]--; updateInventoryDisplay(); // Play sound LK.getSound('place').play(); // Save world storage.worldData = worldGrid; // Check physics checkPhysics(gridPos.x, gridPos.y - 1); } } } } } function startMovingLeft() { leftPressed = true; if (!moveTimer) { moveTimer = LK.setInterval(movePlayer, 16); } } function startMovingRight() { rightPressed = true; if (!moveTimer) { moveTimer = LK.setInterval(movePlayer, 16); } } function stopMovingLeft() { leftPressed = false; if (!leftPressed && !rightPressed && moveTimer) { LK.clearInterval(moveTimer); moveTimer = null; player.velocity.x = 0; } } function stopMovingRight() { rightPressed = false; if (!leftPressed && !rightPressed && moveTimer) { LK.clearInterval(moveTimer); moveTimer = null; player.velocity.x = 0; } } function movePlayer() { if (leftPressed) { player.velocity.x = -player.speed; } else if (rightPressed) { player.velocity.x = player.speed; } else { player.velocity.x = 0; } } function jump() { if (player.grounded) { player.velocity.y = -player.jumpStrength; player.grounded = false; } } // Game event handlers game.down = function (x, y, obj) { // Check if click is on UI var isUIClick = false; for (var i = 0; i < uiContainer.children.length; i++) { if (uiContainer.children[i].intersects({ x: x, y: y })) { isUIClick = true; break; } } if (!isUIClick) { // Handle game world interaction handleGameClick(x, y, obj); // Start drag for player movement currentlyDragging = true; dragStartX = x; dragStartY = y; } }; game.up = function (x, y, obj) { if (currentlyDragging) { currentlyDragging = false; stopMovingLeft(); stopMovingRight(); // Check if this was a tap (not a drag) var dx = Math.abs(x - dragStartX); var dy = Math.abs(y - dragStartY); if (dx < 20 && dy < 20) { // This was a tap, check if we should jump if (y < 2732 / 2) { jump(); } } } }; game.move = function (x, y, obj) { if (currentlyDragging) { var dx = x - dragStartX; if (dx < -30) { startMovingLeft(); } else if (dx > 30) { startMovingRight(); } else { stopMovingLeft(); stopMovingRight(); } } }; // Game update function game.update = function () { // Skip if player not initialized yet if (!player) { return; } // Player and physics updates happen automatically through the Player class }; // Initialize game initWorld();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
worldData: undefined,
inventory: {
dirt: 0,
stone: 0,
wood: 0,
special: 0
}
});
/****
* Classes
****/
var Block = Container.expand(function (type, solid) {
var self = Container.call(this);
self.type = type || 'dirt';
self.solid = solid !== undefined ? solid : true;
var colors = {
'dirt': 0x8B4513,
'stone': 0x777777,
'wood': 0x8B5A2B,
'special': 0x00BFFF
};
// Create block graphic
var blockGraphic = self.attachAsset(self.type + 'Block', {
anchorX: 0.5,
anchorY: 0.5
});
// Make block interactive for mining
self.interactive = true;
self.down = function (x, y, obj) {
if (self.solid && currentTool === 'mine') {
// Mine the block
LK.getSound('mine').play();
// Add to inventory
storage.inventory[self.type]++;
updateInventoryDisplay();
// Remove block from world
var gridPos = worldToGrid(self.x, self.y);
worldGrid[gridPos.y][gridPos.x] = null;
self.destroy();
// Check surrounding blocks for physics updates
checkPhysics(gridPos.x, gridPos.y - 1);
}
};
return self;
});
var InventorySlot = Container.expand(function (index, type) {
var self = Container.call(this);
self.index = index;
self.type = type;
// Create background slot
var slotGraphic = self.attachAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5
});
// Create block preview if this slot has a block type
if (type) {
var blockPreview = self.attachAsset(type + 'Block', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
}
// Create count text
self.countText = new Text2('0', {
size: 30,
fill: 0xFFFFFF
});
self.countText.anchor.set(1, 1);
self.countText.x = 40;
self.countText.y = 40;
self.addChild(self.countText);
self.updateCount = function (count) {
self.countText.setText(count.toString());
};
self.setSelected = function (selected) {
if (selected) {
slotGraphic.tint = 0xFFFFFF;
tween(slotGraphic, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200
});
} else {
slotGraphic.tint = 0xAAAAAA;
tween(slotGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
};
// Make slot interactive
self.interactive = true;
self.down = function (x, y, obj) {
selectInventorySlot(self.index);
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphic = self.attachAsset('playerShape', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocity = {
x: 0,
y: 0
};
self.grounded = false;
self.speed = 8;
self.gravity = 0.5;
self.jumpStrength = 12;
self.update = function () {
// Apply gravity
if (!self.grounded) {
self.velocity.y += self.gravity;
} else {
self.velocity.y = 0;
}
// Apply movement
self.x += self.velocity.x;
self.y += self.velocity.y;
// Check for collisions
checkPlayerCollisions();
// Keep player in bounds
if (self.x < 50) {
self.x = 50;
}
if (self.x > worldWidth * blockSize - 50) {
self.x = worldWidth * blockSize - 50;
}
if (self.y < 50) {
self.y = 50;
}
if (self.y > worldHeight * blockSize - 50) {
self.y = worldHeight * blockSize - 50;
}
// Update camera to follow player
updateCamera();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Constants
var blockSize = 100;
var worldWidth = 50;
var worldHeight = 30;
var gravity = 0.5;
var jumpStrength = 12;
// Game state
var worldGrid = [];
var player = null;
var camera = {
x: 0,
y: 0
};
var currentTool = 'mine'; // 'mine' or 'place'
var selectedBlockType = null;
var selectedInventorySlot = 0;
var inventorySlots = [];
var worldContainer = null;
var uiContainer = null;
var currentlyDragging = false;
var dragStartX = 0;
var dragStartY = 0;
// Initialize world
function initWorld() {
// If we have saved world data, use it
if (storage.worldData) {
worldGrid = storage.worldData;
} else {
// Generate new world
generateWorld();
}
// Create a container for all world elements
worldContainer = new Container();
game.addChild(worldContainer);
// Create blocks based on world grid
for (var y = 0; y < worldHeight; y++) {
for (var x = 0; x < worldWidth; x++) {
if (worldGrid[y][x]) {
var block = new Block(worldGrid[y][x], true);
block.x = x * blockSize + blockSize / 2;
block.y = y * blockSize + blockSize / 2;
worldContainer.addChild(block);
}
}
}
// Create player
player = new Player();
player.x = worldWidth * blockSize / 2;
player.y = 500;
worldContainer.addChild(player);
// Initialize UI
initUI();
// Apply initial camera position
updateCamera();
// Start music
LK.playMusic('gameMusic');
}
function generateWorld() {
// Initialize empty grid
for (var y = 0; y < worldHeight; y++) {
worldGrid[y] = [];
for (var x = 0; x < worldWidth; x++) {
worldGrid[y][x] = null;
}
}
// Generate ground
var groundHeight = Math.floor(worldHeight * 0.7);
for (var x = 0; x < worldWidth; x++) {
// Surface layer
worldGrid[groundHeight][x] = 'dirt';
// Dirt layer (3 blocks)
for (var d = 1; d < 4; d++) {
if (groundHeight + d < worldHeight) {
worldGrid[groundHeight + d][x] = 'dirt';
}
}
// Stone layer (below dirt)
for (var s = 4; s < worldHeight - groundHeight; s++) {
if (groundHeight + s < worldHeight) {
worldGrid[groundHeight + s][x] = 'stone';
}
}
}
// Generate some trees
generateTrees(groundHeight);
// Generate some special blocks
generateSpecialBlocks(groundHeight);
}
function generateTrees(groundHeight) {
var treePositions = [];
var treeCount = Math.floor(worldWidth / 10);
// Generate random tree positions
for (var i = 0; i < treeCount; i++) {
var treeX = Math.floor(Math.random() * (worldWidth - 4)) + 2;
treePositions.push(treeX);
}
// Create trees
for (var t = 0; t < treePositions.length; t++) {
var x = treePositions[t];
var treeHeight = Math.floor(Math.random() * 3) + 3;
// Tree trunk
for (var h = 1; h <= treeHeight; h++) {
worldGrid[groundHeight - h][x] = 'wood';
}
// Tree leaves
worldGrid[groundHeight - treeHeight - 1][x] = 'wood';
if (x > 0) {
worldGrid[groundHeight - treeHeight][x - 1] = 'wood';
}
if (x < worldWidth - 1) {
worldGrid[groundHeight - treeHeight][x + 1] = 'wood';
}
}
}
function generateSpecialBlocks(groundHeight) {
var specialCount = Math.floor(worldWidth / 15);
for (var i = 0; i < specialCount; i++) {
var x = Math.floor(Math.random() * worldWidth);
var y = Math.floor(Math.random() * (worldHeight - groundHeight - 5)) + groundHeight + 3;
worldGrid[y][x] = 'special';
}
}
function initUI() {
// Create UI container
uiContainer = new Container();
game.addChild(uiContainer);
// Create inventory bar
var inventoryBar = LK.getAsset('inventoryBar', {
anchorX: 0.5,
anchorY: 0.5
});
inventoryBar.x = 2048 / 2;
inventoryBar.y = 2732 - 70;
uiContainer.addChild(inventoryBar);
// Create inventory slots
var slotTypes = ['dirt', 'stone', 'wood', 'special'];
for (var i = 0; i < 4; i++) {
var slot = new InventorySlot(i, slotTypes[i]);
slot.x = 2048 / 2 - 300 + i * 200;
slot.y = 2732 - 70;
inventorySlots.push(slot);
uiContainer.addChild(slot);
}
// Create tool toggle button
var toolButton = new Text2("MINE", {
size: 50,
fill: 0xFFFFFF
});
toolButton.anchor.set(0.5, 0.5);
toolButton.x = 2048 - 150;
toolButton.y = 2732 - 70;
toolButton.interactive = true;
toolButton.down = function (x, y, obj) {
if (currentTool === 'mine') {
currentTool = 'place';
toolButton.setText("PLACE");
} else {
currentTool = 'mine';
toolButton.setText("MINE");
}
};
uiContainer.addChild(toolButton);
// Select the first inventory slot by default
selectInventorySlot(0);
// Update inventory display
updateInventoryDisplay();
}
function updateInventoryDisplay() {
var slotTypes = ['dirt', 'stone', 'wood', 'special'];
for (var i = 0; i < inventorySlots.length; i++) {
inventorySlots[i].updateCount(storage.inventory[slotTypes[i]]);
}
}
function selectInventorySlot(index) {
// Deselect previous slot
if (selectedInventorySlot !== null) {
inventorySlots[selectedInventorySlot].setSelected(false);
}
// Select new slot
selectedInventorySlot = index;
inventorySlots[selectedInventorySlot].setSelected(true);
// Set selected block type
var slotTypes = ['dirt', 'stone', 'wood', 'special'];
selectedBlockType = slotTypes[selectedInventorySlot];
}
function worldToGrid(worldX, worldY) {
return {
x: Math.floor(worldX / blockSize),
y: Math.floor(worldY / blockSize)
};
}
function gridToWorld(gridX, gridY) {
return {
x: gridX * blockSize + blockSize / 2,
y: gridY * blockSize + blockSize / 2
};
}
function checkPlayerCollisions() {
// Get player bounds
var playerWidth = 80;
var playerHeight = 180;
var playerLeft = player.x - playerWidth / 2;
var playerRight = player.x + playerWidth / 2;
var playerTop = player.y - playerHeight / 2;
var playerBottom = player.y + playerHeight / 2;
// Get surrounding grid cells
var gridX = Math.floor(player.x / blockSize);
var gridY = Math.floor(player.y / blockSize);
// Check each surrounding cell
player.grounded = false;
for (var y = Math.max(0, gridY - 2); y <= Math.min(worldHeight - 1, gridY + 2); y++) {
for (var x = Math.max(0, gridX - 2); x <= Math.min(worldWidth - 1, gridX + 2); x++) {
// Skip empty cells
if (!worldGrid[y][x]) {
continue;
}
// Calculate block bounds
var blockLeft = x * blockSize;
var blockRight = blockLeft + blockSize;
var blockTop = y * blockSize;
var blockBottom = blockTop + blockSize;
// Check for collision
if (playerRight > blockLeft && playerLeft < blockRight && playerBottom > blockTop && playerTop < blockBottom) {
// Calculate overlap
var overlapLeft = playerRight - blockLeft;
var overlapRight = blockRight - playerLeft;
var overlapTop = playerBottom - blockTop;
var overlapBottom = blockBottom - playerTop;
// Find smallest overlap
var minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom);
// Resolve collision
if (minOverlap === overlapTop) {
player.y -= overlapTop;
player.velocity.y = 0;
player.grounded = true;
} else if (minOverlap === overlapBottom) {
player.y += overlapBottom;
player.velocity.y = 0;
} else if (minOverlap === overlapLeft) {
player.x -= overlapLeft;
player.velocity.x = 0;
} else if (minOverlap === overlapRight) {
player.x += overlapRight;
player.velocity.x = 0;
}
}
}
}
}
function updateCamera() {
// Calculate target camera position (centered on player)
var targetX = player.x - 2048 / 2;
var targetY = player.y - 2732 / 2;
// Apply camera constraints
targetX = Math.max(0, Math.min(targetX, worldWidth * blockSize - 2048));
targetY = Math.max(0, Math.min(targetY, worldHeight * blockSize - 2732));
// Smooth camera movement
camera.x = targetX;
camera.y = targetY;
// Apply camera position to world container
worldContainer.x = -camera.x;
worldContainer.y = -camera.y;
}
function checkPhysics(x, y) {
// Skip if out of bounds
if (x < 0 || x >= worldWidth || y < 0 || y >= worldHeight) {
return;
}
// Skip if empty
if (!worldGrid[y][x]) {
return;
}
// Skip if supported
if (y + 1 < worldHeight && worldGrid[y + 1][x]) {
return;
}
// Block is unsupported, apply gravity
applyGravityToBlock(x, y);
}
function applyGravityToBlock(x, y) {
// Skip special blocks (they don't fall)
if (worldGrid[y][x] === 'special') {
return;
}
// Find all world objects at this position
var blockToMove = null;
for (var i = 0; i < worldContainer.children.length; i++) {
var child = worldContainer.children[i];
if (child instanceof Block) {
var gridPos = worldToGrid(child.x, child.y);
if (gridPos.x === x && gridPos.y === y) {
blockToMove = child;
break;
}
}
}
if (!blockToMove) {
return;
}
// Remove from current position
worldGrid[y][x] = null;
// Find landing position
var newY = y;
while (newY + 1 < worldHeight && !worldGrid[newY + 1][x]) {
newY++;
}
// Update grid
worldGrid[newY][x] = blockToMove.type;
// Animate block falling
tween(blockToMove, {
y: newY * blockSize + blockSize / 2
}, {
duration: (newY - y) * 100,
easing: tween.easeIn,
onFinish: function onFinish() {
// Check surrounding blocks for more physics updates
checkPhysics(x, newY - 1);
checkPhysics(x - 1, newY);
checkPhysics(x + 1, newY);
}
});
}
// Handle player movement and game interaction
var leftPressed = false;
var rightPressed = false;
var moveTimer = null;
function handleGameClick(x, y, obj) {
// Convert screen position to world position
var worldX = x + camera.x;
var worldY = y + camera.y;
// Convert to grid position
var gridPos = worldToGrid(worldX, worldY);
// Check if position is within grid bounds
if (gridPos.x < 0 || gridPos.x >= worldWidth || gridPos.y < 0 || gridPos.y >= worldHeight) {
return;
}
if (currentTool === 'place' && selectedBlockType) {
// Check if we have blocks of this type in inventory
if (storage.inventory[selectedBlockType] > 0) {
// Check if position is empty
if (!worldGrid[gridPos.y][gridPos.x]) {
// Check if position is within reach of player
var playerGridPos = worldToGrid(player.x, player.y);
var distance = Math.sqrt(Math.pow(playerGridPos.x - gridPos.x, 2) + Math.pow(playerGridPos.y - gridPos.y, 2));
if (distance <= 5) {
// Place block
worldGrid[gridPos.y][gridPos.x] = selectedBlockType;
// Create block
var block = new Block(selectedBlockType, true);
block.x = gridPos.x * blockSize + blockSize / 2;
block.y = gridPos.y * blockSize + blockSize / 2;
worldContainer.addChild(block);
// Remove from inventory
storage.inventory[selectedBlockType]--;
updateInventoryDisplay();
// Play sound
LK.getSound('place').play();
// Save world
storage.worldData = worldGrid;
// Check physics
checkPhysics(gridPos.x, gridPos.y - 1);
}
}
}
}
}
function startMovingLeft() {
leftPressed = true;
if (!moveTimer) {
moveTimer = LK.setInterval(movePlayer, 16);
}
}
function startMovingRight() {
rightPressed = true;
if (!moveTimer) {
moveTimer = LK.setInterval(movePlayer, 16);
}
}
function stopMovingLeft() {
leftPressed = false;
if (!leftPressed && !rightPressed && moveTimer) {
LK.clearInterval(moveTimer);
moveTimer = null;
player.velocity.x = 0;
}
}
function stopMovingRight() {
rightPressed = false;
if (!leftPressed && !rightPressed && moveTimer) {
LK.clearInterval(moveTimer);
moveTimer = null;
player.velocity.x = 0;
}
}
function movePlayer() {
if (leftPressed) {
player.velocity.x = -player.speed;
} else if (rightPressed) {
player.velocity.x = player.speed;
} else {
player.velocity.x = 0;
}
}
function jump() {
if (player.grounded) {
player.velocity.y = -player.jumpStrength;
player.grounded = false;
}
}
// Game event handlers
game.down = function (x, y, obj) {
// Check if click is on UI
var isUIClick = false;
for (var i = 0; i < uiContainer.children.length; i++) {
if (uiContainer.children[i].intersects({
x: x,
y: y
})) {
isUIClick = true;
break;
}
}
if (!isUIClick) {
// Handle game world interaction
handleGameClick(x, y, obj);
// Start drag for player movement
currentlyDragging = true;
dragStartX = x;
dragStartY = y;
}
};
game.up = function (x, y, obj) {
if (currentlyDragging) {
currentlyDragging = false;
stopMovingLeft();
stopMovingRight();
// Check if this was a tap (not a drag)
var dx = Math.abs(x - dragStartX);
var dy = Math.abs(y - dragStartY);
if (dx < 20 && dy < 20) {
// This was a tap, check if we should jump
if (y < 2732 / 2) {
jump();
}
}
}
};
game.move = function (x, y, obj) {
if (currentlyDragging) {
var dx = x - dragStartX;
if (dx < -30) {
startMovingLeft();
} else if (dx > 30) {
startMovingRight();
} else {
stopMovingLeft();
stopMovingRight();
}
}
};
// Game update function
game.update = function () {
// Skip if player not initialized yet
if (!player) {
return;
}
// Player and physics updates happen automatically through the Player class
};
// Initialize game
initWorld();