User prompt
change name to archery master
User prompt
change the color of the text
User prompt
i want bow loading sound while power meter activating that sound should come
User prompt
let's make sure the game over triggers correctly when the player runs out of arrows and hasn’t hit all the targets. Triggering "Game Over" if all arrows are used and not all targets are hit. Keeping your original structure. Logging in console when Game Over triggers (for debugging).
User prompt
2. Improve Collision Reliability Replace: js Copy Edit if (obj.data?.isTarget && LK.hitTestRect(arrow, obj)) { With: js Copy Edit if (obj.data?.isTarget && LK.hitTestRect(arrow, obj)) { if (!obj._hit) { // Prevent double-count obj._hit = true; LK.remove(obj); LK.remove(arrow); score++; checkGameProgress(); } }
User prompt
s-check with the Current Game Code ✔️ Score Tracking ✅ We increase the score++ correctly when a target is hit, and we update the UI. ❗ Level-Up Logic (Important) ✅ We're checking for targets remaining: js Copy Edit const targetsRemaining = LK.all().filter(obj => obj.data?.isTarget).length; if (targetsRemaining === 0) { currentLevel++; setupLevel(currentLevel); } ⚠️ However, this might fail if you fire arrows before targets are spawned or if targets are not being removed due to a collision bug. ✔️ Event Timing ✅ The level-up is triggered inside checkGameProgress() which is called both when an arrow is removed and when a target is hit. Looks okay. ✔️ State Management ✅ currentLevel, arrowsFired, score, etc. are being managed properly. ⚠️ Initialization of New Level ✅ We use setupLevel(currentLevel), but we need to make sure it is not called when currentLevel >= levels.length — otherwise the game could crash. ❗ Collision Detection ❗ This is a common bug. If: arrow or target isn't updating properly Or hitTestRect is misaligned (e.g., rotation not considered well) → hits won’t register and progression will fail. ✔️ Game Over Conditions ✅ Game Over is triggered only if all arrows are used and targets remain. This looks good.
User prompt
after scoring 30 in level 1 change the text to level 27 arrows and add 5 targets and
User prompt
To detect hits and change levels, the game typically needs: Score Tracking — To know when to change level. Target Hit Detection — Which you seem to have via arrow.stickTo(target, score). Level Manager — A function or object that tracks the current level and changes game state accordingly Track Score Detect Target Hit and Add Score Level-Up Logic Define loadLevel()
User prompt
After score in 30 in the first level change the level to 2
User prompt
Start the arrow count from 5 instead of 4
User prompt
Review all the aspects and make me to go to next level
User prompt
Trigger game over when arrow count become 0
User prompt
why this is not working Trigger game over when no arrows are left to aim
User prompt
make the game over when the no arrows left to aim
User prompt
State Tracking Event Triggering Score and Target Management Level Transition Logic Game State Variables Tween Effects ensure\ that these aspects are correctly implemented and checked, the game should be able to advance to the next level once all targets are hit.
User prompt
not working\
User prompt
Once all targets are hit gave the levelup text with tween effect and swap to level2 and place the level2 targets and arrows ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
still not working
User prompt
Advance to the next level when all targets are hit is not working
User prompt
Once all targets are hit , the game will automatically advance to the next level.
User prompt
Position the level text at the top-left corner of the screen
User prompt
The level text is positioned at the top-right corner of the screen
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ var Arrow = Container.expand(function () { var self = Container.call(this); // Arrow body var arrowBody = self.attachAsset('arrow', { anchorX: 0.5, anchorY: 0.5 }); // Arrow tip var arrowTip = self.attachAsset('arrowTip', { anchorX: 0.5, anchorY: 0.5, x: 65 }); // Properties self.velocity = { x: 0, y: 0 }; self.gravity = 0.3; self.friction = 0.99; self.flying = false; self.stuck = false; self.targetHit = null; // Update arrow physics self.update = function () { if (self.lastX === undefined) { self.lastX = self.x; } if (self.lastY === undefined) { self.lastY = self.y; } if (self.flying && !self.stuck) { // Apply physics self.velocity.y += self.gravity; self.x += self.velocity.x; self.y += self.velocity.y; // Update rotation to match trajectory self.rotation = Math.atan2(self.velocity.y, self.velocity.x); // Check if arrow is off-screen if (self.y > 2732 || self.x < -100 || self.x > 2148) { if (!self.hasHitGround) { self.hasHitGround = true; LK.getSound('miss').play(); } } self.lastX = self.x; self.lastY = self.y; self.lastWasIntersecting = false; // Reset intersection state for next checks } }; // Fire the arrow with given power and angle self.fire = function (power, angle) { self.flying = true; self.velocity.x = Math.cos(angle) * power; self.velocity.y = Math.sin(angle) * power; self.rotation = angle; LK.getSound('bowRelease').play(); }; // Stick arrow to target self.stickTo = function (target, score) { self.stuck = true; self.flying = false; self.targetHit = target; self.score = score; // Play sound LK.getSound('targetHit').play(); }; return self; }); var Bow = Container.expand(function () { var self = Container.call(this); // Bow body var bowBody = self.attachAsset('bow', { anchorX: 0.5, anchorY: 0.5 }); // Bow string var bowString = self.attachAsset('bowString', { anchorX: 0.5, anchorY: 0.5, x: -10 }); // Properties self.aimAngle = -Math.PI / 4; // Default angle (slightly up) self.power = 0; self.maxPower = 35; self.charging = false; // Update bow self.update = function () { // Update bow rotation to match aim angle self.rotation = self.aimAngle; // Update string position/appearance based on pull if (self.charging) { var pullFactor = self.power / self.maxPower; bowString.scaleX = 1 + pullFactor * 0.5; // Thicker when pulled } else { bowString.scaleX = 1; } }; // Start charging (pulling back) self.startCharging = function () { self.charging = true; self.power = 0; }; // Continue charging self.updateCharging = function () { if (self.charging) { if (!self.loadingSoundPlayed) { LK.getSound('bowLoading').play(); self.loadingSoundPlayed = true; } self.power += 0.4; if (self.power > self.maxPower) { self.power = self.maxPower; } } }; // Release arrow self.releaseArrow = function () { var finalPower = self.power; self.charging = false; self.loadingSoundPlayed = false; self.power = 0; return finalPower; }; return self; }); var PowerMeter = Container.expand(function () { var self = Container.call(this); // Background var background = self.attachAsset('powerMeter', { anchorX: 0.5, anchorY: 0.5 }); // Fill var fill = self.attachAsset('powerFill', { anchorX: 0.5, anchorY: 1, // Anchor to bottom y: 195 // Half height of background }); fill.height = 0; // Start empty // Update power meter self.updatePower = function (power, maxPower) { var percentage = power / maxPower; fill.height = 390 * percentage; // 390 is the max height of fill // Change color based on power if (percentage < 0.33) { fill.tint = 0x00FF00; // Green } else if (percentage < 0.66) { fill.tint = 0xFFFF00; // Yellow } else { fill.tint = 0xFF0000; // Red } }; return self; }); var Target = Container.expand(function () { var self = Container.call(this); // Create rings from outside to inside var outerRing = self.attachAsset('target', { anchorX: 0.5, anchorY: 0.5 }); var ring1 = self.attachAsset('targetRing1', { anchorX: 0.5, anchorY: 0.5 }); var ring2 = self.attachAsset('targetRing2', { anchorX: 0.5, anchorY: 0.5 }); var ring3 = self.attachAsset('targetRing3', { anchorX: 0.5, anchorY: 0.5 }); var bullseye = self.attachAsset('targetRing4', { anchorX: 0.5, anchorY: 0.5 }); // Target properties self.radius = 100; // Outer radius self.direction = 1; // 1 for right, -1 for left self.speed = 2; self.minX = 300; self.maxX = 1748; // 2048 - 300 // Score values for each ring self.scoreValues = [10, 25, 50, 75, 100]; // Outer to inner // Update target movement self.update = function () { if (!self["static"]) { self.x += self.speed * self.direction; // Reverse direction at edges if (self.x > self.maxX || self.x < self.minX) { self.direction *= -1; } } }; // Get score based on distance from center self.getScore = function (hitX, hitY) { // Calculate distance from center var dx = hitX - self.x; var dy = hitY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Determine which ring was hit if (distance < 20) { return self.scoreValues[4]; // Bullseye } else if (distance < 40) { return self.scoreValues[3]; } else if (distance < 60) { return self.scoreValues[2]; } else if (distance < 80) { return self.scoreValues[1]; } else if (distance < 100) { return self.scoreValues[0]; // Outer ring } return 0; // Miss }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ // No title, no description // Always backgroundColor is black backgroundColor: 0x000000 }); /**** * Game Code ****/ // Load level function to initialize targets and reset game state function loadLevel(level) { currentLevel = level; maxArrows = levels[currentLevel].arrows; arrowCount = 0; arrows = []; initializeTargets(); gameActive = true; arrowsTxt.setText('Arrows: ' + (maxArrows - arrowCount) + '/' + maxArrows); levelTxt.setText('Level: ' + (currentLevel + 1)); // Update level display } var arrows = []; var targets = []; var currentArrow = null; var arrowCount = 0; var levels = [{ targets: 3, arrows: 5 }, { targets: 5, arrows: 7 }, { targets: 7, arrows: 9 }, { targets: 9, arrows: 11 }]; var currentLevel = 0; var maxArrows = levels[currentLevel].arrows; var totalScore = 0; var gameActive = true; var aimPoint = { x: 0, y: 0 }; var dragStart = { x: 0, y: 0 }; var isDragging = false; // Create the background var skyBackground = game.addChild(LK.getAsset('sky', { anchorX: 0, anchorY: 0, y: 0 })); var ground = game.addChild(LK.getAsset('ground', { anchorX: 0, anchorY: 0, y: 2532 // Position at bottom of screen })); // Create bow var bow = new Bow(); bow.x = 1024; // Center the bow horizontally on the screen bow.y = 2500; // Position near bottom game.addChild(bow); // Create power meter var powerMeter = new PowerMeter(); powerMeter.x = 100; powerMeter.y = 1800; game.addChild(powerMeter); // Create targets function createTarget(x, y, isStatic, speed) { var target = new Target(); target.x = x; target.y = y; target["static"] = isStatic; if (speed !== undefined) { target.speed = speed; } game.addChild(target); targets.push(target); return target; } // Create initial targets based on current level function initializeTargets() { targets = []; for (var i = 0; i < levels[currentLevel].targets; i++) { var x = 300 + Math.random() * 1448; // Random x position within bounds var y = 500 + i * 300; // Staggered y positions var speed = 2 + Math.random() * 4; // Random speed between 2 and 6 createTarget(x, y, false, speed); } } initializeTargets(); // Score display var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0x0000FF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Arrows left display var arrowsTxt = new Text2('Arrows: ' + (maxArrows - arrowCount) + '/' + maxArrows, { size: 80, fill: 0x00FF00 }); arrowsTxt.anchor.set(0.5, 0); arrowsTxt.y = 100; LK.gui.top.addChild(arrowsTxt); // High score display var highScoreTxt = new Text2('High Score: ' + storage.highScore, { size: 60, fill: 0xFFA500 }); highScoreTxt.anchor.set(1, 0); highScoreTxt.y = 20; LK.gui.topRight.addChild(highScoreTxt); // Level display var levelTxt = new Text2('Level: ' + (currentLevel + 1), { size: 80, fill: 0x800080 }); levelTxt.anchor.set(0, 0); levelTxt.x = 20; levelTxt.y = 20; LK.gui.topLeft.addChild(levelTxt); // Aim guide var aimGuideTxt = new Text2('Touch and drag to aim, release to shoot', { size: 60, fill: 0xFF0000 }); aimGuideTxt.anchor.set(0.5, 0); aimGuideTxt.y = 200; LK.gui.top.addChild(aimGuideTxt); // Create a new arrow function createArrow() { if (arrowCount >= maxArrows) { if (arrows.length === 0) { // Check if all arrows have been used and none are flying LK.showGameOver(); // Trigger game over } return null; } var arrow = new Arrow(); arrow.x = bow.x; arrow.y = bow.y; arrow.rotation = bow.aimAngle; game.addChild(arrow); arrows.push(arrow); arrowCount++; // Update arrows left display arrowsTxt.setText('Arrows: ' + (maxArrows - arrowCount) + '/' + maxArrows); return arrow; } // Handle collision between arrow and targets function checkArrowCollisions() { for (var i = 0; i < arrows.length; i++) { var arrow = arrows[i]; if (arrow.flying && !arrow.stuck) { // Check collision with each target for (var j = 0; j < targets.length; j++) { var target = targets[j]; // Arrow tip position var tipX = arrow.x + Math.cos(arrow.rotation) * 65; var tipY = arrow.y + Math.sin(arrow.rotation) * 65; // Check if tip is inside target var dx = tipX - target.x; var dy = tipY - target.y; var distance = Math.sqrt(dx * dx + dy * dy); if (arrow.lastWasIntersecting === undefined) { arrow.lastWasIntersecting = false; } if (!arrow.lastWasIntersecting && distance <= target.radius) { if (!target._hit) { // Prevent double-count target._hit = true; arrow.lastWasIntersecting = true; // Ensure we update the intersection state // Hit! Calculate score var score = target.getScore(tipX, tipY); totalScore += score; scoreTxt.setText('Score: ' + totalScore); // Stick arrow to target and remove from screen arrow.stickTo(target, score); arrow.destroy(); arrows.splice(i, 1); // Create explosion effect var explosion = new Container(); var explosionParticle = LK.getAsset('target', { anchorX: 0.5, anchorY: 0.5 }); explosion.addChild(explosionParticle); explosion.x = target.x; explosion.y = target.y; game.addChild(explosion); // Animate explosion effect tween(explosion, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { explosion.destroy(); } }); // Remove the hit target targets.splice(j, 1); target.destroy(); arrow.lastWasIntersecting = false; // Reset intersection state for next checks // Create score popup var scorePop = new Text2("+" + score, { size: 60, fill: 0xFFFF00 }); scorePop.x = tipX; scorePop.y = tipY; game.addChild(scorePop); // Animate score popup tween(scorePop, { y: scorePop.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { scorePop.destroy(); } }); break; } arrow.lastWasIntersecting = distance <= target.radius; } } } // Move arrows that are stuck to targets with the targets if (arrow.stuck && arrow.targetHit) { var targetPos = arrow.targetHit; var dx = arrow.x - targetPos.x; var dy = arrow.y - targetPos.y; arrow.x = targetPos.x + dx; arrow.y = targetPos.y + dy; } } } // Check if game is over function checkGameOver() { if (arrowCount >= maxArrows && arrows.length === 0) { var allArrowsLanded = true; // Check if all arrows have landed for (var i = 0; i < arrows.length; i++) { if (arrows[i].flying) { allArrowsLanded = false; break; } } if (allArrowsLanded && gameActive) { gameActive = false; console.log("Game Over: All arrows used and not all targets hit."); // Debugging log // Update high score if needed if (totalScore > storage.highScore) { storage.highScore = totalScore; highScoreTxt.setText('High Score: ' + storage.highScore); } // Check if all targets are hit or score condition for level 1 is met if (targets.length === 0 || currentLevel === 0 && totalScore >= 30) { // Create level up text var levelUpTxt = new Text2('Level Up!', { size: 120, fill: 0xFFFF00 }); levelUpTxt.anchor.set(0.5, 0.5); levelUpTxt.x = 1024; // Center horizontally levelUpTxt.y = 1366; // Center vertically game.addChild(levelUpTxt); // Tween effect for level up text tween(levelUpTxt, { alpha: 0 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { levelUpTxt.destroy(); currentLevel++; if (currentLevel < levels.length) { // Advance to next level using loadLevel function loadLevel(currentLevel); levelTxt.setText('Level: 27'); // Update level text to 27 levels[currentLevel].targets += 5; // Add 5 targets initializeTargets(); // Reinitialize targets for the new level } else { // All levels completed, show game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } } }); } else { // Wait 2 seconds before showing game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } } } } // Game loop game.update = function () { // Update all targets for (var i = 0; i < targets.length; i++) { targets[i].update(); } // Update all arrows for (var i = 0; i < arrows.length; i++) { arrows[i].update(); } // Update bow charging if (bow.charging) { bow.updateCharging(); powerMeter.updatePower(bow.power, bow.maxPower); } // Check for collisions checkArrowCollisions(); // Check if game is over checkGameOver(); }; // Touch/mouse events game.down = function (x, y, obj) { if (!gameActive || arrowCount >= maxArrows) { return; } isDragging = true; dragStart.x = x; dragStart.y = y; // Start charging bow bow.startCharging(); // Hide aim guide aimGuideTxt.alpha = 0; // Create new arrow currentArrow = createArrow(); }; game.move = function (x, y, obj) { if (!isDragging || !currentArrow) { return; } // Calculate aim angle var dx = dragStart.x - x; var dy = dragStart.y - y; var angle = Math.atan2(dy, dx); // Constrain angle (can't aim down into ground or directly backward) if (angle > 0 && angle < Math.PI / 2) { angle = 0; } else if (angle > Math.PI / 2 && angle < Math.PI) { angle = Math.PI; } bow.aimAngle = angle; // Position current arrow currentArrow.x = bow.x; currentArrow.y = bow.y; currentArrow.rotation = angle; }; game.up = function (x, y, obj) { if (!isDragging || !currentArrow) { return; } isDragging = false; // Fire arrow with current power and angle var power = bow.releaseArrow(); currentArrow.fire(power, bow.aimAngle); // Reset power meter powerMeter.updatePower(0, bow.maxPower); currentArrow = null; }; // Play background music LK.playMusic('bgMusic');
===================================================================
--- original.js
+++ change.js
@@ -233,9 +233,11 @@
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x87CEEB // Sky blue
+ // No title, no description
+ // Always backgroundColor is black
+ backgroundColor: 0x000000
});
/****
* Game Code
a sharp cartoon-style arrow flying to the right, with colorful string, 2D game asset, minimal shading, pixel-perfect edges, isolated, flat art style. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A 2D flat digital illustration of a sharp and colorful cartoonish sleek arrow tip, designed for a mobile archery game. The arrow tip should be metallic (steel or iron), with subtle gradients for a polished look. It should have a pointed triangular shape with a slightly stylized, game-friendly appearance, matching the clean, minimal aesthetic of vector-based graphics. Use a transparent background and ensure it's facing upward. Resolution: 512x512.". Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
"A 2D digital illustration of a bright, cartoony sky background for a mobile archery game. The sky is a soft gradient from light blue at the top to pale near the horizon. Include fluffy white clouds scattered naturally. Style is flat, colorful, and minimal—perfect for a fun, casual game. No sun or dramatic lighting. Resolution: 1920x1080. Seamless and loopable edges. Transparent-free, clean background.". Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows