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.attackCooldown = 0;
self.attackInterval = 60; // Attack every second at 60fps
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)) {
// Store the original position for safe restoration
var originalX = self.x;
var originalY = self.y;
// Move to target position using tween
tween(self, {
x: targetX,
y: targetY
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
// Ensure enemy is at a valid position after movement
if (!canMoveTo(self.x, self.y)) {
// If somehow ended up in invalid position, restore to original
self.x = originalX;
self.y = originalY;
}
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 () {
// Add bouncing animation when enemy is not moving (idle/waiting state)
if (!self.isMoving) {
if (!self.bounceTimer) self.bounceTimer = 0;
self.bounceTimer++;
// Create a subtle bouncing effect
var bounceOffset = Math.sin(self.bounceTimer * 0.15) * 2;
// Use current position as base instead of startPosition to avoid conflicts
var baseY = self.startPosition.y;
self.y = baseY + bounceOffset;
} else {
// Reset bounce timer when moving to ensure smooth transitions
self.bounceTimer = 0;
}
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var detectionRange = CELL_SIZE * 4; // Enemy can see player from 4 cells away
// Check if player is within detection range and line of sight (optimized - check every 10 frames)
var canSeePlayer = false;
if (distance < detectionRange) {
// Only do expensive line of sight calculation every 10 frames
if (!self.losCheckTimer) self.losCheckTimer = 0;
self.losCheckTimer++;
if (self.losCheckTimer >= 10 || !self.hasOwnProperty('lastCanSeePlayer')) {
self.losCheckTimer = 0;
// Simple line of sight check - check if there are walls between enemy and player
var steps = Math.ceil(distance / 40); // Reduced precision from 20 to 40
var stepX = dx / steps;
var stepY = dy / steps;
self.lastCanSeePlayer = true;
for (var step = 1; step < steps; step++) {
var checkX = self.x + stepX * step;
var checkY = self.y + stepY * step;
if (!canMoveTo(checkX, checkY)) {
self.lastCanSeePlayer = false;
break;
}
}
}
canSeePlayer = self.lastCanSeePlayer;
} else {
canSeePlayer = self.lastCanSeePlayer;
}
// If can see player and not in attack range, move towards player
if (canSeePlayer && distance > self.attackRange) {
if (!self.isMoving) {
self.isMoving = true;
// Stop current patrol movement
tween.stop(self);
// Calculate next position towards player (one cell at a time)
var moveDistance = CELL_SIZE;
var normalizedDx = dx / distance;
var normalizedDy = dy / distance;
var targetX = self.x + normalizedDx * moveDistance;
var targetY = self.y + normalizedDy * moveDistance;
// Try to move towards player, prioritize the axis with larger distance
if (Math.abs(dx) > Math.abs(dy)) {
// Try horizontal movement first
var horizontalTarget = self.x + (dx > 0 ? moveDistance : -moveDistance);
if (canMoveTo(horizontalTarget, self.y)) {
targetX = horizontalTarget;
targetY = self.y;
} else if (canMoveTo(self.x, self.y + (dy > 0 ? moveDistance : -moveDistance))) {
// If horizontal blocked, try vertical
targetX = self.x;
targetY = self.y + (dy > 0 ? moveDistance : -moveDistance);
} else {
// Can't move towards player
targetX = self.x;
targetY = self.y;
}
} else {
// Try vertical movement first
var verticalTarget = self.y + (dy > 0 ? moveDistance : -moveDistance);
if (canMoveTo(self.x, verticalTarget)) {
targetX = self.x;
targetY = verticalTarget;
} else if (canMoveTo(self.x + (dx > 0 ? moveDistance : -moveDistance), self.y)) {
// If vertical blocked, try horizontal
targetX = self.x + (dx > 0 ? moveDistance : -moveDistance);
targetY = self.y;
} else {
// Can't move towards player
targetX = self.x;
targetY = self.y;
}
}
// Move towards calculated target
if (targetX !== self.x || targetY !== self.y) {
// Store current position for safety
var safeX = self.x;
var safeY = self.y;
tween(self, {
x: targetX,
y: targetY
}, {
duration: 1000,
easing: tween.linear,
onFinish: function onFinish() {
// Validate final position
if (!canMoveTo(self.x, self.y)) {
self.x = safeX;
self.y = safeY;
}
self.isMoving = false;
}
});
} else {
self.isMoving = false;
}
}
} else if (!canSeePlayer) {
// Start patrol movement if not already moving and can't see player
if (!self.isMoving) {
self.startPatrol();
}
}
// Attack player if in range
if (distance < self.attackRange) {
// Stop patrolling when in attack range
if (!self.lastPlayerDistance || self.lastPlayerDistance >= self.attackRange) {
tween.stop(self);
self.isMoving = false;
}
// Continuously attack while in range
if (self.attackCooldown <= 0) {
// 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
});
}
});
// Reset attack cooldown
self.attackCooldown = self.attackInterval;
}
}
// Update attack cooldown
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
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;
}
}
}
// Create detailed background with various environmental elements
function createDetailedBackground() {
if (!gameContainer) {
console.log("gameContainer not available for background creation");
return;
}
var backgroundElements = [];
// Select one of 9 background variations randomly
var backgroundType = Math.floor(Math.random() * 9);
// Background variation 0: Rock dominant
if (backgroundType === 0) {
// Add many background rocks
for (var i = 0; i < 15; i++) {
var bgRock1 = gameContainer.addChild(LK.getAsset('bgRock1', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.4,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgRock1);
}
for (var i = 0; i < 20; i++) {
var bgRock2 = gameContainer.addChild(LK.getAsset('bgRock2', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgRock2);
}
}
// Background variation 1: Crystal cave
else if (backgroundType === 1) {
for (var i = 0; i < 30; i++) {
var bgCrystal = gameContainer.addChild(LK.getAsset('bgCrystal', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5,
rotation: Math.random() * Math.PI * 2,
scaleY: 0.8 + Math.random() * 0.4
}));
backgroundElements.push(bgCrystal);
}
}
// Background variation 2: Moss covered
else if (backgroundType === 2) {
for (var i = 0; i < 40; i++) {
var bgMoss = gameContainer.addChild(LK.getAsset('bgMoss', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.45,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgMoss);
}
// Add some vines
for (var i = 0; i < 15; i++) {
var bgVines = gameContainer.addChild(LK.getAsset('bgVines', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgVines);
}
}
// Background variation 3: Stalactite heavy
else if (backgroundType === 3) {
for (var i = 0; i < 25; i++) {
var bgStalactite = gameContainer.addChild(LK.getAsset('bgStalactite', {
x: Math.random() * 2048,
y: Math.random() * 400,
// Extended from top
anchorX: 0.5,
anchorY: 0,
alpha: 0.4,
rotation: Math.random() * 0.4 - 0.2,
scaleY: 0.8 + Math.random() * 0.6
}));
backgroundElements.push(bgStalactite);
}
}
// Background variation 4: Pebble field
else if (backgroundType === 4) {
for (var i = 0; i < 35; i++) {
var bgPebbles = gameContainer.addChild(LK.getAsset('bgPebbles', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.35,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgPebbles);
}
}
// Background variation 5: Cracked terrain
else if (backgroundType === 5) {
for (var i = 0; i < 50; i++) {
var bgCracks = gameContainer.addChild(LK.getAsset('bgCracks', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.25,
rotation: Math.random() * Math.PI * 2,
scaleX: 0.5 + Math.random() * 1.5
}));
backgroundElements.push(bgCracks);
}
}
// Background variation 6: Boulder field
else if (backgroundType === 6) {
for (var i = 0; i < 12; i++) {
var bgBoulder = gameContainer.addChild(LK.getAsset('bgBoulder', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgBoulder);
}
}
// Background variation 7: Mixed cave
else if (backgroundType === 7) {
// Mixed environment with moderate amounts of everything
for (var i = 0; i < 8; i++) {
var bgRock1 = gameContainer.addChild(LK.getAsset('bgRock1', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgRock1);
}
for (var i = 0; i < 10; i++) {
var bgCrystal = gameContainer.addChild(LK.getAsset('bgCrystal', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.4,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgCrystal);
}
for (var i = 0; i < 15; i++) {
var bgMoss = gameContainer.addChild(LK.getAsset('bgMoss', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.35,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgMoss);
}
}
// Background variation 8: Vine jungle cave
else if (backgroundType === 8) {
for (var i = 0; i < 30; i++) {
var bgVines = gameContainer.addChild(LK.getAsset('bgVines', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.4,
rotation: Math.random() * Math.PI * 2,
scaleX: 0.8 + Math.random() * 0.4
}));
backgroundElements.push(bgVines);
}
for (var i = 0; i < 25; i++) {
var bgMoss = gameContainer.addChild(LK.getAsset('bgMoss', {
x: Math.random() * 2048,
y: Math.random() * 2732,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
rotation: Math.random() * Math.PI * 2
}));
backgroundElements.push(bgMoss);
}
}
// Send all background elements to back
for (var i = 0; i < backgroundElements.length; i++) {
gameContainer.setChildIndex(backgroundElements[i], 0);
}
}
// 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;
// Add detailed background
var background = game.addChild(LK.getAsset('background', {
x: 0,
y: 0,
width: 2048,
height: 2732
}));
// Generate new maze
generateMaze();
createMazeVisual();
// Create detailed background elements
createDetailedBackground();
// 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;
function shoot(targetX, targetY) {
if (shootCooldown > 0) return;
// Limit maximum bullets to prevent lag
if (bullets.length >= 15) 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
// Calculate base direction
var baseDirectionX = dx / distance;
var baseDirectionY = dy / distance;
// Create three bullets with spread angles
var spreadAngles = [-0.3, 0, 0.3]; // Left, center, right (in radians, about 17 degrees each side)
for (var i = 0; i < spreadAngles.length; i++) {
var angle = Math.atan2(baseDirectionY, baseDirectionX) + spreadAngles[i];
var bullet = gameContainer.addChild(new Bullet());
bullet.x = player.x;
bullet.y = player.y;
bullet.direction.x = Math.cos(angle);
bullet.direction.y = Math.sin(angle);
bullets.push(bullet);
}
shootCooldown = 15; // Quarter second cooldown
LK.getSound('shoot').play();
}
// Main game loop
game.update = function () {
if (shootCooldown > 0) shootCooldown--;
// Handle hold movement
if (isTracking && !isHolding) {
var currentTime = Date.now();
var holdTime = currentTime - holdStartTime;
// Check if we should start hold movement
if (holdTime >= holdThreshold) {
var dx = swipeEnd.x - swipeStart.x;
var dy = swipeEnd.y - swipeStart.y;
var swipeDistance = Math.sqrt(dx * dx + dy * dy);
// Only start hold if not moving much (stationary hold)
if (swipeDistance < swipeThreshold) {
isHolding = true;
lastHoldMoveTime = currentTime;
// Determine hold direction based on player center to touch position
var holdDx = swipeStart.x - player.x;
var holdDy = swipeStart.y - player.y;
var holdDistance = Math.sqrt(holdDx * holdDx + holdDy * holdDy);
if (holdDistance > 30) {
// Must be reasonable distance from center
if (Math.abs(holdDx) > Math.abs(holdDy)) {
// Horizontal hold movement
holdDirection.x = holdDx > 0 ? 1 : -1;
holdDirection.y = 0;
} else {
// Vertical hold movement
holdDirection.x = 0;
holdDirection.y = holdDy > 0 ? 1 : -1;
}
}
}
}
}
// Process hold movement
if (isHolding && !isPlayerMoving) {
var currentTime = Date.now();
if (currentTime - lastHoldMoveTime >= holdMoveInterval) {
var moveX = holdDirection.x * playerSpeed;
var moveY = holdDirection.y * playerSpeed;
var newX = player.x + moveX;
var newY = player.y + moveY;
// Try to move in hold direction
if (canMoveTo(newX, player.y) && holdDirection.x !== 0) {
// Flip player sprite based on hold movement direction
if (holdDirection.x > 0) {
// Moving right - face right (normal)
player.scaleX = 1;
} else {
// Moving left - face left (flipped)
player.scaleX = -1;
}
isPlayerMoving = true;
tween(player, {
x: newX
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
isPlayerMoving = false;
}
});
lastHoldMoveTime = currentTime;
} else if (canMoveTo(player.x, newY) && holdDirection.y !== 0) {
isPlayerMoving = true;
tween(player, {
y: newY
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
isPlayerMoving = false;
}
});
lastHoldMoveTime = currentTime;
}
}
}
// 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 (optimized - only check every other frame for performance)
var hitEnemy = false;
if (LK.ticks % 2 === 0 || bullet.lifetime < 10) {
// Always check new bullets
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 red circular explosion animation
var dyingEnemy = enemies[j];
var explosionX = dyingEnemy.x;
var explosionY = dyingEnemy.y;
// Create red explosion circle
var explosion = gameContainer.addChild(LK.getAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
x: explosionX,
y: explosionY,
scaleX: 0.1,
scaleY: 0.1,
tint: 0xFF0000
}));
// Animate explosion circle expanding and fading
tween(explosion, {
scaleX: 8,
scaleY: 8,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Create enemy death animation with spinning
tween(dyingEnemy, {
tint: 0xFF0000,
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.PI * 2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Second stage: Continue growing while fading to dark red and spinning faster
tween(dyingEnemy, {
tint: 0x800000,
scaleX: 2.5,
scaleY: 2.5,
alpha: 0.7,
rotation: Math.PI * 6
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Final stage: Fade out completely with final spin
tween(dyingEnemy, {
alpha: 0,
scaleX: 3,
scaleY: 3,
rotation: Math.PI * 10
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
dyingEnemy.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 and hold-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;
// Hold movement system
var isHolding = false;
var holdStartTime = 0;
var holdThreshold = 300; // Time to distinguish between tap and hold (ms)
var holdMoveInterval = 150; // Interval between moves while holding
var lastHoldMoveTime = 0;
var holdDirection = {
x: 0,
y: 0
};
game.down = function (x, y, obj) {
swipeStart.x = x;
swipeStart.y = y;
isTracking = true;
holdStartTime = Date.now();
isHolding = false;
};
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;
isHolding = false; // Stop hold movement
var holdTime = Date.now() - holdStartTime;
// Check if this was a hold operation
if (holdTime >= holdThreshold) {
// This was a hold, don't process as tap
return;
}
// Check if this is a swipe for shooting
var dx = swipeEnd.x - swipeStart.x;
var dy = swipeEnd.y - swipeStart.y;
var swipeDistance = Math.sqrt(dx * dx + dy * dy);
// If swipe distance is significant, shoot towards swipe direction
if (swipeDistance >= swipeThreshold) {
// Calculate target position based on swipe direction
var targetX = player.x + dx * 3; // Multiply for longer range
var targetY = player.y + dy * 3;
shoot(targetX, targetY);
return; // Don't process as movement
}
// Tap only - move towards target position
// Prevent too frequent moves and simultaneous movements
var currentTime = Date.now();
if (currentTime - lastMoveTime < moveDelay || isPlayerMoving) return;
// Calculate direction from player to tap position
var tapDx = x - player.x;
var tapDy = y - player.y;
var distance = Math.sqrt(tapDx * tapDx + tapDy * tapDy);
if (distance < 50) return; // Don't move if tapped too close to player
// Determine movement direction (one cell at a time)
var moveX = 0;
var moveY = 0;
if (Math.abs(tapDx) > Math.abs(tapDy)) {
// Move horizontally towards tap
moveX = tapDx > 0 ? playerSpeed : -playerSpeed;
} else {
// Move vertically towards tap
moveY = tapDy > 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) {
// Flip player sprite based on movement direction
if (moveX > 0) {
// Moving right - face right (normal)
player.scaleX = 1;
} else {
// Moving left - face left (flipped)
player.scaleX = -1;
}
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();
// Start background music
LK.playMusic('1dwarftheme'); ===================================================================
--- original.js
+++ change.js
@@ -449,8 +449,12 @@
}
}
// Create detailed background with various environmental elements
function createDetailedBackground() {
+ if (!gameContainer) {
+ console.log("gameContainer not available for background creation");
+ return;
+ }
var backgroundElements = [];
// Select one of 9 background variations randomly
var backgroundType = Math.floor(Math.random() * 9);
// Background variation 0: Rock dominant
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