/**** * 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 ****/ // Background music asset (looping western theme) // 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 + 100 + 70 + 50; 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 + 380 + 80 + 80 + 80; 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 = 80; // moved higher by 40px 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); // Mute button (top right) var isMusicMuted = false; var muteBtn = new Text2('🔊', { size: 110, fill: 0xFFF7D0 }); muteBtn.anchor.set(1, 0); // right-top muteBtn.x = LK.gui.topRight.width - 20; muteBtn.y = 20; muteBtn.interactive = true; muteBtn.buttonMode = true; muteBtn.down = function () { isMusicMuted = !isMusicMuted; if (isMusicMuted) { LK.stopMusic(); muteBtn.setText('🔇'); } else { LK.playMusic('bgmusic'); muteBtn.setText('🔊'); } }; LK.gui.topRight.addChild(muteBtn); // 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); // Removed overlay DRAW! text, as it's already on the asset 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, aiming for the center of the AI gun var aiGunTargetX = aiGun.x; // center of AI gun var aiGunTargetY = aiGun.y + aiGun.gun.height * 0.1; // slightly below center for realism var dx = aiGunTargetX - bullet.x; var dy = aiGunTargetY - 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, aiming for the center of the player gun var playerGunTargetX = playerGun.x; // center of player gun var playerGunTargetY = playerGun.y - playerGun.gun.height * 0.1; // slightly above center for realism var dx = playerGunTargetX - bullet.x; var dy = playerGunTargetY - 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'; // Hide DRAW! sign immediately so it doesn't overlap round end alerts hideDrawSign(); // 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!'); // Show youWin image asset in the center of the game for round win var roundYouWinImg = LK.getAsset('youWin', { anchorX: 0.5, anchorY: 0.5 }); roundYouWinImg.x = centerX; roundYouWinImg.y = 2732 / 2; game.addChild(roundYouWinImg); LK.setTimeout(function () { if (roundYouWinImg && game.children.indexOf(roundYouWinImg) !== -1) { game.removeChild(roundYouWinImg); } }, 1200); // Hide resultText for this case resultText.visible = false; // 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!'); // Remove previous tooEarlyAlert if present if (typeof tooEarlyAlertImg !== 'undefined' && tooEarlyAlertImg && game.children.indexOf(tooEarlyAlertImg) !== -1) { game.removeChild(tooEarlyAlertImg); tooEarlyAlertImg = null; } var tooEarlyAlertImg = LK.getAsset('tooEarlyAlert', { anchorX: 0.5, anchorY: 0.5 }); tooEarlyAlertImg.x = centerX; tooEarlyAlertImg.y = 2732 / 2; game.addChild(tooEarlyAlertImg); // Hide resultText for this case resultText.visible = false; // Remove the alert after a short delay LK.setTimeout(function () { if (tooEarlyAlertImg && game.children.indexOf(tooEarlyAlertImg) !== -1) { game.removeChild(tooEarlyAlertImg); tooEarlyAlertImg = null; } }, 1200); } else { infoText.setText('AI Wins the Round!'); // Show aiWin image asset in the center of the game for round win var roundAiWinImg = LK.getAsset('aiWin', { anchorX: 0.5, anchorY: 0.5 }); roundAiWinImg.x = centerX; roundAiWinImg.y = 2732 / 2; game.addChild(roundAiWinImg); LK.setTimeout(function () { if (roundAiWinImg && game.children.indexOf(roundAiWinImg) !== -1) { game.removeChild(roundAiWinImg); } }, 1200); // Hide resultText for this case resultText.visible = false; } // 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(); // Show youWin image asset in the center of the game var youWinImg = LK.getAsset('youWin', { anchorX: 0.5, anchorY: 0.5 }); youWinImg.x = centerX; youWinImg.y = 2732 / 2; game.addChild(youWinImg); LK.setTimeout(function () { if (youWinImg && game.children.indexOf(youWinImg) !== -1) { game.removeChild(youWinImg); } 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(); // Show aiWin image asset in the center of the game var aiWinImg = LK.getAsset('aiWin', { anchorX: 0.5, anchorY: 0.5 }); aiWinImg.x = centerX; aiWinImg.y = 2732 / 2; game.addChild(aiWinImg); LK.setTimeout(function () { if (aiWinImg && game.children.indexOf(aiWinImg) !== -1) { game.removeChild(aiWinImg); } 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(); // Play background music on loop LK.playMusic('bgmusic'); // No need for update loop, as all logic is event/timer driven;
/****
* 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
****/
// Background music asset (looping western theme)
// 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 + 100 + 70 + 50;
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 + 380 + 80 + 80 + 80;
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 = 80; // moved higher by 40px
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);
// Mute button (top right)
var isMusicMuted = false;
var muteBtn = new Text2('🔊', {
size: 110,
fill: 0xFFF7D0
});
muteBtn.anchor.set(1, 0); // right-top
muteBtn.x = LK.gui.topRight.width - 20;
muteBtn.y = 20;
muteBtn.interactive = true;
muteBtn.buttonMode = true;
muteBtn.down = function () {
isMusicMuted = !isMusicMuted;
if (isMusicMuted) {
LK.stopMusic();
muteBtn.setText('🔇');
} else {
LK.playMusic('bgmusic');
muteBtn.setText('🔊');
}
};
LK.gui.topRight.addChild(muteBtn);
// 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);
// Removed overlay DRAW! text, as it's already on the asset
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, aiming for the center of the AI gun
var aiGunTargetX = aiGun.x; // center of AI gun
var aiGunTargetY = aiGun.y + aiGun.gun.height * 0.1; // slightly below center for realism
var dx = aiGunTargetX - bullet.x;
var dy = aiGunTargetY - 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, aiming for the center of the player gun
var playerGunTargetX = playerGun.x; // center of player gun
var playerGunTargetY = playerGun.y - playerGun.gun.height * 0.1; // slightly above center for realism
var dx = playerGunTargetX - bullet.x;
var dy = playerGunTargetY - 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';
// Hide DRAW! sign immediately so it doesn't overlap round end alerts
hideDrawSign();
// 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!');
// Show youWin image asset in the center of the game for round win
var roundYouWinImg = LK.getAsset('youWin', {
anchorX: 0.5,
anchorY: 0.5
});
roundYouWinImg.x = centerX;
roundYouWinImg.y = 2732 / 2;
game.addChild(roundYouWinImg);
LK.setTimeout(function () {
if (roundYouWinImg && game.children.indexOf(roundYouWinImg) !== -1) {
game.removeChild(roundYouWinImg);
}
}, 1200);
// Hide resultText for this case
resultText.visible = false;
// 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!');
// Remove previous tooEarlyAlert if present
if (typeof tooEarlyAlertImg !== 'undefined' && tooEarlyAlertImg && game.children.indexOf(tooEarlyAlertImg) !== -1) {
game.removeChild(tooEarlyAlertImg);
tooEarlyAlertImg = null;
}
var tooEarlyAlertImg = LK.getAsset('tooEarlyAlert', {
anchorX: 0.5,
anchorY: 0.5
});
tooEarlyAlertImg.x = centerX;
tooEarlyAlertImg.y = 2732 / 2;
game.addChild(tooEarlyAlertImg);
// Hide resultText for this case
resultText.visible = false;
// Remove the alert after a short delay
LK.setTimeout(function () {
if (tooEarlyAlertImg && game.children.indexOf(tooEarlyAlertImg) !== -1) {
game.removeChild(tooEarlyAlertImg);
tooEarlyAlertImg = null;
}
}, 1200);
} else {
infoText.setText('AI Wins the Round!');
// Show aiWin image asset in the center of the game for round win
var roundAiWinImg = LK.getAsset('aiWin', {
anchorX: 0.5,
anchorY: 0.5
});
roundAiWinImg.x = centerX;
roundAiWinImg.y = 2732 / 2;
game.addChild(roundAiWinImg);
LK.setTimeout(function () {
if (roundAiWinImg && game.children.indexOf(roundAiWinImg) !== -1) {
game.removeChild(roundAiWinImg);
}
}, 1200);
// Hide resultText for this case
resultText.visible = false;
}
// 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();
// Show youWin image asset in the center of the game
var youWinImg = LK.getAsset('youWin', {
anchorX: 0.5,
anchorY: 0.5
});
youWinImg.x = centerX;
youWinImg.y = 2732 / 2;
game.addChild(youWinImg);
LK.setTimeout(function () {
if (youWinImg && game.children.indexOf(youWinImg) !== -1) {
game.removeChild(youWinImg);
}
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();
// Show aiWin image asset in the center of the game
var aiWinImg = LK.getAsset('aiWin', {
anchorX: 0.5,
anchorY: 0.5
});
aiWinImg.x = centerX;
aiWinImg.y = 2732 / 2;
game.addChild(aiWinImg);
LK.setTimeout(function () {
if (aiWinImg && game.children.indexOf(aiWinImg) !== -1) {
game.removeChild(aiWinImg);
}
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();
// Play background music on loop
LK.playMusic('bgmusic');
// No need for update loop, as all logic is event/timer driven;
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