/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.update = function () { self.y += self.speed; }; return self; }); var EnemyCowboy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemyCowboy', { anchorX: 0.5, anchorY: 0.5 }); var weapon = self.attachAsset('enemyWeapon', { anchorX: 0.5, anchorY: 0.5, x: 30, y: 0 }); self.lane = 1; self.speed = 3; self.lastShot = 0; self.shootCooldown = 180; // 3 seconds at 60fps self.targetLane = 1; self.laneChangeSpeed = 8; self.aiType = 'A'; // A: stay same lane, B: random switch, C: track player self.lastLaneChange = 0; self.update = function () { self.y += self.speed; // Move towards target lane var targetX = getLaneX(self.targetLane); if (Math.abs(self.x - targetX) > self.laneChangeSpeed) { if (self.x < targetX) { self.x += self.laneChangeSpeed; } else { self.x -= self.laneChangeSpeed; } } else { self.x = targetX; self.lane = self.targetLane; } // Shooting logic self.lastShot++; if (self.lastShot >= self.shootCooldown) { self.lastShot = 0; // Create enemy bullet var bullet = new EnemyBullet(); var weaponPos = weapon.parent.toGlobal(weapon.position); var gamePos = game.toLocal(weaponPos); bullet.x = gamePos.x; bullet.y = gamePos.y; enemyBullets.push(bullet); game.addChild(bullet); // Animate weapon recoil tween(weapon, { scaleY: 0.8 }, { duration: 100, onFinish: function onFinish() { tween(weapon, { scaleY: 1 }, { duration: 100 }); } }); } // AI behavior self.lastLaneChange++; if (self.lastLaneChange >= 120) { // Every 2 seconds self.lastLaneChange = 0; if (self.aiType === 'B') { // Random switch self.targetLane = Math.floor(Math.random() * 3); } else if (self.aiType === 'C') { // Track player if (player) { self.targetLane = player.lane; } } } // Type A stays in same lane (no change needed) }; return self; }); var MiniBoss = Container.expand(function () { var self = Container.call(this); var bossGraphics = self.attachAsset('miniBoss', { anchorX: 0.5, anchorY: 0.5 }); var weapon = self.attachAsset('enemyWeapon', { anchorX: 0.5, anchorY: 0.5, x: 40, y: 0 }); self.lane = 1; self.speed = 4; self.health = 3; self.maxHealth = 3; self.lastShot = 0; self.shootCooldown = 120; // 2 seconds at 60fps self.targetLane = 1; self.laneChangeSpeed = 10; self.update = function () { self.y += self.speed; // Move towards target lane var targetX = getLaneX(self.targetLane); if (Math.abs(self.x - targetX) > self.laneChangeSpeed) { if (self.x < targetX) { self.x += self.laneChangeSpeed; } else { self.x -= self.laneChangeSpeed; } } else { self.x = targetX; self.lane = self.targetLane; } // Shooting logic self.lastShot++; if (self.lastShot >= self.shootCooldown) { self.lastShot = 0; var bullet = new EnemyBullet(); var weaponPos = weapon.parent.toGlobal(weapon.position); var gamePos = game.toLocal(weaponPos); bullet.x = gamePos.x; bullet.y = gamePos.y; enemyBullets.push(bullet); game.addChild(bullet); // Animate weapon recoil tween(weapon, { scaleY: 0.8 }, { duration: 100, onFinish: function onFinish() { tween(weapon, { scaleY: 1 }, { duration: 100 }); } }); } // Random lane changing if (LK.ticks % 120 === 0 && Math.random() < 0.5) { self.targetLane = Math.floor(Math.random() * 3); } }; self.takeDamage = function () { self.health--; LK.getSound('miniBossHit').play(); // Flash red when hit tween(bossGraphics, { tint: 0xFF0000 }, { duration: 200, onFinish: function onFinish() { tween(bossGraphics, { tint: 0xFFFFFF }, { duration: 200 }); } }); }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('cowboy', { anchorX: 0.5, anchorY: 0.5 }); var weapon = self.attachAsset('playerWeapon', { anchorX: 0.5, anchorY: 0.5, x: -25, y: -10 }); self.lane = 1; self.targetLane = 1; self.laneChangeSpeed = 12; self.lastShot = 0; self.shootCooldown = 72; // 1.2 seconds at 60fps self.update = function () { // Move towards target lane var targetX = getLaneX(self.targetLane); if (Math.abs(self.x - targetX) > self.laneChangeSpeed) { if (self.x < targetX) { self.x += self.laneChangeSpeed; } else { self.x -= self.laneChangeSpeed; } } else { self.x = targetX; self.lane = self.targetLane; } self.lastShot++; }; self.moveLeft = function () { if (self.targetLane > 0) { self.targetLane--; } }; self.moveRight = function () { if (self.targetLane < 2) { self.targetLane++; } }; self.shoot = function () { var cooldown = playerRapidFire > 0 ? 30 : self.shootCooldown; // Rapid fire reduces cooldown if (self.lastShot >= cooldown) { self.lastShot = 0; var bullet = new PlayerBullet(); var weaponPos = weapon.parent.toGlobal(weapon.position); var gamePos = game.toLocal(weaponPos); bullet.x = gamePos.x; bullet.y = gamePos.y; // Apply explosive shot if active if (playerExplosiveShot) { bullet.makeExplosive(); playerExplosiveShot = false; // One-time use } playerBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); // Animate weapon recoil tween(weapon, { scaleY: 0.7 }, { duration: 80, onFinish: function onFinish() { tween(weapon, { scaleY: 1 }, { duration: 120 }); } }); } }; return self; }); var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -20; self.isExplosive = false; self.update = function () { self.y += self.speed; }; // Make bullet explosive self.makeExplosive = function () { self.isExplosive = true; bulletGraphics.tint = 0xFF4500; // Orange tint for explosive bulletGraphics.scaleX = 1.5; bulletGraphics.scaleY = 1.5; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); self.type = 'rapidFire'; // rapidFire, shield, explosive self.speed = 5; self.update = function () { self.y += self.speed; }; return self; }); var Wall = Container.expand(function () { var self = Container.call(this); var wallGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 250; self.health = self.maxHealth; self.isDestroyed = false; self.takeDamage = function (damage) { if (self.isDestroyed) { return; } self.health -= damage; LK.getSound('wallHit').play(); // Visual damage feedback var damagePercent = 1 - self.health / self.maxHealth; wallGraphics.tint = 0xFFFFFF - 0x444444 * damagePercent; // Shake effect tween(self, { x: self.x + 10 }, { duration: 100, onFinish: function onFinish() { tween(self, { x: self.x - 10 }, { duration: 100 }); } }); if (self.health <= 0) { self.destroyWall(); } }; self.destroyWall = function () { if (self.isDestroyed) { return; } self.isDestroyed = true; LK.getSound('wallBreak').play(); // Destruction animation tween(self, { alpha: 0, scaleY: 0.1 }, { duration: 500, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xFF8C00 }); /**** * Game Code ****/ // Game variables var player; var enemies = []; var playerBullets = []; var enemyBullets = []; var gameSpeed = 1; var survivalTime = 0; var killCount = 0; var lastEnemySpawn = 0; var enemySpawnRate = 200; // 5 seconds at 60fps var speedIncreaseTimer = 0; var wall; var powerUps = []; var miniBosses = []; var lastMiniBossSpawn = 0; var lastPowerUpSpawn = 0; var lastExplosiveSpawn = 0; var playerHasShield = false; var playerRapidFire = 0; var playerExplosiveShot = false; var sandstormActive = false; var sandstormTimer = 0; var lastSandstorm = 0; var repairBtn = null; // Lane positions function getLaneX(lane) { var laneWidth = 2048 / 3; return laneWidth * lane + laneWidth / 2; } // Add orange background var orangeBackground = game.addChild(LK.getAsset('orangeBackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Create wall wall = game.addChild(new Wall()); wall.x = 1024; wall.y = 1800; // Create player player = game.addChild(new Player()); player.x = getLaneX(1); player.y = 2200; // Create UI var scoreTxt = new Text2('SCORE: 0', { size: 70, fill: 0x00FF00 }); scoreTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(scoreTxt); scoreTxt.x = 120; scoreTxt.y = 20; var killsTxt = new Text2('KILLS: 0', { size: 70, fill: 0xFF0080 }); killsTxt.anchor.set(1, 0); LK.gui.topRight.addChild(killsTxt); killsTxt.y = 20; // Wall health bar var wallHealthBar = new Text2('WALL: 100/100', { size: 60, fill: 0x00CCFF }); wallHealthBar.anchor.set(0.5, 0); LK.gui.top.addChild(wallHealthBar); wallHealthBar.y = 80; // Control buttons var leftBtn = new Text2('โ', { size: 130, fill: 0xFFFF00 }); leftBtn.anchor.set(0.5, 0.5); LK.gui.bottomLeft.addChild(leftBtn); leftBtn.x = 200; leftBtn.y = -150; var rightBtn = new Text2('โถ', { size: 130, fill: 0xFFFF00 }); rightBtn.anchor.set(0.5, 0.5); LK.gui.bottomRight.addChild(rightBtn); rightBtn.x = -200; rightBtn.y = -150; var shootBtn = LK.getAsset('fireButton', { anchorX: 0.5, anchorY: 0.5 }); LK.gui.bottom.addChild(shootBtn); shootBtn.y = -150; // Button event handlers leftBtn.down = function () { player.moveLeft(); }; rightBtn.down = function () { player.moveRight(); }; shootBtn.down = function () { player.shoot(); }; // Function to show/hide repair button function updateRepairButton() { if (LK.getScore() >= 50 && wall && !wall.isDestroyed && wall.health < wall.maxHealth) { if (!repairBtn) { repairBtn = LK.getAsset('repairButton', { anchorX: 0.5, anchorY: 0.5 }); LK.gui.center.addChild(repairBtn); repairBtn.y = 200; repairBtn.down = function () { if (LK.getScore() >= 50 && wall && wall.health < wall.maxHealth) { LK.setScore(LK.getScore() - 50); wall.health = Math.min(wall.health + 50, wall.maxHealth); scoreTxt.setText('SCORE: ' + LK.getScore()); updateRepairButton(); } }; } } else if (repairBtn) { repairBtn.destroy(); repairBtn = null; } } // Game update loop game.update = function () { // Update power-up timers if (playerRapidFire > 0) { playerRapidFire--; } if (sandstormActive) { sandstormTimer--; if (sandstormTimer <= 0) { sandstormActive = false; game.alpha = 1; // Remove sandstorm effect } } // Update survival time and score survivalTime++; if (survivalTime % 60 === 0) { // Every second LK.setScore(LK.getScore() + 1); scoreTxt.setText('SCORE: ' + LK.getScore()); } // Update repair button updateRepairButton(); // Spawn sandstorm event lastSandstorm++; if (lastSandstorm >= 2700 && !sandstormActive) { // 45-60 seconds if (Math.random() < 0.5) { sandstormActive = true; sandstormTimer = 600; // 10 seconds game.alpha = 0.6; // Reduce visibility lastSandstorm = 0; } } // Spawn power-ups lastPowerUpSpawn++; if (lastPowerUpSpawn >= 1200) { // 20-30 seconds for rapid fire if (Math.random() < 0.7) { var powerUp = new PowerUp(); powerUp.type = 'rapidFire'; var rapidFireGraphics = powerUp.attachAsset('rapidFire', { anchorX: 0.5, anchorY: 0.5 }); powerUp.x = getLaneX(Math.floor(Math.random() * 3)); powerUp.y = -100; powerUps.push(powerUp); game.addChild(powerUp); lastPowerUpSpawn = 0; } } // Spawn explosive shot power-up lastExplosiveSpawn++; if (lastExplosiveSpawn >= 3600) { // 60 seconds var powerUp = new PowerUp(); powerUp.type = 'explosive'; var explosiveGraphics = powerUp.attachAsset('explosive', { anchorX: 0.5, anchorY: 0.5 }); powerUp.x = getLaneX(Math.floor(Math.random() * 3)); powerUp.y = -100; powerUps.push(powerUp); game.addChild(powerUp); lastExplosiveSpawn = 0; } // Spawn mini boss lastMiniBossSpawn++; if (lastMiniBossSpawn >= 1800) { // 30 seconds lastMiniBossSpawn = 0; var miniBoss = new MiniBoss(); miniBoss.lane = Math.floor(Math.random() * 3); miniBoss.targetLane = Math.floor(Math.random() * 3); miniBoss.x = getLaneX(miniBoss.lane); miniBoss.y = -150; miniBoss.speed *= gameSpeed; miniBosses.push(miniBoss); game.addChild(miniBoss); } // Update wall health bar if (wall && !wall.isDestroyed) { var healthPercent = wall.health / wall.maxHealth; if (healthPercent > 0.6) { wallHealthBar.fill = 0x00FF00; // Green for healthy } else if (healthPercent > 0.3) { wallHealthBar.fill = 0xFFFF00; // Yellow for damaged } else { wallHealthBar.fill = 0xFF0000; // Red for critical } wallHealthBar.setText('WALL: ' + wall.health + '/' + wall.maxHealth); } else { wallHealthBar.fill = 0xFF0000; wallHealthBar.setText('WALL: DESTROYED'); } // Increase game speed over time speedIncreaseTimer++; if (speedIncreaseTimer % 600 === 0) { // Every 10 seconds gameSpeed += 0.2; if (enemySpawnRate > 120) { enemySpawnRate -= 20; } } // Spawn enemies lastEnemySpawn++; if (lastEnemySpawn >= enemySpawnRate) { lastEnemySpawn = 0; var enemy = new EnemyCowboy(); enemy.lane = Math.floor(Math.random() * 3); enemy.targetLane = Math.floor(Math.random() * 3); // Set AI type var aiRand = Math.random(); if (aiRand < 0.4) { enemy.aiType = 'A'; } // Stay same lane else if (aiRand < 0.7) { enemy.aiType = 'B'; } // Random switch else { enemy.aiType = 'C'; } // Track player enemy.x = getLaneX(enemy.lane); enemy.y = -100; enemy.speed *= gameSpeed; // Sandstorm effect on enemies if (sandstormActive) { enemy.speed *= 1.25; // Move 25% faster enemy.shootCooldown = 999999; // Cannot shoot } enemies.push(enemy); game.addChild(enemy); } // Update power-ups for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; // Remove power-ups that went off screen if (powerUp.y > 2800) { powerUp.destroy(); powerUps.splice(i, 1); continue; } // Check collision with player if (powerUp.intersects(player)) { LK.getSound('powerUp').play(); if (powerUp.type === 'rapidFire') { playerRapidFire = 600; // 10 seconds at 60fps } else if (powerUp.type === 'shield') { playerHasShield = true; } else if (powerUp.type === 'explosive') { playerExplosiveShot = true; } powerUp.destroy(); powerUps.splice(i, 1); } } // Update mini bosses for (var i = miniBosses.length - 1; i >= 0; i--) { var miniBoss = miniBosses[i]; // Remove mini bosses that went off screen if (miniBoss.y > 2800) { miniBoss.destroy(); miniBosses.splice(i, 1); continue; } // Check collision with wall if (wall && !wall.isDestroyed && miniBoss.intersects(wall)) { miniBoss.speed = 0; if (miniBoss.lastWallDamage === undefined) { miniBoss.lastWallDamage = 0; } miniBoss.lastWallDamage++; if (miniBoss.lastWallDamage >= 30) { wall.takeDamage(20); // Mini boss deals more damage miniBoss.lastWallDamage = 0; } } else if (wall && wall.isDestroyed) { miniBoss.speed = 4 * gameSpeed; } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; // Remove enemies that went off screen if (enemy.y > 2800) { enemy.destroy(); enemies.splice(i, 1); continue; } // Check collision with wall - enemies cannot pass through if (wall && !wall.isDestroyed && enemy.intersects(wall)) { // Stop enemy movement when hitting wall enemy.speed = 0; // Deal damage to wall when enemy touches it if (enemy.lastWallDamage === undefined) { enemy.lastWallDamage = 0; } enemy.lastWallDamage++; if (enemy.lastWallDamage >= 30) { // Damage every 0.5 seconds wall.takeDamage(10); enemy.lastWallDamage = 0; } } else if (wall && wall.isDestroyed) { // If wall is destroyed, enemies can move normally enemy.speed = 3 * gameSpeed; } } // Update player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; // Remove bullets that went off screen if (bullet.y < -50) { bullet.destroy(); playerBullets.splice(i, 1); continue; } // Check collision with enemies var bulletHit = false; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { // Enemy hit LK.getSound('enemyHit').play(); killCount++; LK.setScore(LK.getScore() + 5); scoreTxt.setText('SCORE: ' + LK.getScore()); killsTxt.setText('KILLS: ' + killCount); // Drop shield power-up with 15% chance if (Math.random() < 0.15) { var shieldPowerUp = new PowerUp(); shieldPowerUp.type = 'shield'; var shieldGraphics = shieldPowerUp.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5 }); shieldPowerUp.x = enemy.x; shieldPowerUp.y = enemy.y; powerUps.push(shieldPowerUp); game.addChild(shieldPowerUp); } // Remove enemy enemy.destroy(); enemies.splice(j, 1); if (!bullet.isExplosive) { bulletHit = true; break; } } } // Check collision with mini bosses for (var j = miniBosses.length - 1; j >= 0; j--) { var miniBoss = miniBosses[j]; if (bullet.intersects(miniBoss)) { miniBoss.takeDamage(); if (miniBoss.health <= 0) { killCount++; LK.setScore(LK.getScore() + 20); scoreTxt.setText('SCORE: ' + LK.getScore()); killsTxt.setText('KILLS: ' + killCount); // Drop random power-up var powerUp = new PowerUp(); var powerTypes = ['rapidFire', 'shield', 'explosive']; powerUp.type = powerTypes[Math.floor(Math.random() * powerTypes.length)]; var powerGraphics = powerUp.attachAsset(powerUp.type, { anchorX: 0.5, anchorY: 0.5 }); powerUp.x = miniBoss.x; powerUp.y = miniBoss.y; powerUps.push(powerUp); game.addChild(powerUp); miniBoss.destroy(); miniBosses.splice(j, 1); } if (!bullet.isExplosive) { bulletHit = true; break; } } } // Handle explosive shots if (bullet.isExplosive) { // Explosive shot passes through wall and kills all enemies in lane var bulletLane = Math.floor((bullet.x - getLaneX(0) + 2048 / 6) / (2048 / 3)); for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (enemy.lane === bulletLane) { LK.getSound('explosion').play(); killCount++; LK.setScore(LK.getScore() + 5); enemy.destroy(); enemies.splice(j, 1); } } // Also kill mini bosses in same lane for (var j = miniBosses.length - 1; j >= 0; j--) { var miniBoss = miniBosses[j]; if (miniBoss.lane === bulletLane) { LK.getSound('explosion').play(); killCount++; LK.setScore(LK.getScore() + 20); miniBoss.destroy(); miniBosses.splice(j, 1); } } bulletHit = true; } // Remove bullet if it hit something (unless explosive) if (bulletHit) { bullet.destroy(); playerBullets.splice(i, 1); } } // Update enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; // Remove bullets that went off screen if (bullet.y > 2800) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } // Check collision with wall (bullets pass through but don't damage) if (wall && !wall.isDestroyed && bullet.intersects(wall)) { // Enemy bullets pass through wall without stopping } // Check collision with player if (bullet.intersects(player)) { if (playerHasShield) { // Shield absorbs hit playerHasShield = false; LK.effects.flashObject(player, 0x00FF00, 500); bullet.destroy(); enemyBullets.splice(i, 1); continue; } else { // Player hit - game over LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyCowboy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyCowboy', {
anchorX: 0.5,
anchorY: 0.5
});
var weapon = self.attachAsset('enemyWeapon', {
anchorX: 0.5,
anchorY: 0.5,
x: 30,
y: 0
});
self.lane = 1;
self.speed = 3;
self.lastShot = 0;
self.shootCooldown = 180; // 3 seconds at 60fps
self.targetLane = 1;
self.laneChangeSpeed = 8;
self.aiType = 'A'; // A: stay same lane, B: random switch, C: track player
self.lastLaneChange = 0;
self.update = function () {
self.y += self.speed;
// Move towards target lane
var targetX = getLaneX(self.targetLane);
if (Math.abs(self.x - targetX) > self.laneChangeSpeed) {
if (self.x < targetX) {
self.x += self.laneChangeSpeed;
} else {
self.x -= self.laneChangeSpeed;
}
} else {
self.x = targetX;
self.lane = self.targetLane;
}
// Shooting logic
self.lastShot++;
if (self.lastShot >= self.shootCooldown) {
self.lastShot = 0;
// Create enemy bullet
var bullet = new EnemyBullet();
var weaponPos = weapon.parent.toGlobal(weapon.position);
var gamePos = game.toLocal(weaponPos);
bullet.x = gamePos.x;
bullet.y = gamePos.y;
enemyBullets.push(bullet);
game.addChild(bullet);
// Animate weapon recoil
tween(weapon, {
scaleY: 0.8
}, {
duration: 100,
onFinish: function onFinish() {
tween(weapon, {
scaleY: 1
}, {
duration: 100
});
}
});
}
// AI behavior
self.lastLaneChange++;
if (self.lastLaneChange >= 120) {
// Every 2 seconds
self.lastLaneChange = 0;
if (self.aiType === 'B') {
// Random switch
self.targetLane = Math.floor(Math.random() * 3);
} else if (self.aiType === 'C') {
// Track player
if (player) {
self.targetLane = player.lane;
}
}
}
// Type A stays in same lane (no change needed)
};
return self;
});
var MiniBoss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('miniBoss', {
anchorX: 0.5,
anchorY: 0.5
});
var weapon = self.attachAsset('enemyWeapon', {
anchorX: 0.5,
anchorY: 0.5,
x: 40,
y: 0
});
self.lane = 1;
self.speed = 4;
self.health = 3;
self.maxHealth = 3;
self.lastShot = 0;
self.shootCooldown = 120; // 2 seconds at 60fps
self.targetLane = 1;
self.laneChangeSpeed = 10;
self.update = function () {
self.y += self.speed;
// Move towards target lane
var targetX = getLaneX(self.targetLane);
if (Math.abs(self.x - targetX) > self.laneChangeSpeed) {
if (self.x < targetX) {
self.x += self.laneChangeSpeed;
} else {
self.x -= self.laneChangeSpeed;
}
} else {
self.x = targetX;
self.lane = self.targetLane;
}
// Shooting logic
self.lastShot++;
if (self.lastShot >= self.shootCooldown) {
self.lastShot = 0;
var bullet = new EnemyBullet();
var weaponPos = weapon.parent.toGlobal(weapon.position);
var gamePos = game.toLocal(weaponPos);
bullet.x = gamePos.x;
bullet.y = gamePos.y;
enemyBullets.push(bullet);
game.addChild(bullet);
// Animate weapon recoil
tween(weapon, {
scaleY: 0.8
}, {
duration: 100,
onFinish: function onFinish() {
tween(weapon, {
scaleY: 1
}, {
duration: 100
});
}
});
}
// Random lane changing
if (LK.ticks % 120 === 0 && Math.random() < 0.5) {
self.targetLane = Math.floor(Math.random() * 3);
}
};
self.takeDamage = function () {
self.health--;
LK.getSound('miniBossHit').play();
// Flash red when hit
tween(bossGraphics, {
tint: 0xFF0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(bossGraphics, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
});
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('cowboy', {
anchorX: 0.5,
anchorY: 0.5
});
var weapon = self.attachAsset('playerWeapon', {
anchorX: 0.5,
anchorY: 0.5,
x: -25,
y: -10
});
self.lane = 1;
self.targetLane = 1;
self.laneChangeSpeed = 12;
self.lastShot = 0;
self.shootCooldown = 72; // 1.2 seconds at 60fps
self.update = function () {
// Move towards target lane
var targetX = getLaneX(self.targetLane);
if (Math.abs(self.x - targetX) > self.laneChangeSpeed) {
if (self.x < targetX) {
self.x += self.laneChangeSpeed;
} else {
self.x -= self.laneChangeSpeed;
}
} else {
self.x = targetX;
self.lane = self.targetLane;
}
self.lastShot++;
};
self.moveLeft = function () {
if (self.targetLane > 0) {
self.targetLane--;
}
};
self.moveRight = function () {
if (self.targetLane < 2) {
self.targetLane++;
}
};
self.shoot = function () {
var cooldown = playerRapidFire > 0 ? 30 : self.shootCooldown; // Rapid fire reduces cooldown
if (self.lastShot >= cooldown) {
self.lastShot = 0;
var bullet = new PlayerBullet();
var weaponPos = weapon.parent.toGlobal(weapon.position);
var gamePos = game.toLocal(weaponPos);
bullet.x = gamePos.x;
bullet.y = gamePos.y;
// Apply explosive shot if active
if (playerExplosiveShot) {
bullet.makeExplosive();
playerExplosiveShot = false; // One-time use
}
playerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
// Animate weapon recoil
tween(weapon, {
scaleY: 0.7
}, {
duration: 80,
onFinish: function onFinish() {
tween(weapon, {
scaleY: 1
}, {
duration: 120
});
}
});
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -20;
self.isExplosive = false;
self.update = function () {
self.y += self.speed;
};
// Make bullet explosive
self.makeExplosive = function () {
self.isExplosive = true;
bulletGraphics.tint = 0xFF4500; // Orange tint for explosive
bulletGraphics.scaleX = 1.5;
bulletGraphics.scaleY = 1.5;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
self.type = 'rapidFire'; // rapidFire, shield, explosive
self.speed = 5;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 250;
self.health = self.maxHealth;
self.isDestroyed = false;
self.takeDamage = function (damage) {
if (self.isDestroyed) {
return;
}
self.health -= damage;
LK.getSound('wallHit').play();
// Visual damage feedback
var damagePercent = 1 - self.health / self.maxHealth;
wallGraphics.tint = 0xFFFFFF - 0x444444 * damagePercent;
// Shake effect
tween(self, {
x: self.x + 10
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
x: self.x - 10
}, {
duration: 100
});
}
});
if (self.health <= 0) {
self.destroyWall();
}
};
self.destroyWall = function () {
if (self.isDestroyed) {
return;
}
self.isDestroyed = true;
LK.getSound('wallBreak').play();
// Destruction animation
tween(self, {
alpha: 0,
scaleY: 0.1
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xFF8C00
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var playerBullets = [];
var enemyBullets = [];
var gameSpeed = 1;
var survivalTime = 0;
var killCount = 0;
var lastEnemySpawn = 0;
var enemySpawnRate = 200; // 5 seconds at 60fps
var speedIncreaseTimer = 0;
var wall;
var powerUps = [];
var miniBosses = [];
var lastMiniBossSpawn = 0;
var lastPowerUpSpawn = 0;
var lastExplosiveSpawn = 0;
var playerHasShield = false;
var playerRapidFire = 0;
var playerExplosiveShot = false;
var sandstormActive = false;
var sandstormTimer = 0;
var lastSandstorm = 0;
var repairBtn = null;
// Lane positions
function getLaneX(lane) {
var laneWidth = 2048 / 3;
return laneWidth * lane + laneWidth / 2;
}
// Add orange background
var orangeBackground = game.addChild(LK.getAsset('orangeBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create wall
wall = game.addChild(new Wall());
wall.x = 1024;
wall.y = 1800;
// Create player
player = game.addChild(new Player());
player.x = getLaneX(1);
player.y = 2200;
// Create UI
var scoreTxt = new Text2('SCORE: 0', {
size: 70,
fill: 0x00FF00
});
scoreTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreTxt);
scoreTxt.x = 120;
scoreTxt.y = 20;
var killsTxt = new Text2('KILLS: 0', {
size: 70,
fill: 0xFF0080
});
killsTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(killsTxt);
killsTxt.y = 20;
// Wall health bar
var wallHealthBar = new Text2('WALL: 100/100', {
size: 60,
fill: 0x00CCFF
});
wallHealthBar.anchor.set(0.5, 0);
LK.gui.top.addChild(wallHealthBar);
wallHealthBar.y = 80;
// Control buttons
var leftBtn = new Text2('โ', {
size: 130,
fill: 0xFFFF00
});
leftBtn.anchor.set(0.5, 0.5);
LK.gui.bottomLeft.addChild(leftBtn);
leftBtn.x = 200;
leftBtn.y = -150;
var rightBtn = new Text2('โถ', {
size: 130,
fill: 0xFFFF00
});
rightBtn.anchor.set(0.5, 0.5);
LK.gui.bottomRight.addChild(rightBtn);
rightBtn.x = -200;
rightBtn.y = -150;
var shootBtn = LK.getAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.bottom.addChild(shootBtn);
shootBtn.y = -150;
// Button event handlers
leftBtn.down = function () {
player.moveLeft();
};
rightBtn.down = function () {
player.moveRight();
};
shootBtn.down = function () {
player.shoot();
};
// Function to show/hide repair button
function updateRepairButton() {
if (LK.getScore() >= 50 && wall && !wall.isDestroyed && wall.health < wall.maxHealth) {
if (!repairBtn) {
repairBtn = LK.getAsset('repairButton', {
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.center.addChild(repairBtn);
repairBtn.y = 200;
repairBtn.down = function () {
if (LK.getScore() >= 50 && wall && wall.health < wall.maxHealth) {
LK.setScore(LK.getScore() - 50);
wall.health = Math.min(wall.health + 50, wall.maxHealth);
scoreTxt.setText('SCORE: ' + LK.getScore());
updateRepairButton();
}
};
}
} else if (repairBtn) {
repairBtn.destroy();
repairBtn = null;
}
}
// Game update loop
game.update = function () {
// Update power-up timers
if (playerRapidFire > 0) {
playerRapidFire--;
}
if (sandstormActive) {
sandstormTimer--;
if (sandstormTimer <= 0) {
sandstormActive = false;
game.alpha = 1; // Remove sandstorm effect
}
}
// Update survival time and score
survivalTime++;
if (survivalTime % 60 === 0) {
// Every second
LK.setScore(LK.getScore() + 1);
scoreTxt.setText('SCORE: ' + LK.getScore());
}
// Update repair button
updateRepairButton();
// Spawn sandstorm event
lastSandstorm++;
if (lastSandstorm >= 2700 && !sandstormActive) {
// 45-60 seconds
if (Math.random() < 0.5) {
sandstormActive = true;
sandstormTimer = 600; // 10 seconds
game.alpha = 0.6; // Reduce visibility
lastSandstorm = 0;
}
}
// Spawn power-ups
lastPowerUpSpawn++;
if (lastPowerUpSpawn >= 1200) {
// 20-30 seconds for rapid fire
if (Math.random() < 0.7) {
var powerUp = new PowerUp();
powerUp.type = 'rapidFire';
var rapidFireGraphics = powerUp.attachAsset('rapidFire', {
anchorX: 0.5,
anchorY: 0.5
});
powerUp.x = getLaneX(Math.floor(Math.random() * 3));
powerUp.y = -100;
powerUps.push(powerUp);
game.addChild(powerUp);
lastPowerUpSpawn = 0;
}
}
// Spawn explosive shot power-up
lastExplosiveSpawn++;
if (lastExplosiveSpawn >= 3600) {
// 60 seconds
var powerUp = new PowerUp();
powerUp.type = 'explosive';
var explosiveGraphics = powerUp.attachAsset('explosive', {
anchorX: 0.5,
anchorY: 0.5
});
powerUp.x = getLaneX(Math.floor(Math.random() * 3));
powerUp.y = -100;
powerUps.push(powerUp);
game.addChild(powerUp);
lastExplosiveSpawn = 0;
}
// Spawn mini boss
lastMiniBossSpawn++;
if (lastMiniBossSpawn >= 1800) {
// 30 seconds
lastMiniBossSpawn = 0;
var miniBoss = new MiniBoss();
miniBoss.lane = Math.floor(Math.random() * 3);
miniBoss.targetLane = Math.floor(Math.random() * 3);
miniBoss.x = getLaneX(miniBoss.lane);
miniBoss.y = -150;
miniBoss.speed *= gameSpeed;
miniBosses.push(miniBoss);
game.addChild(miniBoss);
}
// Update wall health bar
if (wall && !wall.isDestroyed) {
var healthPercent = wall.health / wall.maxHealth;
if (healthPercent > 0.6) {
wallHealthBar.fill = 0x00FF00; // Green for healthy
} else if (healthPercent > 0.3) {
wallHealthBar.fill = 0xFFFF00; // Yellow for damaged
} else {
wallHealthBar.fill = 0xFF0000; // Red for critical
}
wallHealthBar.setText('WALL: ' + wall.health + '/' + wall.maxHealth);
} else {
wallHealthBar.fill = 0xFF0000;
wallHealthBar.setText('WALL: DESTROYED');
}
// Increase game speed over time
speedIncreaseTimer++;
if (speedIncreaseTimer % 600 === 0) {
// Every 10 seconds
gameSpeed += 0.2;
if (enemySpawnRate > 120) {
enemySpawnRate -= 20;
}
}
// Spawn enemies
lastEnemySpawn++;
if (lastEnemySpawn >= enemySpawnRate) {
lastEnemySpawn = 0;
var enemy = new EnemyCowboy();
enemy.lane = Math.floor(Math.random() * 3);
enemy.targetLane = Math.floor(Math.random() * 3);
// Set AI type
var aiRand = Math.random();
if (aiRand < 0.4) {
enemy.aiType = 'A';
} // Stay same lane
else if (aiRand < 0.7) {
enemy.aiType = 'B';
} // Random switch
else {
enemy.aiType = 'C';
} // Track player
enemy.x = getLaneX(enemy.lane);
enemy.y = -100;
enemy.speed *= gameSpeed;
// Sandstorm effect on enemies
if (sandstormActive) {
enemy.speed *= 1.25; // Move 25% faster
enemy.shootCooldown = 999999; // Cannot shoot
}
enemies.push(enemy);
game.addChild(enemy);
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
// Remove power-ups that went off screen
if (powerUp.y > 2800) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check collision with player
if (powerUp.intersects(player)) {
LK.getSound('powerUp').play();
if (powerUp.type === 'rapidFire') {
playerRapidFire = 600; // 10 seconds at 60fps
} else if (powerUp.type === 'shield') {
playerHasShield = true;
} else if (powerUp.type === 'explosive') {
playerExplosiveShot = true;
}
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Update mini bosses
for (var i = miniBosses.length - 1; i >= 0; i--) {
var miniBoss = miniBosses[i];
// Remove mini bosses that went off screen
if (miniBoss.y > 2800) {
miniBoss.destroy();
miniBosses.splice(i, 1);
continue;
}
// Check collision with wall
if (wall && !wall.isDestroyed && miniBoss.intersects(wall)) {
miniBoss.speed = 0;
if (miniBoss.lastWallDamage === undefined) {
miniBoss.lastWallDamage = 0;
}
miniBoss.lastWallDamage++;
if (miniBoss.lastWallDamage >= 30) {
wall.takeDamage(20); // Mini boss deals more damage
miniBoss.lastWallDamage = 0;
}
} else if (wall && wall.isDestroyed) {
miniBoss.speed = 4 * gameSpeed;
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Remove enemies that went off screen
if (enemy.y > 2800) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with wall - enemies cannot pass through
if (wall && !wall.isDestroyed && enemy.intersects(wall)) {
// Stop enemy movement when hitting wall
enemy.speed = 0;
// Deal damage to wall when enemy touches it
if (enemy.lastWallDamage === undefined) {
enemy.lastWallDamage = 0;
}
enemy.lastWallDamage++;
if (enemy.lastWallDamage >= 30) {
// Damage every 0.5 seconds
wall.takeDamage(10);
enemy.lastWallDamage = 0;
}
} else if (wall && wall.isDestroyed) {
// If wall is destroyed, enemies can move normally
enemy.speed = 3 * gameSpeed;
}
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
// Remove bullets that went off screen
if (bullet.y < -50) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
var bulletHit = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Enemy hit
LK.getSound('enemyHit').play();
killCount++;
LK.setScore(LK.getScore() + 5);
scoreTxt.setText('SCORE: ' + LK.getScore());
killsTxt.setText('KILLS: ' + killCount);
// Drop shield power-up with 15% chance
if (Math.random() < 0.15) {
var shieldPowerUp = new PowerUp();
shieldPowerUp.type = 'shield';
var shieldGraphics = shieldPowerUp.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
shieldPowerUp.x = enemy.x;
shieldPowerUp.y = enemy.y;
powerUps.push(shieldPowerUp);
game.addChild(shieldPowerUp);
}
// Remove enemy
enemy.destroy();
enemies.splice(j, 1);
if (!bullet.isExplosive) {
bulletHit = true;
break;
}
}
}
// Check collision with mini bosses
for (var j = miniBosses.length - 1; j >= 0; j--) {
var miniBoss = miniBosses[j];
if (bullet.intersects(miniBoss)) {
miniBoss.takeDamage();
if (miniBoss.health <= 0) {
killCount++;
LK.setScore(LK.getScore() + 20);
scoreTxt.setText('SCORE: ' + LK.getScore());
killsTxt.setText('KILLS: ' + killCount);
// Drop random power-up
var powerUp = new PowerUp();
var powerTypes = ['rapidFire', 'shield', 'explosive'];
powerUp.type = powerTypes[Math.floor(Math.random() * powerTypes.length)];
var powerGraphics = powerUp.attachAsset(powerUp.type, {
anchorX: 0.5,
anchorY: 0.5
});
powerUp.x = miniBoss.x;
powerUp.y = miniBoss.y;
powerUps.push(powerUp);
game.addChild(powerUp);
miniBoss.destroy();
miniBosses.splice(j, 1);
}
if (!bullet.isExplosive) {
bulletHit = true;
break;
}
}
}
// Handle explosive shots
if (bullet.isExplosive) {
// Explosive shot passes through wall and kills all enemies in lane
var bulletLane = Math.floor((bullet.x - getLaneX(0) + 2048 / 6) / (2048 / 3));
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (enemy.lane === bulletLane) {
LK.getSound('explosion').play();
killCount++;
LK.setScore(LK.getScore() + 5);
enemy.destroy();
enemies.splice(j, 1);
}
}
// Also kill mini bosses in same lane
for (var j = miniBosses.length - 1; j >= 0; j--) {
var miniBoss = miniBosses[j];
if (miniBoss.lane === bulletLane) {
LK.getSound('explosion').play();
killCount++;
LK.setScore(LK.getScore() + 20);
miniBoss.destroy();
miniBosses.splice(j, 1);
}
}
bulletHit = true;
}
// Remove bullet if it hit something (unless explosive)
if (bulletHit) {
bullet.destroy();
playerBullets.splice(i, 1);
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Remove bullets that went off screen
if (bullet.y > 2800) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with wall (bullets pass through but don't damage)
if (wall && !wall.isDestroyed && bullet.intersects(wall)) {
// Enemy bullets pass through wall without stopping
}
// Check collision with player
if (bullet.intersects(player)) {
if (playerHasShield) {
// Shield absorbs hit
playerHasShield = false;
LK.effects.flashObject(player, 0x00FF00, 500);
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
} else {
// Player hit - game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
};
2d cowboy character head. In-Game asset. 2d. High contrast. No shadows
2d revolver bullet. In-Game asset. 2d. High contrast. No shadows
2d old concrete wall suitable for desert atmosphere. In-Game asset. 2d. High contrast. No shadows
2d edgy red themed hostile cowboy character head
A 2d fired revolver. In-Game asset. 2d. High contrast. No shadows
a 2d revolver without firing effect
Let it be red themed
2d simple repair button. In-Game asset. 2d. High contrast. No shadows
2d protection shield. In-Game asset. 2d. High contrast. No shadows
2d explosion effect. In-Game asset. 2d. High contrast. No shadows