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