User prompt
ya sayılar daha büyük olsun. Bir de cevap kutucuğunun altına kadar hareket edebilsinler.
User prompt
reis timer ile balonların assetini ayır bence
User prompt
oyuncu doğru bilince tebrikler diye bir pop up gesin. oyuncu pop up'a tıkayınca yeni oyuna geçsin
User prompt
alttaki sayılar önce yavaş hareket etsin süre bitmeye yaklaştıkça daha hızlansınlar ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
reis bence işlemi mor kutucuk ile timer'ın ortasına koy
User prompt
işlem ve timer üst üste geldi
User prompt
60 saniyesi olsun oyuncunun. geri sayımı da daha belirgin göster
User prompt
tamam. oyunu tamamen hard mode yapalım. hard mode seçeneğini kaldır. oyun tamamen hard mode şeklinde olsun. sayılr biraz daha yavaş hareket etsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'Quadratic')' in or related to this line: 'tween.to(digitCubes[i], {' Line Number: 352 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Timeout.tick error: tween is not defined' in or related to this line: 'tween.to(digitCubes[i], {' Line Number: 346
User prompt
fail olunca doğru cevabı yazsın ekranda. bir de hard mode yapalım. sağ üstte görünsün. Hard mode'a tıklayınca alttaki sayılar random hareket etsin ekranda ve tıklamaya çalışalım hareket ederken cevaplayabilmek için
User prompt
arkaplan resmi koyalım. yanda üç joker hakkı olsun. bir tanesi ilk basamağı yazsın. diğeri sonuçta geçmeyen iki sayıyı alttan silsin. üçüncüsü de başka işleme geçirsin. bu jokerler tek seferlik olsun. kullanılınca rengi yeşiilden kırmızıya dönüşsün
User prompt
reis cevap kaç haneliyse o kadar sayıya tıklamam izin vermelisin.
User prompt
bilgisayardayım. tamam o zaman karakteri kaldıralım. ben tıklayarak sonucu yazayım. tıkladığım sayı ortaya gitsin. Mesela cevap üç haneliyse sonuna kadar beklesin kontrol etmek için. dört ise dört
User prompt
karakteri hareket ettiremiyorum ki
User prompt
kahramanımız verilen süre içerisinde ekranda görünen matematiksel dört işlemin sonucunu ortadaki beyaz kutucuğa götürmek zorunda. aşağıda küp şeklinde sıfırdan dokuza kadar saılar var. kahraman sonucu bu sayıları sırayla kutucuğun içine götürerek tahmin ediyor. doğruysa yeni oyuna geçiliyor. yanlışsa fail oluyor
User prompt
Matematik Kahramanı: Sonucu Bul!
Initial prompt
kahramanımız verilen süre içerisinde ekranda görünen matematiksel dört işlemin sonucunu ortadaki beyaz kutucuğa götürmek zorunda. aşağıda küp şeklinde sıfırdan dokuza kadar sayılar var. kahraman sonucu bu sayıları sırayla kutucuğun içine götürerek tahmin ediyor. doğruysa yeni oyuna geçiliyor. yanlışsa fail oluyor
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Bird class for background animation var Bird = Container.expand(function () { var self = Container.call(this); // Randomly pick one of the two bird assets var birdType = Math.random() < 0.5 ? 'bird1' : 'bird2'; var birdAsset = self.attachAsset(birdType, { anchorX: 0.5, anchorY: 0.5 }); // Set initial scale (can be randomized for depth effect) var scale = 0.8 + Math.random() * 0.6; birdAsset.scaleX = scale; birdAsset.scaleY = scale; self.width = birdAsset.width * scale; self.height = birdAsset.height * scale; // Set random vertical position (avoid top 200px and bottom 400px) self.y = 150 + Math.random() * (1800 - 150); // Start just off the right edge self.x = 2048 + self.width; // Set speed (pixels per frame) self.speed = 3 + Math.random() * 2; // For possible future: flip bird horizontally if needed birdAsset.scaleX = -scale; // Face left // No interaction self.interactive = false; // Track lastX for event logic if needed self.lastX = self.x; // Update method for movement self.update = function () { self.lastX = self.x; self.x -= self.speed; // If off the left edge, destroy if (self.x < -self.width) { if (self.parent) self.parent.removeChild(self); self.destroy(); } }; return self; }); // GoldenStitch class: moves evasively, hard to catch, player wins if caught var GoldenStitch = Container.expand(function () { var self = Container.call(this); // Use the unique goldenStitch asset var stitchAsset = self.attachAsset('goldenStitch', { anchorX: 0.5, anchorY: 0.5 }); stitchAsset.width = 120; stitchAsset.height = 120; // Evasive movement parameters self.x = 2048 / 2; self.y = 600 + Math.random() * 1000; self.lastX = self.x; self.lastY = self.y; self.targetX = self.x; self.targetY = self.y; self.moveTimer = 0; self.moveInterval = 30 + Math.floor(Math.random() * 40); // frames between moves self.speed = 18 + Math.random() * 8; // pixels per frame, fast! self.evasionRadius = 400; // how far it jumps per move self.interactive = true; // so it can be caught // Make it hard to tap: only allow catching if tap is very close to center self.down = function (x, y, obj) { // Only allow catching if tap is within 60px of center var dx = x - self.x; var dy = y - self.y; if (dx * dx + dy * dy < 60 * 60) { // Player caught the stitch, win! if (typeof timer !== "undefined" && timer) { LK.clearInterval(timer); timer = null; } LK.showYouWin(); } }; // Evasive movement: picks a new random target, tweens there, repeats self.update = function () { self.lastX = self.x; self.lastY = self.y; self.moveTimer++; // If close to target or time to pick new target, pick a new one var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 20 || self.moveTimer > self.moveInterval) { // Pick a new target far from current, but inside screen var angle = Math.random() * Math.PI * 2; var radius = self.evasionRadius * (0.5 + Math.random() * 0.7); var tx = self.x + Math.cos(angle) * radius; var ty = self.y + Math.sin(angle) * radius; // Clamp to screen bounds (avoid top 200, bottom 400) tx = Math.max(100, Math.min(2048 - 100, tx)); ty = Math.max(200, Math.min(2732 - 400, ty)); self.targetX = tx; self.targetY = ty; self.moveTimer = 0; self.moveInterval = 24 + Math.floor(Math.random() * 32); // Tween to new target tween(self, { x: self.targetX, y: self.targetY }, { duration: 400 + Math.random() * 200, easing: tween.cubicInOut }); } }; return self; }); // Rocket class for background animation var Rocket = Container.expand(function () { var self = Container.call(this); var rocketAsset = self.attachAsset('rocket', { anchorX: 0.5, anchorY: 1 // Anchor at the bottom of the rocket }); // Set scale (can be randomized) var scale = 0.6 + Math.random() * 0.4; rocketAsset.scaleX = scale; rocketAsset.scaleY = scale; self.width = rocketAsset.width * scale; self.height = rocketAsset.height * scale; // Start just off the bottom edge self.y = 2732 + self.height; // Set random horizontal position (avoid edges) self.x = 100 + Math.random() * (2048 - 200); // Set speed (pixels per frame) self.speed = 5 + Math.random() * 3; // No interaction self.interactive = false; // Track lastY for event logic if needed self.lastY = self.y; // Update method for movement self.update = function () { self.lastY = self.y; self.y -= self.speed; // If off the top edge, destroy if (self.y < -self.height) { if (self.parent) self.parent.removeChild(self); self.destroy(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Bird assets for background animation (use two different images) // --- Game Variables --- // Import tween plugin for animations var currentQuestion = null; // Holds the current math question object var answerDigits = []; // Array of selected digit values (as strings) var digitCubes = []; // Array of digit cube objects (0-9) var answerBox = null; // The answer drop zone var questionText = null; // The question display var timerText = null; // Timer display var timer = null; // Timer interval id var timeLeft = 60; // Total seconds for the game var timerBar = null; // Visual timer bar var timerBarBg = null; // Timer bar background var timerBarWidth = 1200; // Width of the timer bar var timerBarHeight = 60; // Height of the timer bar var timerBarX = 2048 / 2 - timerBarWidth / 2; var timerBarY = 240; var timerBarColor = 0xFF3333; var timerBarBgColor = 0x222222; var timerBarPadding = 8; // Removed hero and drag logic; input is now by clicking digit cubes var score = 0; // Player score // --- Bird Animation Variables --- var birds = []; // Array to hold active bird objects var birdSpawnTimer = 0; // Timer for spawning birds var birdSpawnInterval = 120; // Frames between bird spawns (2 seconds at 60fps) // --- Rocket Animation Variables --- var rockets = []; // Array to hold active rocket objects var rocketSpawnTimer = 0; // Timer for spawning rockets var rocketSpawnInterval = 240; // Frames between rocket spawns (4 seconds at 60fps) // --- Background Image --- var bgImage = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChildAt(bgImage, 0); // Add as background // --- Joker State --- var jokers = [{ used: false, label: "First Digit", color: 0x00cc00 }, { used: false, label: "Remove Wrong", color: 0x00cc00 }, { used: false, label: "Skip", color: 0x00cc00 }]; var jokerButtons = []; // --- Utility Functions --- function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } // Generates a random math question object: {text, answer} function generateQuestion() { var ops = ['+', '-', '×', '÷']; var op = ops[randomInt(0, ops.length - 1)]; var a, b, text, answer; if (op === '+') { a = randomInt(1, 99); b = randomInt(1, 99); answer = a + b; } else if (op === '-') { a = randomInt(10, 99); b = randomInt(1, a); answer = a - b; } else if (op === '×') { a = randomInt(2, 12); b = randomInt(2, 12); answer = a * b; } else { // ÷ b = randomInt(2, 12); answer = randomInt(2, 12); a = b * answer; } text = a + " " + op + " " + b + " = ?"; return { text: text, answer: answer }; } // Resets the answer input and updates the answer box display function resetAnswer() { answerDigits = []; updateAnswerBox(); } // Updates the answer box text to show current input function updateAnswerBox() { if (answerBox && answerBox.textObj) { answerBox.textObj.setText(answerDigits.length ? answerDigits.join('') : ""); } } // Starts a new question function startNewQuestion() { if (typeof updateStatsText === "function") updateStatsText(); if (timer) { LK.clearInterval(timer); } currentQuestion = generateQuestion(); questionText.setText(currentQuestion.text); resetAnswer(); // Reset digit cubes visibility for new question for (var d = 0; d < digitCubes.length; d++) { digitCubes[d].visible = true; } // Do not reset timeLeft here; timer is for the whole game // Only set timer if not already running if (!timer) { timerText.setText("⏰ " + timeLeft); timerBar.width = timerBarWidth; timer = LK.setInterval(function () { timeLeft--; timerText.setText("⏰ " + timeLeft); // Update timer bar width timerBar.width = Math.max(0, timerBarWidth * (timeLeft / 60)); // --- Auto-drop two non-answer digits if timer < 20s --- if (timeLeft === 20) { // Find digits not in the answer var ansStr = currentQuestion.answer + ""; var digitsInAnswer = {}; for (var k = 0; k < ansStr.length; k++) { digitsInAnswer[ansStr[k]] = true; } var toDrop = []; for (var d = 0; d < digitCubes.length; d++) { if (!digitCubes[d].visible) continue; if (!digitsInAnswer.hasOwnProperty(digitCubes[d].digit + "")) { toDrop.push(digitCubes[d]); if (toDrop.length === 2) break; } } // Animate and hide the cubes for (var i = 0; i < toDrop.length; i++) { (function (cube) { tween(cube, { y: 2900 }, { duration: 1600, // Slower drop effect (was 700) easing: tween.cubicIn, onFinish: function onFinish() { cube.visible = false; } }); })(toDrop[i]); } } if (timeLeft <= 0) { LK.clearInterval(timer); timer = null; timerBar.width = 0; if (typeof updateStatsText === "function") updateStatsText(); LK.showGameOver(); } }, 1000); } } // Checks the answer and proceeds accordingly function checkAnswer() { var guess = parseInt(answerDigits.join('')); if (guess === currentQuestion.answer) { score++; // Show 'Tebrikler' popup var congratsPopup = new Container(); var popupBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5 }); popupBg.width = 800; popupBg.height = 400; popupBg.tint = 0x8720fe; congratsPopup.addChild(popupBg); var popupText = new Text2("Congratulations!", { size: 140, fill: 0xffffff }); popupText.anchor.set(0.5, 0.5); popupText.x = 0; popupText.y = -40; congratsPopup.addChild(popupText); var popupSubText = new Text2("Tap to continue", { size: 60, fill: 0xffffff }); popupSubText.anchor.set(0.5, 0.5); popupSubText.x = 0; popupSubText.y = 90; congratsPopup.addChild(popupSubText); congratsPopup.x = 2048 / 2; congratsPopup.y = 1200; // Block input to game while popup is up congratsPopup.interactive = true; congratsPopup.down = function () { // Remove popup if (congratsPopup.parent) congratsPopup.parent.removeChild(congratsPopup); timeLeft = 60; // Reset timer to 60 seconds if (timer) { LK.clearInterval(timer); timer = null; } startNewQuestion(); }; game.addChild(congratsPopup); } else { LK.clearInterval(timer); timer = null; if (timerBar) timerBar.width = 0; // Show correct answer in the answer box before game over if (answerBox && answerBox.textObj) { answerBox.textObj.setText("Correct: " + currentQuestion.answer); } LK.setTimeout(function () { if (typeof updateStatsText === "function") updateStatsText(); LK.showGameOver(); }, 1200); } } // --- UI Setup --- // --- Question Box (purple) centered between timer and answer box --- var questionBox = new Container(); var questionBoxAsset = LK.getAsset('questionBox', { anchorX: 0.5, anchorY: 0.5 }); questionBoxAsset.width = 600; questionBoxAsset.height = 180; questionBox.addChild(questionBoxAsset); // Place questionBox between timerText (y=20, height~160) and answerBox (y=900, height=200) // Let's center it at y = (timerBarY + answerBox.y) / 2, but visually, a bit above answerBox questionBox.x = 2048 / 2; questionBox.y = (timerBarY + 900) / 2 - 60; // visually balanced questionText = new Text2("", { size: 120, fill: 0xFFFFFF }); questionText.anchor.set(0.5, 0.5); questionText.x = 0; questionText.y = 0; questionBox.addChild(questionText); game.addChild(questionBox); // Timer at top center, larger and more visible timerText = new Text2("⏰ 60", { size: 160, fill: 0xFF3333, fontWeight: "bold" }); timerText.anchor.set(0.5, 0); timerText.x = 2048 / 2; // Move timerText higher to avoid overlap with questionText timerText.y = 20; game.addChild(timerText); // Timer bar background timerBarBg = LK.getAsset('timerBarBg', { anchorX: 0, anchorY: 0 }); timerBarBg.width = timerBarWidth + timerBarPadding * 2; timerBarBg.height = timerBarHeight + timerBarPadding * 2; timerBarBg.x = timerBarX - timerBarPadding; timerBarBg.y = timerBarY - timerBarPadding; game.addChild(timerBarBg); // Timer bar (foreground) timerBar = LK.getAsset('timerBar', { anchorX: 0, anchorY: 0 }); timerBar.width = timerBarWidth; timerBar.height = timerBarHeight; timerBar.x = timerBarX; timerBar.y = timerBarY; game.addChild(timerBar); // --- Hard Mode: Always enabled, no toggle button --- // Joker buttons (right side, vertically spaced) var jokerStartY = 400; var jokerSpacing = 220; for (var j = 0; j < 3; j++) { var jokerBtn = new Container(); var jokerAssetName = j === 0 ? 'joker1' : j === 1 ? 'joker2' : 'joker3'; var btnAsset = LK.getAsset(jokerAssetName, { anchorX: 0.5, anchorY: 0.5 }); btnAsset.width = 180; btnAsset.height = 180; btnAsset.tint = jokers[j].color; jokerBtn.addChild(btnAsset); var btnText = new Text2(jokers[j].label, { size: 38, fill: 0xffffff }); btnText.anchor.set(0.5, 0.5); btnText.x = 0; btnText.y = 0; jokerBtn.addChild(btnText); jokerBtn.x = 2048 - 180; jokerBtn.y = jokerStartY + j * jokerSpacing; jokerBtn.jokerIndex = j; // Joker button logic jokerBtn.down = function (idx) { return function (x, y, obj) { if (jokers[idx].used) return; jokers[idx].used = true; // Change color to red jokerButtons[idx].children[0].tint = 0xcc0000; // Joker 1: Fill first digit if (idx === 0) { var ansStr = currentQuestion.answer + ""; if (answerDigits.length < ansStr.length) { answerDigits = [ansStr[0]]; updateAnswerBox(); } } // Joker 2: Remove two incorrect digits from cubes else if (idx === 1) { var ansStr2 = currentQuestion.answer + ""; var digitsInAnswer = {}; for (var k = 0; k < ansStr2.length; k++) { digitsInAnswer[ansStr2[k]] = true; } var removed = 0; for (var d = 0; d < digitCubes.length; d++) { if (!digitsInAnswer.hasOwnProperty(digitCubes[d].digit + "") && removed < 2) { digitCubes[d].visible = false; removed++; } } } // Joker 3: Skip to next question else if (idx === 2) { startNewQuestion(); } }; }(j); jokerButtons.push(jokerBtn); game.addChild(jokerBtn); } // Answer box in center answerBox = new Container(); var boxAsset = LK.getAsset('answerBox', { anchorX: 0.5, anchorY: 0.5 }); boxAsset.width = 400; boxAsset.height = 200; answerBox.addChild(boxAsset); answerBox.x = 2048 / 2; answerBox.y = 900; answerBox.textObj = new Text2("", { size: 120, fill: 0x000000 }); answerBox.textObj.anchor.set(0.5, 0.5); answerBox.textObj.x = 0; answerBox.textObj.y = 0; answerBox.addChild(answerBox.textObj); game.addChild(answerBox); // Digit cubes (0-9) at bottom, spaced evenly, now clickable var cubeSpacing = 180; var startX = (2048 - (cubeSpacing * 10 - 40)) / 2; for (var i = 0; i < 10; i++) { var cube = new Container(); var asset = LK.getAsset('balloon', { anchorX: 0.5, anchorY: 0.5 }); asset.width = 220; asset.height = 220; cube.addChild(asset); var txt = new Text2(i + "", { size: 140, fill: 0x000000 }); txt.anchor.set(0.5, 0.5); txt.x = 0; txt.y = 0; cube.addChild(txt); cube.x = startX + i * cubeSpacing; cube.y = 2400; cube.digit = i; // Add click/tap handler cube.down = function (digit) { return function (x, y, obj) { // Only allow input if we haven't reached the required number of digits if (answerDigits.length < (currentQuestion.answer + "").length) { answerDigits.push(digit + ""); updateAnswerBox(); // If we've reached the required number of digits, check the answer if (answerDigits.length === (currentQuestion.answer + "").length) { checkAnswer(); } } // If already at max digits, ignore further input }; }(i); digitCubes.push(cube); game.addChild(cube); } // --- Delete Button (bottom left) --- var deleteBtn = new Container(); var deleteAsset = LK.getAsset('deleteBtn', { anchorX: 0.5, anchorY: 0.5 }); deleteAsset.width = 180; deleteAsset.height = 180; deleteBtn.addChild(deleteAsset); // Optional: Add a "←" icon/text on top of the button for clarity var delTxt = new Text2("←", { size: 120, fill: 0xffffff }); delTxt.anchor.set(0.5, 0.5); delTxt.x = 0; delTxt.y = 0; deleteBtn.addChild(delTxt); // Place at bottom left, but not in the top left 100x100 reserved area deleteBtn.x = 120; deleteBtn.y = 2550; deleteBtn.interactive = true; deleteBtn.down = function (x, y, obj) { if (answerDigits.length > 0) { answerDigits.pop(); updateAnswerBox(); } }; game.addChild(deleteBtn); // Hero character and drag logic removed; input is now by clicking digit cubes // --- Start Game --- startNewQuestion(); // --- Golden Stitch setup --- var goldenStitch = new GoldenStitch(); goldenStitch.x = 2048 / 2; goldenStitch.y = 900; game.addChildAt(goldenStitch, 2); // Above birds, below main UI // --- Stats Tracking --- var seriesCount = 0; // How many questions answered (right or wrong) var goldenSnitchCaught = 0; // Total golden snitch caught // --- Stats Display (bottom right) --- // --- Stats Display (bottom right) with background --- var statsBg = LK.getAsset('timerBarBg', { anchorX: 1, anchorY: 1 }); statsBg.width = 520; // widened for more left coverage statsBg.height = 180; statsBg.tint = 0x222222; statsBg.alpha = 0.85; statsBg.x = 2048 - 20; statsBg.y = 2732 - 20; game.addChild(statsBg); var statsText = new Text2("", { size: 60, fill: 0xFFFFFF }); statsText.anchor.set(1, 1); // bottom right statsText.x = 2048 - 40; statsText.y = 2732 - 40; game.addChild(statsText); function updateStatsText() { if (typeof statsText !== "undefined" && statsText && typeof statsText.setText === "function") { statsText.setText("Streak: " + seriesCount + "\nGolden Snitch: " + goldenSnitchCaught); } } updateStatsText(); // --- Golden Snitch Win Handler Patch --- var _origGoldenStitchDown = goldenStitch.down; goldenStitch.down = function (x, y, obj) { var dx = x - goldenStitch.x; var dy = y - goldenStitch.y; if (dx * dx + dy * dy < 60 * 60) { goldenSnitchCaught++; updateStatsText(); if (typeof timer !== "undefined" && timer) { LK.clearInterval(timer); timer = null; } LK.showYouWin(); } }; // --- Patch checkAnswer to increment seriesCount only --- var _origCheckAnswer = checkAnswer; checkAnswer = function checkAnswer() { seriesCount++; updateStatsText(); _origCheckAnswer(); }; // --- Patch game over to reset seriesCount only --- var _origShowGameOver = LK.showGameOver; LK.showGameOver = function () { updateStatsText(); seriesCount = 0; _origShowGameOver(); }; // --- Bird background animation logic --- game.update = function () { // Bird spawn logic birdSpawnTimer++; if (birdSpawnTimer >= birdSpawnInterval) { birdSpawnTimer = 0; // Spawn a new bird var bird = new Bird(); // Place behind all main game elements, but above background game.addChildAt(bird, 1); birds.push(bird); // Randomize next spawn interval (between 1.5s and 3.5s) birdSpawnInterval = 90 + Math.floor(Math.random() * 120); } // Update all birds for (var i = birds.length - 1; i >= 0; i--) { if (birds[i].update) birds[i].update(); // Remove from array if destroyed if (!birds[i].parent) { birds.splice(i, 1); } } // Rocket spawn logic rocketSpawnTimer++; if (rocketSpawnTimer >= rocketSpawnInterval) { rocketSpawnTimer = 0; // Spawn a new rocket var rocket = new Rocket(); // Place behind all main game elements, but above background game.addChildAt(rocket, 1); rockets.push(rocket); // Randomize next spawn interval (between 3s and 6s) rocketSpawnInterval = 180 + Math.floor(Math.random() * 180); } // Update all rockets for (var i = rockets.length - 1; i >= 0; i--) { if (rockets[i].update) rockets[i].update(); // Remove from array if destroyed if (!rockets[i].parent) { rockets.splice(i, 1); } } // Update golden stitch movement if (goldenStitch && goldenStitch.update) { goldenStitch.update(); } }; // --- Hard Mode Digit Cube Movement: Always enabled, slower movement --- var hardModeMoveTimer = null; function updateHardModeMovement() { // Movement speed: slow at start, fast at end // At 60s: 1200ms, at 0s: 350ms var minDuration = 350; var maxDuration = 1200; var t = Math.max(0, Math.min(1, timeLeft / 60)); // 1 at start, 0 at end var moveDuration = Math.round(minDuration + (maxDuration - minDuration) * t); // Helper to check overlap between two cubes function cubesOverlap(cubeA, xA, yA, cubeB, xB, yB) { var rA = 110; // half of 220 (cube size) var rB = 110; var dx = xA - xB; var dy = yA - yB; var distSq = dx * dx + dy * dy; var minDist = rA + rB + 10; // 10px margin return distSq < minDist * minDist; } var placedPositions = []; // Helper to check overlap with answer box function cubeOverlapsAnswerBox(x, y) { var rCube = 110; var rBox = Math.max(answerBox.width, answerBox.height) / 2; var dx = x - answerBox.x; var dy = y - answerBox.y; var distSq = dx * dx + dy * dy; var minDist = rCube + rBox + 10; return distSq < minDist * minDist; } for (var i = 0; i < digitCubes.length; i++) { // Only move visible cubes if (!digitCubes[i].visible) continue; var minX = 100; var maxX = 2048 - 100; var minY = 2200; var maxY = answerBox.y - 120; var tryCount = 0; var targetX, targetY, overlap, boxOverlap; do { targetX = randomInt(minX, maxX); targetY = randomInt(minY, maxY); overlap = false; boxOverlap = cubeOverlapsAnswerBox(targetX, targetY); for (var j = 0; j < placedPositions.length; j++) { if (cubesOverlap(digitCubes[i], targetX, targetY, placedPositions[j].cube, placedPositions[j].x, placedPositions[j].y)) { overlap = true; break; } } tryCount++; } while ((overlap || boxOverlap) && tryCount < 30); placedPositions.push({ cube: digitCubes[i], x: targetX, y: targetY }); tween(digitCubes[i], { x: targetX, y: targetY }, { duration: moveDuration, easing: tween.quadraticInOut }); } // Bounce logic: if cubes overlap after tween, reverse their direction for (var i = 0; i < digitCubes.length; i++) { if (!digitCubes[i].visible) continue; for (var j = i + 1; j < digitCubes.length; j++) { if (!digitCubes[j].visible) continue; var dx = digitCubes[i].x - digitCubes[j].x; var dy = digitCubes[i].y - digitCubes[j].y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 220) { // Bounce: move both cubes away from each other var angle = Math.atan2(dy, dx); var moveDist = 30; var nx = Math.cos(angle) * moveDist; var ny = Math.sin(angle) * moveDist; digitCubes[i].x += nx; digitCubes[i].y += ny; digitCubes[j].x -= nx; digitCubes[j].y -= ny; } } // Bounce off answer box var dxBox = digitCubes[i].x - answerBox.x; var dyBox = digitCubes[i].y - answerBox.y; var distBox = Math.sqrt(dxBox * dxBox + dyBox * dyBox); var minDistBox = 110 + Math.max(answerBox.width, answerBox.height) / 2 + 10; if (distBox < minDistBox) { // Move cube away from answer box var angleBox = Math.atan2(dyBox, dxBox); var moveDistBox = minDistBox - distBox + 10; digitCubes[i].x = answerBox.x + Math.cos(angleBox) * (minDistBox + 10); digitCubes[i].y = answerBox.y + Math.sin(angleBox) * (minDistBox + 10); } } } // Set up interval for hard mode movement (interval will be dynamically updated) var hardModeMoveTimer = null; function scheduleHardModeMove() { // Movement speed: slow at start, fast at end var minInterval = 350; var maxInterval = 1200; var t = Math.max(0, Math.min(1, timeLeft / 60)); var moveInterval = Math.round(minInterval + (maxInterval - minInterval) * t); if (hardModeMoveTimer) LK.clearTimeout(hardModeMoveTimer); updateHardModeMovement(); hardModeMoveTimer = LK.setTimeout(scheduleHardModeMove, moveInterval); } scheduleHardModeMove(); // When starting a new question, do not reset cube positions (always hard mode) var _origStartNewQuestion = startNewQuestion; startNewQuestion = function startNewQuestion() { _origStartNewQuestion(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Bird class for background animation
var Bird = Container.expand(function () {
var self = Container.call(this);
// Randomly pick one of the two bird assets
var birdType = Math.random() < 0.5 ? 'bird1' : 'bird2';
var birdAsset = self.attachAsset(birdType, {
anchorX: 0.5,
anchorY: 0.5
});
// Set initial scale (can be randomized for depth effect)
var scale = 0.8 + Math.random() * 0.6;
birdAsset.scaleX = scale;
birdAsset.scaleY = scale;
self.width = birdAsset.width * scale;
self.height = birdAsset.height * scale;
// Set random vertical position (avoid top 200px and bottom 400px)
self.y = 150 + Math.random() * (1800 - 150);
// Start just off the right edge
self.x = 2048 + self.width;
// Set speed (pixels per frame)
self.speed = 3 + Math.random() * 2;
// For possible future: flip bird horizontally if needed
birdAsset.scaleX = -scale; // Face left
// No interaction
self.interactive = false;
// Track lastX for event logic if needed
self.lastX = self.x;
// Update method for movement
self.update = function () {
self.lastX = self.x;
self.x -= self.speed;
// If off the left edge, destroy
if (self.x < -self.width) {
if (self.parent) self.parent.removeChild(self);
self.destroy();
}
};
return self;
});
// GoldenStitch class: moves evasively, hard to catch, player wins if caught
var GoldenStitch = Container.expand(function () {
var self = Container.call(this);
// Use the unique goldenStitch asset
var stitchAsset = self.attachAsset('goldenStitch', {
anchorX: 0.5,
anchorY: 0.5
});
stitchAsset.width = 120;
stitchAsset.height = 120;
// Evasive movement parameters
self.x = 2048 / 2;
self.y = 600 + Math.random() * 1000;
self.lastX = self.x;
self.lastY = self.y;
self.targetX = self.x;
self.targetY = self.y;
self.moveTimer = 0;
self.moveInterval = 30 + Math.floor(Math.random() * 40); // frames between moves
self.speed = 18 + Math.random() * 8; // pixels per frame, fast!
self.evasionRadius = 400; // how far it jumps per move
self.interactive = true; // so it can be caught
// Make it hard to tap: only allow catching if tap is very close to center
self.down = function (x, y, obj) {
// Only allow catching if tap is within 60px of center
var dx = x - self.x;
var dy = y - self.y;
if (dx * dx + dy * dy < 60 * 60) {
// Player caught the stitch, win!
if (typeof timer !== "undefined" && timer) {
LK.clearInterval(timer);
timer = null;
}
LK.showYouWin();
}
};
// Evasive movement: picks a new random target, tweens there, repeats
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
self.moveTimer++;
// If close to target or time to pick new target, pick a new one
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 20 || self.moveTimer > self.moveInterval) {
// Pick a new target far from current, but inside screen
var angle = Math.random() * Math.PI * 2;
var radius = self.evasionRadius * (0.5 + Math.random() * 0.7);
var tx = self.x + Math.cos(angle) * radius;
var ty = self.y + Math.sin(angle) * radius;
// Clamp to screen bounds (avoid top 200, bottom 400)
tx = Math.max(100, Math.min(2048 - 100, tx));
ty = Math.max(200, Math.min(2732 - 400, ty));
self.targetX = tx;
self.targetY = ty;
self.moveTimer = 0;
self.moveInterval = 24 + Math.floor(Math.random() * 32);
// Tween to new target
tween(self, {
x: self.targetX,
y: self.targetY
}, {
duration: 400 + Math.random() * 200,
easing: tween.cubicInOut
});
}
};
return self;
});
// Rocket class for background animation
var Rocket = Container.expand(function () {
var self = Container.call(this);
var rocketAsset = self.attachAsset('rocket', {
anchorX: 0.5,
anchorY: 1 // Anchor at the bottom of the rocket
});
// Set scale (can be randomized)
var scale = 0.6 + Math.random() * 0.4;
rocketAsset.scaleX = scale;
rocketAsset.scaleY = scale;
self.width = rocketAsset.width * scale;
self.height = rocketAsset.height * scale;
// Start just off the bottom edge
self.y = 2732 + self.height;
// Set random horizontal position (avoid edges)
self.x = 100 + Math.random() * (2048 - 200);
// Set speed (pixels per frame)
self.speed = 5 + Math.random() * 3;
// No interaction
self.interactive = false;
// Track lastY for event logic if needed
self.lastY = self.y;
// Update method for movement
self.update = function () {
self.lastY = self.y;
self.y -= self.speed;
// If off the top edge, destroy
if (self.y < -self.height) {
if (self.parent) self.parent.removeChild(self);
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Bird assets for background animation (use two different images)
// --- Game Variables ---
// Import tween plugin for animations
var currentQuestion = null; // Holds the current math question object
var answerDigits = []; // Array of selected digit values (as strings)
var digitCubes = []; // Array of digit cube objects (0-9)
var answerBox = null; // The answer drop zone
var questionText = null; // The question display
var timerText = null; // Timer display
var timer = null; // Timer interval id
var timeLeft = 60; // Total seconds for the game
var timerBar = null; // Visual timer bar
var timerBarBg = null; // Timer bar background
var timerBarWidth = 1200; // Width of the timer bar
var timerBarHeight = 60; // Height of the timer bar
var timerBarX = 2048 / 2 - timerBarWidth / 2;
var timerBarY = 240;
var timerBarColor = 0xFF3333;
var timerBarBgColor = 0x222222;
var timerBarPadding = 8;
// Removed hero and drag logic; input is now by clicking digit cubes
var score = 0; // Player score
// --- Bird Animation Variables ---
var birds = []; // Array to hold active bird objects
var birdSpawnTimer = 0; // Timer for spawning birds
var birdSpawnInterval = 120; // Frames between bird spawns (2 seconds at 60fps)
// --- Rocket Animation Variables ---
var rockets = []; // Array to hold active rocket objects
var rocketSpawnTimer = 0; // Timer for spawning rockets
var rocketSpawnInterval = 240; // Frames between rocket spawns (4 seconds at 60fps)
// --- Background Image ---
var bgImage = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
game.addChildAt(bgImage, 0); // Add as background
// --- Joker State ---
var jokers = [{
used: false,
label: "First Digit",
color: 0x00cc00
}, {
used: false,
label: "Remove Wrong",
color: 0x00cc00
}, {
used: false,
label: "Skip",
color: 0x00cc00
}];
var jokerButtons = [];
// --- Utility Functions ---
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Generates a random math question object: {text, answer}
function generateQuestion() {
var ops = ['+', '-', '×', '÷'];
var op = ops[randomInt(0, ops.length - 1)];
var a, b, text, answer;
if (op === '+') {
a = randomInt(1, 99);
b = randomInt(1, 99);
answer = a + b;
} else if (op === '-') {
a = randomInt(10, 99);
b = randomInt(1, a);
answer = a - b;
} else if (op === '×') {
a = randomInt(2, 12);
b = randomInt(2, 12);
answer = a * b;
} else {
// ÷
b = randomInt(2, 12);
answer = randomInt(2, 12);
a = b * answer;
}
text = a + " " + op + " " + b + " = ?";
return {
text: text,
answer: answer
};
}
// Resets the answer input and updates the answer box display
function resetAnswer() {
answerDigits = [];
updateAnswerBox();
}
// Updates the answer box text to show current input
function updateAnswerBox() {
if (answerBox && answerBox.textObj) {
answerBox.textObj.setText(answerDigits.length ? answerDigits.join('') : "");
}
}
// Starts a new question
function startNewQuestion() {
if (typeof updateStatsText === "function") updateStatsText();
if (timer) {
LK.clearInterval(timer);
}
currentQuestion = generateQuestion();
questionText.setText(currentQuestion.text);
resetAnswer();
// Reset digit cubes visibility for new question
for (var d = 0; d < digitCubes.length; d++) {
digitCubes[d].visible = true;
}
// Do not reset timeLeft here; timer is for the whole game
// Only set timer if not already running
if (!timer) {
timerText.setText("⏰ " + timeLeft);
timerBar.width = timerBarWidth;
timer = LK.setInterval(function () {
timeLeft--;
timerText.setText("⏰ " + timeLeft);
// Update timer bar width
timerBar.width = Math.max(0, timerBarWidth * (timeLeft / 60));
// --- Auto-drop two non-answer digits if timer < 20s ---
if (timeLeft === 20) {
// Find digits not in the answer
var ansStr = currentQuestion.answer + "";
var digitsInAnswer = {};
for (var k = 0; k < ansStr.length; k++) {
digitsInAnswer[ansStr[k]] = true;
}
var toDrop = [];
for (var d = 0; d < digitCubes.length; d++) {
if (!digitCubes[d].visible) continue;
if (!digitsInAnswer.hasOwnProperty(digitCubes[d].digit + "")) {
toDrop.push(digitCubes[d]);
if (toDrop.length === 2) break;
}
}
// Animate and hide the cubes
for (var i = 0; i < toDrop.length; i++) {
(function (cube) {
tween(cube, {
y: 2900
}, {
duration: 1600,
// Slower drop effect (was 700)
easing: tween.cubicIn,
onFinish: function onFinish() {
cube.visible = false;
}
});
})(toDrop[i]);
}
}
if (timeLeft <= 0) {
LK.clearInterval(timer);
timer = null;
timerBar.width = 0;
if (typeof updateStatsText === "function") updateStatsText();
LK.showGameOver();
}
}, 1000);
}
}
// Checks the answer and proceeds accordingly
function checkAnswer() {
var guess = parseInt(answerDigits.join(''));
if (guess === currentQuestion.answer) {
score++;
// Show 'Tebrikler' popup
var congratsPopup = new Container();
var popupBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5
});
popupBg.width = 800;
popupBg.height = 400;
popupBg.tint = 0x8720fe;
congratsPopup.addChild(popupBg);
var popupText = new Text2("Congratulations!", {
size: 140,
fill: 0xffffff
});
popupText.anchor.set(0.5, 0.5);
popupText.x = 0;
popupText.y = -40;
congratsPopup.addChild(popupText);
var popupSubText = new Text2("Tap to continue", {
size: 60,
fill: 0xffffff
});
popupSubText.anchor.set(0.5, 0.5);
popupSubText.x = 0;
popupSubText.y = 90;
congratsPopup.addChild(popupSubText);
congratsPopup.x = 2048 / 2;
congratsPopup.y = 1200;
// Block input to game while popup is up
congratsPopup.interactive = true;
congratsPopup.down = function () {
// Remove popup
if (congratsPopup.parent) congratsPopup.parent.removeChild(congratsPopup);
timeLeft = 60; // Reset timer to 60 seconds
if (timer) {
LK.clearInterval(timer);
timer = null;
}
startNewQuestion();
};
game.addChild(congratsPopup);
} else {
LK.clearInterval(timer);
timer = null;
if (timerBar) timerBar.width = 0;
// Show correct answer in the answer box before game over
if (answerBox && answerBox.textObj) {
answerBox.textObj.setText("Correct: " + currentQuestion.answer);
}
LK.setTimeout(function () {
if (typeof updateStatsText === "function") updateStatsText();
LK.showGameOver();
}, 1200);
}
}
// --- UI Setup ---
// --- Question Box (purple) centered between timer and answer box ---
var questionBox = new Container();
var questionBoxAsset = LK.getAsset('questionBox', {
anchorX: 0.5,
anchorY: 0.5
});
questionBoxAsset.width = 600;
questionBoxAsset.height = 180;
questionBox.addChild(questionBoxAsset);
// Place questionBox between timerText (y=20, height~160) and answerBox (y=900, height=200)
// Let's center it at y = (timerBarY + answerBox.y) / 2, but visually, a bit above answerBox
questionBox.x = 2048 / 2;
questionBox.y = (timerBarY + 900) / 2 - 60; // visually balanced
questionText = new Text2("", {
size: 120,
fill: 0xFFFFFF
});
questionText.anchor.set(0.5, 0.5);
questionText.x = 0;
questionText.y = 0;
questionBox.addChild(questionText);
game.addChild(questionBox);
// Timer at top center, larger and more visible
timerText = new Text2("⏰ 60", {
size: 160,
fill: 0xFF3333,
fontWeight: "bold"
});
timerText.anchor.set(0.5, 0);
timerText.x = 2048 / 2;
// Move timerText higher to avoid overlap with questionText
timerText.y = 20;
game.addChild(timerText);
// Timer bar background
timerBarBg = LK.getAsset('timerBarBg', {
anchorX: 0,
anchorY: 0
});
timerBarBg.width = timerBarWidth + timerBarPadding * 2;
timerBarBg.height = timerBarHeight + timerBarPadding * 2;
timerBarBg.x = timerBarX - timerBarPadding;
timerBarBg.y = timerBarY - timerBarPadding;
game.addChild(timerBarBg);
// Timer bar (foreground)
timerBar = LK.getAsset('timerBar', {
anchorX: 0,
anchorY: 0
});
timerBar.width = timerBarWidth;
timerBar.height = timerBarHeight;
timerBar.x = timerBarX;
timerBar.y = timerBarY;
game.addChild(timerBar);
// --- Hard Mode: Always enabled, no toggle button ---
// Joker buttons (right side, vertically spaced)
var jokerStartY = 400;
var jokerSpacing = 220;
for (var j = 0; j < 3; j++) {
var jokerBtn = new Container();
var jokerAssetName = j === 0 ? 'joker1' : j === 1 ? 'joker2' : 'joker3';
var btnAsset = LK.getAsset(jokerAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
btnAsset.width = 180;
btnAsset.height = 180;
btnAsset.tint = jokers[j].color;
jokerBtn.addChild(btnAsset);
var btnText = new Text2(jokers[j].label, {
size: 38,
fill: 0xffffff
});
btnText.anchor.set(0.5, 0.5);
btnText.x = 0;
btnText.y = 0;
jokerBtn.addChild(btnText);
jokerBtn.x = 2048 - 180;
jokerBtn.y = jokerStartY + j * jokerSpacing;
jokerBtn.jokerIndex = j;
// Joker button logic
jokerBtn.down = function (idx) {
return function (x, y, obj) {
if (jokers[idx].used) return;
jokers[idx].used = true;
// Change color to red
jokerButtons[idx].children[0].tint = 0xcc0000;
// Joker 1: Fill first digit
if (idx === 0) {
var ansStr = currentQuestion.answer + "";
if (answerDigits.length < ansStr.length) {
answerDigits = [ansStr[0]];
updateAnswerBox();
}
}
// Joker 2: Remove two incorrect digits from cubes
else if (idx === 1) {
var ansStr2 = currentQuestion.answer + "";
var digitsInAnswer = {};
for (var k = 0; k < ansStr2.length; k++) {
digitsInAnswer[ansStr2[k]] = true;
}
var removed = 0;
for (var d = 0; d < digitCubes.length; d++) {
if (!digitsInAnswer.hasOwnProperty(digitCubes[d].digit + "") && removed < 2) {
digitCubes[d].visible = false;
removed++;
}
}
}
// Joker 3: Skip to next question
else if (idx === 2) {
startNewQuestion();
}
};
}(j);
jokerButtons.push(jokerBtn);
game.addChild(jokerBtn);
}
// Answer box in center
answerBox = new Container();
var boxAsset = LK.getAsset('answerBox', {
anchorX: 0.5,
anchorY: 0.5
});
boxAsset.width = 400;
boxAsset.height = 200;
answerBox.addChild(boxAsset);
answerBox.x = 2048 / 2;
answerBox.y = 900;
answerBox.textObj = new Text2("", {
size: 120,
fill: 0x000000
});
answerBox.textObj.anchor.set(0.5, 0.5);
answerBox.textObj.x = 0;
answerBox.textObj.y = 0;
answerBox.addChild(answerBox.textObj);
game.addChild(answerBox);
// Digit cubes (0-9) at bottom, spaced evenly, now clickable
var cubeSpacing = 180;
var startX = (2048 - (cubeSpacing * 10 - 40)) / 2;
for (var i = 0; i < 10; i++) {
var cube = new Container();
var asset = LK.getAsset('balloon', {
anchorX: 0.5,
anchorY: 0.5
});
asset.width = 220;
asset.height = 220;
cube.addChild(asset);
var txt = new Text2(i + "", {
size: 140,
fill: 0x000000
});
txt.anchor.set(0.5, 0.5);
txt.x = 0;
txt.y = 0;
cube.addChild(txt);
cube.x = startX + i * cubeSpacing;
cube.y = 2400;
cube.digit = i;
// Add click/tap handler
cube.down = function (digit) {
return function (x, y, obj) {
// Only allow input if we haven't reached the required number of digits
if (answerDigits.length < (currentQuestion.answer + "").length) {
answerDigits.push(digit + "");
updateAnswerBox();
// If we've reached the required number of digits, check the answer
if (answerDigits.length === (currentQuestion.answer + "").length) {
checkAnswer();
}
}
// If already at max digits, ignore further input
};
}(i);
digitCubes.push(cube);
game.addChild(cube);
}
// --- Delete Button (bottom left) ---
var deleteBtn = new Container();
var deleteAsset = LK.getAsset('deleteBtn', {
anchorX: 0.5,
anchorY: 0.5
});
deleteAsset.width = 180;
deleteAsset.height = 180;
deleteBtn.addChild(deleteAsset);
// Optional: Add a "←" icon/text on top of the button for clarity
var delTxt = new Text2("←", {
size: 120,
fill: 0xffffff
});
delTxt.anchor.set(0.5, 0.5);
delTxt.x = 0;
delTxt.y = 0;
deleteBtn.addChild(delTxt);
// Place at bottom left, but not in the top left 100x100 reserved area
deleteBtn.x = 120;
deleteBtn.y = 2550;
deleteBtn.interactive = true;
deleteBtn.down = function (x, y, obj) {
if (answerDigits.length > 0) {
answerDigits.pop();
updateAnswerBox();
}
};
game.addChild(deleteBtn);
// Hero character and drag logic removed; input is now by clicking digit cubes
// --- Start Game ---
startNewQuestion();
// --- Golden Stitch setup ---
var goldenStitch = new GoldenStitch();
goldenStitch.x = 2048 / 2;
goldenStitch.y = 900;
game.addChildAt(goldenStitch, 2); // Above birds, below main UI
// --- Stats Tracking ---
var seriesCount = 0; // How many questions answered (right or wrong)
var goldenSnitchCaught = 0; // Total golden snitch caught
// --- Stats Display (bottom right) ---
// --- Stats Display (bottom right) with background ---
var statsBg = LK.getAsset('timerBarBg', {
anchorX: 1,
anchorY: 1
});
statsBg.width = 520; // widened for more left coverage
statsBg.height = 180;
statsBg.tint = 0x222222;
statsBg.alpha = 0.85;
statsBg.x = 2048 - 20;
statsBg.y = 2732 - 20;
game.addChild(statsBg);
var statsText = new Text2("", {
size: 60,
fill: 0xFFFFFF
});
statsText.anchor.set(1, 1); // bottom right
statsText.x = 2048 - 40;
statsText.y = 2732 - 40;
game.addChild(statsText);
function updateStatsText() {
if (typeof statsText !== "undefined" && statsText && typeof statsText.setText === "function") {
statsText.setText("Streak: " + seriesCount + "\nGolden Snitch: " + goldenSnitchCaught);
}
}
updateStatsText();
// --- Golden Snitch Win Handler Patch ---
var _origGoldenStitchDown = goldenStitch.down;
goldenStitch.down = function (x, y, obj) {
var dx = x - goldenStitch.x;
var dy = y - goldenStitch.y;
if (dx * dx + dy * dy < 60 * 60) {
goldenSnitchCaught++;
updateStatsText();
if (typeof timer !== "undefined" && timer) {
LK.clearInterval(timer);
timer = null;
}
LK.showYouWin();
}
};
// --- Patch checkAnswer to increment seriesCount only ---
var _origCheckAnswer = checkAnswer;
checkAnswer = function checkAnswer() {
seriesCount++;
updateStatsText();
_origCheckAnswer();
};
// --- Patch game over to reset seriesCount only ---
var _origShowGameOver = LK.showGameOver;
LK.showGameOver = function () {
updateStatsText();
seriesCount = 0;
_origShowGameOver();
};
// --- Bird background animation logic ---
game.update = function () {
// Bird spawn logic
birdSpawnTimer++;
if (birdSpawnTimer >= birdSpawnInterval) {
birdSpawnTimer = 0;
// Spawn a new bird
var bird = new Bird();
// Place behind all main game elements, but above background
game.addChildAt(bird, 1);
birds.push(bird);
// Randomize next spawn interval (between 1.5s and 3.5s)
birdSpawnInterval = 90 + Math.floor(Math.random() * 120);
}
// Update all birds
for (var i = birds.length - 1; i >= 0; i--) {
if (birds[i].update) birds[i].update();
// Remove from array if destroyed
if (!birds[i].parent) {
birds.splice(i, 1);
}
}
// Rocket spawn logic
rocketSpawnTimer++;
if (rocketSpawnTimer >= rocketSpawnInterval) {
rocketSpawnTimer = 0;
// Spawn a new rocket
var rocket = new Rocket();
// Place behind all main game elements, but above background
game.addChildAt(rocket, 1);
rockets.push(rocket);
// Randomize next spawn interval (between 3s and 6s)
rocketSpawnInterval = 180 + Math.floor(Math.random() * 180);
}
// Update all rockets
for (var i = rockets.length - 1; i >= 0; i--) {
if (rockets[i].update) rockets[i].update();
// Remove from array if destroyed
if (!rockets[i].parent) {
rockets.splice(i, 1);
}
}
// Update golden stitch movement
if (goldenStitch && goldenStitch.update) {
goldenStitch.update();
}
};
// --- Hard Mode Digit Cube Movement: Always enabled, slower movement ---
var hardModeMoveTimer = null;
function updateHardModeMovement() {
// Movement speed: slow at start, fast at end
// At 60s: 1200ms, at 0s: 350ms
var minDuration = 350;
var maxDuration = 1200;
var t = Math.max(0, Math.min(1, timeLeft / 60)); // 1 at start, 0 at end
var moveDuration = Math.round(minDuration + (maxDuration - minDuration) * t);
// Helper to check overlap between two cubes
function cubesOverlap(cubeA, xA, yA, cubeB, xB, yB) {
var rA = 110; // half of 220 (cube size)
var rB = 110;
var dx = xA - xB;
var dy = yA - yB;
var distSq = dx * dx + dy * dy;
var minDist = rA + rB + 10; // 10px margin
return distSq < minDist * minDist;
}
var placedPositions = [];
// Helper to check overlap with answer box
function cubeOverlapsAnswerBox(x, y) {
var rCube = 110;
var rBox = Math.max(answerBox.width, answerBox.height) / 2;
var dx = x - answerBox.x;
var dy = y - answerBox.y;
var distSq = dx * dx + dy * dy;
var minDist = rCube + rBox + 10;
return distSq < minDist * minDist;
}
for (var i = 0; i < digitCubes.length; i++) {
// Only move visible cubes
if (!digitCubes[i].visible) continue;
var minX = 100;
var maxX = 2048 - 100;
var minY = 2200;
var maxY = answerBox.y - 120;
var tryCount = 0;
var targetX, targetY, overlap, boxOverlap;
do {
targetX = randomInt(minX, maxX);
targetY = randomInt(minY, maxY);
overlap = false;
boxOverlap = cubeOverlapsAnswerBox(targetX, targetY);
for (var j = 0; j < placedPositions.length; j++) {
if (cubesOverlap(digitCubes[i], targetX, targetY, placedPositions[j].cube, placedPositions[j].x, placedPositions[j].y)) {
overlap = true;
break;
}
}
tryCount++;
} while ((overlap || boxOverlap) && tryCount < 30);
placedPositions.push({
cube: digitCubes[i],
x: targetX,
y: targetY
});
tween(digitCubes[i], {
x: targetX,
y: targetY
}, {
duration: moveDuration,
easing: tween.quadraticInOut
});
}
// Bounce logic: if cubes overlap after tween, reverse their direction
for (var i = 0; i < digitCubes.length; i++) {
if (!digitCubes[i].visible) continue;
for (var j = i + 1; j < digitCubes.length; j++) {
if (!digitCubes[j].visible) continue;
var dx = digitCubes[i].x - digitCubes[j].x;
var dy = digitCubes[i].y - digitCubes[j].y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 220) {
// Bounce: move both cubes away from each other
var angle = Math.atan2(dy, dx);
var moveDist = 30;
var nx = Math.cos(angle) * moveDist;
var ny = Math.sin(angle) * moveDist;
digitCubes[i].x += nx;
digitCubes[i].y += ny;
digitCubes[j].x -= nx;
digitCubes[j].y -= ny;
}
}
// Bounce off answer box
var dxBox = digitCubes[i].x - answerBox.x;
var dyBox = digitCubes[i].y - answerBox.y;
var distBox = Math.sqrt(dxBox * dxBox + dyBox * dyBox);
var minDistBox = 110 + Math.max(answerBox.width, answerBox.height) / 2 + 10;
if (distBox < minDistBox) {
// Move cube away from answer box
var angleBox = Math.atan2(dyBox, dxBox);
var moveDistBox = minDistBox - distBox + 10;
digitCubes[i].x = answerBox.x + Math.cos(angleBox) * (minDistBox + 10);
digitCubes[i].y = answerBox.y + Math.sin(angleBox) * (minDistBox + 10);
}
}
}
// Set up interval for hard mode movement (interval will be dynamically updated)
var hardModeMoveTimer = null;
function scheduleHardModeMove() {
// Movement speed: slow at start, fast at end
var minInterval = 350;
var maxInterval = 1200;
var t = Math.max(0, Math.min(1, timeLeft / 60));
var moveInterval = Math.round(minInterval + (maxInterval - minInterval) * t);
if (hardModeMoveTimer) LK.clearTimeout(hardModeMoveTimer);
updateHardModeMovement();
hardModeMoveTimer = LK.setTimeout(scheduleHardModeMove, moveInterval);
}
scheduleHardModeMove();
// When starting a new question, do not reset cube positions (always hard mode)
var _origStartNewQuestion = startNewQuestion;
startNewQuestion = function startNewQuestion() {
_origStartNewQuestion();
};
sky. In-Game asset. 2d. High contrast. No shadows
cloud. In-Game asset. 2d. High contrast. No shadows
grey cloud. In-Game asset. 2d. High contrast. No shadows
angry bird. In-Game asset. 2d. High contrast. No shadows
yellow angry bird. In-Game asset. 2d. High contrast. No shadows
golden snitch. In-Game asset. 2d. High contrast. No shadows
trashcan. In-Game asset. 2d. High contrast. No shadows
Rocketship. In-Game asset. 2d. High contrast. No shadows
A sign with oval corners. Light blue. In-Game asset. 2d. High contrast. No shadows