/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); // Animation self.animateCoin = function () { tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.sinusoidalInOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.sinusoidalInOut, onFinish: self.animateCoin }); } }); }; self.animateCoin(); return self; }); var Goblin = Container.expand(function () { var self = Container.call(this); var goblinGraphics = self.attachAsset('goblin', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.isStunned = false; self.stunTimer = 0; self.stunDuration = 120; // 2 seconds at 60fps self.direction = { x: Math.random() < 0.5 ? -1 : 1, y: Math.random() < 0.5 ? -1 : 1 }; // Normalize diagonal movement if (self.direction.x !== 0 && self.direction.y !== 0) { self.direction.x *= 0.7071; // √2/2 self.direction.y *= 0.7071; } self.getPushed = function (dx, dy, strength) { if (self.isStunned) { return; } self.isStunned = true; self.stunTimer = 0; // Flash the goblin to indicate it's being pushed LK.effects.flashObject(self, 0xFF0000, 300); // Push the goblin based on warrior's direction and strength var pushDistance = 100 * strength; var targetX = self.x + dx * pushDistance; var targetY = self.y + dy * pushDistance; // Check if the push would collide with a wall var willCollideWithWall = false; var wallCollisionPos = { x: self.x, y: self.y }; for (var i = 0; i < walls.length; i++) { var wall = walls[i]; var path = { x: self.x, y: self.y, width: goblinGraphics.width, height: goblinGraphics.height, targetX: targetX, targetY: targetY }; var collision = checkPathCollision(path, wall); if (collision) { willCollideWithWall = true; wallCollisionPos = collision; break; } } if (willCollideWithWall) { // If colliding with wall, stun for longer and stop at collision point self.stunDuration = 180; // 3 seconds tween(self, { x: wallCollisionPos.x, y: wallCollisionPos.y }, { duration: 300, easing: tween.bounceOut }); } else { // Normal push self.stunDuration = 120; // 2 seconds tween(self, { x: targetX, y: targetY }, { duration: 300, easing: tween.bounceOut }); } }; self.shoot = function () { if (!self.lastShot || LK.ticks - self.lastShot > 300) { // 5 seconds at 60 FPS var bullet = new GoblinBullet(); bullet.x = self.x; bullet.y = self.y; game.addChild(bullet); self.lastShot = LK.ticks; } }; self.update = function () { if (Math.random() < 0.01) { // Random chance to shoot self.shoot(); } if (self.isStunned) { self.stunTimer++; if (self.stunTimer >= self.stunDuration) { self.isStunned = false; // Change direction after stun self.direction = { x: Math.random() < 0.5 ? -1 : 1, y: Math.random() < 0.5 ? -1 : 1 }; // Normalize diagonal movement if (self.direction.x !== 0 && self.direction.y !== 0) { self.direction.x *= 0.7071; self.direction.y *= 0.7071; } } return; } var newX = self.x + self.direction.x * self.speed; var newY = self.y + self.direction.y * self.speed; // Check wall collisions var willCollide = false; for (var i = 0; i < walls.length; i++) { var wall = walls[i]; var futurePos = { x: newX, y: newY, width: goblinGraphics.width, height: goblinGraphics.height }; if (checkCollision(futurePos, wall)) { willCollide = true; break; } } if (willCollide) { // Change direction when hitting a wall if (Math.random() < 0.5) { self.direction.x *= -1; } else { self.direction.y *= -1; } } else { self.x = newX; self.y = newY; } // Keep goblins within game bounds if (self.x < 30) { self.x = 30; self.direction.x *= -1; } else if (self.x > 2048 - 30) { self.x = 2048 - 30; self.direction.x *= -1; } if (self.y < 30) { self.y = 30; self.direction.y *= -1; } else if (self.y > 2732 - 30) { self.y = 2732 - 30; self.direction.y *= -1; } }; return self; }); var GoblinBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.update = function () { self.x += self.speed; // Move horizontally if (self.x > gameWidth || self.x < 0) { // Check horizontal bounds self.destroy(); } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); // Animation with rotation self.update = function () { self.rotation += 0.02; }; // Pulse animation self.animatePowerup = function () { tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 700, easing: tween.sinusoidalInOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 700, easing: tween.sinusoidalInOut, onFinish: self.animatePowerup }); } }); }; self.animatePowerup(); return self; }); var Wall = Container.expand(function () { var self = Container.call(this); var wallGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Warrior = Container.expand(function () { var self = Container.call(this); self.speed = 15; self.isMoving = false; self.direction = { x: 0, y: 0 }; self.isPoweredUp = false; self.pushStrength = 1; var warriorGraphics = self.attachAsset('warrior', { anchorX: 0.5, anchorY: 0.5 }); self.startPowerup = function () { self.isPoweredUp = true; self.pushStrength = 3; // Visual indication of power-up tween(warriorGraphics, { tint: 0xFF4500 }, { duration: 300 }); // Reset after 5 seconds LK.setTimeout(function () { self.isPoweredUp = false; self.pushStrength = 1; tween(warriorGraphics, { tint: 0xFFFFFF }, { duration: 300 }); }, 5000); }; self.move = function (dx, dy) { if (dx === 0 && dy === 0) { self.isMoving = false; return; } self.isMoving = true; self.direction.x = dx; self.direction.y = dy; }; self.update = function () { if (!self.isMoving) { return; } var newX = self.x + self.direction.x * self.speed; var newY = self.y + self.direction.y * self.speed; // Check wall collisions before moving var willCollide = false; for (var i = 0; i < walls.length; i++) { var wall = walls[i]; var futurePos = { x: newX, y: newY, width: warriorGraphics.width, height: warriorGraphics.height }; if (checkCollision(futurePos, wall)) { willCollide = true; break; } } if (!willCollide) { self.x = newX; self.y = newY; } // Update goblin interactions self.checkPushGoblin(); }; // Check if this warrior is pushing a goblin self.checkPushGoblin = function () { if (!self.isMoving) { return; } for (var i = 0; i < goblins.length; i++) { var goblin = goblins[i]; if (self.intersects(goblin) && !goblin.isStunned) { // Push the goblin in the direction we're moving goblin.getPushed(self.direction.x, self.direction.y, self.pushStrength); LK.getSound('push').play(); break; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game variables var level = 1; var score = 0; var coins = []; var walls = []; var goblins = []; var powerups = []; var warrior; var isGameOver = false; var joystick = { active: false, startX: 0, startY: 0, currentX: 0, currentY: 0 }; // Game settings var gameWidth = 2048; var gameHeight = 2732; var wallSize = 60; var mazeWidth = 10; // Number of cells wide var mazeHeight = 14; // Number of cells high var cellSize = Math.min(gameWidth / mazeWidth, gameHeight / mazeHeight); // UI Elements var scoreTxt = new Text2('Score: 0', { size: 50, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -200; // Offset from top right var levelTxt = new Text2('Level: 1', { size: 50, fill: 0xFFFFFF }); levelTxt.anchor.set(1, 0); LK.gui.topLeft.addChild(levelTxt); levelTxt.x = 200; // Offset from top left // Helper functions function checkCollision(obj1, obj2) { return !(obj1.x + obj1.width / 2 < obj2.x - obj2.width / 2 || obj1.x - obj1.width / 2 > obj2.x + obj2.width / 2 || obj1.y + obj1.height / 2 < obj2.y - obj2.height / 2 || obj1.y - obj1.height / 2 > obj2.y + obj2.height / 2); } function checkPathCollision(path, wall) { // Simple line-rectangle collision check for push path // This is a simplification - a more accurate implementation would use line-segment/rectangle collision // Check if either endpoint is inside the wall if (checkCollision({ x: path.x, y: path.y, width: path.width, height: path.height }, wall) || checkCollision({ x: path.targetX, y: path.targetY, width: path.width, height: path.height }, wall)) { // Return approximate collision point return { x: (path.x + wall.x) / 2, y: (path.y + wall.y) / 2 }; } return null; } function updateScore(points) { score += points; scoreTxt.setText('Score: ' + score); } function buildMaze() { clearMaze(); // Create a simple maze based on level var complexity = Math.min(0.3 + level * 0.05, 0.7); // Increases wall density with level // Calculate maze position to center it var mazeOffsetX = (gameWidth - mazeWidth * cellSize) / 2; var mazeOffsetY = (gameHeight - mazeHeight * cellSize) / 2; // Build outer walls for (var x = 0; x < mazeWidth; x++) { addWall(mazeOffsetX + x * cellSize, mazeOffsetY); addWall(mazeOffsetX + x * cellSize, mazeOffsetY + (mazeHeight - 1) * cellSize); } for (var y = 0; y < mazeHeight; y++) { addWall(mazeOffsetX, mazeOffsetY + y * cellSize); addWall(mazeOffsetX + (mazeWidth - 1) * cellSize, mazeOffsetY + y * cellSize); } // Add random internal walls for (var x = 1; x < mazeWidth - 1; x++) { for (var y = 1; y < mazeHeight - 1; y++) { if (Math.random() < complexity) { addWall(mazeOffsetX + x * cellSize, mazeOffsetY + y * cellSize); } } } // Position warrior in an empty spot var warriorPlaced = false; while (!warriorPlaced) { var wx = Math.floor(Math.random() * (mazeWidth - 2)) + 1; var wy = Math.floor(Math.random() * (mazeHeight - 2)) + 1; var posX = mazeOffsetX + wx * cellSize; var posY = mazeOffsetY + wy * cellSize; var validPosition = true; for (var i = 0; i < walls.length; i++) { if (checkCollision({ x: posX, y: posY, width: 70, height: 70 }, walls[i])) { validPosition = false; break; } } if (validPosition) { warrior.x = posX; warrior.y = posY; warriorPlaced = true; } } // Add coins and powerups var coinCount = 10 + level * 2; // More coins with each level for (var i = 0; i < coinCount; i++) { addCoinAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY); } var powerupCount = 1 + Math.floor(level / 3); // More powerups in later levels for (var i = 0; i < powerupCount; i++) { addPowerupAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY); } // Add goblins var goblinCount = 3 + level; // More goblins with each level for (var i = 0; i < goblinCount; i++) { addGoblinAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY); } } function clearMaze() { // Clear existing maze elements for (var i = walls.length - 1; i >= 0; i--) { walls[i].destroy(); walls.splice(i, 1); } for (var i = coins.length - 1; i >= 0; i--) { coins[i].destroy(); coins.splice(i, 1); } for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].destroy(); powerups.splice(i, 1); } for (var i = goblins.length - 1; i >= 0; i--) { goblins[i].destroy(); goblins.splice(i, 1); } } function addWall(x, y) { var wall = new Wall(); wall.x = x; wall.y = y; walls.push(wall); game.addChild(wall); } function addCoinAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY) { var placed = false; var maxAttempts = 50; var attempts = 0; while (!placed && attempts < maxAttempts) { attempts++; var x = Math.floor(Math.random() * (mazeWidth - 2)) + 1; var y = Math.floor(Math.random() * (mazeHeight - 2)) + 1; var posX = mazeOffsetX + x * cellSize; var posY = mazeOffsetY + y * cellSize; if (isValidPosition(posX, posY, 30)) { var coin = new Coin(); coin.x = posX; coin.y = posY; coins.push(coin); game.addChild(coin); placed = true; } } } function addPowerupAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY) { var placed = false; var maxAttempts = 50; var attempts = 0; while (!placed && attempts < maxAttempts) { attempts++; var x = Math.floor(Math.random() * (mazeWidth - 2)) + 1; var y = Math.floor(Math.random() * (mazeHeight - 2)) + 1; var posX = mazeOffsetX + x * cellSize; var posY = mazeOffsetY + y * cellSize; if (isValidPosition(posX, posY, 40)) { var powerup = new PowerUp(); powerup.x = posX; powerup.y = posY; powerups.push(powerup); game.addChild(powerup); placed = true; } } } function addGoblinAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY) { var placed = false; var maxAttempts = 50; var attempts = 0; while (!placed && attempts < maxAttempts) { attempts++; var x = Math.floor(Math.random() * (mazeWidth - 2)) + 1; var y = Math.floor(Math.random() * (mazeHeight - 2)) + 1; var posX = mazeOffsetX + x * cellSize; var posY = mazeOffsetY + y * cellSize; // Make sure goblins aren't too close to the warrior var distToWarrior = Math.sqrt(Math.pow(posX - warrior.x, 2) + Math.pow(posY - warrior.y, 2)); if (isValidPosition(posX, posY, 60) && distToWarrior > cellSize * 3) { var goblin = new Goblin(); goblin.x = posX; goblin.y = posY; goblins.push(goblin); game.addChild(goblin); placed = true; } } } function isValidPosition(x, y, size) { // Check if position collides with walls for (var i = 0; i < walls.length; i++) { if (checkCollision({ x: x, y: y, width: size, height: size }, walls[i])) { return false; } } // Check if position collides with warrior if (warrior && checkCollision({ x: x, y: y, width: size, height: size }, { x: warrior.x, y: warrior.y, width: 70, height: 70 })) { return false; } // Check if position collides with coins for (var i = 0; i < coins.length; i++) { if (checkCollision({ x: x, y: y, width: size, height: size }, { x: coins[i].x, y: coins[i].y, width: 30, height: 30 })) { return false; } } // Check if position collides with powerups for (var i = 0; i < powerups.length; i++) { if (checkCollision({ x: x, y: y, width: size, height: size }, { x: powerups[i].x, y: powerups[i].y, width: 40, height: 40 })) { return false; } } // Check if position collides with goblins for (var i = 0; i < goblins.length; i++) { if (checkCollision({ x: x, y: y, width: size, height: size }, { x: goblins[i].x, y: goblins[i].y, width: 60, height: 60 })) { return false; } } return true; } function advanceToNextLevel() { level++; levelTxt.setText('Level: ' + level); clearMaze(); // Clear existing goblins and other elements buildMaze(); // Flash screen to indicate level change LK.effects.flashScreen(0x00FF00, 500); } function initializeGame() { // Set background color game.setBackgroundColor(0x2F4F4F); // Attach background image var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 }); background.x = gameWidth / 2; background.y = gameHeight / 2; game.addChild(background); // Create warrior and position at the bottom of the screen warrior = new Warrior(); warrior.x = gameWidth / 2; warrior.y = gameHeight - 100; // Position warrior near the bottom game.addChild(warrior); // Reset game state level = 1; score = 0; updateScore(0); levelTxt.setText('Level: ' + level); isGameOver = false; // Build initial maze buildMaze(); // Play background music LK.playMusic('gameMusic'); } // Initialize the game initializeGame(); // Touch/mouse control handlers game.down = function (x, y, obj) { joystick.active = true; joystick.startX = x; joystick.startY = y; joystick.currentX = x; joystick.currentY = y; }; game.move = function (x, y, obj) { if (joystick.active) { joystick.currentX = x; joystick.currentY = y; // Calculate direction vector var dx = joystick.currentX - joystick.startX; var dy = joystick.currentY - joystick.startY; // Only move if drag distance is significant if (Math.abs(dx) > 10 || Math.abs(dy) > 10) { // Normalize var length = Math.sqrt(dx * dx + dy * dy); dx /= length; dy /= length; // Move warrior based on swipe direction warrior.move(dx, dy); } else { warrior.move(0, 0); } } }; game.up = function (x, y, obj) { joystick.active = false; warrior.move(0, 0); }; // Main game update function game.update = function () { if (isGameOver) { return; } // Update warrior warrior.update(); // Check if warrior is pushing goblins warrior.checkPushGoblin(); // Set interval for goblin shooting every 5 seconds if (LK.ticks % 300 === 0) { // 5 seconds at 60 FPS if (goblins.length > 0) { var randomGoblinIndex = Math.floor(Math.random() * goblins.length); goblins[randomGoblinIndex].shoot(); } } // Update goblins for (var i = 0; i < goblins.length; i++) { goblins[i].update(); // Check if goblin caught warrior if (!goblins[i].isStunned && goblins[i].intersects(warrior)) { // Game over isGameOver = true; LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); return; } } // Update goblin bullets for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child instanceof GoblinBullet) { child.update(); if (child.intersects(warrior)) { // Game over if goblin bullet hits warrior isGameOver = true; LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); return; } } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].update(); // Check if warrior collected powerup if (powerups[i].intersects(warrior)) { warrior.startPowerup(); powerups[i].destroy(); powerups.splice(i, 1); LK.getSound('powerup').play(); updateScore(50); } } // Check if warrior collected coins for (var i = coins.length - 1; i >= 0; i--) { if (coins[i].intersects(warrior)) { coins[i].destroy(); coins.splice(i, 1); LK.getSound('collect').play(); updateScore(10); } } // Check if all coins are collected if (coins.length === 0) { advanceToNextLevel(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
// Animation
self.animateCoin = function () {
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.sinusoidalInOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.sinusoidalInOut,
onFinish: self.animateCoin
});
}
});
};
self.animateCoin();
return self;
});
var Goblin = Container.expand(function () {
var self = Container.call(this);
var goblinGraphics = self.attachAsset('goblin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.isStunned = false;
self.stunTimer = 0;
self.stunDuration = 120; // 2 seconds at 60fps
self.direction = {
x: Math.random() < 0.5 ? -1 : 1,
y: Math.random() < 0.5 ? -1 : 1
};
// Normalize diagonal movement
if (self.direction.x !== 0 && self.direction.y !== 0) {
self.direction.x *= 0.7071; // √2/2
self.direction.y *= 0.7071;
}
self.getPushed = function (dx, dy, strength) {
if (self.isStunned) {
return;
}
self.isStunned = true;
self.stunTimer = 0;
// Flash the goblin to indicate it's being pushed
LK.effects.flashObject(self, 0xFF0000, 300);
// Push the goblin based on warrior's direction and strength
var pushDistance = 100 * strength;
var targetX = self.x + dx * pushDistance;
var targetY = self.y + dy * pushDistance;
// Check if the push would collide with a wall
var willCollideWithWall = false;
var wallCollisionPos = {
x: self.x,
y: self.y
};
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
var path = {
x: self.x,
y: self.y,
width: goblinGraphics.width,
height: goblinGraphics.height,
targetX: targetX,
targetY: targetY
};
var collision = checkPathCollision(path, wall);
if (collision) {
willCollideWithWall = true;
wallCollisionPos = collision;
break;
}
}
if (willCollideWithWall) {
// If colliding with wall, stun for longer and stop at collision point
self.stunDuration = 180; // 3 seconds
tween(self, {
x: wallCollisionPos.x,
y: wallCollisionPos.y
}, {
duration: 300,
easing: tween.bounceOut
});
} else {
// Normal push
self.stunDuration = 120; // 2 seconds
tween(self, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.bounceOut
});
}
};
self.shoot = function () {
if (!self.lastShot || LK.ticks - self.lastShot > 300) {
// 5 seconds at 60 FPS
var bullet = new GoblinBullet();
bullet.x = self.x;
bullet.y = self.y;
game.addChild(bullet);
self.lastShot = LK.ticks;
}
};
self.update = function () {
if (Math.random() < 0.01) {
// Random chance to shoot
self.shoot();
}
if (self.isStunned) {
self.stunTimer++;
if (self.stunTimer >= self.stunDuration) {
self.isStunned = false;
// Change direction after stun
self.direction = {
x: Math.random() < 0.5 ? -1 : 1,
y: Math.random() < 0.5 ? -1 : 1
};
// Normalize diagonal movement
if (self.direction.x !== 0 && self.direction.y !== 0) {
self.direction.x *= 0.7071;
self.direction.y *= 0.7071;
}
}
return;
}
var newX = self.x + self.direction.x * self.speed;
var newY = self.y + self.direction.y * self.speed;
// Check wall collisions
var willCollide = false;
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
var futurePos = {
x: newX,
y: newY,
width: goblinGraphics.width,
height: goblinGraphics.height
};
if (checkCollision(futurePos, wall)) {
willCollide = true;
break;
}
}
if (willCollide) {
// Change direction when hitting a wall
if (Math.random() < 0.5) {
self.direction.x *= -1;
} else {
self.direction.y *= -1;
}
} else {
self.x = newX;
self.y = newY;
}
// Keep goblins within game bounds
if (self.x < 30) {
self.x = 30;
self.direction.x *= -1;
} else if (self.x > 2048 - 30) {
self.x = 2048 - 30;
self.direction.x *= -1;
}
if (self.y < 30) {
self.y = 30;
self.direction.y *= -1;
} else if (self.y > 2732 - 30) {
self.y = 2732 - 30;
self.direction.y *= -1;
}
};
return self;
});
var GoblinBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
self.x += self.speed; // Move horizontally
if (self.x > gameWidth || self.x < 0) {
// Check horizontal bounds
self.destroy();
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Animation with rotation
self.update = function () {
self.rotation += 0.02;
};
// Pulse animation
self.animatePowerup = function () {
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 700,
easing: tween.sinusoidalInOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 700,
easing: tween.sinusoidalInOut,
onFinish: self.animatePowerup
});
}
});
};
self.animatePowerup();
return self;
});
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Warrior = Container.expand(function () {
var self = Container.call(this);
self.speed = 15;
self.isMoving = false;
self.direction = {
x: 0,
y: 0
};
self.isPoweredUp = false;
self.pushStrength = 1;
var warriorGraphics = self.attachAsset('warrior', {
anchorX: 0.5,
anchorY: 0.5
});
self.startPowerup = function () {
self.isPoweredUp = true;
self.pushStrength = 3;
// Visual indication of power-up
tween(warriorGraphics, {
tint: 0xFF4500
}, {
duration: 300
});
// Reset after 5 seconds
LK.setTimeout(function () {
self.isPoweredUp = false;
self.pushStrength = 1;
tween(warriorGraphics, {
tint: 0xFFFFFF
}, {
duration: 300
});
}, 5000);
};
self.move = function (dx, dy) {
if (dx === 0 && dy === 0) {
self.isMoving = false;
return;
}
self.isMoving = true;
self.direction.x = dx;
self.direction.y = dy;
};
self.update = function () {
if (!self.isMoving) {
return;
}
var newX = self.x + self.direction.x * self.speed;
var newY = self.y + self.direction.y * self.speed;
// Check wall collisions before moving
var willCollide = false;
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
var futurePos = {
x: newX,
y: newY,
width: warriorGraphics.width,
height: warriorGraphics.height
};
if (checkCollision(futurePos, wall)) {
willCollide = true;
break;
}
}
if (!willCollide) {
self.x = newX;
self.y = newY;
}
// Update goblin interactions
self.checkPushGoblin();
};
// Check if this warrior is pushing a goblin
self.checkPushGoblin = function () {
if (!self.isMoving) {
return;
}
for (var i = 0; i < goblins.length; i++) {
var goblin = goblins[i];
if (self.intersects(goblin) && !goblin.isStunned) {
// Push the goblin in the direction we're moving
goblin.getPushed(self.direction.x, self.direction.y, self.pushStrength);
LK.getSound('push').play();
break;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game variables
var level = 1;
var score = 0;
var coins = [];
var walls = [];
var goblins = [];
var powerups = [];
var warrior;
var isGameOver = false;
var joystick = {
active: false,
startX: 0,
startY: 0,
currentX: 0,
currentY: 0
};
// Game settings
var gameWidth = 2048;
var gameHeight = 2732;
var wallSize = 60;
var mazeWidth = 10; // Number of cells wide
var mazeHeight = 14; // Number of cells high
var cellSize = Math.min(gameWidth / mazeWidth, gameHeight / mazeHeight);
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 50,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -200; // Offset from top right
var levelTxt = new Text2('Level: 1', {
size: 50,
fill: 0xFFFFFF
});
levelTxt.anchor.set(1, 0);
LK.gui.topLeft.addChild(levelTxt);
levelTxt.x = 200; // Offset from top left
// Helper functions
function checkCollision(obj1, obj2) {
return !(obj1.x + obj1.width / 2 < obj2.x - obj2.width / 2 || obj1.x - obj1.width / 2 > obj2.x + obj2.width / 2 || obj1.y + obj1.height / 2 < obj2.y - obj2.height / 2 || obj1.y - obj1.height / 2 > obj2.y + obj2.height / 2);
}
function checkPathCollision(path, wall) {
// Simple line-rectangle collision check for push path
// This is a simplification - a more accurate implementation would use line-segment/rectangle collision
// Check if either endpoint is inside the wall
if (checkCollision({
x: path.x,
y: path.y,
width: path.width,
height: path.height
}, wall) || checkCollision({
x: path.targetX,
y: path.targetY,
width: path.width,
height: path.height
}, wall)) {
// Return approximate collision point
return {
x: (path.x + wall.x) / 2,
y: (path.y + wall.y) / 2
};
}
return null;
}
function updateScore(points) {
score += points;
scoreTxt.setText('Score: ' + score);
}
function buildMaze() {
clearMaze();
// Create a simple maze based on level
var complexity = Math.min(0.3 + level * 0.05, 0.7); // Increases wall density with level
// Calculate maze position to center it
var mazeOffsetX = (gameWidth - mazeWidth * cellSize) / 2;
var mazeOffsetY = (gameHeight - mazeHeight * cellSize) / 2;
// Build outer walls
for (var x = 0; x < mazeWidth; x++) {
addWall(mazeOffsetX + x * cellSize, mazeOffsetY);
addWall(mazeOffsetX + x * cellSize, mazeOffsetY + (mazeHeight - 1) * cellSize);
}
for (var y = 0; y < mazeHeight; y++) {
addWall(mazeOffsetX, mazeOffsetY + y * cellSize);
addWall(mazeOffsetX + (mazeWidth - 1) * cellSize, mazeOffsetY + y * cellSize);
}
// Add random internal walls
for (var x = 1; x < mazeWidth - 1; x++) {
for (var y = 1; y < mazeHeight - 1; y++) {
if (Math.random() < complexity) {
addWall(mazeOffsetX + x * cellSize, mazeOffsetY + y * cellSize);
}
}
}
// Position warrior in an empty spot
var warriorPlaced = false;
while (!warriorPlaced) {
var wx = Math.floor(Math.random() * (mazeWidth - 2)) + 1;
var wy = Math.floor(Math.random() * (mazeHeight - 2)) + 1;
var posX = mazeOffsetX + wx * cellSize;
var posY = mazeOffsetY + wy * cellSize;
var validPosition = true;
for (var i = 0; i < walls.length; i++) {
if (checkCollision({
x: posX,
y: posY,
width: 70,
height: 70
}, walls[i])) {
validPosition = false;
break;
}
}
if (validPosition) {
warrior.x = posX;
warrior.y = posY;
warriorPlaced = true;
}
}
// Add coins and powerups
var coinCount = 10 + level * 2; // More coins with each level
for (var i = 0; i < coinCount; i++) {
addCoinAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY);
}
var powerupCount = 1 + Math.floor(level / 3); // More powerups in later levels
for (var i = 0; i < powerupCount; i++) {
addPowerupAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY);
}
// Add goblins
var goblinCount = 3 + level; // More goblins with each level
for (var i = 0; i < goblinCount; i++) {
addGoblinAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY);
}
}
function clearMaze() {
// Clear existing maze elements
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
walls.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
coins.splice(i, 1);
}
for (var i = powerups.length - 1; i >= 0; i--) {
powerups[i].destroy();
powerups.splice(i, 1);
}
for (var i = goblins.length - 1; i >= 0; i--) {
goblins[i].destroy();
goblins.splice(i, 1);
}
}
function addWall(x, y) {
var wall = new Wall();
wall.x = x;
wall.y = y;
walls.push(wall);
game.addChild(wall);
}
function addCoinAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY) {
var placed = false;
var maxAttempts = 50;
var attempts = 0;
while (!placed && attempts < maxAttempts) {
attempts++;
var x = Math.floor(Math.random() * (mazeWidth - 2)) + 1;
var y = Math.floor(Math.random() * (mazeHeight - 2)) + 1;
var posX = mazeOffsetX + x * cellSize;
var posY = mazeOffsetY + y * cellSize;
if (isValidPosition(posX, posY, 30)) {
var coin = new Coin();
coin.x = posX;
coin.y = posY;
coins.push(coin);
game.addChild(coin);
placed = true;
}
}
}
function addPowerupAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY) {
var placed = false;
var maxAttempts = 50;
var attempts = 0;
while (!placed && attempts < maxAttempts) {
attempts++;
var x = Math.floor(Math.random() * (mazeWidth - 2)) + 1;
var y = Math.floor(Math.random() * (mazeHeight - 2)) + 1;
var posX = mazeOffsetX + x * cellSize;
var posY = mazeOffsetY + y * cellSize;
if (isValidPosition(posX, posY, 40)) {
var powerup = new PowerUp();
powerup.x = posX;
powerup.y = posY;
powerups.push(powerup);
game.addChild(powerup);
placed = true;
}
}
}
function addGoblinAtRandomEmptyPosition(mazeOffsetX, mazeOffsetY) {
var placed = false;
var maxAttempts = 50;
var attempts = 0;
while (!placed && attempts < maxAttempts) {
attempts++;
var x = Math.floor(Math.random() * (mazeWidth - 2)) + 1;
var y = Math.floor(Math.random() * (mazeHeight - 2)) + 1;
var posX = mazeOffsetX + x * cellSize;
var posY = mazeOffsetY + y * cellSize;
// Make sure goblins aren't too close to the warrior
var distToWarrior = Math.sqrt(Math.pow(posX - warrior.x, 2) + Math.pow(posY - warrior.y, 2));
if (isValidPosition(posX, posY, 60) && distToWarrior > cellSize * 3) {
var goblin = new Goblin();
goblin.x = posX;
goblin.y = posY;
goblins.push(goblin);
game.addChild(goblin);
placed = true;
}
}
}
function isValidPosition(x, y, size) {
// Check if position collides with walls
for (var i = 0; i < walls.length; i++) {
if (checkCollision({
x: x,
y: y,
width: size,
height: size
}, walls[i])) {
return false;
}
}
// Check if position collides with warrior
if (warrior && checkCollision({
x: x,
y: y,
width: size,
height: size
}, {
x: warrior.x,
y: warrior.y,
width: 70,
height: 70
})) {
return false;
}
// Check if position collides with coins
for (var i = 0; i < coins.length; i++) {
if (checkCollision({
x: x,
y: y,
width: size,
height: size
}, {
x: coins[i].x,
y: coins[i].y,
width: 30,
height: 30
})) {
return false;
}
}
// Check if position collides with powerups
for (var i = 0; i < powerups.length; i++) {
if (checkCollision({
x: x,
y: y,
width: size,
height: size
}, {
x: powerups[i].x,
y: powerups[i].y,
width: 40,
height: 40
})) {
return false;
}
}
// Check if position collides with goblins
for (var i = 0; i < goblins.length; i++) {
if (checkCollision({
x: x,
y: y,
width: size,
height: size
}, {
x: goblins[i].x,
y: goblins[i].y,
width: 60,
height: 60
})) {
return false;
}
}
return true;
}
function advanceToNextLevel() {
level++;
levelTxt.setText('Level: ' + level);
clearMaze(); // Clear existing goblins and other elements
buildMaze();
// Flash screen to indicate level change
LK.effects.flashScreen(0x00FF00, 500);
}
function initializeGame() {
// Set background color
game.setBackgroundColor(0x2F4F4F);
// Attach background image
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = gameWidth / 2;
background.y = gameHeight / 2;
game.addChild(background);
// Create warrior and position at the bottom of the screen
warrior = new Warrior();
warrior.x = gameWidth / 2;
warrior.y = gameHeight - 100; // Position warrior near the bottom
game.addChild(warrior);
// Reset game state
level = 1;
score = 0;
updateScore(0);
levelTxt.setText('Level: ' + level);
isGameOver = false;
// Build initial maze
buildMaze();
// Play background music
LK.playMusic('gameMusic');
}
// Initialize the game
initializeGame();
// Touch/mouse control handlers
game.down = function (x, y, obj) {
joystick.active = true;
joystick.startX = x;
joystick.startY = y;
joystick.currentX = x;
joystick.currentY = y;
};
game.move = function (x, y, obj) {
if (joystick.active) {
joystick.currentX = x;
joystick.currentY = y;
// Calculate direction vector
var dx = joystick.currentX - joystick.startX;
var dy = joystick.currentY - joystick.startY;
// Only move if drag distance is significant
if (Math.abs(dx) > 10 || Math.abs(dy) > 10) {
// Normalize
var length = Math.sqrt(dx * dx + dy * dy);
dx /= length;
dy /= length;
// Move warrior based on swipe direction
warrior.move(dx, dy);
} else {
warrior.move(0, 0);
}
}
};
game.up = function (x, y, obj) {
joystick.active = false;
warrior.move(0, 0);
};
// Main game update function
game.update = function () {
if (isGameOver) {
return;
}
// Update warrior
warrior.update();
// Check if warrior is pushing goblins
warrior.checkPushGoblin();
// Set interval for goblin shooting every 5 seconds
if (LK.ticks % 300 === 0) {
// 5 seconds at 60 FPS
if (goblins.length > 0) {
var randomGoblinIndex = Math.floor(Math.random() * goblins.length);
goblins[randomGoblinIndex].shoot();
}
}
// Update goblins
for (var i = 0; i < goblins.length; i++) {
goblins[i].update();
// Check if goblin caught warrior
if (!goblins[i].isStunned && goblins[i].intersects(warrior)) {
// Game over
isGameOver = true;
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
}
// Update goblin bullets
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child instanceof GoblinBullet) {
child.update();
if (child.intersects(warrior)) {
// Game over if goblin bullet hits warrior
isGameOver = true;
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
powerups[i].update();
// Check if warrior collected powerup
if (powerups[i].intersects(warrior)) {
warrior.startPowerup();
powerups[i].destroy();
powerups.splice(i, 1);
LK.getSound('powerup').play();
updateScore(50);
}
}
// Check if warrior collected coins
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i].intersects(warrior)) {
coins[i].destroy();
coins.splice(i, 1);
LK.getSound('collect').play();
updateScore(10);
}
}
// Check if all coins are collected
if (coins.length === 0) {
advanceToNextLevel();
}
};
chibi indiana jones treasure hunter run Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
chibi treasure chest. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
chibi anger bulk and bold guy tomb raider bandit. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
chibi inca aztec wall pattern. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
2d tropical sout america deep jungle. not far away, a ruins of ancient aztec temple.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
horizontal chinbi gun bullet. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows