/**** * Classes ****/ // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); var bulletSprite = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, flipY: 1 // flip vertically }); // Target coordinates for the bullet self.targetX = null; self.targetY = null; self.speed = 48; // pixels per frame, positive value self.dirX = 0; self.dirY = -1; self.setTarget = function (tx, ty) { // Calculate direction vector var dx = tx - self.x; var dy = ty - self.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { self.dirX = dx / len; self.dirY = dy / len; } else { self.dirX = 0; self.dirY = -1; } self.targetX = tx; self.targetY = ty; }; self.update = function () { // Store lastX/lastY for event triggers if (typeof self.lastX === "undefined") self.lastX = self.x; if (typeof self.lastY === "undefined") self.lastY = self.y; // Move in direction self.x += self.dirX * self.speed; self.y += self.dirY * self.speed; // Rotate bullet sprite to face movement direction if (self.dirX !== 0 || self.dirY !== 0) { // atan2 returns angle in radians, 0 is to the right, so subtract Math.PI/2 to make 0 point up bulletSprite.rotation = Math.atan2(self.dirY, self.dirX) - Math.PI / 2; } // Update lastX/lastY for next frame self.lastX = self.x; self.lastY = self.y; }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); var enemySprite = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.radius = enemySprite.width * 0.5; self.speed = (5 + Math.random() * 3) * 0.5; // slightly faster zombies self.update = function () { // Move toward player if (typeof self.lastX === "undefined") self.lastX = self.x; if (typeof self.lastY === "undefined") self.lastY = self.y; if (player) { var dx = player.x - self.x; var dy = player.y - self.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { self.x += dx / len * self.speed; self.y += dy / len * self.speed; } else { self.y += self.speed; } } else { self.y += self.speed; } // Update lastX/lastY for event triggers self.lastX = self.x; self.lastY = self.y; }; return self; }); // FastZombie class var FastZombie = Container.expand(function () { var self = Container.call(this); var fastZombieSprite = self.attachAsset('FastZombie', { anchorX: 0.5, anchorY: 0.5 }); self.radius = fastZombieSprite.width * 0.5; self.speed = (10 + Math.random() * 4) * 0.4; // much faster than normal zombies, but slowed down self.update = function () { // Move toward player if (typeof self.lastX === "undefined") self.lastX = self.x; if (typeof self.lastY === "undefined") self.lastY = self.y; if (player) { var dx = player.x - self.x; var dy = player.y - self.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { self.x += dx / len * self.speed; self.y += dy / len * self.speed; } else { self.y += self.speed; } } else { self.y += self.speed; } // Update lastX/lastY for event triggers self.lastX = self.x; self.lastY = self.y; }; return self; }); // Obstacle class var Obstacle = Container.expand(function () { var self = Container.call(this); var obsSprite = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsSprite.width; self.height = obsSprite.height; self.speed = 12 + Math.random() * 8; self.update = function () { self.y += self.speed; }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var playerSprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.radius = playerSprite.width * 0.5; self.lives = 1; self.invincible = false; self.invincibleTicks = 0; self.shootCooldown = 0; self.update = function () { if (self.invincible) { self.invincibleTicks--; if (self.invincibleTicks <= 0) { self.invincible = false; playerSprite.alpha = 1; } else { // Flicker effect playerSprite.alpha = LK.ticks % 10 < 5 ? 0.4 : 1; } } if (self.shootCooldown > 0) self.shootCooldown--; }; // Called when player is hit self.hit = function () { if (self.invincible) return; self.lives--; self.invincible = true; self.invincibleTicks = 90; // 1.5 seconds playerSprite.alpha = 0.4; LK.effects.flashObject(self, 0xff0000, 500); LK.getSound('hit').play(); }; // Called when player picks up a powerup self.powerup = function () { self.invincible = true; self.invincibleTicks = 180; // 3 seconds playerSprite.alpha = 0.4; LK.getSound('powerup').play(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Game state variables // Player character: blue box // Enemy: red ellipse // Obstacle: orange box // Bullet: yellow box // Powerup: green ellipse // Sound effects // Music var player; var bullets = []; var enemies = []; // Removed obstacles array as obstacles are deleted from the game var dragNode = null; var lastTouch = { x: 0, y: 0 }; var scoreTxt, livesTxt; var spawnTick = 0; var difficulty = 1; var gameOver = false; // UI scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); livesTxt = new Text2('♥♥♥', { size: 90, fill: 0xFF5252 }); livesTxt.anchor.set(1, 0); LK.gui.topRight.addChild(livesTxt); // Start music LK.playMusic('music'); // Create player player = new Player(); player.x = 2048 / 2; player.y = 2732 / 2; game.addChild(player); // Helper: update lives display function updateLives() { var s = ''; for (var i = 0; i < player.lives; i++) s += '♥'; livesTxt.setText(s); } // Helper: spawn enemy function spawnEnemy() { var e = new Enemy(); // Randomly pick a spawn edge: 0=top, 1=bottom, 2=left, 3=right var edge = Math.floor(Math.random() * 4); if (edge === 0) { // top e.x = 200 + Math.random() * (2048 - 400); e.y = -100; } else if (edge === 1) { // bottom e.x = 200 + Math.random() * (2048 - 400); e.y = 2732 + 100; } else if (edge === 2) { // left e.x = -100; e.y = 200 + Math.random() * (2732 - 400); } else { // right e.x = 2048 + 100; e.y = 200 + Math.random() * (2732 - 400); } enemies.push(e); game.addChild(e); } // Removed spawnObstacle function as obstacles are deleted from the game // Powerup spawn helper removed as per requirements // Touch controls: drag player game.down = function (x, y, obj) { // Don't allow drag from top left 100x100 if (x < 100 && y < 100) return; if (player && !gameOver) { dragNode = player; lastTouch.x = x; lastTouch.y = y; } }; game.move = function (x, y, obj) { if (dragNode && !gameOver) { // Player movement disabled: do not update player.x or player.y lastTouch.x = x; lastTouch.y = y; } }; game.up = function (x, y, obj) { dragNode = null; }; // Tap to shoot (anywhere except top left 100x100) game.on('down', function (x, y, obj) { if (x < 100 && y < 100) return; if (player && !gameOver && player.shootCooldown <= 0) { var b = new Bullet(); b.x = player.x; b.y = player.y - player.radius - 20; b.setTarget(x, y); // Set bullet direction toward tap bullets.push(b); game.addChild(b); player.shootCooldown = 12; // 0.2s LK.getSound('shoot').play(); } }); // Main game loop game.update = function () { if (gameOver) return; // Increase difficulty over time // Only increase Powerup and FastZombie spawn rates, not enemy spawn rate var newDifficulty = 1 + Math.floor(LK.getScore() / 50) * 0.1; if (newDifficulty !== difficulty) { difficulty = newDifficulty; } // Enemy spawn rate stays constant, but we use difficulty for powerup and fastzombie rates // Player update player.update(); // Spawn logic spawnTick++; if (spawnTick % 30 === 0) { // Limit total number of enemies, fastzombies, and powerups to 10 var totalActive = enemies.length; var maxActive = 10; // Enemy spawn rate is constant, not affected by difficulty if (totalActive < maxActive && Math.random() < 0.5) { spawnEnemy(); totalActive++; } if (totalActive < maxActive && Math.random() < 0.10) { spawnEnemy(); totalActive++; } // FastZombie: 7% base chance, scales with difficulty, only after score >= 25 // After score > 50, FastZombie spawn chance is 50% var fastZombieChance = 0.07 * difficulty; if (LK.getScore() > 50) { fastZombieChance = 0.5; } if (totalActive < maxActive && LK.getScore() >= 25 && Math.random() < fastZombieChance) { var fz = new FastZombie(); // Randomly pick a spawn edge: 0=top, 1=bottom, 2=left, 3=right var edge = Math.floor(Math.random() * 4); if (edge === 0) { // top fz.x = 200 + Math.random() * (2048 - 400); fz.y = -100; } else if (edge === 1) { // bottom fz.x = 200 + Math.random() * (2048 - 400); fz.y = 2732 + 100; } else if (edge === 2) { // left fz.x = -100; fz.y = 200 + Math.random() * (2732 - 400); } else { // right fz.x = 2048 + 100; fz.y = 200 + Math.random() * (2732 - 400); } enemies.push(fz); game.addChild(fz); totalActive++; } } // Bulletpowerup timer logic // bulletpowerupActive is now permanent once collected; timer logic removed // Bullets for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); if (b.y < -60) { b.destroy(); bullets.splice(i, 1); continue; } // Bullet hits enemy for (var j = enemies.length - 1; j >= 0; j--) { var e = enemies[j]; if (b.intersects(e)) { LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); if (LK.getScore() >= 150) { gameOver = true; LK.showYouWin(); return; } LK.getSound('enemyDown').play(); e.destroy(); enemies.splice(j, 1); b.destroy(); bullets.splice(i, 1); break; } } } // Enemies for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; e.update(); if (e.y > 2732 + 100) { e.destroy(); enemies.splice(i, 1); continue; } // Enemy hits player if (e.intersects(player)) { if (!player.invincible) { player.hit(); updateLives(); if (player.lives <= 0) { gameOver = true; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } e.destroy(); enemies.splice(i, 1); } } // Obstacles removed from game }; // Score display scoreTxt.setText(LK.getScore()); updateLives();
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
flipY: 1 // flip vertically
});
// Target coordinates for the bullet
self.targetX = null;
self.targetY = null;
self.speed = 48; // pixels per frame, positive value
self.dirX = 0;
self.dirY = -1;
self.setTarget = function (tx, ty) {
// Calculate direction vector
var dx = tx - self.x;
var dy = ty - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
self.dirX = dx / len;
self.dirY = dy / len;
} else {
self.dirX = 0;
self.dirY = -1;
}
self.targetX = tx;
self.targetY = ty;
};
self.update = function () {
// Store lastX/lastY for event triggers
if (typeof self.lastX === "undefined") self.lastX = self.x;
if (typeof self.lastY === "undefined") self.lastY = self.y;
// Move in direction
self.x += self.dirX * self.speed;
self.y += self.dirY * self.speed;
// Rotate bullet sprite to face movement direction
if (self.dirX !== 0 || self.dirY !== 0) {
// atan2 returns angle in radians, 0 is to the right, so subtract Math.PI/2 to make 0 point up
bulletSprite.rotation = Math.atan2(self.dirY, self.dirX) - Math.PI / 2;
}
// Update lastX/lastY for next frame
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemySprite = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = enemySprite.width * 0.5;
self.speed = (5 + Math.random() * 3) * 0.5; // slightly faster zombies
self.update = function () {
// Move toward player
if (typeof self.lastX === "undefined") self.lastX = self.x;
if (typeof self.lastY === "undefined") self.lastY = self.y;
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
self.x += dx / len * self.speed;
self.y += dy / len * self.speed;
} else {
self.y += self.speed;
}
} else {
self.y += self.speed;
}
// Update lastX/lastY for event triggers
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// FastZombie class
var FastZombie = Container.expand(function () {
var self = Container.call(this);
var fastZombieSprite = self.attachAsset('FastZombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = fastZombieSprite.width * 0.5;
self.speed = (10 + Math.random() * 4) * 0.4; // much faster than normal zombies, but slowed down
self.update = function () {
// Move toward player
if (typeof self.lastX === "undefined") self.lastX = self.x;
if (typeof self.lastY === "undefined") self.lastY = self.y;
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
self.x += dx / len * self.speed;
self.y += dy / len * self.speed;
} else {
self.y += self.speed;
}
} else {
self.y += self.speed;
}
// Update lastX/lastY for event triggers
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Obstacle class
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obsSprite = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsSprite.width;
self.height = obsSprite.height;
self.speed = 12 + Math.random() * 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var playerSprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = playerSprite.width * 0.5;
self.lives = 1;
self.invincible = false;
self.invincibleTicks = 0;
self.shootCooldown = 0;
self.update = function () {
if (self.invincible) {
self.invincibleTicks--;
if (self.invincibleTicks <= 0) {
self.invincible = false;
playerSprite.alpha = 1;
} else {
// Flicker effect
playerSprite.alpha = LK.ticks % 10 < 5 ? 0.4 : 1;
}
}
if (self.shootCooldown > 0) self.shootCooldown--;
};
// Called when player is hit
self.hit = function () {
if (self.invincible) return;
self.lives--;
self.invincible = true;
self.invincibleTicks = 90; // 1.5 seconds
playerSprite.alpha = 0.4;
LK.effects.flashObject(self, 0xff0000, 500);
LK.getSound('hit').play();
};
// Called when player picks up a powerup
self.powerup = function () {
self.invincible = true;
self.invincibleTicks = 180; // 3 seconds
playerSprite.alpha = 0.4;
LK.getSound('powerup').play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Game state variables
// Player character: blue box
// Enemy: red ellipse
// Obstacle: orange box
// Bullet: yellow box
// Powerup: green ellipse
// Sound effects
// Music
var player;
var bullets = [];
var enemies = [];
// Removed obstacles array as obstacles are deleted from the game
var dragNode = null;
var lastTouch = {
x: 0,
y: 0
};
var scoreTxt, livesTxt;
var spawnTick = 0;
var difficulty = 1;
var gameOver = false;
// UI
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
livesTxt = new Text2('♥♥♥', {
size: 90,
fill: 0xFF5252
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
// Start music
LK.playMusic('music');
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// Helper: update lives display
function updateLives() {
var s = '';
for (var i = 0; i < player.lives; i++) s += '♥';
livesTxt.setText(s);
}
// Helper: spawn enemy
function spawnEnemy() {
var e = new Enemy();
// Randomly pick a spawn edge: 0=top, 1=bottom, 2=left, 3=right
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// top
e.x = 200 + Math.random() * (2048 - 400);
e.y = -100;
} else if (edge === 1) {
// bottom
e.x = 200 + Math.random() * (2048 - 400);
e.y = 2732 + 100;
} else if (edge === 2) {
// left
e.x = -100;
e.y = 200 + Math.random() * (2732 - 400);
} else {
// right
e.x = 2048 + 100;
e.y = 200 + Math.random() * (2732 - 400);
}
enemies.push(e);
game.addChild(e);
}
// Removed spawnObstacle function as obstacles are deleted from the game
// Powerup spawn helper removed as per requirements
// Touch controls: drag player
game.down = function (x, y, obj) {
// Don't allow drag from top left 100x100
if (x < 100 && y < 100) return;
if (player && !gameOver) {
dragNode = player;
lastTouch.x = x;
lastTouch.y = y;
}
};
game.move = function (x, y, obj) {
if (dragNode && !gameOver) {
// Player movement disabled: do not update player.x or player.y
lastTouch.x = x;
lastTouch.y = y;
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Tap to shoot (anywhere except top left 100x100)
game.on('down', function (x, y, obj) {
if (x < 100 && y < 100) return;
if (player && !gameOver && player.shootCooldown <= 0) {
var b = new Bullet();
b.x = player.x;
b.y = player.y - player.radius - 20;
b.setTarget(x, y); // Set bullet direction toward tap
bullets.push(b);
game.addChild(b);
player.shootCooldown = 12; // 0.2s
LK.getSound('shoot').play();
}
});
// Main game loop
game.update = function () {
if (gameOver) return;
// Increase difficulty over time
// Only increase Powerup and FastZombie spawn rates, not enemy spawn rate
var newDifficulty = 1 + Math.floor(LK.getScore() / 50) * 0.1;
if (newDifficulty !== difficulty) {
difficulty = newDifficulty;
}
// Enemy spawn rate stays constant, but we use difficulty for powerup and fastzombie rates
// Player update
player.update();
// Spawn logic
spawnTick++;
if (spawnTick % 30 === 0) {
// Limit total number of enemies, fastzombies, and powerups to 10
var totalActive = enemies.length;
var maxActive = 10;
// Enemy spawn rate is constant, not affected by difficulty
if (totalActive < maxActive && Math.random() < 0.5) {
spawnEnemy();
totalActive++;
}
if (totalActive < maxActive && Math.random() < 0.10) {
spawnEnemy();
totalActive++;
}
// FastZombie: 7% base chance, scales with difficulty, only after score >= 25
// After score > 50, FastZombie spawn chance is 50%
var fastZombieChance = 0.07 * difficulty;
if (LK.getScore() > 50) {
fastZombieChance = 0.5;
}
if (totalActive < maxActive && LK.getScore() >= 25 && Math.random() < fastZombieChance) {
var fz = new FastZombie();
// Randomly pick a spawn edge: 0=top, 1=bottom, 2=left, 3=right
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// top
fz.x = 200 + Math.random() * (2048 - 400);
fz.y = -100;
} else if (edge === 1) {
// bottom
fz.x = 200 + Math.random() * (2048 - 400);
fz.y = 2732 + 100;
} else if (edge === 2) {
// left
fz.x = -100;
fz.y = 200 + Math.random() * (2732 - 400);
} else {
// right
fz.x = 2048 + 100;
fz.y = 200 + Math.random() * (2732 - 400);
}
enemies.push(fz);
game.addChild(fz);
totalActive++;
}
}
// Bulletpowerup timer logic
// bulletpowerupActive is now permanent once collected; timer logic removed
// Bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
if (b.y < -60) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Bullet hits enemy
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
if (b.intersects(e)) {
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
if (LK.getScore() >= 150) {
gameOver = true;
LK.showYouWin();
return;
}
LK.getSound('enemyDown').play();
e.destroy();
enemies.splice(j, 1);
b.destroy();
bullets.splice(i, 1);
break;
}
}
}
// Enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.update();
if (e.y > 2732 + 100) {
e.destroy();
enemies.splice(i, 1);
continue;
}
// Enemy hits player
if (e.intersects(player)) {
if (!player.invincible) {
player.hit();
updateLives();
if (player.lives <= 0) {
gameOver = true;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
e.destroy();
enemies.splice(i, 1);
}
}
// Obstacles removed from game
};
// Score display
scoreTxt.setText(LK.getScore());
updateLives();
soldier pixel. In-Game asset. 2d. High contrast. No shadows
pixel ammo. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
pixel brick wall. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
blood pixel. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
White ghost with red eyes pixel. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
blue ghost pixel. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
White ghost pixel. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat