Code edit (1 edits merged)
Please save this source code
User prompt
Cowboy Rush: Shootout Road
Initial prompt
🎮 Game Title: Cowboy Rush: Shootout Road --- 📝 Game Description Welcome to Cowboy Rush, a fast-paced 2D arcade shooter where YOU are the last hope of the wild west! Dodge, shoot, and survive on a triple-lane desert road while enemy cowboys chase you down. --- 🎯 Game Objective Stay alive as long as you can. Switch between 3 lanes, avoid bullets, and shoot down enemies chasing you. The longer you survive, the faster the game gets! --- 🕹️ Gameplay Mechanics You are a lone cowboy running forward endlessly. Behind you: a gang of enemy cowboys chasing you. There are 3 lanes — left, middle, right. Use the Left and Right buttons to switch lanes. Enemies also change lanes randomly to match your position. Tap the Shoot button to fire your revolver. You can shoot once every 1.2 seconds. Enemies shoot once every 3 seconds. Both you and enemies die with a single hit. The game gets faster over time. Reaction time shortens! --- 💀 Game Over Conditions If an enemy bullet hits you — Game Over. The longer you survive, the higher your Score (based on time + kills). --- 🏆 Leaderboard Feature Enable global leaderboards so players can compete for the Highest Score: Survive longer = Higher score Kill enemies = Bonus points Leaderboard tracks: Username Top Score Kill Count --- 🔘 UI Buttons ⬅️ Left: Move to the left lane ➡️ Right: Move to the right lane 🎯 Shoot: Fire a bullet (cooldown: 1.2 sec) 🏁 Restart: Restart game after Game Over --- 📈 Score System Action Points Survive 1 sec +1 Kill 1 enemy +5 --- 🎨 Visual/Style Suggestions Pixel art or cartoon 2D Desert background with cacti and old western town in distance Enemies with cowboy hats and red bandanas Speed lines as difficulty increases
/****
* 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