/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Block = Container.expand(function (blockType, x, y) {
var self = Container.call(this);
self.blockType = blockType;
self.gridX = x;
self.gridY = y;
// Main block texture
var blockGraphic = self.attachAsset(blockType, {
anchorX: 0,
anchorY: 0
});
// Add realistic layered details based on block type
if (blockType === 'grass') {
var grassTop = self.attachAsset('grass_top', {
anchorX: 0,
anchorY: 0
});
grassTop.y = 0;
// Add grass blades for realism
for (var i = 0; i < 8; i++) {
var blade = self.attachAsset('grass_blade', {
anchorX: 0.5,
anchorY: 1
});
blade.x = Math.random() * 60 + 2;
blade.y = Math.random() * 4 + 2;
blade.rotation = (Math.random() - 0.5) * 0.3;
}
} else if (blockType === 'stone') {
// Add stone texture details
for (var i = 0; i < 6; i++) {
var texture = self.attachAsset('stone_texture', {
anchorX: 0,
anchorY: 0
});
texture.x = Math.random() * 48 + 0;
texture.y = Math.random() * 48 + 0;
texture.alpha = 0.3;
}
} else if (blockType === 'wood') {
// Add wood grain
for (var i = 0; i < 16; i++) {
var grain = self.attachAsset('wood_grain', {
anchorX: 0,
anchorY: 0
});
grain.y = i * 4;
grain.alpha = 0.4;
}
// Add tree rings
for (var i = 0; i < 3; i++) {
var ring = self.attachAsset('wood_ring', {
anchorX: 0.5,
anchorY: 0.5
});
ring.x = 32;
ring.y = 32;
ring.scaleX = 0.3 + i * 0.2;
ring.scaleY = 0.3 + i * 0.2;
ring.alpha = 0.6;
}
} else if (blockType === 'dirt') {
// Add dirt particles
for (var i = 0; i < 12; i++) {
var particle = self.attachAsset('dirt_particle', {
anchorX: 0.5,
anchorY: 0.5
});
particle.x = Math.random() * 56 + 4;
particle.y = Math.random() * 56 + 4;
particle.alpha = 0.7;
}
} else if (blockType === 'coal') {
// Add coal veins
for (var i = 0; i < 4; i++) {
var vein = self.attachAsset('coal_vein', {
anchorX: 0,
anchorY: 0
});
vein.x = Math.random() * 48 + 0;
vein.y = Math.random() * 48 + 0;
vein.rotation = Math.random() * Math.PI * 2;
}
} else if (blockType === 'iron') {
// Add iron ore deposits
for (var i = 0; i < 3; i++) {
var ore = self.attachAsset('iron_ore', {
anchorX: 0.5,
anchorY: 0.5
});
ore.x = Math.random() * 44 + 10;
ore.y = Math.random() * 44 + 10;
ore.alpha = 0.8;
}
} else if (blockType === 'bedrock') {
// Add bedrock highlights
for (var i = 0; i < 4; i++) {
var highlight = self.attachAsset('bedrock_highlight', {
anchorX: 0,
anchorY: 0
});
highlight.x = Math.random() * 32;
highlight.y = Math.random() * 32;
highlight.width = Math.random() * 20 + 10;
highlight.height = Math.random() * 20 + 10;
highlight.alpha = 0.2;
}
}
// Add subtle shadow effect for depth
var shadow = self.attachAsset(blockType, {
anchorX: 0,
anchorY: 0
});
shadow.x = 2;
shadow.y = 2;
shadow.alpha = 0.2;
shadow.tint = 0x000000;
self.x = x * BLOCK_SIZE;
self.y = y * BLOCK_SIZE;
return self;
});
var Hotbar = Container.expand(function () {
var self = Container.call(this);
self.slots = [];
for (var i = 0; i < 9; i++) {
var slot = self.addChild(LK.getAsset('hotbar_slot', {
anchorX: 0,
anchorY: 0
}));
slot.x = i * 85;
slot.y = 0;
self.slots.push(slot);
// Add item text
var itemText = new Text2('', {
size: 20,
fill: 0xFFFFFF
});
itemText.anchor.set(0.5, 0.5);
itemText.x = slot.x + 40;
itemText.y = slot.y + 40;
slot.itemText = itemText;
self.addChild(itemText);
}
self.selectedIndicator = self.addChild(LK.getAsset('hotbar_selected', {
anchorX: 0,
anchorY: 0
}));
self.selectedIndicator.x = -2;
self.selectedIndicator.y = -2;
self.updateDisplay = function () {
for (var i = 0; i < 9; i++) {
var item = player.inventory[i];
if (item) {
self.slots[i].itemText.setText(item.type.charAt(0).toUpperCase() + '\n' + item.count);
} else {
self.slots[i].itemText.setText('');
}
}
self.selectedIndicator.x = player.selectedSlot * 85 - 2;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
// Create detailed player body parts
self.body = self.attachAsset('player_body', {
anchorX: 0.5,
anchorY: 1
});
self.head = self.attachAsset('player_head', {
anchorX: 0.5,
anchorY: 1
});
self.head.y = -48;
self.hair = self.attachAsset('player_hair', {
anchorX: 0.5,
anchorY: 1
});
self.hair.y = -48;
self.leftEye = self.attachAsset('player_eyes', {
anchorX: 0.5,
anchorY: 0.5
});
self.leftEye.x = -6;
self.leftEye.y = -36;
self.leftEye.width = 4;
self.rightEye = self.attachAsset('player_eyes', {
anchorX: 0.5,
anchorY: 0.5
});
self.rightEye.x = 6;
self.rightEye.y = -36;
self.rightEye.width = 4;
self.leftArm = self.attachAsset('player_arm', {
anchorX: 0.5,
anchorY: 0
});
self.leftArm.x = -18;
self.leftArm.y = -40;
self.rightArm = self.attachAsset('player_arm', {
anchorX: 0.5,
anchorY: 0
});
self.rightArm.x = 18;
self.rightArm.y = -40;
self.leftLeg = self.attachAsset('player_leg', {
anchorX: 0.5,
anchorY: 0
});
self.leftLeg.x = -8;
self.leftLeg.y = -24;
self.rightLeg = self.attachAsset('player_leg', {
anchorX: 0.5,
anchorY: 0
});
self.rightLeg.x = 8;
self.rightLeg.y = -24;
self.velocity = {
x: 0,
y: 0
};
self.speed = 300;
self.jumpPower = 600;
self.onGround = false;
self.health = 100;
self.hunger = 100;
self.selectedSlot = 0;
self.walkCycle = 0;
self.facingDirection = 1; // 1 for right, -1 for left
self.isWalking = false;
self.isJumping = false;
self.inventory = [{
type: 'dirt',
count: 64
}, {
type: 'stone',
count: 32
}, {
type: 'wood',
count: 16
}, {
type: 'grass',
count: 24
}, null, null, null, null, null];
self.update = function () {
// Apply gravity
self.velocity.y += GRAVITY;
// Check if walking for animations
self.isWalking = Math.abs(self.velocity.x) > 50;
self.isJumping = !self.onGround;
// Movement
self.x += self.velocity.x / 60;
self.y += self.velocity.y / 60;
// Ground collision with more realistic physics
var groundY = getGroundLevel(Math.floor(self.x / BLOCK_SIZE)) * BLOCK_SIZE;
if (self.y >= groundY) {
self.y = groundY;
if (self.velocity.y > 0) {
// Landing impact
if (self.velocity.y > 200) {
LK.effects.flashObject(self, 0xffffff, 100);
}
}
self.velocity.y = 0;
self.onGround = true;
} else {
self.onGround = false;
}
// Realistic friction and air resistance
if (self.onGround) {
self.velocity.x *= 0.85; // Ground friction
} else {
self.velocity.x *= 0.95; // Air resistance
}
// Keep player in bounds
if (self.x < 0) self.x = 0;
if (self.x > WORLD_WIDTH * BLOCK_SIZE) self.x = WORLD_WIDTH * BLOCK_SIZE;
// Update walking animation
if (self.isWalking) {
self.walkCycle += 0.3;
var armSwing = Math.sin(self.walkCycle) * 0.3;
var legSwing = Math.sin(self.walkCycle) * 0.4;
self.leftArm.rotation = armSwing;
self.rightArm.rotation = -armSwing;
self.leftLeg.rotation = legSwing;
self.rightLeg.rotation = -legSwing;
// Head bob
self.head.y = -48 + Math.abs(Math.sin(self.walkCycle * 2)) * 2;
} else {
// Reset to neutral positions
self.leftArm.rotation = 0;
self.rightArm.rotation = 0;
self.leftLeg.rotation = 0;
self.rightLeg.rotation = 0;
self.head.y = -48;
}
// Jumping animation
if (self.isJumping) {
self.leftArm.rotation = -0.5;
self.rightArm.rotation = -0.5;
self.leftLeg.rotation = 0.3;
self.rightLeg.rotation = 0.3;
}
// Facing direction
if (self.velocity.x > 10) {
self.facingDirection = 1;
} else if (self.velocity.x < -10) {
self.facingDirection = -1;
}
self.scaleX = self.facingDirection;
};
self.moveLeft = function () {
self.velocity.x = -self.speed;
};
self.moveRight = function () {
self.velocity.x = self.speed;
};
self.jump = function () {
if (self.onGround) {
self.velocity.y = -self.jumpPower;
// Jump animation
tween(self.head).to({
y: -52
}, 200).start();
tween(self.head).to({
y: -48
}, 400, 200).start();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Realistic block textures with detailed colors and shading
// Sounds
// UI elements
// Player
// Block types
// Game constants with realistic physics
var BLOCK_SIZE = 64;
var WORLD_WIDTH = 128;
var WORLD_HEIGHT = 64;
var GRAVITY = 1200; // More realistic gravity
var SEA_LEVEL = 32;
var WIND_STRENGTH = 0;
var WEATHER_EFFECTS = true;
var PARTICLE_COUNT = 0;
// Game state
var gameMode = 'creative'; // 'survival' or 'creative'
var currentTime = 0;
var dayLength = 120000; // 2 minutes per day
var worldBlocks = {};
var worldGenerated = false;
// Camera
var camera = {
x: 0,
y: 0
};
// Create player
var player = game.addChild(new Player());
player.x = WORLD_WIDTH * BLOCK_SIZE / 2;
player.y = SEA_LEVEL * BLOCK_SIZE;
// Create UI
var healthText = new Text2('Health: 100', {
size: 32,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
healthText.x = 120;
healthText.y = 10;
var hungerText = new Text2('Hunger: 100', {
size: 32,
fill: 0xFFFFFF
});
hungerText.anchor.set(0, 0);
LK.gui.topLeft.addChild(hungerText);
hungerText.x = 120;
hungerText.y = 50;
var modeText = new Text2('Mode: Creative', {
size: 32,
fill: 0xFFFFFF
});
modeText.anchor.set(0, 0);
LK.gui.topRight.addChild(modeText);
modeText.x = -200;
modeText.y = 10;
// Create hotbar
var hotbar = new Hotbar();
LK.gui.bottom.addChild(hotbar);
hotbar.x = -380;
hotbar.y = -100;
// World generation functions
function getBlockKey(x, y) {
return x + ',' + y;
}
function setBlock(x, y, blockType) {
var key = getBlockKey(x, y);
if (blockType === null) {
if (worldBlocks[key]) {
game.removeChild(worldBlocks[key]);
delete worldBlocks[key];
}
} else {
if (worldBlocks[key]) {
game.removeChild(worldBlocks[key]);
}
var block = new Block(blockType, x, y);
worldBlocks[key] = block;
game.addChild(block);
}
}
function getBlock(x, y) {
var key = getBlockKey(x, y);
return worldBlocks[key] ? worldBlocks[key].blockType : null;
}
function getGroundLevel(x) {
// Simple terrain generation
var baseHeight = SEA_LEVEL - Math.sin(x * 0.1) * 8 - Math.sin(x * 0.05) * 16;
return Math.floor(baseHeight);
}
function generateTerrain() {
for (var x = 0; x < WORLD_WIDTH; x++) {
var groundLevel = getGroundLevel(x);
// Generate terrain layers
for (var y = 0; y < WORLD_HEIGHT; y++) {
if (y > groundLevel + 20) {
// Bedrock layer
setBlock(x, y, 'bedrock');
} else if (y > groundLevel + 5) {
// Stone layer with occasional ores
if (Math.random() < 0.1) {
setBlock(x, y, Math.random() < 0.5 ? 'iron' : 'coal');
} else {
setBlock(x, y, 'stone');
}
} else if (y > groundLevel) {
// Dirt layer
setBlock(x, y, 'dirt');
} else if (y === groundLevel) {
// Surface layer
setBlock(x, y, 'grass');
}
}
// Generate trees occasionally
if (Math.random() < 0.1 && groundLevel < SEA_LEVEL + 5) {
var treeHeight = 3 + Math.floor(Math.random() * 3);
for (var t = 1; t <= treeHeight; t++) {
if (groundLevel - t >= 0) {
setBlock(x, groundLevel - t, 'wood');
}
}
}
}
}
// Input handling
var keys = {
left: false,
right: false,
up: false,
dig: false,
place: false
};
// Keyboard event handlers for PC
LK.on('keydown', function (event) {
switch (event.code) {
case 'KeyA':
case 'ArrowLeft':
keys.left = true;
break;
case 'KeyD':
case 'ArrowRight':
keys.right = true;
break;
case 'KeyW':
case 'ArrowUp':
case 'Space':
keys.up = true;
break;
case 'Digit1':
player.selectedSlot = 0;
hotbar.updateDisplay();
break;
case 'Digit2':
player.selectedSlot = 1;
hotbar.updateDisplay();
break;
case 'Digit3':
player.selectedSlot = 2;
hotbar.updateDisplay();
break;
case 'Digit4':
player.selectedSlot = 3;
hotbar.updateDisplay();
break;
case 'Digit5':
player.selectedSlot = 4;
hotbar.updateDisplay();
break;
case 'Digit6':
player.selectedSlot = 5;
hotbar.updateDisplay();
break;
case 'Digit7':
player.selectedSlot = 6;
hotbar.updateDisplay();
break;
case 'Digit8':
player.selectedSlot = 7;
hotbar.updateDisplay();
break;
case 'Digit9':
player.selectedSlot = 8;
hotbar.updateDisplay();
break;
}
});
LK.on('keyup', function (event) {
switch (event.code) {
case 'KeyA':
case 'ArrowLeft':
keys.left = false;
break;
case 'KeyD':
case 'ArrowRight':
keys.right = false;
break;
case 'KeyW':
case 'ArrowUp':
case 'Space':
keys.up = false;
break;
}
});
game.down = function (x, y, obj) {
var worldX = (x + camera.x) / BLOCK_SIZE;
var worldY = (y + camera.y) / BLOCK_SIZE;
var blockX = Math.floor(worldX);
var blockY = Math.floor(worldY);
// Check if clicking on hotbar
if (y > 2732 - 150) {
var slotIndex = Math.floor((x - (2048 / 2 - 380)) / 85);
if (slotIndex >= 0 && slotIndex < 9) {
player.selectedSlot = slotIndex;
hotbar.updateDisplay();
return;
}
}
var playerBlockX = Math.floor(player.x / BLOCK_SIZE);
var playerBlockY = Math.floor((player.y - player.height / 2) / BLOCK_SIZE);
var distance = Math.abs(blockX - playerBlockX) + Math.abs(blockY - playerBlockY);
if (distance <= 4) {
var existingBlock = getBlock(blockX, blockY);
if (existingBlock) {
// Mine block
if (gameMode === 'creative' || canMineBlock(existingBlock)) {
mineBlock(blockX, blockY, existingBlock);
}
} else {
// Place block
var selectedItem = player.inventory[player.selectedSlot];
if (selectedItem && selectedItem.count > 0) {
placeBlock(blockX, blockY, selectedItem.type);
}
}
}
};
// Right-click handler for PC (alternative block interaction)
LK.on('rightclick', function (x, y) {
var worldX = (x + camera.x) / BLOCK_SIZE;
var worldY = (y + camera.y) / BLOCK_SIZE;
var blockX = Math.floor(worldX);
var blockY = Math.floor(worldY);
var playerBlockX = Math.floor(player.x / BLOCK_SIZE);
var playerBlockY = Math.floor((player.y - player.height / 2) / BLOCK_SIZE);
var distance = Math.abs(blockX - playerBlockX) + Math.abs(blockY - playerBlockY);
if (distance <= 4) {
var existingBlock = getBlock(blockX, blockY);
if (!existingBlock) {
// Place block with right-click
var selectedItem = player.inventory[player.selectedSlot];
if (selectedItem && selectedItem.count > 0) {
placeBlock(blockX, blockY, selectedItem.type);
}
}
}
});
// Mouse move handler (for potential future features like block highlighting)
game.move = function (x, y, obj) {
// PC users can use mouse for highlighting blocks or other interactions
// Touch users can still tap to interact with blocks
};
game.up = function (x, y, obj) {
// Touch release handler - movement is now handled by keyboard for PC
// Keep this for any future touch-specific interactions
};
function canMineBlock(blockType) {
if (blockType === 'bedrock') return false;
return true;
}
function mineBlock(x, y, blockType) {
setBlock(x, y, null);
if (gameMode === 'survival') {
addToInventory(blockType, 1);
}
LK.getSound('dig').play();
// Create realistic mining particles
for (var i = 0; i < 12; i++) {
var particle = game.addChild(LK.getAsset('dirt_particle', {
anchorX: 0.5,
anchorY: 0.5
}));
particle.x = x * BLOCK_SIZE + BLOCK_SIZE / 2;
particle.y = y * BLOCK_SIZE + BLOCK_SIZE / 2;
particle.tint = getBlockColor(blockType);
// Random particle movement
var angle = Math.random() * Math.PI * 2;
var speed = 100 + Math.random() * 150;
var velX = Math.cos(angle) * speed;
var velY = Math.sin(angle) * speed - 100; // Upward bias
tween(particle).to({
x: particle.x + velX / 60 * 30,
y: particle.y + velY / 60 * 30,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, 500).onComplete(function () {
game.removeChild(particle);
}).start();
}
// Screen shake for impact
var originalX = game.x;
var originalY = game.y;
var shakeIntensity = 8;
for (var i = 0; i < 5; i++) {
tween(game).to({
x: originalX + (Math.random() - 0.5) * shakeIntensity,
y: originalY + (Math.random() - 0.5) * shakeIntensity
}, 50, i * 50).start();
}
tween(game).to({
x: originalX,
y: originalY
}, 100, 250).start();
}
function getBlockColor(blockType) {
var colors = {
'dirt': 0x6b4226,
'stone': 0x696969,
'grass': 0x228b22,
'wood': 0xd2691e,
'coal': 0x0f0f0f,
'iron': 0xa0522d,
'bedrock': 0x1a1a1a
};
return colors[blockType] || 0xffffff;
}
function placeBlock(x, y, blockType) {
// Don't place blocks inside player
var playerBlockX = Math.floor(player.x / BLOCK_SIZE);
var playerBlockY = Math.floor((player.y - player.height / 2) / BLOCK_SIZE);
if (x === playerBlockX && (y === playerBlockY || y === playerBlockY - 1)) {
return;
}
setBlock(x, y, blockType);
if (gameMode === 'survival') {
removeFromInventory(blockType, 1);
hotbar.updateDisplay();
}
LK.getSound('place').play();
}
function addToInventory(itemType, count) {
for (var i = 0; i < player.inventory.length; i++) {
var slot = player.inventory[i];
if (slot && slot.type === itemType) {
slot.count += count;
return;
}
}
// Find empty slot
for (var i = 0; i < player.inventory.length; i++) {
if (!player.inventory[i]) {
player.inventory[i] = {
type: itemType,
count: count
};
return;
}
}
}
function removeFromInventory(itemType, count) {
var slot = player.inventory[player.selectedSlot];
if (slot && slot.type === itemType && slot.count >= count) {
slot.count -= count;
if (slot.count <= 0) {
player.inventory[player.selectedSlot] = null;
}
}
}
function updateCamera() {
// Follow player
var targetX = player.x - 2048 / 2;
var targetY = player.y - 2732 / 2;
// Smooth camera movement
camera.x += (targetX - camera.x) * 0.1;
camera.y += (targetY - camera.y) * 0.1;
// Apply camera position to game
game.x = -camera.x;
game.y = -camera.y;
}
function updateUI() {
healthText.setText('Health: ' + Math.floor(player.health));
hungerText.setText('Hunger: ' + Math.floor(player.hunger));
modeText.setText('Mode: ' + (gameMode === 'creative' ? 'Creative' : 'Survival'));
hotbar.updateDisplay();
}
function updateDayNight() {
currentTime += 1000 / 60; // 60fps
var dayProgress = currentTime % dayLength / dayLength;
var skyColor;
if (dayProgress < 0.1 || dayProgress > 0.9) {
// Deep night
skyColor = 0x0c0c2a; // Very dark blue
} else if (dayProgress < 0.2 || dayProgress > 0.8) {
// Late night/early dawn
skyColor = 0x191970; // Midnight blue
} else if (dayProgress < 0.3 || dayProgress > 0.7) {
// Dawn/dusk transition
var r = Math.floor(255 * 0.8);
var g = Math.floor(100 * 0.6);
var b = Math.floor(71 * 0.4);
skyColor = r << 16 | g << 8 | b;
} else if (dayProgress < 0.4 || dayProgress > 0.6) {
// Morning/evening
skyColor = 0xffa500; // Orange
} else {
// Full day
skyColor = 0x87ceeb; // Sky blue
}
game.setBackgroundColor(skyColor);
// Add weather effects
if (WEATHER_EFFECTS && Math.random() < 0.001) {
// Rare weather events
if (Math.random() < 0.5) {
// Rain particles
for (var i = 0; i < 50; i++) {
createRainDrop();
}
} else {
// Wind effect
WIND_STRENGTH = (Math.random() - 0.5) * 20;
}
}
}
function createRainDrop() {
// Simple rain effect using existing assets
if (PARTICLE_COUNT < 100) {
var drop = game.addChild(LK.getAsset('dirt_particle', {
anchorX: 0.5,
anchorY: 0.5
}));
drop.x = Math.random() * 2048 + camera.x;
drop.y = camera.y - 100;
drop.alpha = 0.6;
drop.tint = 0x4169e1;
var fallSpeed = 400 + Math.random() * 200;
// Store drop reference for closure
var dropRef = drop;
tween(dropRef, {
y: camera.y + 2732
}, {
duration: 2832 / fallSpeed * 1000,
onFinish: function onFinish() {
game.removeChild(dropRef);
PARTICLE_COUNT--;
}
});
PARTICLE_COUNT++;
}
}
// Generate initial world
generateTerrain();
// Game update loop
game.update = function () {
// Handle input
if (keys.left) {
player.moveLeft();
}
if (keys.right) {
player.moveRight();
}
if (keys.up) {
player.jump();
keys.up = false; // Prevent continuous jumping
}
// Update game systems
updateCamera();
updateUI();
updateDayNight();
// Survival mode updates
if (gameMode === 'survival') {
// Slowly decrease hunger
if (LK.ticks % 300 === 0) {
player.hunger = Math.max(0, player.hunger - 1);
// Lose health if hungry
if (player.hunger <= 0 && LK.ticks % 60 === 0) {
player.health = Math.max(0, player.health - 1);
}
// Game over if health reaches 0
if (player.health <= 0) {
LK.showGameOver();
}
}
}
// Toggle game mode with double-tap detection
if (LK.ticks % 60 === 0) {
// Mode switching could be added here with UI buttons
}
};
// Initialize UI
updateUI(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Block = Container.expand(function (blockType, x, y) {
var self = Container.call(this);
self.blockType = blockType;
self.gridX = x;
self.gridY = y;
// Main block texture
var blockGraphic = self.attachAsset(blockType, {
anchorX: 0,
anchorY: 0
});
// Add realistic layered details based on block type
if (blockType === 'grass') {
var grassTop = self.attachAsset('grass_top', {
anchorX: 0,
anchorY: 0
});
grassTop.y = 0;
// Add grass blades for realism
for (var i = 0; i < 8; i++) {
var blade = self.attachAsset('grass_blade', {
anchorX: 0.5,
anchorY: 1
});
blade.x = Math.random() * 60 + 2;
blade.y = Math.random() * 4 + 2;
blade.rotation = (Math.random() - 0.5) * 0.3;
}
} else if (blockType === 'stone') {
// Add stone texture details
for (var i = 0; i < 6; i++) {
var texture = self.attachAsset('stone_texture', {
anchorX: 0,
anchorY: 0
});
texture.x = Math.random() * 48 + 0;
texture.y = Math.random() * 48 + 0;
texture.alpha = 0.3;
}
} else if (blockType === 'wood') {
// Add wood grain
for (var i = 0; i < 16; i++) {
var grain = self.attachAsset('wood_grain', {
anchorX: 0,
anchorY: 0
});
grain.y = i * 4;
grain.alpha = 0.4;
}
// Add tree rings
for (var i = 0; i < 3; i++) {
var ring = self.attachAsset('wood_ring', {
anchorX: 0.5,
anchorY: 0.5
});
ring.x = 32;
ring.y = 32;
ring.scaleX = 0.3 + i * 0.2;
ring.scaleY = 0.3 + i * 0.2;
ring.alpha = 0.6;
}
} else if (blockType === 'dirt') {
// Add dirt particles
for (var i = 0; i < 12; i++) {
var particle = self.attachAsset('dirt_particle', {
anchorX: 0.5,
anchorY: 0.5
});
particle.x = Math.random() * 56 + 4;
particle.y = Math.random() * 56 + 4;
particle.alpha = 0.7;
}
} else if (blockType === 'coal') {
// Add coal veins
for (var i = 0; i < 4; i++) {
var vein = self.attachAsset('coal_vein', {
anchorX: 0,
anchorY: 0
});
vein.x = Math.random() * 48 + 0;
vein.y = Math.random() * 48 + 0;
vein.rotation = Math.random() * Math.PI * 2;
}
} else if (blockType === 'iron') {
// Add iron ore deposits
for (var i = 0; i < 3; i++) {
var ore = self.attachAsset('iron_ore', {
anchorX: 0.5,
anchorY: 0.5
});
ore.x = Math.random() * 44 + 10;
ore.y = Math.random() * 44 + 10;
ore.alpha = 0.8;
}
} else if (blockType === 'bedrock') {
// Add bedrock highlights
for (var i = 0; i < 4; i++) {
var highlight = self.attachAsset('bedrock_highlight', {
anchorX: 0,
anchorY: 0
});
highlight.x = Math.random() * 32;
highlight.y = Math.random() * 32;
highlight.width = Math.random() * 20 + 10;
highlight.height = Math.random() * 20 + 10;
highlight.alpha = 0.2;
}
}
// Add subtle shadow effect for depth
var shadow = self.attachAsset(blockType, {
anchorX: 0,
anchorY: 0
});
shadow.x = 2;
shadow.y = 2;
shadow.alpha = 0.2;
shadow.tint = 0x000000;
self.x = x * BLOCK_SIZE;
self.y = y * BLOCK_SIZE;
return self;
});
var Hotbar = Container.expand(function () {
var self = Container.call(this);
self.slots = [];
for (var i = 0; i < 9; i++) {
var slot = self.addChild(LK.getAsset('hotbar_slot', {
anchorX: 0,
anchorY: 0
}));
slot.x = i * 85;
slot.y = 0;
self.slots.push(slot);
// Add item text
var itemText = new Text2('', {
size: 20,
fill: 0xFFFFFF
});
itemText.anchor.set(0.5, 0.5);
itemText.x = slot.x + 40;
itemText.y = slot.y + 40;
slot.itemText = itemText;
self.addChild(itemText);
}
self.selectedIndicator = self.addChild(LK.getAsset('hotbar_selected', {
anchorX: 0,
anchorY: 0
}));
self.selectedIndicator.x = -2;
self.selectedIndicator.y = -2;
self.updateDisplay = function () {
for (var i = 0; i < 9; i++) {
var item = player.inventory[i];
if (item) {
self.slots[i].itemText.setText(item.type.charAt(0).toUpperCase() + '\n' + item.count);
} else {
self.slots[i].itemText.setText('');
}
}
self.selectedIndicator.x = player.selectedSlot * 85 - 2;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
// Create detailed player body parts
self.body = self.attachAsset('player_body', {
anchorX: 0.5,
anchorY: 1
});
self.head = self.attachAsset('player_head', {
anchorX: 0.5,
anchorY: 1
});
self.head.y = -48;
self.hair = self.attachAsset('player_hair', {
anchorX: 0.5,
anchorY: 1
});
self.hair.y = -48;
self.leftEye = self.attachAsset('player_eyes', {
anchorX: 0.5,
anchorY: 0.5
});
self.leftEye.x = -6;
self.leftEye.y = -36;
self.leftEye.width = 4;
self.rightEye = self.attachAsset('player_eyes', {
anchorX: 0.5,
anchorY: 0.5
});
self.rightEye.x = 6;
self.rightEye.y = -36;
self.rightEye.width = 4;
self.leftArm = self.attachAsset('player_arm', {
anchorX: 0.5,
anchorY: 0
});
self.leftArm.x = -18;
self.leftArm.y = -40;
self.rightArm = self.attachAsset('player_arm', {
anchorX: 0.5,
anchorY: 0
});
self.rightArm.x = 18;
self.rightArm.y = -40;
self.leftLeg = self.attachAsset('player_leg', {
anchorX: 0.5,
anchorY: 0
});
self.leftLeg.x = -8;
self.leftLeg.y = -24;
self.rightLeg = self.attachAsset('player_leg', {
anchorX: 0.5,
anchorY: 0
});
self.rightLeg.x = 8;
self.rightLeg.y = -24;
self.velocity = {
x: 0,
y: 0
};
self.speed = 300;
self.jumpPower = 600;
self.onGround = false;
self.health = 100;
self.hunger = 100;
self.selectedSlot = 0;
self.walkCycle = 0;
self.facingDirection = 1; // 1 for right, -1 for left
self.isWalking = false;
self.isJumping = false;
self.inventory = [{
type: 'dirt',
count: 64
}, {
type: 'stone',
count: 32
}, {
type: 'wood',
count: 16
}, {
type: 'grass',
count: 24
}, null, null, null, null, null];
self.update = function () {
// Apply gravity
self.velocity.y += GRAVITY;
// Check if walking for animations
self.isWalking = Math.abs(self.velocity.x) > 50;
self.isJumping = !self.onGround;
// Movement
self.x += self.velocity.x / 60;
self.y += self.velocity.y / 60;
// Ground collision with more realistic physics
var groundY = getGroundLevel(Math.floor(self.x / BLOCK_SIZE)) * BLOCK_SIZE;
if (self.y >= groundY) {
self.y = groundY;
if (self.velocity.y > 0) {
// Landing impact
if (self.velocity.y > 200) {
LK.effects.flashObject(self, 0xffffff, 100);
}
}
self.velocity.y = 0;
self.onGround = true;
} else {
self.onGround = false;
}
// Realistic friction and air resistance
if (self.onGround) {
self.velocity.x *= 0.85; // Ground friction
} else {
self.velocity.x *= 0.95; // Air resistance
}
// Keep player in bounds
if (self.x < 0) self.x = 0;
if (self.x > WORLD_WIDTH * BLOCK_SIZE) self.x = WORLD_WIDTH * BLOCK_SIZE;
// Update walking animation
if (self.isWalking) {
self.walkCycle += 0.3;
var armSwing = Math.sin(self.walkCycle) * 0.3;
var legSwing = Math.sin(self.walkCycle) * 0.4;
self.leftArm.rotation = armSwing;
self.rightArm.rotation = -armSwing;
self.leftLeg.rotation = legSwing;
self.rightLeg.rotation = -legSwing;
// Head bob
self.head.y = -48 + Math.abs(Math.sin(self.walkCycle * 2)) * 2;
} else {
// Reset to neutral positions
self.leftArm.rotation = 0;
self.rightArm.rotation = 0;
self.leftLeg.rotation = 0;
self.rightLeg.rotation = 0;
self.head.y = -48;
}
// Jumping animation
if (self.isJumping) {
self.leftArm.rotation = -0.5;
self.rightArm.rotation = -0.5;
self.leftLeg.rotation = 0.3;
self.rightLeg.rotation = 0.3;
}
// Facing direction
if (self.velocity.x > 10) {
self.facingDirection = 1;
} else if (self.velocity.x < -10) {
self.facingDirection = -1;
}
self.scaleX = self.facingDirection;
};
self.moveLeft = function () {
self.velocity.x = -self.speed;
};
self.moveRight = function () {
self.velocity.x = self.speed;
};
self.jump = function () {
if (self.onGround) {
self.velocity.y = -self.jumpPower;
// Jump animation
tween(self.head).to({
y: -52
}, 200).start();
tween(self.head).to({
y: -48
}, 400, 200).start();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Realistic block textures with detailed colors and shading
// Sounds
// UI elements
// Player
// Block types
// Game constants with realistic physics
var BLOCK_SIZE = 64;
var WORLD_WIDTH = 128;
var WORLD_HEIGHT = 64;
var GRAVITY = 1200; // More realistic gravity
var SEA_LEVEL = 32;
var WIND_STRENGTH = 0;
var WEATHER_EFFECTS = true;
var PARTICLE_COUNT = 0;
// Game state
var gameMode = 'creative'; // 'survival' or 'creative'
var currentTime = 0;
var dayLength = 120000; // 2 minutes per day
var worldBlocks = {};
var worldGenerated = false;
// Camera
var camera = {
x: 0,
y: 0
};
// Create player
var player = game.addChild(new Player());
player.x = WORLD_WIDTH * BLOCK_SIZE / 2;
player.y = SEA_LEVEL * BLOCK_SIZE;
// Create UI
var healthText = new Text2('Health: 100', {
size: 32,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
healthText.x = 120;
healthText.y = 10;
var hungerText = new Text2('Hunger: 100', {
size: 32,
fill: 0xFFFFFF
});
hungerText.anchor.set(0, 0);
LK.gui.topLeft.addChild(hungerText);
hungerText.x = 120;
hungerText.y = 50;
var modeText = new Text2('Mode: Creative', {
size: 32,
fill: 0xFFFFFF
});
modeText.anchor.set(0, 0);
LK.gui.topRight.addChild(modeText);
modeText.x = -200;
modeText.y = 10;
// Create hotbar
var hotbar = new Hotbar();
LK.gui.bottom.addChild(hotbar);
hotbar.x = -380;
hotbar.y = -100;
// World generation functions
function getBlockKey(x, y) {
return x + ',' + y;
}
function setBlock(x, y, blockType) {
var key = getBlockKey(x, y);
if (blockType === null) {
if (worldBlocks[key]) {
game.removeChild(worldBlocks[key]);
delete worldBlocks[key];
}
} else {
if (worldBlocks[key]) {
game.removeChild(worldBlocks[key]);
}
var block = new Block(blockType, x, y);
worldBlocks[key] = block;
game.addChild(block);
}
}
function getBlock(x, y) {
var key = getBlockKey(x, y);
return worldBlocks[key] ? worldBlocks[key].blockType : null;
}
function getGroundLevel(x) {
// Simple terrain generation
var baseHeight = SEA_LEVEL - Math.sin(x * 0.1) * 8 - Math.sin(x * 0.05) * 16;
return Math.floor(baseHeight);
}
function generateTerrain() {
for (var x = 0; x < WORLD_WIDTH; x++) {
var groundLevel = getGroundLevel(x);
// Generate terrain layers
for (var y = 0; y < WORLD_HEIGHT; y++) {
if (y > groundLevel + 20) {
// Bedrock layer
setBlock(x, y, 'bedrock');
} else if (y > groundLevel + 5) {
// Stone layer with occasional ores
if (Math.random() < 0.1) {
setBlock(x, y, Math.random() < 0.5 ? 'iron' : 'coal');
} else {
setBlock(x, y, 'stone');
}
} else if (y > groundLevel) {
// Dirt layer
setBlock(x, y, 'dirt');
} else if (y === groundLevel) {
// Surface layer
setBlock(x, y, 'grass');
}
}
// Generate trees occasionally
if (Math.random() < 0.1 && groundLevel < SEA_LEVEL + 5) {
var treeHeight = 3 + Math.floor(Math.random() * 3);
for (var t = 1; t <= treeHeight; t++) {
if (groundLevel - t >= 0) {
setBlock(x, groundLevel - t, 'wood');
}
}
}
}
}
// Input handling
var keys = {
left: false,
right: false,
up: false,
dig: false,
place: false
};
// Keyboard event handlers for PC
LK.on('keydown', function (event) {
switch (event.code) {
case 'KeyA':
case 'ArrowLeft':
keys.left = true;
break;
case 'KeyD':
case 'ArrowRight':
keys.right = true;
break;
case 'KeyW':
case 'ArrowUp':
case 'Space':
keys.up = true;
break;
case 'Digit1':
player.selectedSlot = 0;
hotbar.updateDisplay();
break;
case 'Digit2':
player.selectedSlot = 1;
hotbar.updateDisplay();
break;
case 'Digit3':
player.selectedSlot = 2;
hotbar.updateDisplay();
break;
case 'Digit4':
player.selectedSlot = 3;
hotbar.updateDisplay();
break;
case 'Digit5':
player.selectedSlot = 4;
hotbar.updateDisplay();
break;
case 'Digit6':
player.selectedSlot = 5;
hotbar.updateDisplay();
break;
case 'Digit7':
player.selectedSlot = 6;
hotbar.updateDisplay();
break;
case 'Digit8':
player.selectedSlot = 7;
hotbar.updateDisplay();
break;
case 'Digit9':
player.selectedSlot = 8;
hotbar.updateDisplay();
break;
}
});
LK.on('keyup', function (event) {
switch (event.code) {
case 'KeyA':
case 'ArrowLeft':
keys.left = false;
break;
case 'KeyD':
case 'ArrowRight':
keys.right = false;
break;
case 'KeyW':
case 'ArrowUp':
case 'Space':
keys.up = false;
break;
}
});
game.down = function (x, y, obj) {
var worldX = (x + camera.x) / BLOCK_SIZE;
var worldY = (y + camera.y) / BLOCK_SIZE;
var blockX = Math.floor(worldX);
var blockY = Math.floor(worldY);
// Check if clicking on hotbar
if (y > 2732 - 150) {
var slotIndex = Math.floor((x - (2048 / 2 - 380)) / 85);
if (slotIndex >= 0 && slotIndex < 9) {
player.selectedSlot = slotIndex;
hotbar.updateDisplay();
return;
}
}
var playerBlockX = Math.floor(player.x / BLOCK_SIZE);
var playerBlockY = Math.floor((player.y - player.height / 2) / BLOCK_SIZE);
var distance = Math.abs(blockX - playerBlockX) + Math.abs(blockY - playerBlockY);
if (distance <= 4) {
var existingBlock = getBlock(blockX, blockY);
if (existingBlock) {
// Mine block
if (gameMode === 'creative' || canMineBlock(existingBlock)) {
mineBlock(blockX, blockY, existingBlock);
}
} else {
// Place block
var selectedItem = player.inventory[player.selectedSlot];
if (selectedItem && selectedItem.count > 0) {
placeBlock(blockX, blockY, selectedItem.type);
}
}
}
};
// Right-click handler for PC (alternative block interaction)
LK.on('rightclick', function (x, y) {
var worldX = (x + camera.x) / BLOCK_SIZE;
var worldY = (y + camera.y) / BLOCK_SIZE;
var blockX = Math.floor(worldX);
var blockY = Math.floor(worldY);
var playerBlockX = Math.floor(player.x / BLOCK_SIZE);
var playerBlockY = Math.floor((player.y - player.height / 2) / BLOCK_SIZE);
var distance = Math.abs(blockX - playerBlockX) + Math.abs(blockY - playerBlockY);
if (distance <= 4) {
var existingBlock = getBlock(blockX, blockY);
if (!existingBlock) {
// Place block with right-click
var selectedItem = player.inventory[player.selectedSlot];
if (selectedItem && selectedItem.count > 0) {
placeBlock(blockX, blockY, selectedItem.type);
}
}
}
});
// Mouse move handler (for potential future features like block highlighting)
game.move = function (x, y, obj) {
// PC users can use mouse for highlighting blocks or other interactions
// Touch users can still tap to interact with blocks
};
game.up = function (x, y, obj) {
// Touch release handler - movement is now handled by keyboard for PC
// Keep this for any future touch-specific interactions
};
function canMineBlock(blockType) {
if (blockType === 'bedrock') return false;
return true;
}
function mineBlock(x, y, blockType) {
setBlock(x, y, null);
if (gameMode === 'survival') {
addToInventory(blockType, 1);
}
LK.getSound('dig').play();
// Create realistic mining particles
for (var i = 0; i < 12; i++) {
var particle = game.addChild(LK.getAsset('dirt_particle', {
anchorX: 0.5,
anchorY: 0.5
}));
particle.x = x * BLOCK_SIZE + BLOCK_SIZE / 2;
particle.y = y * BLOCK_SIZE + BLOCK_SIZE / 2;
particle.tint = getBlockColor(blockType);
// Random particle movement
var angle = Math.random() * Math.PI * 2;
var speed = 100 + Math.random() * 150;
var velX = Math.cos(angle) * speed;
var velY = Math.sin(angle) * speed - 100; // Upward bias
tween(particle).to({
x: particle.x + velX / 60 * 30,
y: particle.y + velY / 60 * 30,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, 500).onComplete(function () {
game.removeChild(particle);
}).start();
}
// Screen shake for impact
var originalX = game.x;
var originalY = game.y;
var shakeIntensity = 8;
for (var i = 0; i < 5; i++) {
tween(game).to({
x: originalX + (Math.random() - 0.5) * shakeIntensity,
y: originalY + (Math.random() - 0.5) * shakeIntensity
}, 50, i * 50).start();
}
tween(game).to({
x: originalX,
y: originalY
}, 100, 250).start();
}
function getBlockColor(blockType) {
var colors = {
'dirt': 0x6b4226,
'stone': 0x696969,
'grass': 0x228b22,
'wood': 0xd2691e,
'coal': 0x0f0f0f,
'iron': 0xa0522d,
'bedrock': 0x1a1a1a
};
return colors[blockType] || 0xffffff;
}
function placeBlock(x, y, blockType) {
// Don't place blocks inside player
var playerBlockX = Math.floor(player.x / BLOCK_SIZE);
var playerBlockY = Math.floor((player.y - player.height / 2) / BLOCK_SIZE);
if (x === playerBlockX && (y === playerBlockY || y === playerBlockY - 1)) {
return;
}
setBlock(x, y, blockType);
if (gameMode === 'survival') {
removeFromInventory(blockType, 1);
hotbar.updateDisplay();
}
LK.getSound('place').play();
}
function addToInventory(itemType, count) {
for (var i = 0; i < player.inventory.length; i++) {
var slot = player.inventory[i];
if (slot && slot.type === itemType) {
slot.count += count;
return;
}
}
// Find empty slot
for (var i = 0; i < player.inventory.length; i++) {
if (!player.inventory[i]) {
player.inventory[i] = {
type: itemType,
count: count
};
return;
}
}
}
function removeFromInventory(itemType, count) {
var slot = player.inventory[player.selectedSlot];
if (slot && slot.type === itemType && slot.count >= count) {
slot.count -= count;
if (slot.count <= 0) {
player.inventory[player.selectedSlot] = null;
}
}
}
function updateCamera() {
// Follow player
var targetX = player.x - 2048 / 2;
var targetY = player.y - 2732 / 2;
// Smooth camera movement
camera.x += (targetX - camera.x) * 0.1;
camera.y += (targetY - camera.y) * 0.1;
// Apply camera position to game
game.x = -camera.x;
game.y = -camera.y;
}
function updateUI() {
healthText.setText('Health: ' + Math.floor(player.health));
hungerText.setText('Hunger: ' + Math.floor(player.hunger));
modeText.setText('Mode: ' + (gameMode === 'creative' ? 'Creative' : 'Survival'));
hotbar.updateDisplay();
}
function updateDayNight() {
currentTime += 1000 / 60; // 60fps
var dayProgress = currentTime % dayLength / dayLength;
var skyColor;
if (dayProgress < 0.1 || dayProgress > 0.9) {
// Deep night
skyColor = 0x0c0c2a; // Very dark blue
} else if (dayProgress < 0.2 || dayProgress > 0.8) {
// Late night/early dawn
skyColor = 0x191970; // Midnight blue
} else if (dayProgress < 0.3 || dayProgress > 0.7) {
// Dawn/dusk transition
var r = Math.floor(255 * 0.8);
var g = Math.floor(100 * 0.6);
var b = Math.floor(71 * 0.4);
skyColor = r << 16 | g << 8 | b;
} else if (dayProgress < 0.4 || dayProgress > 0.6) {
// Morning/evening
skyColor = 0xffa500; // Orange
} else {
// Full day
skyColor = 0x87ceeb; // Sky blue
}
game.setBackgroundColor(skyColor);
// Add weather effects
if (WEATHER_EFFECTS && Math.random() < 0.001) {
// Rare weather events
if (Math.random() < 0.5) {
// Rain particles
for (var i = 0; i < 50; i++) {
createRainDrop();
}
} else {
// Wind effect
WIND_STRENGTH = (Math.random() - 0.5) * 20;
}
}
}
function createRainDrop() {
// Simple rain effect using existing assets
if (PARTICLE_COUNT < 100) {
var drop = game.addChild(LK.getAsset('dirt_particle', {
anchorX: 0.5,
anchorY: 0.5
}));
drop.x = Math.random() * 2048 + camera.x;
drop.y = camera.y - 100;
drop.alpha = 0.6;
drop.tint = 0x4169e1;
var fallSpeed = 400 + Math.random() * 200;
// Store drop reference for closure
var dropRef = drop;
tween(dropRef, {
y: camera.y + 2732
}, {
duration: 2832 / fallSpeed * 1000,
onFinish: function onFinish() {
game.removeChild(dropRef);
PARTICLE_COUNT--;
}
});
PARTICLE_COUNT++;
}
}
// Generate initial world
generateTerrain();
// Game update loop
game.update = function () {
// Handle input
if (keys.left) {
player.moveLeft();
}
if (keys.right) {
player.moveRight();
}
if (keys.up) {
player.jump();
keys.up = false; // Prevent continuous jumping
}
// Update game systems
updateCamera();
updateUI();
updateDayNight();
// Survival mode updates
if (gameMode === 'survival') {
// Slowly decrease hunger
if (LK.ticks % 300 === 0) {
player.hunger = Math.max(0, player.hunger - 1);
// Lose health if hungry
if (player.hunger <= 0 && LK.ticks % 60 === 0) {
player.health = Math.max(0, player.health - 1);
}
// Game over if health reaches 0
if (player.health <= 0) {
LK.showGameOver();
}
}
}
// Toggle game mode with double-tap detection
if (LK.ticks % 60 === 0) {
// Mode switching could be added here with UI buttons
}
};
// Initialize UI
updateUI();