/****
* Classes
****/
// Block class for a single voxel block
var Block = Container.expand(function () {
var self = Container.call(this);
// Default block type is 'dirt'
self.type = 'dirt';
// Attach the block asset, anchor at center
self.blockAsset = self.attachAsset('block_' + self.type, {
anchorX: 0.5,
anchorY: 0.5
});
// Supported types: 'dirt', 'grass', 'stone'
// Set block type and update asset
self.setType = function (type) {
self.type = type;
// Remove old asset if present
if (self.blockAsset) {
self.removeChild(self.blockAsset);
}
self.blockAsset = self.attachAsset('block_' + self.type, {
anchorX: 0.5,
anchorY: 0.5
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
;
// --- Block Placement/Removal Controls ---
// Helper: Convert screen/game coordinates to grid coordinates
function getGridCoords(x, y) {
var gx = Math.floor((x - gridOffsetX) / BLOCK_SIZE);
var gy = Math.floor((y - gridOffsetY) / BLOCK_SIZE);
if (gx < 0 || gx >= GRID_WIDTH || gy < 0 || gy >= GRID_HEIGHT) return null;
return {
x: gx,
y: gy
};
}
// Track current action: 'place' or 'remove'
var currentAction = 'place'; // Default to placing blocks
// Track current block type for placement
var blockTypes = ['dirt', 'grass', 'stone'];
var currentBlockTypeIndex = 0;
var currentBlockType = blockTypes[currentBlockTypeIndex];
// Palette UI: tap top-right to toggle between 'place' and 'remove', and select block type
var paletteSize = 180;
var paletteX = 2048 - paletteSize - 40;
var paletteY = 40;
// Draw palette action button (place/remove)
var paletteBtn = LK.getAsset('block_dirt', {
anchorX: 0.5,
anchorY: 0.5,
x: paletteX + paletteSize / 2,
y: paletteY + paletteSize / 2,
width: paletteSize,
height: paletteSize
});
game.addChild(paletteBtn);
// Draw block swap button (cycle block type)
var swapBtnSize = 120;
var swapBtnX = paletteX + paletteSize / 2;
var swapBtnY = paletteY + paletteSize + 40 + swapBtnSize / 2;
var swapBtn = LK.getAsset('block_' + currentBlockType, {
anchorX: 0.5,
anchorY: 0.5,
x: swapBtnX,
y: swapBtnY,
width: swapBtnSize,
height: swapBtnSize
});
game.addChild(swapBtn);
// Overlay text for mode
var paletteTxt = new Text2('Place', {
size: 60,
fill: "#fff"
});
paletteTxt.anchor.set(0.5, 0.5);
paletteTxt.x = paletteBtn.x;
paletteTxt.y = paletteBtn.y;
game.addChild(paletteTxt);
// Overlay text for block type
var swapTxt = new Text2(currentBlockType.charAt(0).toUpperCase() + currentBlockType.slice(1), {
size: 40,
fill: "#fff"
});
swapTxt.anchor.set(0.5, 0.5);
swapTxt.x = swapBtn.x;
swapTxt.y = swapBtn.y;
game.addChild(swapTxt);
// Toggle action on palette tap
paletteBtn.down = function (x, y, obj) {
currentAction = currentAction === 'place' ? 'remove' : 'place';
paletteTxt.setText(currentAction.charAt(0).toUpperCase() + currentAction.slice(1));
};
// Cycle block type on swapBtn tap
swapBtn.down = function (x, y, obj) {
currentBlockTypeIndex = (currentBlockTypeIndex + 1) % blockTypes.length;
currentBlockType = blockTypes[currentBlockTypeIndex];
// Remove old asset if present
if (swapBtn.blockAsset) {
swapBtn.removeChild(swapBtn.blockAsset);
}
swapBtn.blockAsset = swapBtn.attachAsset('block_' + currentBlockType, {
anchorX: 0.5,
anchorY: 0.5,
x: swapBtnX,
y: swapBtnY,
width: swapBtnSize,
height: swapBtnSize
});
swapTxt.setText(currentBlockType.charAt(0).toUpperCase() + currentBlockType.slice(1));
};
// Handle placing/removing blocks on grid
game.down = function (x, y, obj) {
// Ignore palette area
if (x >= paletteX && x <= paletteX + paletteSize && y >= paletteY && y <= paletteY + paletteSize) {
// Let paletteBtn handle its own .down
return;
}
var grid = getGridCoords(x, y);
if (!grid) return;
var gx = grid.x,
gy = grid.y;
if (currentAction === 'place') {
if (!worldGrid[gy][gx]) {
// Place a block of the selected type
worldGrid[gy][gx] = currentBlockType;
var block = new Block();
block.setType(currentBlockType);
block.x = gridOffsetX + gx * BLOCK_SIZE + BLOCK_SIZE / 2;
block.y = gridOffsetY + gy * BLOCK_SIZE + BLOCK_SIZE / 2;
game.addChild(block);
blockObjects[gy][gx] = block;
}
} else if (currentAction === 'remove') {
if (worldGrid[gy][gx]) {
// Remove block
worldGrid[gy][gx] = null;
if (blockObjects[gy][gx]) {
blockObjects[gy][gx].destroy();
blockObjects[gy][gx] = null;
}
}
}
};
// --- Voxel 2D Sandbox Setup ---
// Grid size (number of blocks)
var GRID_WIDTH = 20;
var GRID_HEIGHT = 15;
// Block size in pixels (auto from asset, but fallback to 100)
var BLOCK_SIZE = 100;
// 2D array to store block types, initialize with 'dirt' for a flat world
var worldGrid = [];
for (var y = 0; y < GRID_HEIGHT; y++) {
worldGrid[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
if (y === Math.floor(GRID_HEIGHT / 2)) {
worldGrid[y][x] = 'grass';
} else if (y > Math.floor(GRID_HEIGHT / 2) && y < GRID_HEIGHT - 2) {
worldGrid[y][x] = 'dirt';
} else if (y >= GRID_HEIGHT - 2) {
worldGrid[y][x] = 'stone';
} else {
worldGrid[y][x] = null;
}
}
}
// Store block objects for easy access/removal
var blockObjects = [];
// Center the grid in the game area
var gridOffsetX = (2048 - GRID_WIDTH * BLOCK_SIZE) / 2;
var gridOffsetY = (2732 - GRID_HEIGHT * BLOCK_SIZE) / 2;
// Render the initial world
for (var y = 0; y < GRID_HEIGHT; y++) {
blockObjects[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
if (worldGrid[y][x]) {
var block = new Block();
block.setType(worldGrid[y][x]);
block.x = gridOffsetX + x * BLOCK_SIZE + BLOCK_SIZE / 2;
block.y = gridOffsetY + y * BLOCK_SIZE + BLOCK_SIZE / 2;
game.addChild(block);
blockObjects[y][x] = block;
} else {
blockObjects[y][x] = null;
}
}
} /****
* Classes
****/
// Block class for a single voxel block
var Block = Container.expand(function () {
var self = Container.call(this);
// Default block type is 'dirt'
self.type = 'dirt';
// Attach the block asset, anchor at center
self.blockAsset = self.attachAsset('block_' + self.type, {
anchorX: 0.5,
anchorY: 0.5
});
// Supported types: 'dirt', 'grass', 'stone'
// Set block type and update asset
self.setType = function (type) {
self.type = type;
// Remove old asset if present
if (self.blockAsset) {
self.removeChild(self.blockAsset);
}
self.blockAsset = self.attachAsset('block_' + self.type, {
anchorX: 0.5,
anchorY: 0.5
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
;
// --- Block Placement/Removal Controls ---
// Helper: Convert screen/game coordinates to grid coordinates
function getGridCoords(x, y) {
var gx = Math.floor((x - gridOffsetX) / BLOCK_SIZE);
var gy = Math.floor((y - gridOffsetY) / BLOCK_SIZE);
if (gx < 0 || gx >= GRID_WIDTH || gy < 0 || gy >= GRID_HEIGHT) return null;
return {
x: gx,
y: gy
};
}
// Track current action: 'place' or 'remove'
var currentAction = 'place'; // Default to placing blocks
// Track current block type for placement
var blockTypes = ['dirt', 'grass', 'stone'];
var currentBlockTypeIndex = 0;
var currentBlockType = blockTypes[currentBlockTypeIndex];
// Palette UI: tap top-right to toggle between 'place' and 'remove', and select block type
var paletteSize = 180;
var paletteX = 2048 - paletteSize - 40;
var paletteY = 40;
// Draw palette action button (place/remove)
var paletteBtn = LK.getAsset('block_dirt', {
anchorX: 0.5,
anchorY: 0.5,
x: paletteX + paletteSize / 2,
y: paletteY + paletteSize / 2,
width: paletteSize,
height: paletteSize
});
game.addChild(paletteBtn);
// Draw block swap button (cycle block type)
var swapBtnSize = 120;
var swapBtnX = paletteX + paletteSize / 2;
var swapBtnY = paletteY + paletteSize + 40 + swapBtnSize / 2;
var swapBtn = LK.getAsset('block_' + currentBlockType, {
anchorX: 0.5,
anchorY: 0.5,
x: swapBtnX,
y: swapBtnY,
width: swapBtnSize,
height: swapBtnSize
});
game.addChild(swapBtn);
// Overlay text for mode
var paletteTxt = new Text2('Place', {
size: 60,
fill: "#fff"
});
paletteTxt.anchor.set(0.5, 0.5);
paletteTxt.x = paletteBtn.x;
paletteTxt.y = paletteBtn.y;
game.addChild(paletteTxt);
// Overlay text for block type
var swapTxt = new Text2(currentBlockType.charAt(0).toUpperCase() + currentBlockType.slice(1), {
size: 40,
fill: "#fff"
});
swapTxt.anchor.set(0.5, 0.5);
swapTxt.x = swapBtn.x;
swapTxt.y = swapBtn.y;
game.addChild(swapTxt);
// Toggle action on palette tap
paletteBtn.down = function (x, y, obj) {
currentAction = currentAction === 'place' ? 'remove' : 'place';
paletteTxt.setText(currentAction.charAt(0).toUpperCase() + currentAction.slice(1));
};
// Cycle block type on swapBtn tap
swapBtn.down = function (x, y, obj) {
currentBlockTypeIndex = (currentBlockTypeIndex + 1) % blockTypes.length;
currentBlockType = blockTypes[currentBlockTypeIndex];
// Remove old asset if present
if (swapBtn.blockAsset) {
swapBtn.removeChild(swapBtn.blockAsset);
}
swapBtn.blockAsset = swapBtn.attachAsset('block_' + currentBlockType, {
anchorX: 0.5,
anchorY: 0.5,
x: swapBtnX,
y: swapBtnY,
width: swapBtnSize,
height: swapBtnSize
});
swapTxt.setText(currentBlockType.charAt(0).toUpperCase() + currentBlockType.slice(1));
};
// Handle placing/removing blocks on grid
game.down = function (x, y, obj) {
// Ignore palette area
if (x >= paletteX && x <= paletteX + paletteSize && y >= paletteY && y <= paletteY + paletteSize) {
// Let paletteBtn handle its own .down
return;
}
var grid = getGridCoords(x, y);
if (!grid) return;
var gx = grid.x,
gy = grid.y;
if (currentAction === 'place') {
if (!worldGrid[gy][gx]) {
// Place a block of the selected type
worldGrid[gy][gx] = currentBlockType;
var block = new Block();
block.setType(currentBlockType);
block.x = gridOffsetX + gx * BLOCK_SIZE + BLOCK_SIZE / 2;
block.y = gridOffsetY + gy * BLOCK_SIZE + BLOCK_SIZE / 2;
game.addChild(block);
blockObjects[gy][gx] = block;
}
} else if (currentAction === 'remove') {
if (worldGrid[gy][gx]) {
// Remove block
worldGrid[gy][gx] = null;
if (blockObjects[gy][gx]) {
blockObjects[gy][gx].destroy();
blockObjects[gy][gx] = null;
}
}
}
};
// --- Voxel 2D Sandbox Setup ---
// Grid size (number of blocks)
var GRID_WIDTH = 20;
var GRID_HEIGHT = 15;
// Block size in pixels (auto from asset, but fallback to 100)
var BLOCK_SIZE = 100;
// 2D array to store block types, initialize with 'dirt' for a flat world
var worldGrid = [];
for (var y = 0; y < GRID_HEIGHT; y++) {
worldGrid[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
if (y === Math.floor(GRID_HEIGHT / 2)) {
worldGrid[y][x] = 'grass';
} else if (y > Math.floor(GRID_HEIGHT / 2) && y < GRID_HEIGHT - 2) {
worldGrid[y][x] = 'dirt';
} else if (y >= GRID_HEIGHT - 2) {
worldGrid[y][x] = 'stone';
} else {
worldGrid[y][x] = null;
}
}
}
// Store block objects for easy access/removal
var blockObjects = [];
// Center the grid in the game area
var gridOffsetX = (2048 - GRID_WIDTH * BLOCK_SIZE) / 2;
var gridOffsetY = (2732 - GRID_HEIGHT * BLOCK_SIZE) / 2;
// Render the initial world
for (var y = 0; y < GRID_HEIGHT; y++) {
blockObjects[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
if (worldGrid[y][x]) {
var block = new Block();
block.setType(worldGrid[y][x]);
block.x = gridOffsetX + x * BLOCK_SIZE + BLOCK_SIZE / 2;
block.y = gridOffsetY + y * BLOCK_SIZE + BLOCK_SIZE / 2;
game.addChild(block);
blockObjects[y][x] = block;
} else {
blockObjects[y][x] = null;
}
}
}