/****
* 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.directionX = 0;
self.directionY = 0;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.moveTimer = 0;
self.moveDirection = 0; // 0=up, 1=right, 2=down, 3=left
self.speed = 1;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Multi-directional movement pattern - can move in any direction
self.moveTimer++;
if (self.moveTimer > 120) {
// Change direction every 2 seconds
// Stop current tweens
tween.stop(self, {
x: true,
y: true
});
// Calculate movement range in all directions
var leftBound = self.x - 100;
var rightBound = self.x + 100;
var upBound = self.y - 100;
var downBound = self.y + 100;
// Ensure bounds are within maze
var gridLeftX = Math.floor(leftBound / cellSize);
var gridRightX = Math.floor(rightBound / cellSize);
var gridUpY = Math.floor((upBound - mazeOffsetY) / cellSize);
var gridDownY = Math.floor((downBound - mazeOffsetY) / cellSize);
var gridCurrentY = Math.floor((self.y - mazeOffsetY) / cellSize);
var gridCurrentX = Math.floor(self.x / cellSize);
// Adjust bounds to avoid walls
while (gridLeftX >= 0 && maze[gridCurrentY] && maze[gridCurrentY][gridLeftX] === 1) {
leftBound += cellSize;
gridLeftX++;
}
while (gridRightX < mazeWidth && maze[gridCurrentY] && maze[gridCurrentY][gridRightX] === 1) {
rightBound -= cellSize;
gridRightX--;
}
while (gridUpY >= 0 && maze[gridUpY] && maze[gridUpY][gridCurrentX] === 1) {
upBound += cellSize;
gridUpY++;
}
while (gridDownY < mazeHeight && maze[gridDownY] && maze[gridDownY][gridCurrentX] === 1) {
downBound -= cellSize;
gridDownY--;
}
// Choose direction: 0 = right, 1 = left, 2 = up, 3 = down
var direction = Math.floor(Math.random() * 4);
var targetX = self.x;
var targetY = self.y;
switch (direction) {
case 0:
// right
targetX = rightBound;
// Flip to face right
enemyGraphics.scaleX = Math.abs(enemyGraphics.scaleX);
break;
case 1:
// left
targetX = leftBound;
// Flip to face left
enemyGraphics.scaleX = -Math.abs(enemyGraphics.scaleX);
break;
case 2:
// up
targetY = upBound;
break;
case 3:
// down
targetY = downBound;
break;
}
// Ensure target is valid
if (!checkWallCollision(targetX, targetY)) {
// Move to target position over 2 seconds
tween(self, {
x: targetX,
y: targetY
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// After reaching target, choose a new random direction
var newDirection = Math.floor(Math.random() * 4);
var newTargetX = self.x;
var newTargetY = self.y;
switch (newDirection) {
case 0:
// right
newTargetX = rightBound;
// Flip to face right
enemyGraphics.scaleX = Math.abs(enemyGraphics.scaleX);
break;
case 1:
// left
newTargetX = leftBound;
// Flip to face left
enemyGraphics.scaleX = -Math.abs(enemyGraphics.scaleX);
break;
case 2:
// up
newTargetY = upBound;
break;
case 3:
// down
newTargetY = downBound;
break;
}
if (!checkWallCollision(newTargetX, newTargetY)) {
tween(self, {
x: newTargetX,
y: newTargetY
}, {
duration: 2000,
easing: tween.easeInOut
});
}
}
});
}
self.moveTimer = 0;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.speed = 3;
self.shootCooldown = 0;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.setDirection = function (deltaX) {
if (deltaX > 0) {
// Moving right - face right
playerGraphics.scaleX = Math.abs(playerGraphics.scaleX);
} else if (deltaX < 0) {
// Moving left - face left
playerGraphics.scaleX = -Math.abs(playerGraphics.scaleX);
}
};
self.shoot = function (targetX, targetY) {
if (self.shootCooldown > 0) return;
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.directionX = dx / distance;
bullet.directionY = dy / distance;
bullet.lastX = bullet.x;
bullet.lastY = bullet.y;
bullets.push(bullet);
game.addChild(bullet);
self.shootCooldown = 15;
LK.getSound('shoot').play();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var bullets = [];
var walls = [];
var wall2s = [];
var mazeWidth = 28;
var mazeHeight = 22;
var cellSize = 50;
var maze = [];
var mazeOffsetY = 150; // Consistent offset for maze positioning
var currentBackground = null;
var backgroundAssets = ['background1', 'background2', 'background3', 'background4', 'background5', 'background6', 'background7'];
function setRandomBackground() {
// Remove current background if exists
if (currentBackground) {
currentBackground.destroy();
}
// Select random background
var randomIndex = Math.floor(Math.random() * backgroundAssets.length);
var selectedBackground = backgroundAssets[randomIndex];
// Create and add new background
currentBackground = LK.getAsset(selectedBackground, {
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
// Add background at the bottom layer
game.addChildAt(currentBackground, 0);
}
// UI elements
var healthText = new Text2('Health: 3', {
size: 50,
fill: 0xFF0000
});
healthText.anchor.set(0, 0);
healthText.x = 150;
healthText.y = 20;
LK.gui.topLeft.addChild(healthText);
var enemyCountText = new Text2('Enemies: 0', {
size: 50,
fill: 0xFFFF00
});
enemyCountText.anchor.set(1, 0);
LK.gui.topRight.addChild(enemyCountText);
// Maze generation
function generateMaze() {
// Initialize maze with all floors (open space)
maze = [];
for (var y = 0; y < mazeHeight; y++) {
maze[y] = [];
for (var x = 0; x < mazeWidth; x++) {
maze[y][x] = 0; // 0 = floor, 1 = wall
}
}
// Add border walls
for (var x = 0; x < mazeWidth; x++) {
maze[0][x] = 1; // top border
maze[mazeHeight - 1][x] = 1; // bottom border
}
for (var y = 0; y < mazeHeight; y++) {
maze[y][0] = 1; // left border
maze[y][mazeWidth - 1] = 1; // right border
}
// Add a few scattered walls randomly for minimal obstacles
var wallCount = Math.floor(mazeWidth * mazeHeight * 0.1); // Only 10% walls
for (var i = 0; i < wallCount; i++) {
var rx = Math.floor(Math.random() * (mazeWidth - 2)) + 1;
var ry = Math.floor(Math.random() * (mazeHeight - 2)) + 1;
maze[ry][rx] = 1;
}
}
function createMazeWalls() {
// Clear existing walls
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
for (var i = wall2s.length - 1; i >= 0; i--) {
wall2s[i].destroy();
}
walls = [];
wall2s = [];
// Create wall objects
for (var y = 0; y < mazeHeight; y++) {
for (var x = 0; x < mazeWidth; x++) {
if (maze[y][x] === 1) {
// Randomly choose between wall types
var useWall2 = Math.random() < 0.5;
if (useWall2) {
var wall = LK.getAsset('wall2', {
x: x * cellSize + cellSize / 2,
y: y * cellSize + cellSize / 2 + mazeOffsetY,
anchorX: 0.5,
anchorY: 0.5
});
wall2s.push(wall);
game.addChild(wall);
} else {
var wall = LK.getAsset('wall', {
x: x * cellSize + cellSize / 2,
y: y * cellSize + cellSize / 2 + mazeOffsetY,
anchorX: 0.5,
anchorY: 0.5
});
walls.push(wall);
game.addChild(wall);
}
}
}
}
}
function findFloorPosition() {
var attempts = 0;
while (attempts < 100) {
var x = Math.floor(Math.random() * mazeWidth);
var y = Math.floor(Math.random() * mazeHeight);
if (maze[y][x] === 0) {
return {
x: x * cellSize + cellSize / 2,
y: y * cellSize + cellSize / 2 + mazeOffsetY
};
}
attempts++;
}
// Fallback to a guaranteed floor position
return {
x: cellSize + cellSize / 2,
y: cellSize + cellSize / 2 + mazeOffsetY
};
}
function checkWallCollision(x, y) {
var gridX = Math.floor(x / cellSize);
var gridY = Math.floor((y - mazeOffsetY) / cellSize);
if (gridX < 0 || gridX >= mazeWidth || gridY < 0 || gridY >= mazeHeight) {
return true;
}
return maze[gridY][gridX] === 1;
}
function spawnEnemies() {
// Clear existing enemies
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
}
enemies = [];
var enemyCount = 15; // Fixed enemy count
for (var i = 0; i < enemyCount; i++) {
var pos = findFloorPosition();
var enemy = new Enemy();
enemy.x = pos.x;
enemy.y = pos.y;
enemy.lastX = enemy.x;
enemy.lastY = enemy.y;
enemies.push(enemy);
game.addChild(enemy);
}
updateEnemyCount();
}
function initLevel() {
setRandomBackground();
generateMaze();
createMazeWalls();
// Position player
var playerPos = findFloorPosition();
player.x = playerPos.x;
player.y = playerPos.y;
player.lastX = player.x;
player.lastY = player.y;
spawnEnemies();
}
function updateEnemyCount() {
enemyCountText.setText('Enemies: ' + enemies.length);
}
function updateHealthText() {
healthText.setText('Health: ' + player.health);
}
function nextMaze() {
// Clear bullets
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
bullets.splice(i, 1);
}
initLevel();
}
// Initialize player
player = new Player();
game.addChild(player);
// Initialize first level
initLevel();
updateHealthText();
// Start background music
LK.playMusic('123huntin');
// Swipe controls
var swipeStartX = 0;
var swipeStartY = 0;
var isSwipeActive = false;
var moveX = 0;
var moveY = 0;
var minSwipeDistance = 30;
// Double tap controls
var lastTapTime = 0;
var doubleTapDelay = 300; // milliseconds
var lastTapX = 0;
var lastTapY = 0;
var tapDistance = 50; // max distance between taps to consider as double tap
game.down = function (x, y, obj) {
var currentTime = Date.now();
var timeDiff = currentTime - lastTapTime;
var distanceDiff = Math.sqrt(Math.pow(x - lastTapX, 2) + Math.pow(y - lastTapY, 2));
// Check for double tap
if (timeDiff < doubleTapDelay && distanceDiff < tapDistance) {
// Double tap detected - shoot
player.shoot(x, y);
lastTapTime = 0; // Reset to prevent triple tap
} else {
// Single tap - prepare for swipe
swipeStartX = x;
swipeStartY = y;
isSwipeActive = true;
lastTapTime = currentTime;
lastTapX = x;
lastTapY = y;
}
};
game.move = function (x, y, obj) {
if (isSwipeActive) {
var swipeDeltaX = x - swipeStartX;
var swipeDeltaY = y - swipeStartY;
var swipeDistance = Math.sqrt(swipeDeltaX * swipeDeltaX + swipeDeltaY * swipeDeltaY);
if (swipeDistance > minSwipeDistance) {
// Normalize swipe direction and apply player speed
moveX = swipeDeltaX / swipeDistance * player.speed;
moveY = swipeDeltaY / swipeDistance * player.speed;
}
}
};
game.up = function (x, y, obj) {
isSwipeActive = false;
moveX = 0;
moveY = 0;
};
// Main game loop
game.update = function () {
// Move player
if (moveX !== 0 || moveY !== 0) {
var newX = player.x + moveX;
var newY = player.y + moveY;
if (!checkWallCollision(newX, newY)) {
// Update player direction for visual flipping
player.setDirection(moveX);
player.x = newX;
player.y = newY;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check wall collision
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bounds
if (bullet.x < 0 || bullet.x > mazeWidth * cellSize || bullet.y < mazeOffsetY || bullet.y > mazeHeight * cellSize + mazeOffsetY) {
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])) {
LK.getSound('enemyHit').play();
LK.effects.flashObject(enemies[j], 0xffffff, 200);
// Store reference to the enemy before starting animation
var enemyToDestroy = enemies[j];
var enemyIndex = j;
// Add spinning animation before destroying enemy
tween(enemyToDestroy, {
rotation: enemyToDestroy.rotation + Math.PI * 4 // Spin 2 full rotations
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Destroy enemy after animation completes
if (enemyToDestroy && enemyToDestroy.parent) {
enemyToDestroy.destroy();
// Find and remove enemy from array safely
var indexToRemove = enemies.indexOf(enemyToDestroy);
if (indexToRemove !== -1) {
enemies.splice(indexToRemove, 1);
}
updateEnemyCount();
}
}
});
bullet.destroy();
bullets.splice(i, 1);
hitEnemy = true;
break;
}
}
if (hitEnemy) continue;
}
// Check player-enemy collision
for (var i = enemies.length - 1; i >= 0; i--) {
if (player.intersects(enemies[i])) {
LK.getSound('playerHit').play();
LK.effects.flashObject(player, 0xff0000, 500);
player.health--;
updateHealthText();
// Calculate knockback direction (away from enemy)
var knockbackX = player.x - enemies[i].x;
var knockbackY = player.y - enemies[i].y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
// Normalize direction and apply knockback force
knockbackX = knockbackX / distance * 80;
knockbackY = knockbackY / distance * 80;
// Calculate target position for knockback
var targetX = player.x + knockbackX;
var targetY = player.y + knockbackY;
// Ensure target position is valid (not in wall)
if (!checkWallCollision(targetX, targetY)) {
// Create bouncing knockback animation
tween(player, {
x: targetX,
y: targetY
}, {
duration: 200,
easing: tween.bounceOut
});
}
}
// Move enemy away to prevent multiple hits
enemies[i].x += (Math.random() - 0.5) * 60;
enemies[i].y += (Math.random() - 0.5) * 60;
if (player.health <= 0) {
LK.showGameOver();
return;
}
}
}
// Check win condition
if (enemies.length === 0) {
LK.showYouWin();
return;
}
}; /****
* 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.directionX = 0;
self.directionY = 0;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.moveTimer = 0;
self.moveDirection = 0; // 0=up, 1=right, 2=down, 3=left
self.speed = 1;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Multi-directional movement pattern - can move in any direction
self.moveTimer++;
if (self.moveTimer > 120) {
// Change direction every 2 seconds
// Stop current tweens
tween.stop(self, {
x: true,
y: true
});
// Calculate movement range in all directions
var leftBound = self.x - 100;
var rightBound = self.x + 100;
var upBound = self.y - 100;
var downBound = self.y + 100;
// Ensure bounds are within maze
var gridLeftX = Math.floor(leftBound / cellSize);
var gridRightX = Math.floor(rightBound / cellSize);
var gridUpY = Math.floor((upBound - mazeOffsetY) / cellSize);
var gridDownY = Math.floor((downBound - mazeOffsetY) / cellSize);
var gridCurrentY = Math.floor((self.y - mazeOffsetY) / cellSize);
var gridCurrentX = Math.floor(self.x / cellSize);
// Adjust bounds to avoid walls
while (gridLeftX >= 0 && maze[gridCurrentY] && maze[gridCurrentY][gridLeftX] === 1) {
leftBound += cellSize;
gridLeftX++;
}
while (gridRightX < mazeWidth && maze[gridCurrentY] && maze[gridCurrentY][gridRightX] === 1) {
rightBound -= cellSize;
gridRightX--;
}
while (gridUpY >= 0 && maze[gridUpY] && maze[gridUpY][gridCurrentX] === 1) {
upBound += cellSize;
gridUpY++;
}
while (gridDownY < mazeHeight && maze[gridDownY] && maze[gridDownY][gridCurrentX] === 1) {
downBound -= cellSize;
gridDownY--;
}
// Choose direction: 0 = right, 1 = left, 2 = up, 3 = down
var direction = Math.floor(Math.random() * 4);
var targetX = self.x;
var targetY = self.y;
switch (direction) {
case 0:
// right
targetX = rightBound;
// Flip to face right
enemyGraphics.scaleX = Math.abs(enemyGraphics.scaleX);
break;
case 1:
// left
targetX = leftBound;
// Flip to face left
enemyGraphics.scaleX = -Math.abs(enemyGraphics.scaleX);
break;
case 2:
// up
targetY = upBound;
break;
case 3:
// down
targetY = downBound;
break;
}
// Ensure target is valid
if (!checkWallCollision(targetX, targetY)) {
// Move to target position over 2 seconds
tween(self, {
x: targetX,
y: targetY
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// After reaching target, choose a new random direction
var newDirection = Math.floor(Math.random() * 4);
var newTargetX = self.x;
var newTargetY = self.y;
switch (newDirection) {
case 0:
// right
newTargetX = rightBound;
// Flip to face right
enemyGraphics.scaleX = Math.abs(enemyGraphics.scaleX);
break;
case 1:
// left
newTargetX = leftBound;
// Flip to face left
enemyGraphics.scaleX = -Math.abs(enemyGraphics.scaleX);
break;
case 2:
// up
newTargetY = upBound;
break;
case 3:
// down
newTargetY = downBound;
break;
}
if (!checkWallCollision(newTargetX, newTargetY)) {
tween(self, {
x: newTargetX,
y: newTargetY
}, {
duration: 2000,
easing: tween.easeInOut
});
}
}
});
}
self.moveTimer = 0;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.speed = 3;
self.shootCooldown = 0;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.setDirection = function (deltaX) {
if (deltaX > 0) {
// Moving right - face right
playerGraphics.scaleX = Math.abs(playerGraphics.scaleX);
} else if (deltaX < 0) {
// Moving left - face left
playerGraphics.scaleX = -Math.abs(playerGraphics.scaleX);
}
};
self.shoot = function (targetX, targetY) {
if (self.shootCooldown > 0) return;
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.directionX = dx / distance;
bullet.directionY = dy / distance;
bullet.lastX = bullet.x;
bullet.lastY = bullet.y;
bullets.push(bullet);
game.addChild(bullet);
self.shootCooldown = 15;
LK.getSound('shoot').play();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var bullets = [];
var walls = [];
var wall2s = [];
var mazeWidth = 28;
var mazeHeight = 22;
var cellSize = 50;
var maze = [];
var mazeOffsetY = 150; // Consistent offset for maze positioning
var currentBackground = null;
var backgroundAssets = ['background1', 'background2', 'background3', 'background4', 'background5', 'background6', 'background7'];
function setRandomBackground() {
// Remove current background if exists
if (currentBackground) {
currentBackground.destroy();
}
// Select random background
var randomIndex = Math.floor(Math.random() * backgroundAssets.length);
var selectedBackground = backgroundAssets[randomIndex];
// Create and add new background
currentBackground = LK.getAsset(selectedBackground, {
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
// Add background at the bottom layer
game.addChildAt(currentBackground, 0);
}
// UI elements
var healthText = new Text2('Health: 3', {
size: 50,
fill: 0xFF0000
});
healthText.anchor.set(0, 0);
healthText.x = 150;
healthText.y = 20;
LK.gui.topLeft.addChild(healthText);
var enemyCountText = new Text2('Enemies: 0', {
size: 50,
fill: 0xFFFF00
});
enemyCountText.anchor.set(1, 0);
LK.gui.topRight.addChild(enemyCountText);
// Maze generation
function generateMaze() {
// Initialize maze with all floors (open space)
maze = [];
for (var y = 0; y < mazeHeight; y++) {
maze[y] = [];
for (var x = 0; x < mazeWidth; x++) {
maze[y][x] = 0; // 0 = floor, 1 = wall
}
}
// Add border walls
for (var x = 0; x < mazeWidth; x++) {
maze[0][x] = 1; // top border
maze[mazeHeight - 1][x] = 1; // bottom border
}
for (var y = 0; y < mazeHeight; y++) {
maze[y][0] = 1; // left border
maze[y][mazeWidth - 1] = 1; // right border
}
// Add a few scattered walls randomly for minimal obstacles
var wallCount = Math.floor(mazeWidth * mazeHeight * 0.1); // Only 10% walls
for (var i = 0; i < wallCount; i++) {
var rx = Math.floor(Math.random() * (mazeWidth - 2)) + 1;
var ry = Math.floor(Math.random() * (mazeHeight - 2)) + 1;
maze[ry][rx] = 1;
}
}
function createMazeWalls() {
// Clear existing walls
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
for (var i = wall2s.length - 1; i >= 0; i--) {
wall2s[i].destroy();
}
walls = [];
wall2s = [];
// Create wall objects
for (var y = 0; y < mazeHeight; y++) {
for (var x = 0; x < mazeWidth; x++) {
if (maze[y][x] === 1) {
// Randomly choose between wall types
var useWall2 = Math.random() < 0.5;
if (useWall2) {
var wall = LK.getAsset('wall2', {
x: x * cellSize + cellSize / 2,
y: y * cellSize + cellSize / 2 + mazeOffsetY,
anchorX: 0.5,
anchorY: 0.5
});
wall2s.push(wall);
game.addChild(wall);
} else {
var wall = LK.getAsset('wall', {
x: x * cellSize + cellSize / 2,
y: y * cellSize + cellSize / 2 + mazeOffsetY,
anchorX: 0.5,
anchorY: 0.5
});
walls.push(wall);
game.addChild(wall);
}
}
}
}
}
function findFloorPosition() {
var attempts = 0;
while (attempts < 100) {
var x = Math.floor(Math.random() * mazeWidth);
var y = Math.floor(Math.random() * mazeHeight);
if (maze[y][x] === 0) {
return {
x: x * cellSize + cellSize / 2,
y: y * cellSize + cellSize / 2 + mazeOffsetY
};
}
attempts++;
}
// Fallback to a guaranteed floor position
return {
x: cellSize + cellSize / 2,
y: cellSize + cellSize / 2 + mazeOffsetY
};
}
function checkWallCollision(x, y) {
var gridX = Math.floor(x / cellSize);
var gridY = Math.floor((y - mazeOffsetY) / cellSize);
if (gridX < 0 || gridX >= mazeWidth || gridY < 0 || gridY >= mazeHeight) {
return true;
}
return maze[gridY][gridX] === 1;
}
function spawnEnemies() {
// Clear existing enemies
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
}
enemies = [];
var enemyCount = 15; // Fixed enemy count
for (var i = 0; i < enemyCount; i++) {
var pos = findFloorPosition();
var enemy = new Enemy();
enemy.x = pos.x;
enemy.y = pos.y;
enemy.lastX = enemy.x;
enemy.lastY = enemy.y;
enemies.push(enemy);
game.addChild(enemy);
}
updateEnemyCount();
}
function initLevel() {
setRandomBackground();
generateMaze();
createMazeWalls();
// Position player
var playerPos = findFloorPosition();
player.x = playerPos.x;
player.y = playerPos.y;
player.lastX = player.x;
player.lastY = player.y;
spawnEnemies();
}
function updateEnemyCount() {
enemyCountText.setText('Enemies: ' + enemies.length);
}
function updateHealthText() {
healthText.setText('Health: ' + player.health);
}
function nextMaze() {
// Clear bullets
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
bullets.splice(i, 1);
}
initLevel();
}
// Initialize player
player = new Player();
game.addChild(player);
// Initialize first level
initLevel();
updateHealthText();
// Start background music
LK.playMusic('123huntin');
// Swipe controls
var swipeStartX = 0;
var swipeStartY = 0;
var isSwipeActive = false;
var moveX = 0;
var moveY = 0;
var minSwipeDistance = 30;
// Double tap controls
var lastTapTime = 0;
var doubleTapDelay = 300; // milliseconds
var lastTapX = 0;
var lastTapY = 0;
var tapDistance = 50; // max distance between taps to consider as double tap
game.down = function (x, y, obj) {
var currentTime = Date.now();
var timeDiff = currentTime - lastTapTime;
var distanceDiff = Math.sqrt(Math.pow(x - lastTapX, 2) + Math.pow(y - lastTapY, 2));
// Check for double tap
if (timeDiff < doubleTapDelay && distanceDiff < tapDistance) {
// Double tap detected - shoot
player.shoot(x, y);
lastTapTime = 0; // Reset to prevent triple tap
} else {
// Single tap - prepare for swipe
swipeStartX = x;
swipeStartY = y;
isSwipeActive = true;
lastTapTime = currentTime;
lastTapX = x;
lastTapY = y;
}
};
game.move = function (x, y, obj) {
if (isSwipeActive) {
var swipeDeltaX = x - swipeStartX;
var swipeDeltaY = y - swipeStartY;
var swipeDistance = Math.sqrt(swipeDeltaX * swipeDeltaX + swipeDeltaY * swipeDeltaY);
if (swipeDistance > minSwipeDistance) {
// Normalize swipe direction and apply player speed
moveX = swipeDeltaX / swipeDistance * player.speed;
moveY = swipeDeltaY / swipeDistance * player.speed;
}
}
};
game.up = function (x, y, obj) {
isSwipeActive = false;
moveX = 0;
moveY = 0;
};
// Main game loop
game.update = function () {
// Move player
if (moveX !== 0 || moveY !== 0) {
var newX = player.x + moveX;
var newY = player.y + moveY;
if (!checkWallCollision(newX, newY)) {
// Update player direction for visual flipping
player.setDirection(moveX);
player.x = newX;
player.y = newY;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check wall collision
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bounds
if (bullet.x < 0 || bullet.x > mazeWidth * cellSize || bullet.y < mazeOffsetY || bullet.y > mazeHeight * cellSize + mazeOffsetY) {
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])) {
LK.getSound('enemyHit').play();
LK.effects.flashObject(enemies[j], 0xffffff, 200);
// Store reference to the enemy before starting animation
var enemyToDestroy = enemies[j];
var enemyIndex = j;
// Add spinning animation before destroying enemy
tween(enemyToDestroy, {
rotation: enemyToDestroy.rotation + Math.PI * 4 // Spin 2 full rotations
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Destroy enemy after animation completes
if (enemyToDestroy && enemyToDestroy.parent) {
enemyToDestroy.destroy();
// Find and remove enemy from array safely
var indexToRemove = enemies.indexOf(enemyToDestroy);
if (indexToRemove !== -1) {
enemies.splice(indexToRemove, 1);
}
updateEnemyCount();
}
}
});
bullet.destroy();
bullets.splice(i, 1);
hitEnemy = true;
break;
}
}
if (hitEnemy) continue;
}
// Check player-enemy collision
for (var i = enemies.length - 1; i >= 0; i--) {
if (player.intersects(enemies[i])) {
LK.getSound('playerHit').play();
LK.effects.flashObject(player, 0xff0000, 500);
player.health--;
updateHealthText();
// Calculate knockback direction (away from enemy)
var knockbackX = player.x - enemies[i].x;
var knockbackY = player.y - enemies[i].y;
var distance = Math.sqrt(knockbackX * knockbackX + knockbackY * knockbackY);
if (distance > 0) {
// Normalize direction and apply knockback force
knockbackX = knockbackX / distance * 80;
knockbackY = knockbackY / distance * 80;
// Calculate target position for knockback
var targetX = player.x + knockbackX;
var targetY = player.y + knockbackY;
// Ensure target position is valid (not in wall)
if (!checkWallCollision(targetX, targetY)) {
// Create bouncing knockback animation
tween(player, {
x: targetX,
y: targetY
}, {
duration: 200,
easing: tween.bounceOut
});
}
}
// Move enemy away to prevent multiple hits
enemies[i].x += (Math.random() - 0.5) * 60;
enemies[i].y += (Math.random() - 0.5) * 60;
if (player.health <= 0) {
LK.showGameOver();
return;
}
}
}
// Check win condition
if (enemies.length === 0) {
LK.showYouWin();
return;
}
};
2d big size side scroller wild warthog image. In-Game asset. 2d. High contrast. No shadows
2d hroizontal sidescroller average year country man is the hunter. holld shootgun and ready shoot. In-Game asset. 2d. High contrast. No shadows
2d side scroller anime green bushs asset. In-Game asset. 2d. High contrast. No shadows