User prompt
Play music file number 17 as background music at game start
User prompt
revolver sound file no. 16
User prompt
make game music file number 4
User prompt
Make the whip sound file number 11
User prompt
The background can be made a little more western and zombie themed.
User prompt
Let's add game time to the game
User prompt
Upgrades do not drop from enemies, you get 1 upgrade every 2 minutes
User prompt
Upgrades only drop from bosses, bosses die in 5 lashes
User prompt
Bosses can only be killed by revolver bullets. Revolver bullets give priority to them. Bosses are pushed back when they are hit with a whip.
User prompt
Dropped add-ons come directly to the character. 1 boss should be added. This boss comes every 1 minute and when it is killed, the upgrades are dropped. When the boss is killed, the game speed increases.
User prompt
The character will remain fixed, there will be no time limit for using the whip, the enemy will be thrown every time it is pressed and will die in a single hit. The monsters in the game are slow at the beginning, the game will speed up a little after every 1 minute, and 1 development will come at the end of 2 minutes. The game is endless, each monster you kill gives 1 point, the duration of the revovlers is 10 seconds, the developments received are reduced to at least 4 seconds, 5 must be purchased, the range of the whip will be a little longer.
User prompt
Shoot at the nearest opponent based on the revolver keys and have a joystick for movement in the game
Code edit (1 edits merged)
Please save this source code
User prompt
Cowboy Whip & Revolver: Forest Showdown
Initial prompt
square, we are in the middle, a map where we can move in all directions, the map is green and forested, enemies come from everywhere, we are cowboys, we hit the characters with a whip in our hands, we have 1 revolver, the firing time is 3 seconds, we can shorten the rewards that drop during the game, when we get 3 features, we switch to weapons, weapon features come as the level speeds up, if we get 3 weapons, a pump-action pistol comes, as the game progresses, the monsters that come speed up
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Boss class
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossSprite = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.2,
scaleY: 2.2,
tint: 0x2222ff
});
self.radius = 120;
self.speed = 2.2;
self.dirX = 0;
self.dirY = 0;
self.hp = 5;
self.maxHp = 5;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
self.x += self.dirX * self.speed;
self.y += self.dirY * self.speed;
};
return self;
});
// Cowboy (player) class
var Cowboy = Container.expand(function () {
var self = Container.call(this);
var cowboySprite = self.attachAsset('cowboy', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 60; // for collision
self.whipCooldown = 0;
self.revolverCooldown = 0;
self.pumpUnlocked = false;
self.upgrades = 0;
self.revolverBaseCooldown = 600; // 10 seconds at 60fps
self.revolverCooldownTime = self.revolverBaseCooldown;
self.pumpCooldown = 0;
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 = 50;
self.speed = 2;
self.dirX = 0;
self.dirY = 0;
self.hp = 1;
self.update = function () {
self.x += self.dirX * self.speed;
self.y += self.dirY * self.speed;
};
return self;
});
// Pump-action bullet class (stronger, wider)
var PumpBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('pump_bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 20;
self.speed = 22;
self.dirX = 0;
self.dirY = 0;
self.update = function () {
self.x += self.dirX * self.speed;
self.y += self.dirY * self.speed;
};
return self;
});
// Revolver bullet class
var RevolverBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('revolver_bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 15;
self.speed = 18;
self.dirX = 0;
self.dirY = 0;
self.update = function () {
self.x += self.dirX * self.speed;
self.y += self.dirY * self.speed;
};
return self;
});
// Upgrade drop class
var UpgradeDrop = Container.expand(function () {
var self = Container.call(this);
var upgradeSprite = self.attachAsset('upgrade', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 30;
self.update = function () {};
return self;
});
// Whip attack class (longer range, short-lived)
var WhipAttack = Container.expand(function () {
var self = Container.call(this);
var whipSprite = self.attachAsset('whip', {
anchorX: 0.0,
anchorY: 0.5
});
self.radius = 120; // longer range
self.dirX = 0;
self.dirY = 0;
self.lifetime = 10; // frames
self.update = function () {
self.lifetime--;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2e7d32 // Forest green
});
/****
* Game Code
****/
// Game area
// Cowboy (player)
// Whip (short range attack)
// Revolver bullet
// Enemy
// Upgrade drop
// Pump-action bullet
var GAME_W = 2048;
var GAME_H = 2732;
// Center position
var centerX = GAME_W / 2;
var centerY = GAME_H / 2;
// Player (fixed in center)
var cowboy = new Cowboy();
cowboy.x = centerX;
cowboy.y = centerY;
game.addChild(cowboy);
// Arrays for game objects
var enemies = [];
var bullets = [];
var whipAttacks = [];
var upgrades = [];
var boss = null;
var bossActive = false;
var bossSpawnTimer = 60 * 60; // 1 minute
// Score and UI
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Game time UI
var timeTxt = new Text2('Time: 0:00', {
size: 60,
fill: "#fff"
});
timeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timeTxt);
timeTxt.y = 70;
// Weapon cooldown UI
var revolverTxt = new Text2('Revolver: Ready', {
size: 60,
fill: "#fff"
});
revolverTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(revolverTxt);
revolverTxt.y = 130;
// Upgrade UI
var upgradeTxt = new Text2('Upgrades: 0/5', {
size: 60,
fill: 0xFFD700
});
upgradeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(upgradeTxt);
upgradeTxt.y = 200;
// Difficulty
var wave = 1;
var spawnTimer = 0;
var spawnInterval = 90; // frames
var enemySpeed = 2;
// Dragging
var dragNode = null;
// Joystick state
var joystick = {
active: false,
baseX: 0,
baseY: 0,
stickX: 0,
stickY: 0,
radius: 120,
dx: 0,
dy: 0
};
// Joystick graphics (simple circles)
var joystickBase = new Container();
var baseCircle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
tint: 0x33691e
});
joystickBase.addChild(baseCircle);
joystickBase.alpha = 0.4;
joystickBase.visible = false;
game.addChild(joystickBase);
var joystickStick = new Container();
var stickCircle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
tint: 0x8bc34a
});
joystickStick.addChild(stickCircle);
joystickStick.alpha = 0.7;
joystickStick.visible = false;
game.addChild(joystickStick);
// Helper: distance
function dist(ax, ay, bx, by) {
var dx = ax - bx;
var dy = ay - by;
return Math.sqrt(dx * dx + dy * dy);
}
// Helper: clamp
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
// Helper: get direction vector
function getDir(ax, ay, bx, by) {
var dx = bx - ax;
var dy = by - ay;
var len = Math.sqrt(dx * dx + dy * dy);
if (len === 0) return {
x: 0,
y: 0
};
return {
x: dx / len,
y: dy / len
};
}
// Helper: spawn enemy at random edge
function spawnEnemy() {
var edge = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
var ex, ey;
if (edge === 0) {
// top
ex = Math.random() * (GAME_W - 200) + 100;
ey = -80;
} else if (edge === 1) {
// right
ex = GAME_W + 80;
ey = Math.random() * (GAME_H - 200) + 100;
} else if (edge === 2) {
// bottom
ex = Math.random() * (GAME_W - 200) + 100;
ey = GAME_H + 80;
} else {
// left
ex = -80;
ey = Math.random() * (GAME_H - 200) + 100;
}
var enemy = new Enemy();
enemy.x = ex;
enemy.y = ey;
var dir = getDir(ex, ey, cowboy.x, cowboy.y);
enemy.dirX = dir.x;
enemy.dirY = dir.y;
enemy.speed = enemySpeed + Math.random() * 0.5 + (wave - 1) * 0.2;
enemy.hp = 1 + Math.floor(wave / 5);
enemies.push(enemy);
game.addChild(enemy);
}
// Helper: spawn upgrade at (x, y)
function spawnUpgrade(x, y) {
var upg = new UpgradeDrop();
upg.x = x;
upg.y = y;
upgrades.push(upg);
game.addChild(upg);
}
// Handle movement (dragging cowboy)
function handleMove(x, y, obj) {
// No movement, cowboy is fixed in center
}
game.move = handleMove;
game.down = function (x, y, obj) {
// No movement, cowboy is fixed in center
};
game.up = function (x, y, obj) {
// No movement, cowboy is fixed in center
};
// Handle tap/attack (whip or revolver)
game.tap = function (x, y, obj) {
// Not used, as LK does not have tap event
};
// Touch: whip (short range, no cooldown)
game.down2 = function (x, y, obj) {
// Not used, as LK does not have down2 event
};
// Touch: fire revolver (if ready)
game.doubletap = function (x, y, obj) {
// Not used, as LK does not have doubletap event
};
// Whip attack: on quick tap (simulate with up event if not dragging)
game.up = function (x, y, obj) {
if (!dragNode) {
// Whip attack in direction of tap, no cooldown, longer range
var dir = getDir(cowboy.x, cowboy.y, x, y);
var whip = new WhipAttack();
whip.x = cowboy.x + dir.x * 120; // longer range
whip.y = cowboy.y + dir.y * 120;
whip.dirX = dir.x;
whip.dirY = dir.y;
whip.rotation = Math.atan2(dir.y, dir.x);
whipAttacks.push(whip);
game.addChild(whip);
// Animate whip
tween(whip, {
alpha: 0
}, {
duration: 200,
easing: tween.linear,
onFinish: function onFinish() {
whip.alpha = 1;
}
});
}
dragNode = null;
};
// Fire revolver: on long press (simulate with two-finger tap or hold, but here use a button)
var fireBtn = new Text2('REVOLVER', {
size: 80,
fill: "#fff"
});
fireBtn.anchor.set(0.5, 0.5);
LK.gui.bottom.addChild(fireBtn);
fireBtn.y = -120;
fireBtn.x = 0;
fireBtn.interactive = true;
fireBtn.down = function (x, y, obj) {
if (cowboy.pumpUnlocked) {
// Fire pump-action (spread shot)
if (cowboy.pumpCooldown <= 0) {
for (var i = -1; i <= 1; i++) {
var dir = getDir(cowboy.x, cowboy.y, cowboy.x + Math.cos(game.lastAimAngle + i * 0.18) * 100, cowboy.y + Math.sin(game.lastAimAngle + i * 0.18) * 100);
var bullet = new PumpBullet();
bullet.x = cowboy.x + dir.x * 70;
bullet.y = cowboy.y + dir.y * 70;
bullet.dirX = dir.x;
bullet.dirY = dir.y;
bullet.rotation = Math.atan2(dir.y, dir.x);
bullets.push(bullet);
game.addChild(bullet);
}
cowboy.pumpCooldown = 90; // 1.5s
}
} else {
// Fire revolver
if (cowboy.revolverCooldown <= 0) {
var angle, dir;
// If boss is present, always aim at boss
if (bossActive && boss) {
var dx = boss.x - cowboy.x;
var dy = boss.y - cowboy.y;
angle = Math.atan2(dy, dx);
dir = {
x: Math.cos(angle),
y: Math.sin(angle)
};
} else {
// Aim at last direction of movement or default right
angle = game.lastAimAngle || 0;
dir = {
x: Math.cos(angle),
y: Math.sin(angle)
};
}
var bullet = new RevolverBullet();
bullet.x = cowboy.x + dir.x * 70;
bullet.y = cowboy.y + dir.y * 70;
bullet.dirX = dir.x;
bullet.dirY = dir.y;
bullet.rotation = Math.atan2(dir.y, dir.x);
bullets.push(bullet);
game.addChild(bullet);
cowboy.revolverCooldown = cowboy.revolverCooldownTime;
}
}
};
// Track last aim direction (for revolver)
game.lastAimAngle = 0;
game.move = function (x, y, obj) {
// Only update aim angle
var dx = x - cowboy.x;
var dy = y - cowboy.y;
if (dx * dx + dy * dy > 10 * 10) {
game.lastAimAngle = Math.atan2(dy, dx);
}
};
// Main update loop
game.update = function () {
// Cooldowns
if (cowboy.whipCooldown > 0) cowboy.whipCooldown--;
if (cowboy.revolverCooldown > 0) cowboy.revolverCooldown--;
if (cowboy.pumpCooldown > 0) cowboy.pumpCooldown--;
// No movement, cowboy is fixed in center
// Auto-aim revolver at nearest enemy
var nearestEnemy = null;
var minDist = 999999;
for (var i = 0; i < enemies.length; i++) {
var e = enemies[i];
var d = dist(cowboy.x, cowboy.y, e.x, e.y);
if (d < minDist) {
minDist = d;
nearestEnemy = e;
}
}
if (nearestEnemy) {
var aimDx = nearestEnemy.x - cowboy.x;
var aimDy = nearestEnemy.y - cowboy.y;
game.lastAimAngle = Math.atan2(aimDy, aimDx);
}
// Update UI
scoreTxt.setText(score);
// Update time UI
var totalSeconds = Math.floor(LK.ticks / 60);
var minutes = Math.floor(totalSeconds / 60);
var seconds = totalSeconds % 60;
var secondsStr = seconds < 10 ? "0" + seconds : "" + seconds;
timeTxt.setText("Time: " + minutes + ":" + secondsStr);
if (cowboy.pumpUnlocked) {
revolverTxt.setText('Pump-Action: ' + (cowboy.pumpCooldown > 0 ? (cowboy.pumpCooldown / 60).toFixed(1) + 's' : 'Ready'));
} else {
revolverTxt.setText('Revolver: ' + (cowboy.revolverCooldown > 0 ? (cowboy.revolverCooldown / 60).toFixed(1) + 's' : 'Ready'));
}
upgradeTxt.setText('Upgrades: ' + cowboy.upgrades + '/5');
// Spawn enemies
spawnTimer--;
if (spawnTimer <= 0) {
spawnEnemy();
spawnTimer = Math.max(30, spawnInterval - wave * 2);
}
// Boss spawn logic
if (!bossActive && LK.ticks > 0 && LK.ticks % (60 * 60) === 0) {
// Spawn boss at random edge
var edge = Math.floor(Math.random() * 4);
var bx, by;
if (edge === 0) {
bx = Math.random() * (GAME_W - 400) + 200;
by = -160;
} else if (edge === 1) {
bx = GAME_W + 160;
by = Math.random() * (GAME_H - 400) + 200;
} else if (edge === 2) {
bx = Math.random() * (GAME_W - 400) + 200;
by = GAME_H + 160;
} else {
bx = -160;
by = Math.random() * (GAME_H - 400) + 200;
}
boss = new Boss();
boss.x = bx;
boss.y = by;
var dir = getDir(boss.x, boss.y, cowboy.x, cowboy.y);
boss.dirX = dir.x;
boss.dirY = dir.y;
boss.hp = boss.maxHp = 10 + Math.floor(wave * 2.5);
boss.speed = enemySpeed + 0.7 + (wave - 1) * 0.25;
bossActive = true;
game.addChild(boss);
}
// Increase difficulty
if (LK.ticks % (60 * 60) === 0 && LK.ticks > 0) {
// every 1 minute
wave++;
enemySpeed += 0.3;
}
// No random upgrade spawn every 2 minutes; upgrades only from bosses
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.update();
// Re-aim at player
var dir = getDir(e.x, e.y, cowboy.x, cowboy.y);
e.dirX = dir.x;
e.dirY = dir.y;
// Out of bounds
if (e.x < -200 || e.x > GAME_W + 200 || e.y < -200 || e.y > GAME_H + 200) {
e.destroy();
enemies.splice(i, 1);
continue;
}
// Collide with player
if (dist(e.x, e.y, cowboy.x, cowboy.y) < e.radius + cowboy.radius - 10) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
// Update boss if active
if (bossActive && boss) {
boss.update();
// Re-aim at player
var bdir = getDir(boss.x, boss.y, cowboy.x, cowboy.y);
boss.dirX = bdir.x;
boss.dirY = bdir.y;
// Out of bounds
if (boss.x < -300) boss.x = -300;
if (boss.x > GAME_W + 300) boss.x = GAME_W + 300;
if (boss.y < -300) boss.y = -300;
if (boss.y > GAME_H + 300) boss.y = GAME_H + 300;
// Collide with player
if (dist(boss.x, boss.y, cowboy.x, cowboy.y) < boss.radius + cowboy.radius - 20) {
LK.effects.flashScreen(0xff0000, 1200);
LK.showGameOver();
return;
}
// Boss defeat check is handled in bullet/whip collision
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Out of bounds
if (b.x < -100 || b.x > GAME_W + 100 || b.y < -100 || b.y > GAME_H + 100) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Hit enemy
var isRevolverBullet = b instanceof RevolverBullet;
var isPumpBullet = b instanceof PumpBullet;
var bossHit = false;
// Boss priority: if boss is present and bullet is revolver, check boss first
if (bossActive && boss && isRevolverBullet && dist(b.x, b.y, boss.x, boss.y) < b.radius + boss.radius) {
boss.hp--;
b.destroy();
bullets.splice(i, 1);
bossHit = true;
if (boss.hp <= 0) {
boss.destroy();
boss = null;
bossActive = false;
// Increase game speed
enemySpeed += 0.7;
wave++;
}
}
// Only allow revolver bullets to hit boss, and only if not already hit this frame
if (!bossHit) {
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
if (dist(b.x, b.y, e.x, e.y) < b.radius + e.radius) {
// Always die in one hit
// No upgrade drop from regular enemies
e.destroy();
enemies.splice(j, 1);
score++;
b.destroy();
bullets.splice(i, 1);
break;
}
}
}
// If boss is present and bullet is NOT a revolver bullet, skip boss damage
if (!bossHit && bossActive && boss && isPumpBullet && dist(b.x, b.y, boss.x, boss.y) < b.radius + boss.radius) {
// Pump bullets do NOT damage boss, just ignore
b.destroy();
bullets.splice(i, 1);
}
}
// Update whip attacks
for (var i = whipAttacks.length - 1; i >= 0; i--) {
var w = whipAttacks[i];
w.update();
// Hit enemy
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
if (dist(w.x + w.dirX * 40, w.y + w.dirY * 40, e.x, e.y) < w.radius + e.radius) {
// Always die in one hit
e.destroy();
enemies.splice(j, 1);
score++;
}
}
// Hit boss
if (bossActive && boss && dist(w.x + w.dirX * 40, w.y + w.dirY * 40, boss.x, boss.y) < w.radius + boss.radius) {
// Whip damages boss (1 hp per hit), and pushes boss back
boss.hp--;
var pushStrength = 120;
boss.x += w.dirX * pushStrength;
boss.y += w.dirY * pushStrength;
// Optionally, add a little visual feedback (flash)
LK.effects.flashObject(boss, 0x00ffff, 200);
// If boss dies from whip, drop upgrades and remove boss
if (boss.hp <= 0) {
boss.destroy();
boss = null;
bossActive = false;
// Increase game speed
enemySpeed += 0.7;
wave++;
}
}
// Lifetime
if (w.lifetime <= 0) {
w.destroy();
whipAttacks.splice(i, 1);
}
}
// Update upgrades
for (var i = upgrades.length - 1; i >= 0; i--) {
var u = upgrades[i];
// Move toward player always
var dir = getDir(u.x, u.y, cowboy.x, cowboy.y);
u.x += dir.x * 10;
u.y += dir.y * 10;
// Collect
if (dist(u.x, u.y, cowboy.x, cowboy.y) < u.radius + cowboy.radius) {
cowboy.upgrades++;
// Each upgrade reduces revolver cooldown by 1.5s, min 4s (240 frames)
cowboy.revolverCooldownTime = Math.max(240, 600 - cowboy.upgrades * 90);
if (cowboy.upgrades >= 5) {
cowboy.pumpUnlocked = true;
}
u.destroy();
upgrades.splice(i, 1);
}
}
// Timed upgrade drop every 2 minutes (120s)
if (typeof upgradeTimer === "undefined") {
upgradeTimer = 60 * 120;
}
upgradeTimer--;
if (upgradeTimer <= 0) {
spawnUpgrade(cowboy.x, cowboy.y - 200); // spawn above player, flies to player
upgradeTimer = 60 * 120;
}
// Win condition: survive 5 minutes or reach 100 score
if (score >= 100 || LK.ticks > 60 * 60 * 5) {
LK.showYouWin();
return;
}
}; ===================================================================
--- original.js
+++ change.js
@@ -171,8 +171,16 @@
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
+// Game time UI
+var timeTxt = new Text2('Time: 0:00', {
+ size: 60,
+ fill: "#fff"
+});
+timeTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(timeTxt);
+timeTxt.y = 70;
// Weapon cooldown UI
var revolverTxt = new Text2('Revolver: Ready', {
size: 60,
fill: "#fff"
@@ -438,8 +446,14 @@
game.lastAimAngle = Math.atan2(aimDy, aimDx);
}
// Update UI
scoreTxt.setText(score);
+ // Update time UI
+ var totalSeconds = Math.floor(LK.ticks / 60);
+ var minutes = Math.floor(totalSeconds / 60);
+ var seconds = totalSeconds % 60;
+ var secondsStr = seconds < 10 ? "0" + seconds : "" + seconds;
+ timeTxt.setText("Time: " + minutes + ":" + secondsStr);
if (cowboy.pumpUnlocked) {
revolverTxt.setText('Pump-Action: ' + (cowboy.pumpCooldown > 0 ? (cowboy.pumpCooldown / 60).toFixed(1) + 's' : 'Ready'));
} else {
revolverTxt.setText('Revolver: ' + (cowboy.revolverCooldown > 0 ? (cowboy.revolverCooldown / 60).toFixed(1) + 's' : 'Ready'));
There is a + on the gun. In-Game asset. 2d. High contrast. No shadows
Zombie. In-Game asset. 2d. High contrast. No shadows
revovler. In-Game asset. 2d. High contrast. No shadows
Pump bullet. In-Game asset. 2d. High contrast. No shadows
Cowboy. In-Game asset. 2d. High contrast. No shadows
whip. In-Game asset. 2d. High contrast. No shadows
center circle. In-Game asset. 2d. High contrast. No shadows