User prompt
perbaiki asset background tidak muncul
User prompt
tambah asset background jadi sembilan asset. background berubah rubah setiap permainan awal muncul
User prompt
musuh mati berputar putar saat ditembak ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'var bgRock1 = gameContainer.addChild(LK.getAsset('bgRock1', {' Line Number: 490
User prompt
add 7 background asset
User prompt
buat swipe kearah target untuk menembak
User prompt
buat aturan tap hanya untuk berjalan
User prompt
rubah aturan. tap layar ke target untuk bergerak. swipe untuk menembak ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
player bisa berbalik kekanan dan kiri
User prompt
player bisa bergerak kekanan dan kekiri juga ke atas dan bawa tanpa haru berputar
User prompt
bua animasi bulat merah meledak saat enemy mati ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
perbaiki untuk karakter orc yang bolak balik jangan tiba tiba menghilang
User prompt
buat animasi untuk orc yang menunggu terlihat seperi meloncat loncat ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
hilangkan bercak bercak pada background
User prompt
buat animasi ledakkan merah saat orc mati ditembak ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make player control to swipe dan hold
User prompt
fix background music ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fix lag game play
User prompt
make background detailed and sharp
User prompt
add background
User prompt
player bisa berbalik ke kanan, bisa berbalik ke kiri, bisa berbalik ke atas, bisa berbalik ke bawah ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat musuh menyerang player berulang saat bertemu ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat peluru player menyebar tiga penjuru didepan ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
musuh mencoba mendekat saat melihat player ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
player ada kemampuan auto target musub ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.direction = { x: 0, y: 0 }; self.lifetime = 0; self.maxLifetime = 120; // 2 seconds at 60fps self.update = function () { self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; self.lifetime++; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, tint: 0xFFFFFF }); self.speed = 1; self.health = 2; self.attackRange = 40; self.patrolDirection = Math.random() > 0.5 ? 1 : -1; // Random initial direction self.patrolAxis = Math.random() > 0.5 ? 'x' : 'y'; // Random patrol axis (horizontal or vertical) self.patrolDistance = CELL_SIZE * 3; // Patrol 3 cells distance self.startPosition = { x: 0, y: 0 }; // Will be set when enemy is placed self.isMoving = false; self.lastPlayerDistance = Infinity; self.startPatrol = function () { if (self.isMoving) return; self.isMoving = true; var targetX = self.x; var targetY = self.y; // Calculate target position based on patrol axis if (self.patrolAxis === 'x') { targetX = self.startPosition.x + self.patrolDirection * self.patrolDistance; } else { targetY = self.startPosition.y + self.patrolDirection * self.patrolDistance; } // Check if target position is valid if (canMoveTo(targetX, targetY)) { // Move to target position using tween tween(self, { x: targetX, y: targetY }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { self.isMoving = false; self.patrolDirection *= -1; // Reverse direction } }); } else { // If can't move in current direction, reverse immediately self.isMoving = false; self.patrolDirection *= -1; } }; self.update = function () { var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Start patrol movement if not already moving if (!self.isMoving) { self.startPatrol(); } // Attack player if in range if (distance < self.attackRange) { if (!self.lastPlayerDistance || self.lastPlayerDistance >= self.attackRange) { // Just entered attack range - perform melee attack playerHealth--; LK.effects.flashObject(player, 0xFF0000, 500); // Visual attack feedback - enemy briefly grows and turns red tween(self, { tint: 0xFF0000, scaleX: 1.3, scaleY: 1.3 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // Return to normal appearance tween(self, { tint: 0xFFFFFF, scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut }); } }); // Stop patrolling when attacking tween.stop(self); self.isMoving = false; } } self.lastPlayerDistance = distance; }; return self; }); var Ore = Container.expand(function () { var self = Container.call(this); var oreGraphics = self.attachAsset('ore', { anchorX: 0.5, anchorY: 0.5 }); self.value = 1; self.bobTimer = 0; self.baseY = self.y; self.update = function () { self.bobTimer++; self.y = self.baseY + Math.sin(self.bobTimer * 0.1) * 3; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2C1810 }); /**** * Game Code ****/ // Game constants var MAZE_WIDTH = 13; var MAZE_HEIGHT = 17; var CELL_SIZE = 80; var MAZE_OFFSET_X = (2048 - MAZE_WIDTH * CELL_SIZE) / 2; var MAZE_OFFSET_Y = 100; // Game variables var maze = []; var player; var enemies = []; var ores = []; var bullets = []; var playerHealth = 3; var oreCollected = 0; var oreTarget = 10; var level = 1; var exit; var gameContainer; // UI elements var healthText = new Text2('Health: 3', { size: 60, fill: 0xFF4444 }); healthText.anchor.set(0, 0); LK.gui.topLeft.addChild(healthText); var oreText = new Text2('Ore: 0/10', { size: 60, fill: 0xFFD700 }); oreText.anchor.set(0.5, 0); LK.gui.top.addChild(oreText); var levelText = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(1, 0); LK.gui.topRight.addChild(levelText); // Initialize maze array function initializeMaze() { maze = []; for (var y = 0; y < MAZE_HEIGHT; y++) { maze[y] = []; for (var x = 0; x < MAZE_WIDTH; x++) { maze[y][x] = 1; // 1 = wall, 0 = floor } } } // Simple maze generation using recursive backtracking function generateMaze() { initializeMaze(); var stack = []; var startX = 1; var startY = 1; maze[startY][startX] = 0; stack.push({ x: startX, y: startY }); while (stack.length > 0) { var current = stack[stack.length - 1]; var neighbors = []; // Check all four directions var directions = [{ x: 0, y: -2 }, { x: 2, y: 0 }, { x: 0, y: 2 }, { x: -2, y: 0 }]; for (var i = 0; i < directions.length; i++) { var nx = current.x + directions[i].x; var ny = current.y + directions[i].y; if (nx > 0 && nx < MAZE_WIDTH - 1 && ny > 0 && ny < MAZE_HEIGHT - 1 && maze[ny][nx] === 1) { neighbors.push({ x: nx, y: ny, dir: directions[i] }); } } if (neighbors.length > 0) { var chosen = neighbors[Math.floor(Math.random() * neighbors.length)]; // Remove wall between current and chosen maze[current.y + chosen.dir.y / 2][current.x + chosen.dir.x / 2] = 0; maze[chosen.y][chosen.x] = 0; stack.push(chosen); } else { stack.pop(); } } } // Create visual maze function createMazeVisual() { gameContainer = game.addChild(new Container()); for (var y = 0; y < MAZE_HEIGHT; y++) { for (var x = 0; x < MAZE_WIDTH; x++) { var cellX = MAZE_OFFSET_X + x * CELL_SIZE; var cellY = MAZE_OFFSET_Y + y * CELL_SIZE; if (maze[y][x] === 1) { // Wall var wall = LK.getAsset('wall', { x: cellX, y: cellY }); gameContainer.addChild(wall); } else { // Floor var floor = LK.getAsset('floor', { x: cellX, y: cellY }); gameContainer.addChild(floor); } } } } // Place ore in maze function placeOre() { var oreCount = oreTarget + Math.floor(level / 2); var placed = 0; while (placed < oreCount) { var x = Math.floor(Math.random() * MAZE_WIDTH); var y = Math.floor(Math.random() * MAZE_HEIGHT); if (maze[y][x] === 0 && (x !== 1 || y !== 1)) { var ore = gameContainer.addChild(new Ore()); ore.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2; ore.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2; ore.baseY = ore.y; ores.push(ore); placed++; } } } // Place enemies in maze function placeEnemies() { var enemyCount = 3 + level; var placed = 0; while (placed < enemyCount) { var x = Math.floor(Math.random() * MAZE_WIDTH); var y = Math.floor(Math.random() * MAZE_HEIGHT); if (maze[y][x] === 0 && (x !== 1 || y !== 1) && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 5) { var enemy = gameContainer.addChild(new Enemy()); enemy.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2; enemy.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2; enemy.startPosition.x = enemy.x; enemy.startPosition.y = enemy.y; enemies.push(enemy); placed++; } } } // Place exit function placeExit() { // Find a position far from start var placed = false; while (!placed) { var x = Math.floor(Math.random() * MAZE_WIDTH); var y = Math.floor(Math.random() * MAZE_HEIGHT); if (maze[y][x] === 0 && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 10) { exit = gameContainer.addChild(LK.getAsset('exit', { x: MAZE_OFFSET_X + x * CELL_SIZE, y: MAZE_OFFSET_Y + y * CELL_SIZE })); placed = true; } } } // Check if position is valid for movement function canMoveTo(x, y) { var mazeX = Math.floor((x - MAZE_OFFSET_X) / CELL_SIZE); var mazeY = Math.floor((y - MAZE_OFFSET_Y) / CELL_SIZE); if (mazeX < 0 || mazeX >= MAZE_WIDTH || mazeY < 0 || mazeY >= MAZE_HEIGHT) { return false; } return maze[mazeY][mazeX] === 0; } // Initialize level function initializeLevel() { // Clear existing game objects if (gameContainer) { gameContainer.destroy(); } enemies = []; ores = []; bullets = []; oreCollected = 0; // Generate new maze generateMaze(); createMazeVisual(); // Create player player = gameContainer.addChild(LK.getAsset('player', { anchorX: 0.5, anchorY: 0.5, x: MAZE_OFFSET_X + 1 * CELL_SIZE + CELL_SIZE / 2, y: MAZE_OFFSET_Y + 1 * CELL_SIZE + CELL_SIZE / 2 })); // Place game objects placeOre(); placeEnemies(); placeExit(); // Update UI updateUI(); } // Update UI function updateUI() { healthText.setText('Health: ' + playerHealth); oreText.setText('Ore: ' + oreCollected + '/' + oreTarget); levelText.setText('Level: ' + level); } // Shooting system var dragNode = null; var shootCooldown = 0; var autoTargetEnabled = true; var autoTargetCooldown = 0; var autoTargetDelay = 30; // Auto-target every half second (30 frames at 60fps) function findNearestEnemy() { if (enemies.length === 0) return null; var nearestEnemy = null; var nearestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - player.x; var dy = enemy.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } return nearestEnemy; } function autoTarget() { if (!autoTargetEnabled || autoTargetCooldown > 0) return; var nearestEnemy = findNearestEnemy(); if (nearestEnemy) { shoot(nearestEnemy.x, nearestEnemy.y); autoTargetCooldown = autoTargetDelay; } } function shoot(targetX, targetY) { if (shootCooldown > 0) return; var dx = targetX - player.x; var dy = targetY - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 50) return; // Don't shoot if too close var bullet = gameContainer.addChild(new Bullet()); bullet.x = player.x; bullet.y = player.y; bullet.direction.x = dx / distance; bullet.direction.y = dy / distance; bullets.push(bullet); shootCooldown = 15; // Quarter second cooldown LK.getSound('shoot').play(); } // Main game loop game.update = function () { if (shootCooldown > 0) shootCooldown--; if (autoTargetCooldown > 0) autoTargetCooldown--; // Auto-target nearest enemy autoTarget(); // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // Check bullet lifetime if (bullet.lifetime >= bullet.maxLifetime) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check wall collision if (!canMoveTo(bullet.x, bullet.y)) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check enemy collision var hitEnemy = false; for (var j = enemies.length - 1; j >= 0; j--) { if (bullet.intersects(enemies[j])) { enemies[j].health--; LK.getSound('enemyHit').play(); if (enemies[j].health <= 0) { // Create explosion effect before destroying enemy tween(enemies[j], { scaleX: 2, scaleY: 2, alpha: 0, tint: 0xFF6600 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Enemy is destroyed after explosion animation } }); enemies[j].destroy(); enemies.splice(j, 1); } bullet.destroy(); bullets.splice(i, 1); hitEnemy = true; break; } } if (hitEnemy) continue; } // Check ore collection for (var i = ores.length - 1; i >= 0; i--) { if (player.intersects(ores[i])) { oreCollected++; LK.getSound('oreCollect').play(); ores[i].destroy(); ores.splice(i, 1); updateUI(); } } // Check exit condition if (exit && player.intersects(exit) && oreCollected >= oreTarget) { level++; oreTarget += 2; initializeLevel(); return; } // Check game over if (playerHealth <= 0) { LK.showGameOver(); return; } // Check win condition (survive 10 levels) if (level > 10) { LK.showYouWin(); return; } }; // Swipe-based movement system var swipeStart = { x: 0, y: 0 }; var swipeEnd = { x: 0, y: 0 }; var isTracking = false; var playerSpeed = 80; // Full cell movement var swipeThreshold = 50; // Minimum distance for swipe detection var lastMoveTime = 0; var moveDelay = 200; // Delay between moves in milliseconds var isPlayerMoving = false; game.down = function (x, y, obj) { swipeStart.x = x; swipeStart.y = y; isTracking = true; }; game.move = function (x, y, obj) { if (isTracking) { swipeEnd.x = x; swipeEnd.y = y; } }; game.up = function (x, y, obj) { if (!isTracking) return; isTracking = false; var dx = swipeEnd.x - swipeStart.x; var dy = swipeEnd.y - swipeStart.y; var swipeDistance = Math.sqrt(dx * dx + dy * dy); // Check if swipe is long enough if (swipeDistance < swipeThreshold) { // Short tap - shoot in that direction shoot(x, y); return; } // Prevent too frequent moves and simultaneous movements var currentTime = Date.now(); if (currentTime - lastMoveTime < moveDelay || isPlayerMoving) return; // Determine swipe direction var moveX = 0; var moveY = 0; if (Math.abs(dx) > Math.abs(dy)) { // Horizontal swipe moveX = dx > 0 ? playerSpeed : -playerSpeed; } else { // Vertical swipe moveY = dy > 0 ? playerSpeed : -playerSpeed; } // Calculate new position var newX = player.x + moveX; var newY = player.y + moveY; // Check if movement is valid and animate smoothly if (canMoveTo(newX, player.y) && Math.abs(moveX) > 0) { isPlayerMoving = true; tween(player, { x: newX }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { isPlayerMoving = false; } }); lastMoveTime = currentTime; } else if (canMoveTo(player.x, newY) && Math.abs(moveY) > 0) { isPlayerMoving = true; tween(player, { y: newY }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { isPlayerMoving = false; } }); lastMoveTime = currentTime; } }; // Initialize the first level initializeLevel();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.direction = {
x: 0,
y: 0
};
self.lifetime = 0;
self.maxLifetime = 120; // 2 seconds at 60fps
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
self.lifetime++;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFFFFF
});
self.speed = 1;
self.health = 2;
self.attackRange = 40;
self.patrolDirection = Math.random() > 0.5 ? 1 : -1; // Random initial direction
self.patrolAxis = Math.random() > 0.5 ? 'x' : 'y'; // Random patrol axis (horizontal or vertical)
self.patrolDistance = CELL_SIZE * 3; // Patrol 3 cells distance
self.startPosition = {
x: 0,
y: 0
}; // Will be set when enemy is placed
self.isMoving = false;
self.lastPlayerDistance = Infinity;
self.startPatrol = function () {
if (self.isMoving) return;
self.isMoving = true;
var targetX = self.x;
var targetY = self.y;
// Calculate target position based on patrol axis
if (self.patrolAxis === 'x') {
targetX = self.startPosition.x + self.patrolDirection * self.patrolDistance;
} else {
targetY = self.startPosition.y + self.patrolDirection * self.patrolDistance;
}
// Check if target position is valid
if (canMoveTo(targetX, targetY)) {
// Move to target position using tween
tween(self, {
x: targetX,
y: targetY
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
self.isMoving = false;
self.patrolDirection *= -1; // Reverse direction
}
});
} else {
// If can't move in current direction, reverse immediately
self.isMoving = false;
self.patrolDirection *= -1;
}
};
self.update = function () {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Start patrol movement if not already moving
if (!self.isMoving) {
self.startPatrol();
}
// Attack player if in range
if (distance < self.attackRange) {
if (!self.lastPlayerDistance || self.lastPlayerDistance >= self.attackRange) {
// Just entered attack range - perform melee attack
playerHealth--;
LK.effects.flashObject(player, 0xFF0000, 500);
// Visual attack feedback - enemy briefly grows and turns red
tween(self, {
tint: 0xFF0000,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return to normal appearance
tween(self, {
tint: 0xFFFFFF,
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
});
// Stop patrolling when attacking
tween.stop(self);
self.isMoving = false;
}
}
self.lastPlayerDistance = distance;
};
return self;
});
var Ore = Container.expand(function () {
var self = Container.call(this);
var oreGraphics = self.attachAsset('ore', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 1;
self.bobTimer = 0;
self.baseY = self.y;
self.update = function () {
self.bobTimer++;
self.y = self.baseY + Math.sin(self.bobTimer * 0.1) * 3;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C1810
});
/****
* Game Code
****/
// Game constants
var MAZE_WIDTH = 13;
var MAZE_HEIGHT = 17;
var CELL_SIZE = 80;
var MAZE_OFFSET_X = (2048 - MAZE_WIDTH * CELL_SIZE) / 2;
var MAZE_OFFSET_Y = 100;
// Game variables
var maze = [];
var player;
var enemies = [];
var ores = [];
var bullets = [];
var playerHealth = 3;
var oreCollected = 0;
var oreTarget = 10;
var level = 1;
var exit;
var gameContainer;
// UI elements
var healthText = new Text2('Health: 3', {
size: 60,
fill: 0xFF4444
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
var oreText = new Text2('Ore: 0/10', {
size: 60,
fill: 0xFFD700
});
oreText.anchor.set(0.5, 0);
LK.gui.top.addChild(oreText);
var levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
// Initialize maze array
function initializeMaze() {
maze = [];
for (var y = 0; y < MAZE_HEIGHT; y++) {
maze[y] = [];
for (var x = 0; x < MAZE_WIDTH; x++) {
maze[y][x] = 1; // 1 = wall, 0 = floor
}
}
}
// Simple maze generation using recursive backtracking
function generateMaze() {
initializeMaze();
var stack = [];
var startX = 1;
var startY = 1;
maze[startY][startX] = 0;
stack.push({
x: startX,
y: startY
});
while (stack.length > 0) {
var current = stack[stack.length - 1];
var neighbors = [];
// Check all four directions
var directions = [{
x: 0,
y: -2
}, {
x: 2,
y: 0
}, {
x: 0,
y: 2
}, {
x: -2,
y: 0
}];
for (var i = 0; i < directions.length; i++) {
var nx = current.x + directions[i].x;
var ny = current.y + directions[i].y;
if (nx > 0 && nx < MAZE_WIDTH - 1 && ny > 0 && ny < MAZE_HEIGHT - 1 && maze[ny][nx] === 1) {
neighbors.push({
x: nx,
y: ny,
dir: directions[i]
});
}
}
if (neighbors.length > 0) {
var chosen = neighbors[Math.floor(Math.random() * neighbors.length)];
// Remove wall between current and chosen
maze[current.y + chosen.dir.y / 2][current.x + chosen.dir.x / 2] = 0;
maze[chosen.y][chosen.x] = 0;
stack.push(chosen);
} else {
stack.pop();
}
}
}
// Create visual maze
function createMazeVisual() {
gameContainer = game.addChild(new Container());
for (var y = 0; y < MAZE_HEIGHT; y++) {
for (var x = 0; x < MAZE_WIDTH; x++) {
var cellX = MAZE_OFFSET_X + x * CELL_SIZE;
var cellY = MAZE_OFFSET_Y + y * CELL_SIZE;
if (maze[y][x] === 1) {
// Wall
var wall = LK.getAsset('wall', {
x: cellX,
y: cellY
});
gameContainer.addChild(wall);
} else {
// Floor
var floor = LK.getAsset('floor', {
x: cellX,
y: cellY
});
gameContainer.addChild(floor);
}
}
}
}
// Place ore in maze
function placeOre() {
var oreCount = oreTarget + Math.floor(level / 2);
var placed = 0;
while (placed < oreCount) {
var x = Math.floor(Math.random() * MAZE_WIDTH);
var y = Math.floor(Math.random() * MAZE_HEIGHT);
if (maze[y][x] === 0 && (x !== 1 || y !== 1)) {
var ore = gameContainer.addChild(new Ore());
ore.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2;
ore.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2;
ore.baseY = ore.y;
ores.push(ore);
placed++;
}
}
}
// Place enemies in maze
function placeEnemies() {
var enemyCount = 3 + level;
var placed = 0;
while (placed < enemyCount) {
var x = Math.floor(Math.random() * MAZE_WIDTH);
var y = Math.floor(Math.random() * MAZE_HEIGHT);
if (maze[y][x] === 0 && (x !== 1 || y !== 1) && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 5) {
var enemy = gameContainer.addChild(new Enemy());
enemy.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2;
enemy.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2;
enemy.startPosition.x = enemy.x;
enemy.startPosition.y = enemy.y;
enemies.push(enemy);
placed++;
}
}
}
// Place exit
function placeExit() {
// Find a position far from start
var placed = false;
while (!placed) {
var x = Math.floor(Math.random() * MAZE_WIDTH);
var y = Math.floor(Math.random() * MAZE_HEIGHT);
if (maze[y][x] === 0 && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 10) {
exit = gameContainer.addChild(LK.getAsset('exit', {
x: MAZE_OFFSET_X + x * CELL_SIZE,
y: MAZE_OFFSET_Y + y * CELL_SIZE
}));
placed = true;
}
}
}
// Check if position is valid for movement
function canMoveTo(x, y) {
var mazeX = Math.floor((x - MAZE_OFFSET_X) / CELL_SIZE);
var mazeY = Math.floor((y - MAZE_OFFSET_Y) / CELL_SIZE);
if (mazeX < 0 || mazeX >= MAZE_WIDTH || mazeY < 0 || mazeY >= MAZE_HEIGHT) {
return false;
}
return maze[mazeY][mazeX] === 0;
}
// Initialize level
function initializeLevel() {
// Clear existing game objects
if (gameContainer) {
gameContainer.destroy();
}
enemies = [];
ores = [];
bullets = [];
oreCollected = 0;
// Generate new maze
generateMaze();
createMazeVisual();
// Create player
player = gameContainer.addChild(LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
x: MAZE_OFFSET_X + 1 * CELL_SIZE + CELL_SIZE / 2,
y: MAZE_OFFSET_Y + 1 * CELL_SIZE + CELL_SIZE / 2
}));
// Place game objects
placeOre();
placeEnemies();
placeExit();
// Update UI
updateUI();
}
// Update UI
function updateUI() {
healthText.setText('Health: ' + playerHealth);
oreText.setText('Ore: ' + oreCollected + '/' + oreTarget);
levelText.setText('Level: ' + level);
}
// Shooting system
var dragNode = null;
var shootCooldown = 0;
var autoTargetEnabled = true;
var autoTargetCooldown = 0;
var autoTargetDelay = 30; // Auto-target every half second (30 frames at 60fps)
function findNearestEnemy() {
if (enemies.length === 0) return null;
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
return nearestEnemy;
}
function autoTarget() {
if (!autoTargetEnabled || autoTargetCooldown > 0) return;
var nearestEnemy = findNearestEnemy();
if (nearestEnemy) {
shoot(nearestEnemy.x, nearestEnemy.y);
autoTargetCooldown = autoTargetDelay;
}
}
function shoot(targetX, targetY) {
if (shootCooldown > 0) return;
var dx = targetX - player.x;
var dy = targetY - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 50) return; // Don't shoot if too close
var bullet = gameContainer.addChild(new Bullet());
bullet.x = player.x;
bullet.y = player.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
bullets.push(bullet);
shootCooldown = 15; // Quarter second cooldown
LK.getSound('shoot').play();
}
// Main game loop
game.update = function () {
if (shootCooldown > 0) shootCooldown--;
if (autoTargetCooldown > 0) autoTargetCooldown--;
// Auto-target nearest enemy
autoTarget();
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check bullet lifetime
if (bullet.lifetime >= bullet.maxLifetime) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check wall collision
if (!canMoveTo(bullet.x, bullet.y)) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check enemy collision
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
if (bullet.intersects(enemies[j])) {
enemies[j].health--;
LK.getSound('enemyHit').play();
if (enemies[j].health <= 0) {
// Create explosion effect before destroying enemy
tween(enemies[j], {
scaleX: 2,
scaleY: 2,
alpha: 0,
tint: 0xFF6600
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Enemy is destroyed after explosion animation
}
});
enemies[j].destroy();
enemies.splice(j, 1);
}
bullet.destroy();
bullets.splice(i, 1);
hitEnemy = true;
break;
}
}
if (hitEnemy) continue;
}
// Check ore collection
for (var i = ores.length - 1; i >= 0; i--) {
if (player.intersects(ores[i])) {
oreCollected++;
LK.getSound('oreCollect').play();
ores[i].destroy();
ores.splice(i, 1);
updateUI();
}
}
// Check exit condition
if (exit && player.intersects(exit) && oreCollected >= oreTarget) {
level++;
oreTarget += 2;
initializeLevel();
return;
}
// Check game over
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
// Check win condition (survive 10 levels)
if (level > 10) {
LK.showYouWin();
return;
}
};
// Swipe-based movement system
var swipeStart = {
x: 0,
y: 0
};
var swipeEnd = {
x: 0,
y: 0
};
var isTracking = false;
var playerSpeed = 80; // Full cell movement
var swipeThreshold = 50; // Minimum distance for swipe detection
var lastMoveTime = 0;
var moveDelay = 200; // Delay between moves in milliseconds
var isPlayerMoving = false;
game.down = function (x, y, obj) {
swipeStart.x = x;
swipeStart.y = y;
isTracking = true;
};
game.move = function (x, y, obj) {
if (isTracking) {
swipeEnd.x = x;
swipeEnd.y = y;
}
};
game.up = function (x, y, obj) {
if (!isTracking) return;
isTracking = false;
var dx = swipeEnd.x - swipeStart.x;
var dy = swipeEnd.y - swipeStart.y;
var swipeDistance = Math.sqrt(dx * dx + dy * dy);
// Check if swipe is long enough
if (swipeDistance < swipeThreshold) {
// Short tap - shoot in that direction
shoot(x, y);
return;
}
// Prevent too frequent moves and simultaneous movements
var currentTime = Date.now();
if (currentTime - lastMoveTime < moveDelay || isPlayerMoving) return;
// Determine swipe direction
var moveX = 0;
var moveY = 0;
if (Math.abs(dx) > Math.abs(dy)) {
// Horizontal swipe
moveX = dx > 0 ? playerSpeed : -playerSpeed;
} else {
// Vertical swipe
moveY = dy > 0 ? playerSpeed : -playerSpeed;
}
// Calculate new position
var newX = player.x + moveX;
var newY = player.y + moveY;
// Check if movement is valid and animate smoothly
if (canMoveTo(newX, player.y) && Math.abs(moveX) > 0) {
isPlayerMoving = true;
tween(player, {
x: newX
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
isPlayerMoving = false;
}
});
lastMoveTime = currentTime;
} else if (canMoveTo(player.x, newY) && Math.abs(moveY) > 0) {
isPlayerMoving = true;
tween(player, {
y: newY
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
isPlayerMoving = false;
}
});
lastMoveTime = currentTime;
}
};
// Initialize the first level
initializeLevel();
2d sprites old dwarf hold shootgun. In-Game asset. 2d. High contrast. No shadows
2d chibi green evil underground fat ork. In-Game asset. 2d. High contrast. No shadows
2d golds ors brigh stone. In-Game asset. 2d. High contrast. No shadows
2d cave tunnel corridor. In-Game asset. 2d. High contrast. No shadows