/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ //Classes can only be defined here. You cannot create inline classes in the games code. var Block = Container.expand(function (type, gridX, gridY) { var self = Container.call(this); self.gridX = gridX; self.gridY = gridY; self.type = type; var assetId = type + 'Block'; var blockGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Adjust position based on grid coordinates self.x = self.gridX * BLOCK_SIZE + BLOCK_SIZE / 2; self.y = self.gridY * BLOCK_SIZE + BLOCK_SIZE / 2; return self; }); var InventorySlot = Container.expand(function (itemType) { var self = Container.call(this); self.itemType = itemType; self.attachAsset('inventorySlot', { anchorX: 0.5, anchorY: 0.5 }); self.itemIcon = self.attachAsset(itemType + 'Block', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); self.countText = new Text2('0', { size: 50, fill: 0xFFFFFF }); self.countText.anchor.set(0.5, 0.5); self.countText.y = 30; self.addChild(self.countText); self.updateCount = function (count) { self.countText.setText(count); }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); self.gridX = 0; self.gridY = 0; var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.inventory = { dirt: 0, grass: 0, stone: 0, wood: 0 }; self.heldItem = null; // What block type is currently selected to be placed // Position player based on grid coordinates self.updatePosition = function () { self.x = self.gridX * BLOCK_SIZE + BLOCK_SIZE / 2; self.y = self.gridY * BLOCK_SIZE + BLOCK_SIZE / 2; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 //Init game with black background }); /**** * Game Code ****/ //Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions //Storage library which should be used for persistent game data //Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property. //Only include the plugins you need to create the game. //We have access to the following plugins. (Note that the variable names used are mandetory for each plugin) // Initialize music // Initialize assets used in this game. Scale them according to what is needed for the game. // or via static code analysis based on their usage in the code. // Assets are automatically created and loaded either dynamically during gameplay var world = []; // 2D array to hold the blocks var player; var inventorySlots = []; var BLOCK_SIZE = 100; var GRID_WIDTH = Math.floor(2048 / BLOCK_SIZE); var GRID_HEIGHT = Math.floor(2732 / BLOCK_SIZE); game.setBackgroundColor(0x87CEEB); // Sky blue background // Generate a simple world function generateWorld() { world = []; for (var y = 0; y < GRID_HEIGHT; y++) { world[y] = []; for (var x = 0; x < GRID_WIDTH; x++) { var block = null; if (y > GRID_HEIGHT / 2) { block = new Block('dirt', x, y); } else if (y === GRID_HEIGHT / 2) { block = new Block('grass', x, y); } world[y][x] = block; if (block) { game.addChild(block); } } } } // Initialize player player = new Player(); player.gridX = Math.floor(GRID_WIDTH / 2); player.gridY = Math.floor(GRID_HEIGHT / 2) - 1; // Place above ground player.updatePosition(); game.addChild(player); // Initialize inventory UI function setupInventoryUI() { var items = ['dirt', 'grass', 'stone', 'wood']; var startX = 150; // Offset from left edge, outside the menu area var startY = 2600; // Near the bottom for (var i = 0; i < items.length; i++) { var slot = new InventorySlot(items[i]); slot.x = startX + i * 140; slot.y = startY; inventorySlots.push(slot); LK.gui.addChild(slot); } } // Update inventory display function updateInventoryUI() { for (var i = 0; i < inventorySlots.length; i++) { var slot = inventorySlots[i]; slot.updateCount(player.inventory[slot.itemType]); } } // Handle tapping the screen game.down = function (x, y, obj) { // Convert screen coordinates to game coordinates var gameCoords = game.toLocal({ x: x, y: y }); // Convert game coordinates to grid coordinates var gridX = Math.floor(gameCoords.x / BLOCK_SIZE); var gridY = Math.floor(gameCoords.y / BLOCK_SIZE); // Check if tap is within the game grid and outside the top-left menu area if (gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT && gameCoords.x > 100 && gameCoords.y > 100) { var block = world[gridY] && world[gridY][gridX]; if (player.heldItem) { // Place block if (!block) { // Check if player is adjacent to the placement location (simplified) var dx = Math.abs(player.gridX - gridX); var dy = Math.abs(player.gridY - gridY); if (dx <= 1 && dy === 0 || dx === 0 && dy <= 1 || dx <= 1 && dy <= 1) { // Allow diagonal placement for simplicity if (player.inventory[player.heldItem] > 0) { var newBlock = new Block(player.heldItem, gridX, gridY); world[gridY][gridX] = newBlock; game.addChild(newBlock); player.inventory[player.heldItem]--; updateInventoryUI(); LK.getSound('place').play(); } } } } else if (block) { // Mine block // Check if player is adjacent to the block (simplified) var dx = Math.abs(player.gridX - gridX); var dy = Math.abs(player.gridY - gridY); if (dx <= 1 && dy === 0 || dx === 0 && dy <= 1 || dx <= 1 && dy <= 1) { // Allow diagonal mining for simplicity player.inventory[block.type]++; updateInventoryUI(); block.destroy(); world[gridY][gridX] = null; LK.getSound('mine').play(); } } } // Check if a tap is on an inventory slot for (var i = 0; i < inventorySlots.length; i++) { var slot = inventorySlots[i]; var slotBounds = slot.getBounds(); // Get global bounds of the slot if (x >= slotBounds.x && x <= slotBounds.x + slotBounds.width && y >= slotBounds.y && y <= slotBounds.y + slotBounds.height) { if (player.heldItem === slot.itemType) { player.heldItem = null; // Deselect slot.alpha = 1; // Reset alpha } else { // Deselect previously held item if any if (player.heldItem) { for (var j = 0; j < inventorySlots.length; j++) { if (inventorySlots[j].itemType === player.heldItem) { inventorySlots[j].alpha = 1; break; } } } player.heldItem = slot.itemType; // Select slot.alpha = 0.7; // Indicate selected } break; // Only interact with one slot at a time } } }; // Game update loop game.update = function () { // Basic player movement (example, can be expanded with controls) // Player follows horizontal movement of a facial feature (e.g., noseTip) if (facekit && facekit.noseTip && facekit.noseTip.x > 0) { var targetGridX = Math.floor(facekit.noseTip.x / BLOCK_SIZE); if (targetGridX < 0) { targetGridX = 0; } if (targetGridX >= GRID_WIDTH) { targetGridX = GRID_WIDTH - 1; } // Simple movement to the target grid cell if (player.gridX < targetGridX) { player.gridX++; } else if (player.gridX > targetGridX) { player.gridX--; } // Prevent player from moving into occupied blocks (basic collision) var blockBelow = world[player.gridY + 1] && world[player.gridY + 1][player.gridX]; if (!blockBelow && player.gridY < GRID_HEIGHT - 1) { player.gridY++; // Gravity } else if (blockBelow && player.gridY > 0) { // Stay on top of the block } player.updatePosition(); } }; // Initial world generation and UI setup generateWorld(); setupInventoryUI(); updateInventoryUI(); // Play background music LK.playMusic('backgroundMusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
//Classes can only be defined here. You cannot create inline classes in the games code.
var Block = Container.expand(function (type, gridX, gridY) {
var self = Container.call(this);
self.gridX = gridX;
self.gridY = gridY;
self.type = type;
var assetId = type + 'Block';
var blockGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Adjust position based on grid coordinates
self.x = self.gridX * BLOCK_SIZE + BLOCK_SIZE / 2;
self.y = self.gridY * BLOCK_SIZE + BLOCK_SIZE / 2;
return self;
});
var InventorySlot = Container.expand(function (itemType) {
var self = Container.call(this);
self.itemType = itemType;
self.attachAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5
});
self.itemIcon = self.attachAsset(itemType + 'Block', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
self.countText = new Text2('0', {
size: 50,
fill: 0xFFFFFF
});
self.countText.anchor.set(0.5, 0.5);
self.countText.y = 30;
self.addChild(self.countText);
self.updateCount = function (count) {
self.countText.setText(count);
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
self.gridX = 0;
self.gridY = 0;
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.inventory = {
dirt: 0,
grass: 0,
stone: 0,
wood: 0
};
self.heldItem = null; // What block type is currently selected to be placed
// Position player based on grid coordinates
self.updatePosition = function () {
self.x = self.gridX * BLOCK_SIZE + BLOCK_SIZE / 2;
self.y = self.gridY * BLOCK_SIZE + BLOCK_SIZE / 2;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 //Init game with black background
});
/****
* Game Code
****/
//Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions
//Storage library which should be used for persistent game data
//Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property.
//Only include the plugins you need to create the game.
//We have access to the following plugins. (Note that the variable names used are mandetory for each plugin)
// Initialize music
// Initialize assets used in this game. Scale them according to what is needed for the game.
// or via static code analysis based on their usage in the code.
// Assets are automatically created and loaded either dynamically during gameplay
var world = []; // 2D array to hold the blocks
var player;
var inventorySlots = [];
var BLOCK_SIZE = 100;
var GRID_WIDTH = Math.floor(2048 / BLOCK_SIZE);
var GRID_HEIGHT = Math.floor(2732 / BLOCK_SIZE);
game.setBackgroundColor(0x87CEEB); // Sky blue background
// Generate a simple world
function generateWorld() {
world = [];
for (var y = 0; y < GRID_HEIGHT; y++) {
world[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
var block = null;
if (y > GRID_HEIGHT / 2) {
block = new Block('dirt', x, y);
} else if (y === GRID_HEIGHT / 2) {
block = new Block('grass', x, y);
}
world[y][x] = block;
if (block) {
game.addChild(block);
}
}
}
}
// Initialize player
player = new Player();
player.gridX = Math.floor(GRID_WIDTH / 2);
player.gridY = Math.floor(GRID_HEIGHT / 2) - 1; // Place above ground
player.updatePosition();
game.addChild(player);
// Initialize inventory UI
function setupInventoryUI() {
var items = ['dirt', 'grass', 'stone', 'wood'];
var startX = 150; // Offset from left edge, outside the menu area
var startY = 2600; // Near the bottom
for (var i = 0; i < items.length; i++) {
var slot = new InventorySlot(items[i]);
slot.x = startX + i * 140;
slot.y = startY;
inventorySlots.push(slot);
LK.gui.addChild(slot);
}
}
// Update inventory display
function updateInventoryUI() {
for (var i = 0; i < inventorySlots.length; i++) {
var slot = inventorySlots[i];
slot.updateCount(player.inventory[slot.itemType]);
}
}
// Handle tapping the screen
game.down = function (x, y, obj) {
// Convert screen coordinates to game coordinates
var gameCoords = game.toLocal({
x: x,
y: y
});
// Convert game coordinates to grid coordinates
var gridX = Math.floor(gameCoords.x / BLOCK_SIZE);
var gridY = Math.floor(gameCoords.y / BLOCK_SIZE);
// Check if tap is within the game grid and outside the top-left menu area
if (gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT && gameCoords.x > 100 && gameCoords.y > 100) {
var block = world[gridY] && world[gridY][gridX];
if (player.heldItem) {
// Place block
if (!block) {
// Check if player is adjacent to the placement location (simplified)
var dx = Math.abs(player.gridX - gridX);
var dy = Math.abs(player.gridY - gridY);
if (dx <= 1 && dy === 0 || dx === 0 && dy <= 1 || dx <= 1 && dy <= 1) {
// Allow diagonal placement for simplicity
if (player.inventory[player.heldItem] > 0) {
var newBlock = new Block(player.heldItem, gridX, gridY);
world[gridY][gridX] = newBlock;
game.addChild(newBlock);
player.inventory[player.heldItem]--;
updateInventoryUI();
LK.getSound('place').play();
}
}
}
} else if (block) {
// Mine block
// Check if player is adjacent to the block (simplified)
var dx = Math.abs(player.gridX - gridX);
var dy = Math.abs(player.gridY - gridY);
if (dx <= 1 && dy === 0 || dx === 0 && dy <= 1 || dx <= 1 && dy <= 1) {
// Allow diagonal mining for simplicity
player.inventory[block.type]++;
updateInventoryUI();
block.destroy();
world[gridY][gridX] = null;
LK.getSound('mine').play();
}
}
}
// Check if a tap is on an inventory slot
for (var i = 0; i < inventorySlots.length; i++) {
var slot = inventorySlots[i];
var slotBounds = slot.getBounds(); // Get global bounds of the slot
if (x >= slotBounds.x && x <= slotBounds.x + slotBounds.width && y >= slotBounds.y && y <= slotBounds.y + slotBounds.height) {
if (player.heldItem === slot.itemType) {
player.heldItem = null; // Deselect
slot.alpha = 1; // Reset alpha
} else {
// Deselect previously held item if any
if (player.heldItem) {
for (var j = 0; j < inventorySlots.length; j++) {
if (inventorySlots[j].itemType === player.heldItem) {
inventorySlots[j].alpha = 1;
break;
}
}
}
player.heldItem = slot.itemType; // Select
slot.alpha = 0.7; // Indicate selected
}
break; // Only interact with one slot at a time
}
}
};
// Game update loop
game.update = function () {
// Basic player movement (example, can be expanded with controls)
// Player follows horizontal movement of a facial feature (e.g., noseTip)
if (facekit && facekit.noseTip && facekit.noseTip.x > 0) {
var targetGridX = Math.floor(facekit.noseTip.x / BLOCK_SIZE);
if (targetGridX < 0) {
targetGridX = 0;
}
if (targetGridX >= GRID_WIDTH) {
targetGridX = GRID_WIDTH - 1;
}
// Simple movement to the target grid cell
if (player.gridX < targetGridX) {
player.gridX++;
} else if (player.gridX > targetGridX) {
player.gridX--;
}
// Prevent player from moving into occupied blocks (basic collision)
var blockBelow = world[player.gridY + 1] && world[player.gridY + 1][player.gridX];
if (!blockBelow && player.gridY < GRID_HEIGHT - 1) {
player.gridY++; // Gravity
} else if (blockBelow && player.gridY > 0) {
// Stay on top of the block
}
player.updatePosition();
}
};
// Initial world generation and UI setup
generateWorld();
setupInventoryUI();
updateInventoryUI();
// Play background music
LK.playMusic('backgroundMusic');