/****
* 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