User prompt
make the gun assets vertical to better display a gun
User prompt
add 1 more variant to each gun asset labeled as "firedgun" display it for a short period of time when a character shoots then go back to displaying the main asset
User prompt
shoot a projectile simulating the bullet from the character who draws first and wins the round
User prompt
scores should be placed behind the players
User prompt
Fix the visual layout and positioning of the elements in the Quick Draw Duel game. 1. Make sure the two characters are correctly positioned: - The player's character should be clearly visible and centered on the **left side** of the screen. - The AI character should be clearly visible and centered on the **right side** of the screen. - Both characters should be vertically aligned near the middle of the screen. 2. The "DRAW!" text should appear centered at the top or middle of the screen and must be clearly visible when triggered. 3. The win indicators (stars, bullets, or icons) for each side should appear: - At the top-left for the player’s score - At the top-right for the AI’s score 4. The tap area should be clearly divided: - The **left half** of the screen should register player taps. - The **right half** can remain inactive or optionally show AI action feedback. 5. After the match ends, show a centered restart button below the characters. Ensure all elements are clearly spaced, properly scaled for mobile screens, and visually balanced. Avoid overlapping or misaligned components.
Code edit (1 edits merged)
Please save this source code
User prompt
Quick Draw Duel
Initial prompt
Create a fast-paced reaction duel game called "Quick Draw Duel". Gameplay Summary: - Two characters face each other in a western-style standoff. - After a short random delay (between 1 to 3 seconds), a big "DRAW!" signal appears at the center of the screen. - The player must tap the gun image located their side of the screen as quickly as possible after the "DRAW!" signal appears. - The AI opponent will also respond with a random reaction time (between 200ms and 350ms). - If the player taps before "DRAW!" appears, it counts as a false start and the round is lost. - If the player taps after "DRAW!" and faster than the AI, the player wins the round. - If the AI is faster, the player loses the round. - The duel is best-of-5: the first to 3 wins is declared the overall winner. UI and Visuals: - Divide the screen into left and right halves. - Show two characters on each side: the player on the left, AI on the right. - Use simple animations or expressions to indicate win or loss (e.g., recoil, smoke puff, victory pose). - Show "DRAW!" as a large centered text when it's time to react. - Show round wins with small icons (e.g. bullet holes or stars) at the top of each side. - Add a restart button after the match ends. Audio: - Include a ticking sound or tense music during wait phase. - Gunshot sound when a tap is registered. - Short "you win" or "you lose" jingle after each round. Make the game loop tight and replayable.
/**** * 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 }); self.gun = gun; self.flash = null; self.shoot = function () { 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; }); // Player Gun Class var PlayerGun = Container.expand(function () { var self = Container.call(this); var gun = self.attachAsset('playerGun', { anchorX: 0.5, anchorY: 0.5 }); self.gun = gun; self.flash = null; // Show muzzle flash self.shoot = function () { 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 ****/ // Game state variables // Guns // Bullet flash // "DRAW!" signal // Win/Lose round indicator // Sound effects 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 guns to game playerGun.x = centerX; playerGun.y = playerGunY; game.addChild(playerGun); aiGun.x = centerX; aiGun.y = aiGunY; 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) { 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) { 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; 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; LK.effects.flashObject(aiGun, 0xFF0000, 600); } updateRoundDots(); // Check for match end if (playerScore >= winScore) { LK.setScore(playerScore); LK.showYouWin(); return; } if (aiScore >= winScore) { LK.setScore(playerScore); LK.showGameOver(); 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
@@ -89,14 +89,14 @@
/****
* Game Code
****/
-// Sound effects
-// Win/Lose round indicator
-// "DRAW!" signal
-// Bullet flash
-// Guns
// Game state variables
+// Guns
+// Bullet flash
+// "DRAW!" signal
+// Win/Lose round indicator
+// Sound effects
var round = 1;
var playerScore = 0;
var aiScore = 0;
var maxRounds = 5;
@@ -119,30 +119,33 @@
var aiRoundDots = [];
var resultText = null;
// Layout constants
var centerX = 2048 / 2;
-var centerY = 2732 / 2;
-var gunOffsetX = 420; // horizontal offset from center for guns
-var gunY = centerY + 320; // both guns at same vertical position, slightly below center for better thumb reach
+var playerGunY = 2732 - 350;
+var aiGunY = 350;
// Add guns to game
-playerGun.x = centerX - gunOffsetX;
-playerGun.y = gunY;
+playerGun.x = centerX;
+playerGun.y = playerGunY;
game.addChild(playerGun);
-aiGun.x = centerX + gunOffsetX;
-aiGun.y = gunY;
+aiGun.x = centerX;
+aiGun.y = aiGunY;
game.addChild(aiGun);
// Draw round win/loss dots
function updateRoundDots() {
// Remove old dots
for (var i = 0; i < roundDots.length; i++) {
- LK.gui.top.removeChild(roundDots[i]);
+ if (playerGun.children.indexOf(roundDots[i]) !== -1) {
+ playerGun.removeChild(roundDots[i]);
+ }
}
for (var i = 0; i < aiRoundDots.length; i++) {
- LK.gui.top.removeChild(aiRoundDots[i]);
+ if (aiGun.children.indexOf(aiRoundDots[i]) !== -1) {
+ aiGun.removeChild(aiRoundDots[i]);
+ }
}
roundDots = [];
aiRoundDots = [];
- // Player dots (left)
+ // Player dots (behind player gun)
for (var i = 0; i < winScore; i++) {
var dot;
if (i < playerScore) {
dot = LK.getAsset('winDot', {
@@ -155,15 +158,15 @@
anchorY: 0.5
});
dot.alpha = 0.3;
}
- // Place at top-left, spaced, but not in the 0-100px menu area
- dot.x = 120 + i * 90;
+ // Arrange dots horizontally behind the player gun
+ dot.x = -180 + i * 80 - (winScore - 1) * 80 / 2;
dot.y = 120;
- LK.gui.top.addChild(dot);
+ playerGun.addChild(dot);
roundDots.push(dot);
}
- // AI dots (right)
+ // AI dots (behind AI gun)
for (var j = 0; j < winScore; j++) {
var dot2;
if (j < aiScore) {
dot2 = LK.getAsset('winDot', {
@@ -176,12 +179,12 @@
anchorY: 0.5
});
dot2.alpha = 0.3;
}
- // Place at top-right, spaced, but not in the 0-100px menu area
- dot2.x = LK.gui.top.width - 120 - (winScore - 1 - j) * 90;
- dot2.y = 120;
- LK.gui.top.addChild(dot2);
+ // 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();
@@ -214,12 +217,12 @@
anchorX: 0.5,
anchorY: 0.5
});
drawSign.x = centerX;
- drawSign.y = 2732 / 2 - 320; // place DRAW! above the guns, visually prominent
+ drawSign.y = 2732 / 2;
game.addChild(drawSign);
var drawText = new Text2('DRAW!', {
- size: 220,
+ size: 180,
fill: "#000"
});
drawText.anchor.set(0.5, 0.5);
drawText.x = drawSign.width / 2;
@@ -385,15 +388,13 @@
// Check for match end
if (playerScore >= winScore) {
LK.setScore(playerScore);
LK.showYouWin();
- showRestartButton();
return;
}
if (aiScore >= winScore) {
LK.setScore(playerScore);
LK.showGameOver();
- showRestartButton();
return;
}
// Next round after short delay
LK.setTimeout(function () {
@@ -406,48 +407,15 @@
if (state === 'draw' || state === 'waiting' || state === 'ready') {
playerShoot();
}
};
-// Only allow tapping in the left half of the screen to shoot (mobile friendly)
+// Also allow tapping anywhere in lower half to shoot (mobile friendly)
game.down = function (x, y, obj) {
- if (x < 2048 / 2) {
+ if (y > 2732 / 2) {
playerShoot();
}
};
// Prevent AI gun from being tapped
-// Show a centered restart button below the guns after match ends
-var restartBtn = null;
-function showRestartButton() {
- if (restartBtn) {
- LK.gui.center.removeChild(restartBtn);
- restartBtn = null;
- }
- restartBtn = new Text2('Restart', {
- size: 120,
- fill: 0xFFF7D0
- });
- restartBtn.anchor.set(0.5, 0.5);
- restartBtn.x = LK.gui.center.width / 2;
- // Place below the guns, but above the bottom
- restartBtn.y = LK.gui.center.height / 2 + 420;
- restartBtn.interactive = true;
- restartBtn.buttonMode = true;
- restartBtn.visible = true;
- restartBtn.down = function (x, y, obj) {
- // Reset game state
- playerScore = 0;
- aiScore = 0;
- round = 1;
- updateRoundDots();
- resultText.visible = false;
- infoText.setText('Get Ready...');
- if (restartBtn) {
- LK.gui.center.removeChild(restartBtn);
- restartBtn = null;
- }
- startRound();
- };
- LK.gui.center.addChild(restartBtn);
-}
+aiGun.down = function (x, y, obj) {};
// Start first round
startRound();
-// No need for update loop, as all logic is event/timer driven;
\ No newline at end of file
+// No need for update loop, as all logic is event/timer driven
\ No newline at end of file
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