User prompt
Draw! asset stays active for too long, it's seen even after round end alerts, please fix it
User prompt
display them at the end of rounds as well, instead of text
User prompt
add ai wins and you win image assets
User prompt
display the tooearlyalert asset instead of You shot too early text
User prompt
add an image asset for the "you shot too early" alert
User prompt
create a background music asset to play on loop, add a mute button to top right corner to mute the music
User prompt
remove the DRAW! texts, it's already written on the asset
User prompt
adjust projectile's path to end in more center for both characters
User prompt
move player score a bit higher, move player gun 50px lower
User prompt
place player gun 70 px lower
User prompt
place player gun 100px lower
User prompt
Place AI gun 80 px lower
User prompt
Place AI gun 80px lower
User prompt
place ai gun 80 px lower
User prompt
place ai gun 80 px lower
User prompt
place ai gun 50 px lower
User prompt
place ai gun 30 px more lower
User prompt
place ai gun more lower
User prompt
place player gun a bit to the right, place AI gun a bit more lower and slightly to the left
User prompt
sounds collapse with each other, let them play correctly
User prompt
play them at the end of the round according to the result
User prompt
add round win and round lose sound assets
User prompt
add background as an asset
User prompt
delay end game alert 2 seconds to play the win or lose sound
User prompt
let's implement the assets so i can add the audios
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// AI Gun Class
var AIGun = Container.expand(function () {
var self = Container.call(this);
var gun = self.attachAsset('aiGun', {
anchorX: 0.5,
anchorY: 0.5
});
gun.rotation = Math.PI / 2;
self.gun = gun;
self.firedGun = null;
self.flash = null;
self.shoot = function () {
// Swap to fired gun asset
if (!self.firedGun) {
var firedGun = LK.getAsset('aiFiredGun', {
anchorX: 0.5,
anchorY: 0.5
});
firedGun.rotation = Math.PI / 2;
firedGun.x = self.gun.x;
firedGun.y = self.gun.y;
firedGun.visible = false;
self.firedGun = firedGun;
self.addChildAt(firedGun, self.getChildIndex(self.gun));
}
self.gun.visible = false;
self.firedGun.visible = true;
// Revert to normal gun after short delay
LK.setTimeout(function () {
if (self.firedGun) self.firedGun.visible = false;
if (self.gun) self.gun.visible = true;
}, 180);
if (self.flash) {
self.removeChild(self.flash);
self.flash = null;
}
var flash = LK.getAsset('muzzleFlash', {
anchorX: 0.5,
anchorY: 0.5
});
flash.x = -120;
flash.y = 0;
self.addChild(flash);
self.flash = flash;
tween(flash, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
if (self.flash) {
self.removeChild(self.flash);
self.flash = null;
}
}
});
};
return self;
});
// Bullet class for simulating the projectile
var Bullet = Container.expand(function () {
var self = Container.call(this);
// shooter: 'player' or 'ai'
self.shooter = null;
// Attach a simple ellipse for the bullet
var bulletShape = self.attachAsset('muzzleFlash', {
anchorX: 0.5,
anchorY: 0.5
});
bulletShape.width = 60;
bulletShape.height = 60;
self.bulletShape = bulletShape;
// Set initial position and velocity
self.vx = 0;
self.vy = 0;
// Track lastY for good-practice event triggers
self.lastY = null;
// Set bullet color based on shooter
self.setShooter = function (shooter) {
self.shooter = shooter;
if (shooter === 'player') {
bulletShape.tint = 0xFFD700;
} else {
bulletShape.tint = 0xAAAAAA;
}
};
// Called every tick
self.update = function () {
if (self.lastY === null) self.lastY = self.y;
self.x += self.vx;
self.y += self.vy;
// Remove bullet if it leaves the screen
if (self.shooter === 'player' && self.lastY >= aiGun.y && self.y < aiGun.y) {
// Player bullet reached AI gun
// Optionally: add a little smoke or effect here
self.destroy();
} else if (self.shooter === 'ai' && self.lastY <= playerGun.y && self.y > playerGun.y) {
// AI bullet reached player gun
self.destroy();
}
self.lastY = self.y;
};
return self;
});
// Player Gun Class
var PlayerGun = Container.expand(function () {
var self = Container.call(this);
var gun = self.attachAsset('playerGun', {
anchorX: 0.5,
anchorY: 0.5
});
gun.rotation = Math.PI / 2;
self.gun = gun;
self.firedGun = null;
self.flash = null;
// Show muzzle flash and swap to fired gun
self.shoot = function () {
// Swap to fired gun asset
if (!self.firedGun) {
var firedGun = LK.getAsset('playerFiredGun', {
anchorX: 0.5,
anchorY: 0.5
});
firedGun.rotation = Math.PI / 2;
firedGun.x = self.gun.x;
firedGun.y = self.gun.y;
firedGun.visible = false;
self.firedGun = firedGun;
self.addChildAt(firedGun, self.getChildIndex(self.gun));
}
self.gun.visible = false;
self.firedGun.visible = true;
// Revert to normal gun after short delay
LK.setTimeout(function () {
if (self.firedGun) self.firedGun.visible = false;
if (self.gun) self.gun.visible = true;
}, 180);
if (self.flash) {
self.removeChild(self.flash);
self.flash = null;
}
var flash = LK.getAsset('muzzleFlash', {
anchorX: 0.5,
anchorY: 0.5
});
flash.x = 120;
flash.y = 0;
self.addChild(flash);
self.flash = flash;
tween(flash, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
if (self.flash) {
self.removeChild(self.flash);
self.flash = null;
}
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d1a07
});
/****
* Game Code
****/
// Sound effects
// Win/Lose round indicator
// "DRAW!" signal
// Bullet flash
// Guns
// Game state variables
// fired variant
// fired variant
var round = 1;
var playerScore = 0;
var aiScore = 0;
var maxRounds = 5;
var winScore = 3;
var state = 'waiting'; // 'waiting', 'ready', 'draw', 'playerShot', 'aiShot', 'falsestart', 'roundEnd'
var drawTimeout = null;
var aiShotTimeout = null;
var canShoot = false;
var playerReactTime = null;
var aiReactTime = null;
var drawTime = null;
var playerShot = false;
var aiShot = false;
// UI elements
var playerGun = new PlayerGun();
var aiGun = new AIGun();
var drawSign = null;
var infoText = null;
var roundDots = [];
var aiRoundDots = [];
var resultText = null;
// Layout constants
var centerX = 2048 / 2;
var playerGunY = 2732 - 350;
var aiGunY = 350;
// Add background image to game
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = centerX;
background.y = 2732 / 2;
game.addChild(background);
// Add guns to game
playerGun.x = centerX + 220;
playerGun.y = playerGunY;
game.addChild(playerGun);
aiGun.x = centerX - 180;
aiGun.y = aiGunY + 220;
game.addChild(aiGun);
// Draw round win/loss dots
function updateRoundDots() {
// Remove old dots
for (var i = 0; i < roundDots.length; i++) {
if (playerGun.children.indexOf(roundDots[i]) !== -1) {
playerGun.removeChild(roundDots[i]);
}
}
for (var i = 0; i < aiRoundDots.length; i++) {
if (aiGun.children.indexOf(aiRoundDots[i]) !== -1) {
aiGun.removeChild(aiRoundDots[i]);
}
}
roundDots = [];
aiRoundDots = [];
// Player dots (behind player gun)
for (var i = 0; i < winScore; i++) {
var dot;
if (i < playerScore) {
dot = LK.getAsset('winDot', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
dot = LK.getAsset('loseDot', {
anchorX: 0.5,
anchorY: 0.5
});
dot.alpha = 0.3;
}
// Arrange dots horizontally behind the player gun
dot.x = -180 + i * 80 - (winScore - 1) * 80 / 2;
dot.y = 120;
playerGun.addChild(dot);
roundDots.push(dot);
}
// AI dots (behind AI gun)
for (var j = 0; j < winScore; j++) {
var dot2;
if (j < aiScore) {
dot2 = LK.getAsset('winDot', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
dot2 = LK.getAsset('loseDot', {
anchorX: 0.5,
anchorY: 0.5
});
dot2.alpha = 0.3;
}
// Arrange dots horizontally behind the AI gun
dot2.x = 180 - j * 80 + (winScore - 1) * 80 / 2;
dot2.y = -120;
aiGun.addChild(dot2);
aiRoundDots.push(dot2);
}
}
updateRoundDots();
// Info text
infoText = new Text2('Get Ready...', {
size: 120,
fill: 0xFFF7D0
});
infoText.anchor.set(0.5, 0);
infoText.x = LK.gui.top.width / 2;
infoText.y = 200;
LK.gui.top.addChild(infoText);
// Result text (centered, hidden by default)
resultText = new Text2('', {
size: 180,
fill: 0xFFF7D0
});
resultText.anchor.set(0.5, 0.5);
resultText.x = LK.gui.center.width / 2;
resultText.y = LK.gui.center.height / 2;
resultText.visible = false;
LK.gui.center.addChild(resultText);
// DRAW! sign (hidden by default)
function showDrawSign() {
if (drawSign) {
game.removeChild(drawSign);
drawSign = null;
}
drawSign = LK.getAsset('drawSign', {
anchorX: 0.5,
anchorY: 0.5
});
drawSign.x = centerX;
drawSign.y = 2732 / 2;
game.addChild(drawSign);
var drawText = new Text2('DRAW!', {
size: 180,
fill: "#000"
});
drawText.anchor.set(0.5, 0.5);
drawText.x = drawSign.width / 2;
drawText.y = drawSign.height / 2;
drawSign.addChild(drawText);
tween(drawSign, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 120,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(drawSign, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.linear
});
}
});
LK.getSound('draw').play();
}
function hideDrawSign() {
if (drawSign) {
game.removeChild(drawSign);
drawSign = null;
}
}
// Start a new round
function startRound() {
state = 'waiting';
canShoot = false;
playerReactTime = null;
aiReactTime = null;
playerShot = false;
aiShot = false;
drawTime = null;
infoText.setText('Get Ready...');
resultText.visible = false;
hideDrawSign();
// Animate guns to neutral
playerGun.rotation = 0;
aiGun.rotation = 0;
// Wait a short moment, then start suspense timer
var suspenseDelay = 700 + Math.floor(Math.random() * 400);
LK.setTimeout(function () {
infoText.setText('...');
// Random suspense before DRAW!
var suspense = 1200 + Math.floor(Math.random() * 1200);
drawTimeout = LK.setTimeout(function () {
state = 'draw';
canShoot = true;
drawTime = Date.now();
showDrawSign();
infoText.setText('DRAW!');
// AI will react after a random delay (simulate reflex)
var aiDelay = 180 + Math.floor(Math.random() * 320); // 180-500ms
aiShotTimeout = LK.setTimeout(function () {
if (!aiShot && !playerShot) {
aiShoot();
}
}, aiDelay);
}, suspense);
}, suspenseDelay);
}
// Player shoots
function playerShoot() {
if (state === 'draw' && canShoot && !playerShot && !aiShot) {
playerShot = true;
playerReactTime = Date.now() - drawTime;
playerGun.shoot();
LK.getSound('gunshot').play();
// Animate gun recoil
tween(playerGun, {
rotation: -0.18
}, {
duration: 80,
onFinish: function onFinish() {
tween(playerGun, {
rotation: 0
}, {
duration: 120
});
}
});
// If AI hasn't shot yet, player wins
if (!aiShot) {
// Fire bullet from player gun toward AI gun
var bullet = new Bullet();
bullet.setShooter('player');
bullet.x = playerGun.x + 120; // muzzle flash offset
bullet.y = playerGun.y;
// Calculate velocity to AI gun
var dx = aiGun.x - bullet.x - 120; // aim for AI muzzle
var dy = aiGun.y - bullet.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = 80; // px per frame, fast for effect
bullet.vx = dx / dist * speed;
bullet.vy = dy / dist * speed;
game.addChild(bullet);
endRound('player');
}
} else if (state === 'waiting' || state === 'ready') {
// False start
state = 'falsestart';
canShoot = false;
playerShot = true;
playerGun.shoot();
LK.getSound('falsestart').play();
infoText.setText('False Start!');
resultText.setText('You Shot Too Early!');
resultText.visible = true;
endRound('ai', true);
}
}
// AI shoots
function aiShoot() {
if (state === 'draw' && canShoot && !aiShot && !playerShot) {
aiShot = true;
aiReactTime = Date.now() - drawTime;
aiGun.shoot();
LK.getSound('gunshot').play();
// Animate gun recoil
tween(aiGun, {
rotation: 0.18
}, {
duration: 80,
onFinish: function onFinish() {
tween(aiGun, {
rotation: 0
}, {
duration: 120
});
}
});
// If player hasn't shot yet, AI wins
if (!playerShot) {
// Fire bullet from AI gun toward player gun
var bullet = new Bullet();
bullet.setShooter('ai');
bullet.x = aiGun.x - 120; // muzzle flash offset
bullet.y = aiGun.y;
// Calculate velocity to player gun
var dx = playerGun.x - bullet.x + 120; // aim for player muzzle
var dy = playerGun.y - bullet.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = 80; // px per frame, fast for effect
bullet.vx = dx / dist * speed;
bullet.vy = dy / dist * speed;
game.addChild(bullet);
endRound('ai');
}
}
}
// End round, winner: 'player' or 'ai', falsestart: true/false
function endRound(winner, falsestart) {
canShoot = false;
state = 'roundEnd';
// Clear timeouts
if (drawTimeout) {
LK.clearTimeout(drawTimeout);
drawTimeout = null;
}
if (aiShotTimeout) {
LK.clearTimeout(aiShotTimeout);
aiShotTimeout = null;
}
// Update scores
if (winner === 'player') {
playerScore += 1;
infoText.setText('You Win the Round!');
resultText.setText('You Win!');
resultText.visible = true;
// Stop lose sound if playing, then play win sound
try {
LK.getSound('roundlose').stop();
} catch (e) {}
LK.getSound('roundwin').play();
LK.effects.flashObject(playerGun, 0x00FF00, 600);
} else {
aiScore += 1;
if (falsestart) {
infoText.setText('False Start!');
resultText.setText('You Shot Too Early!');
} else {
infoText.setText('AI Wins the Round!');
resultText.setText('AI Wins!');
}
resultText.visible = true;
// Stop win sound if playing, then play lose sound
try {
LK.getSound('roundwin').stop();
} catch (e) {}
LK.getSound('roundlose').play();
LK.effects.flashObject(aiGun, 0xFF0000, 600);
}
updateRoundDots();
// Check for match end
if (playerScore >= winScore) {
LK.setScore(playerScore);
// Stop lose sound if playing, then play win sound
try {
LK.getSound('lose').stop();
} catch (e) {}
try {
LK.getSound('win').stop();
} catch (e) {}
LK.getSound('win').play();
LK.setTimeout(function () {
LK.showYouWin();
}, 2000);
return;
}
if (aiScore >= winScore) {
LK.setScore(playerScore);
// Stop win sound if playing, then play lose sound
try {
LK.getSound('win').stop();
} catch (e) {}
try {
LK.getSound('lose').stop();
} catch (e) {}
LK.getSound('lose').play();
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
return;
}
// Next round after short delay
LK.setTimeout(function () {
round += 1;
startRound();
}, 1400);
}
// Handle player tap on gun
playerGun.down = function (x, y, obj) {
if (state === 'draw' || state === 'waiting' || state === 'ready') {
playerShoot();
}
};
// Also allow tapping anywhere in lower half to shoot (mobile friendly)
game.down = function (x, y, obj) {
if (y > 2732 / 2) {
playerShoot();
}
};
// Prevent AI gun from being tapped
aiGun.down = function (x, y, obj) {};
// Start first round
startRound();
// No need for update loop, as all logic is event/timer driven ===================================================================
--- original.js
+++ change.js
@@ -225,9 +225,9 @@
playerGun.x = centerX + 220;
playerGun.y = playerGunY;
game.addChild(playerGun);
aiGun.x = centerX - 180;
-aiGun.y = aiGunY + 120;
+aiGun.y = aiGunY + 220;
game.addChild(aiGun);
// Draw round win/loss dots
function updateRoundDots() {
// Remove old dots
a western revolver. In-Game asset. High contrast. No shadows
a firing western revolver In-Game asset. High contrast. No shadows
bullet. In-Game asset. High contrast. No shadows
empty bullet cap. In-Game asset. High contrast. No shadows
a western themed alert box that says DRAW! on it. In-Game asset. High contrast. No shadows
a western setting duel arena, place one cowboy at the top of the screen facing down and another cowboy at the bottom facing up. In-Game asset. 2d. High contrast. No shadows
western style alert box that says You Shot Too Early!. In-Game asset. 2d. High contrast. No shadows
western style alert box that says "AI Wins!". In-Game asset. 2d. High contrast. No shadows
western style alert box that says "You Win!". In-Game asset. 2d. High contrast. No shadows