User prompt
text on the screen which level is playing
User prompt
If the player uses all arrows show "Game Over."
User prompt
triggger game over when arrows count become 0
User prompt
Show 'Game Over' if all arrows are used and become 0 and targets are left
User prompt
Show 'Game Over' if all arrows are used and targets are left 🔄 Advance to next level if all targets are hit
User prompt
Level Structure: Level 1: 3 targets,5 arrows Level 2: 5 targets,7 arrows Level 3: 7 targets, 9 arrows Level 4: 9 targets, 11 arrows - Increase difficulty with each level.
User prompt
Make the arrow disappear from a screen when it hits a target
User prompt
Disappear arrow also like the target
User prompt
Add the following logic: - Multiple targets move left and right on the field. - When an arrow hits a target, only the hit target should disappear with a blast effect (explosion animation or particles). - Other targets should continue moving as usual. - Play a sound or visual effect to indicate a successful hit. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add this specific logic: - Multiple targets move left and right on the field. - When an arrow hits a target, stop only that specific target's movement. - Other targets should continue moving normally. - The hit target can show a visual effect or change (e.g., flash or turn red). - Do not reset or stop all targets—only the one that was hit.
User prompt
Increase the maximum power of the bow to ensure the arrow reaches the target.
User prompt
Make sure the arrow has enough speed to reach the target.
User prompt
Position of the bow in the middle
Code edit (1 edits merged)
Please save this source code
User prompt
Archery Master 3D
Initial prompt
Create a 3D-style Archery Battle game 1. Player stands on one side of the field with a bow. 2. The target stands on the opposite side of the field and can move left/right slowly. 3. Touch and drag to aim the bow (adjust angle and power). 4. Release to shoot the arrow. The arrow should follow a curved arc (parabolic trajectory). 5. Add a score system based on how close the arrow hits the center of the target. 6. Add a simple UI: Score display and remaining arrows counter. 7. Use simple assets: bow, arrow, and target. 8. Simulate depth using scale and perspective (e.g., far objects smaller). 9. Include a background like trees or mountains for aesthetics. 10. Make the gameplay loop repeatable: 5 arrows per round, then display score and restart option.
/**** * 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.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(); } } } }; // 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 = 25; 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) { 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.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({ backgroundColor: 0x87CEEB // Sky blue }); /**** * Game Code ****/ // Game state variables var arrows = []; var targets = []; var currentArrow = null; var arrowCount = 0; var maxArrows = 5; 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 createTarget(1024, 500, false, 3); createTarget(700, 800, false, 4); createTarget(1300, 1100, false, 5); // Score display var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); 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: 0xFFFFFF }); 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: 0xFFFFFF }); highScoreTxt.anchor.set(1, 0); highScoreTxt.y = 20; LK.gui.topRight.addChild(highScoreTxt); // Aim guide var aimGuideTxt = new Text2('Touch and drag to aim, release to shoot', { size: 60, fill: 0xFFFFFF }); aimGuideTxt.anchor.set(0.5, 0); aimGuideTxt.y = 200; LK.gui.top.addChild(aimGuideTxt); // Create a new arrow function createArrow() { if (arrowCount >= maxArrows) { 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 (distance <= target.radius) { // Hit! Calculate score var score = target.getScore(tipX, tipY); totalScore += score; scoreTxt.setText('Score: ' + totalScore); // Stick arrow to target arrow.stickTo(target, score); // 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; } } } // 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) { 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; // Update high score if needed if (totalScore > storage.highScore) { storage.highScore = totalScore; highScoreTxt.setText('High Score: ' + storage.highScore); } // 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
@@ -84,9 +84,9 @@
});
// Properties
self.aimAngle = -Math.PI / 4; // Default angle (slightly up)
self.power = 0;
- self.maxPower = 15;
+ self.maxPower = 25;
self.charging = false;
// Update bow
self.update = function () {
// Update bow rotation to match aim angle
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