User prompt
2 bölümü hazırla ilk bölüm bittiğinde level2 yazısı ve tekrar ready yazısı gelsin ( level 1 i de böle yap). bu sefer paket sıralarının yanında gelme sürelerini de ayarla levelin kodlarında sabit olsun yine. tek seferlik rasgele aralıklar ekle çoğunlukla 1,72 saniye biraz 2,15 saniye çok az da 1,29 saniye aralıklarla paketler gelsin
User prompt
hazır demeden geri sayım başlamasın
User prompt
oyun başı bir hazır butonu koy ve basınca oyunu başlat. level 1 arkaplanını da buna göre baştan ayarla butona basınca balşasın sadece
User prompt
level 1 sesi çalmıyor tekrar ekle arkaplan müziği
User prompt
ilk bölümde level1 sesi çalsın
User prompt
paket ve hedef boyutlarını %10 daha arttır
User prompt
paket texturelerini değiştir. mavi bluepacket, sarı yellowpacket, kırmızı redpacket, turuncu orangepacket
User prompt
konfeti efektini büyüt ve çok az da olsa diğer renklerin konfeti parçaları da patlayan kofetide gözüksün ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
hedef kutucukları ve gelen paketleri %20 daha büyüt
User prompt
tuttuğumuz paketler de imlece göre hareket etmeli karakterimizin tam ortasında değil dana ön kısmında durmalı ve dönme senkronizasyonları konumları yönleri iyi ayarlanmalı önünde tutuyormuş gibi ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
çok zor oldu 2 saniyede bir gelsin paketler. karakterimizi %30 büyüt, gelen paketleri %10 büyüt ve hedef kutucukları %20 büyüt.ve çok az bize doğru yaklaştır ekrandan çıkmasın kutucukların görüntüsü
User prompt
çok güzel. paketleri sadece karakterimizin üst hizasından aşşağı doğru indir ve hızlarını %15 arttır
Code edit (1 edits merged)
Please save this source code
User prompt
Color Box Rhythm
Initial prompt
hayali bir kare düşün oyunun tam ortasında karakterimiz de bu karenin ortasında bir daire. karakterimiz sürekli imlecimize bakmalı, sabit duruyor ve imlecimize doğru dönüyor olmalı. karenin köşelerine denk gelen yerlerde 4 farklı renkte hedef kutucuk var sarı mavi kırmızı turuncu. üstümüzden bize doğru yavaşca bu renklerde paketler düşecek. bu paketleri kucağımızda tuttuğumuzda imlecimizle tıkladığımızda elindeki paketi imlecimize doğru fırlatıcak. paketimiz kendi rengindeki kutucuğa değdığınde renkli konfetilerle patlamalı. bu bir ritim oyunu ilk bölümde sabit her saniye elimize bir kutu gelecek. elimize geldiği zaman önemli çünkü sonraki bölümlerde özel ritimler yazacağım sana ona göre tam ritme göre yukardan elimize paket gelmeli (yukarda doğması değil elimize geldiği an çök önemli ritim için nunu asla unutma) şimdilik 1 bölüm yapıyoruz ama. bölümler ve ritim altyapısını iyi hazırla. her bölümde üsten gelen paketlerin renklerinin sırası sabit olmalı hiç bir oyunda herkese aynı sabit bölümü oynat. bölümü oluştururken sen seç renklerin sırasını bölümün kodunda kayıtlı olsun herkes aynı sıralamayı oynamalı . ,ilk bölüm basit 30 saniye sürecek ve elimizde her saniye bir paket olacak şekilde yukardan yavaşca paketler inecek ve bizim imlecimize doğru direk olarak fırlatacak karakterimiz zaten sürekli bize dönük olacak sabit yerinde kucağındaki paketle birlikte dönecek. puan sistemi: doğru renkte kutucuğu vurduğumuzda 100 puan. attığımız paket ekran dışına çıkarsa yani doğru rengi vuramadığımız için konfetilerle patlamazsa -60 puan. kucağımızda kutu yokken tıklama yaparsak -15 puan. elimizde paket varken tekrar üstümüze paket gelirse üstümüze gelen paket yokolur ve -150 puan.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Bomb = Container.expand(function () { var self = Container.call(this); var bombGraphics = self.attachAsset('bomb', { anchorX: 0.5, anchorY: 0.5 }); self.isBomb = true; self.speed = 172.5; if (isInfiniteMode) { self.speed = 172.5 * 3.6; // 3.6x faster than normal speed (20% increase) } else if (isHellMode) { self.speed *= 4; // 4x speed in hell mode } self.caught = false; self.thrown = false; self.throwVelocityX = 0; self.throwVelocityY = 0; self.update = function () { if (self.thrown) { self.x += self.throwVelocityX; self.y += self.throwVelocityY; } else if (!self.caught) { self.y += self.speed * (1 / 60); } }; return self; }); var Character = Container.expand(function () { var self = Container.call(this); var characterGraphics = self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); self.heldPackage = null; self.targetRotation = 0; self.update = function () { var rotationDiff = self.targetRotation - self.rotation; while (rotationDiff > Math.PI) rotationDiff -= 2 * Math.PI; while (rotationDiff < -Math.PI) rotationDiff += 2 * Math.PI; self.rotation += rotationDiff * 0.1; if (self.heldPackage) { // Position package in front of character based on rotation var packageDistance = 90; // Distance in front of character var packageX = self.x + Math.cos(self.rotation) * packageDistance; var packageY = self.y + Math.sin(self.rotation) * packageDistance; // Smoothly tween package to new position for better visual flow tween(self.heldPackage, { x: packageX, y: packageY, rotation: self.rotation }, { duration: 100, easing: tween.easeOut }); } }; return self; }); var Confetti = Container.expand(function (colorValue) { var self = Container.call(this); var confettiGraphics = self.attachAsset('confetti', { anchorX: 0.5, anchorY: 0.5 }); confettiGraphics.tint = colorValue; self.velocityX = (Math.random() - 0.5) * 400; self.velocityY = (Math.random() - 0.5) * 400; self.life = 60; self.update = function () { self.x += self.velocityX * (1 / 60); self.y += self.velocityY * (1 / 60); self.velocityY += 300 * (1 / 60); self.life--; if (self.life <= 0) { self.alpha = 0; } }; return self; }); var Package = Container.expand(function (colorValue) { var self = Container.call(this); var assetName = 'yellowpacket'; if (colorValue === 0x0066ff) assetName = 'bluepacket';else if (colorValue === 0xff0000) assetName = 'redpacket';else if (colorValue === 0xff8800) assetName = 'orangepacket'; var packageGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.colorValue = colorValue || 0xffffff; self.speed = 172.5; // 150 * 1.15 = 15% increase if (isInfiniteMode) { self.speed = 172.5 * 3.6; // 3.6x faster than normal speed (20% increase) } else if (isHellMode) { self.speed *= 4; // 4x speed in hell mode } self.caught = false; self.thrown = false; self.throwVelocityX = 0; self.throwVelocityY = 0; self.update = function () { if (self.thrown) { self.x += self.throwVelocityX; self.y += self.throwVelocityY; } else if (!self.caught) { self.y += self.speed * (1 / 60); } }; return self; }); var TargetBox = Container.expand(function (colorValue) { var self = Container.call(this); var assetName = 'targetYellow'; if (colorValue === 0x0066ff) assetName = 'targetBlue';else if (colorValue === 0xff0000) assetName = 'targetRed';else if (colorValue === 0xff8800) assetName = 'targetOrange'; var targetGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.colorValue = colorValue; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ var gameWidth = 2048; var gameHeight = 2732; var arenaSize = 1600; var arenaX = gameWidth / 2; var arenaY = gameHeight / 2; // Game arena var arena = game.addChild(LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5, x: arenaX, y: arenaY })); // Character var character = game.addChild(new Character()); character.x = arenaX; character.y = arenaY; // Target boxes at corners var targets = []; var targetColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800]; // yellow, blue, red, orange var targetPositions = [{ x: arenaX - arenaSize / 2 + 180, y: arenaY - arenaSize / 2 + 180 }, // top-left { x: arenaX + arenaSize / 2 - 180, y: arenaY - arenaSize / 2 + 180 }, // top-right { x: arenaX - arenaSize / 2 + 180, y: arenaY + arenaSize / 2 - 180 }, // bottom-left { x: arenaX + arenaSize / 2 - 180, y: arenaY + arenaSize / 2 - 180 } // bottom-right ]; for (var i = 0; i < 4; i++) { var target = game.addChild(new TargetBox(targetColors[i])); target.x = targetPositions[i].x; target.y = targetPositions[i].y; targets.push(target); } // Game state var packages = []; var confettiParticles = []; var gameTime = 0; var gameDuration = 30000; // 30 seconds for levels 1-3, 240000 for final level var packageSpawnInterval = 2000; // 2 seconds var lastPackageSpawn = 0; var gameStarted = false; var gameEnded = false; var gameReady = false; var currentLevel = 1; var levelCompleted = false; var finalLevelStarted = false; var isHellMode = false; var hellModeSelected = false; var isInfiniteMode = false; var infiniteModeSelected = false; var infiniteMusicTimer = 0; var infiniteMusicInterval = 108000; // 108 seconds in milliseconds // Arena animation variables var arenaAnimationTimes = [11, 23, 31, 41, 53, 63, 75, 85, 96, 107, 116, 128, 137, 149, 157, 169, 180, 190, 202, 214, 222, 232, 241, 253, 263, 271, 280, 290, 301, 310, 321, 329, 339, 349, 361, 370, 382, 394, 405, 414, 423, 435, 444, 452, 461, 471, 479, 490, 500, 510, 519, 527, 538, 546, 558, 567, 575, 584, 596, 608]; var currentArenaAnimationIndex = 0; var isArenaAnimating = false; var arenaAnimationStep = 0; // Bomb mechanic variables var lastBombSpawn = 0; var bombSpawnInterval = 3000; // 3 seconds var bombHoldTimer = 0; var bombWarningText = null; // Predetermined color sequence for level 1 var colorSequenceLevel1 = [0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff0000, 0x0066ff, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xff0000, 0x0066ff, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff8800, 0xff0000, 0xffff00, 0x0066ff]; // Level 2 color sequence and timing intervals (in milliseconds) var colorSequenceLevel2 = [0xff0000, 0xff8800, 0x0066ff, 0xffff00, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0x0066ff, 0xff8800, 0xff0000, 0x0066ff, 0xffff00, 0xff8800, 0x0066ff, 0xffff00]; var timingIntervalsLevel2 = [1720, 2150, 1290, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 1720, 2150, 1720, 1720, 1290, 1720, 1720, 1720, 1720, 1720, 2150, 1720, 1290]; // Level 3 color sequence and timing intervals (in milliseconds) var colorSequenceLevel3 = [0x0066ff, 0xffff00, 0xff8800, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0x0066ff, 0xffff00]; var timingIntervalsLevel3 = [1720, 1720, 2150, 1290, 1720, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 1720, 2150, 1290, 1720]; // Final level color sequence (longer sequence for 4 minutes) var colorSequenceFinal = [0xff0000, 0x0066ff, 0xffff00, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0x0066ff, 0xff0000]; var currentSequenceIndex = 0; var currentTimingIndex = 0; // UI var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var timeTxt = new Text2('Time: 30', { size: 60, fill: 0xFFFFFF }); timeTxt.anchor.set(1, 0); LK.gui.topRight.addChild(timeTxt); // Level display var levelText = new Text2('LEVEL 1', { size: 120, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0.5); levelText.x = gameWidth / 2; levelText.y = gameHeight / 2 - 250; game.addChild(levelText); // Ready button var readyButton = LK.getAsset('ready', { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2, y: gameHeight / 2 }); readyButton.tint = 0x666666; // Dark grey passive effect readyButton.alpha = 0.5; // Additional passive effect game.addChild(readyButton); // Hell mode selection UI var normalModeButton = new Text2('NORMAL', { size: 120, fill: 0x00FF00 }); normalModeButton.anchor.set(0.5, 0.5); normalModeButton.x = gameWidth / 2 - 220; normalModeButton.y = gameHeight / 2 + 130; game.addChild(normalModeButton); var hellModeButton = LK.getAsset('hell', { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2 + 220, y: gameHeight / 2 + 130, scaleX: 2, scaleY: 2 }); game.addChild(hellModeButton); // Infinite button (only for level 1) var infiniteButton = LK.getAsset('infinite1', { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2, y: gameHeight / 2 + 430, scaleX: 4.76, scaleY: 4.76 }); game.addChild(infiniteButton); // Infinite button animation variables var infiniteTextures = ['infinite1', 'infinite2', 'infinite3', 'infinite4', 'infinite5', 'infinite6', 'infinite7', 'infinite8']; var currentInfiniteTextureIndex = 0; var infiniteAnimationTimer = 0; var infiniteAnimationSpeed = 4; // Change texture every 4 frames (about 15 fps at 60fps) // Helper functions function getColorName(colorValue) { switch (colorValue) { case 0xffff00: return 'Yellow'; case 0x0066ff: return 'Blue'; case 0xff0000: return 'Red'; case 0xff8800: return 'Orange'; default: return 'Unknown'; } } function spawnPackage() { var currentColorSequence; var packageColor; if (isInfiniteMode) { // Infinite mode: completely random colors var randomColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800]; packageColor = randomColors[Math.floor(Math.random() * randomColors.length)]; } else { if (currentLevel === 1) { currentColorSequence = colorSequenceLevel1; } else if (currentLevel === 2) { currentColorSequence = colorSequenceLevel2; } else if (currentLevel === 3) { currentColorSequence = colorSequenceLevel3; } else { currentColorSequence = colorSequenceFinal; } if (currentSequenceIndex >= currentColorSequence.length) return; packageColor = currentColorSequence[currentSequenceIndex]; currentSequenceIndex++; } var newPackage = new Package(packageColor); newPackage.x = character.x; // Spawn directly above character newPackage.y = arenaY - arenaSize / 2 - 200; // Spawn higher above arena packages.push(newPackage); game.addChild(newPackage); // Hell mode: 20% chance to spawn a second package 0.05 seconds later if (isHellMode && Math.random() < 0.2) { LK.setTimeout(function () { // Get next color from sequence for the second package var secondPackageColor; if (currentSequenceIndex < currentColorSequence.length) { secondPackageColor = currentColorSequence[currentSequenceIndex]; currentSequenceIndex++; } else if (currentLevel === 4) { // For final level, loop back to beginning currentSequenceIndex = 0; secondPackageColor = currentColorSequence[currentSequenceIndex]; currentSequenceIndex++; } else { // Use random color if sequence exhausted var randomColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800]; secondPackageColor = randomColors[Math.floor(Math.random() * randomColors.length)]; } var secondPackage = new Package(secondPackageColor); secondPackage.x = character.x; secondPackage.y = arenaY - arenaSize / 2 - 200; packages.push(secondPackage); game.addChild(secondPackage); }, 150); // 0.15 seconds = 150ms } } function spawnBomb() { var newBomb = new Bomb(); newBomb.x = character.x; // Spawn directly above character newBomb.y = arenaY - arenaSize / 2 - 200; // Spawn higher above arena packages.push(newBomb); game.addChild(newBomb); } function createConfettiExplosion(x, y, color) { var allColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800]; // yellow, blue, red, orange // Create more particles for bigger explosion (25 instead of 15) for (var i = 0; i < 25; i++) { var confettiColor; if (i < 18) { // Most particles (72%) use the main color confettiColor = color; } else { // Some particles (28%) use random other colors confettiColor = allColors[Math.floor(Math.random() * allColors.length)]; } var confetti = new Confetti(confettiColor); confetti.x = x; confetti.y = y; // Scale up confetti particles by 1.5x for bigger effect tween(confetti, { scaleX: 1.5, scaleY: 1.5 }, { duration: 50, easing: tween.easeOut }); confettiParticles.push(confetti); game.addChild(confetti); } } function startArenaAnimation() { if (isArenaAnimating) return; isArenaAnimating = true; arenaAnimationStep = 0; // Start animation sequence animateArenaStep(); } function animateArenaStep() { var arenaAssets = ['arena2', 'arena3', 'arena4']; if (arenaAnimationStep < arenaAssets.length) { // Change to next animation frame var newArena = LK.getAsset(arenaAssets[arenaAnimationStep], { anchorX: 0.5, anchorY: 0.5, x: arenaX, y: arenaY, scaleX: 12, // Scale to match original arena size scaleY: 12 }); // Add new arena behind all other objects (at index 1, after original arena) game.addChildAt(newArena, 1); // Auto-remove after 1.6 seconds LK.setTimeout(function () { newArena.destroy(); }, 1600); arenaAnimationStep++; // Schedule next step after 400ms LK.setTimeout(function () { animateArenaStep(); }, 400); } else { // Animation complete isArenaAnimating = false; } } function createFireExplosion(x, y) { var flameColors = [0xFF4500, 0xFF6347, 0xFF0000, 0xFFA500, 0xFFD700]; // Orange, tomato, red, orange, gold // Create 30 flame particles for explosion effect for (var i = 0; i < 30; i++) { var flameColor = flameColors[Math.floor(Math.random() * flameColors.length)]; var flame = new Confetti(flameColor); flame.x = x; flame.y = y; // Enhanced velocities for explosive effect flame.velocityX = (Math.random() - 0.5) * 600; flame.velocityY = (Math.random() - 0.5) * 600; flame.life = 90; // Medium life for flames // Scale and fade effect using tween tween(flame, { scaleX: 2, scaleY: 2 }, { duration: 80, easing: tween.easeOut }); tween(flame, { alpha: 0 }, { duration: 1500, easing: tween.easeOut }); confettiParticles.push(flame); game.addChild(flame); } } function createFireworks() { var fireworksColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0x00ff00, 0xff00ff, 0x00ffff]; // Create multiple firework explosions across the screen for (var f = 0; f < 8; f++) { var fireworkX = Math.random() * gameWidth; var fireworkY = Math.random() * (gameHeight * 0.6) + gameHeight * 0.2; var fireworkColor = fireworksColors[Math.floor(Math.random() * fireworksColors.length)]; // Create 40 particles per firework for spectacular effect for (var i = 0; i < 40; i++) { var firework = new Confetti(fireworkColor); firework.x = fireworkX; firework.y = fireworkY; // Enhanced velocities for bigger explosion firework.velocityX = (Math.random() - 0.5) * 800; firework.velocityY = (Math.random() - 0.5) * 600 - 200; firework.life = 120; // Longer life for fireworks // Scale and fade effect using tween tween(firework, { scaleX: 2.5, scaleY: 2.5 }, { duration: 100, easing: tween.easeOut }); tween(firework, { alpha: 0 }, { duration: 2000, easing: tween.easeOut }); confettiParticles.push(firework); game.addChild(firework); } } } function checkPackageTargetCollision(packageObj, target) { var dx = packageObj.x - target.x; var dy = packageObj.y - target.y; var distance = Math.sqrt(dx * dx + dy * dy); // Orange target gets larger hitbox (50% larger than base 120 = 180) if (target.colorValue === 0xff8800) { return distance < 180; // Orange target gets bigger hitbox } return distance < 156; // Increased from 104 to 156 (1.5x scale) for other targets } function throwPackage(targetX, targetY) { if (!character.heldPackage) { // Empty click penalty LK.setScore(LK.getScore() - 15); LK.getSound('miss').play(); return; } var packageToThrow = character.heldPackage; character.heldPackage = null; // Clear bomb warning if it exists if (bombWarningText) { bombWarningText.destroy(); bombWarningText = null; } var dx = targetX - packageToThrow.x; var dy = targetY - packageToThrow.y; var distance = Math.sqrt(dx * dx + dy * dy); var speed = 800; packageToThrow.throwVelocityX = dx / distance * speed * (1 / 60); packageToThrow.throwVelocityY = dy / distance * speed * (1 / 60); packageToThrow.thrown = true; LK.getSound('throw').play(); } // Event handlers game.move = function (x, y, obj) { var dx = x - character.x; var dy = y - character.y; character.targetRotation = Math.atan2(dy, dx); }; game.down = function (x, y, obj) { if (!gameReady) { // Check infinite button first (only for level 1) if (currentLevel === 1) { var infiniteButtonX = gameWidth / 2; var infiniteButtonY = gameHeight / 2 + 430; var infiniteButtonWidth = 476; // 4.76x scale of 200px width = 952, so half is 476 var infiniteButtonHeight = 110; // 4.76x scale of 46.1px height = 219, so half is 110 if (x >= infiniteButtonX - infiniteButtonWidth && x <= infiniteButtonX + infiniteButtonWidth && y >= infiniteButtonY - infiniteButtonHeight && y <= infiniteButtonY + infiniteButtonHeight) { // Start infinite mode isInfiniteMode = true; infiniteModeSelected = true; hellModeSelected = true; // Skip mode selection since infinite mode is already chosen gameReady = true; gameStarted = true; gameTime = 0; lastPackageSpawn = 0; // Set score to 10000 for infinite mode LK.setScore(10000); // Clean up UI elements and stop animation if (infiniteButton && infiniteButton.parent) { infiniteButton.destroy(); infiniteButton = null; } // Clean up any queued infinite buttons from animation for (var q = infiniteButtonQueue.length - 1; q >= 0; q--) { if (infiniteButtonQueue[q] && infiniteButtonQueue[q].parent) { infiniteButtonQueue[q].destroy(); } } infiniteButtonQueue = []; // Clear the queue if (levelText && levelText.parent) { levelText.destroy(); } if (readyButton && readyButton.parent) { readyButton.destroy(); } if (normalModeButton && normalModeButton.parent) { normalModeButton.destroy(); } if (hellModeButton && hellModeButton.parent) { hellModeButton.destroy(); } // Start infinite mode music LK.playMusic('bgmusicinfinite'); return; } } // Check mode selection if not selected if (!hellModeSelected) { // Check normal mode button var normalButtonX = gameWidth / 2 - 220; var normalButtonY = gameHeight / 2 + 130; var normalButtonWidth = 150; var normalButtonHeight = 60; if (x >= normalButtonX - normalButtonWidth && x <= normalButtonX + normalButtonWidth && y >= normalButtonY - normalButtonHeight && y <= normalButtonY + normalButtonHeight) { isHellMode = false; hellModeSelected = true; normalModeButton.destroy(); hellModeButton.destroy(); // Hide infinite button when normal mode is selected if (infiniteButton && infiniteButton.parent) { infiniteButton.destroy(); infiniteButton = null; } // Clean up any queued infinite buttons from animation for (var q = infiniteButtonQueue.length - 1; q >= 0; q--) { if (infiniteButtonQueue[q] && infiniteButtonQueue[q].parent) { infiniteButtonQueue[q].destroy(); } } infiniteButtonQueue = []; // Clear the queue // Remove passive effect from ready button readyButton.tint = 0xFFFFFF; readyButton.alpha = 1; return; } // Check hell mode button var hellButtonX = gameWidth / 2 + 220; var hellButtonY = gameHeight / 2 + 130; var hellButtonWidth = 100; var hellButtonHeight = 100; if (x >= hellButtonX - hellButtonWidth && x <= hellButtonX + hellButtonWidth && y >= hellButtonY - hellButtonHeight && y <= hellButtonY + hellButtonHeight) { isHellMode = true; hellModeSelected = true; normalModeButton.destroy(); hellModeButton.destroy(); // Hide infinite button when hell mode is selected if (infiniteButton && infiniteButton.parent) { infiniteButton.destroy(); infiniteButton = null; } // Clean up any queued infinite buttons from animation for (var q = infiniteButtonQueue.length - 1; q >= 0; q--) { if (infiniteButtonQueue[q] && infiniteButtonQueue[q].parent) { infiniteButtonQueue[q].destroy(); } } infiniteButtonQueue = []; // Clear the queue // Remove passive effect from ready button readyButton.tint = 0xFFFFFF; readyButton.alpha = 1; return; } return; } // Check if clicked on ready button area (only after mode selected) if (hellModeSelected) { var buttonX = gameWidth / 2; var buttonY = gameHeight / 2; var buttonWidth = 200; var buttonHeight = 100; if (x >= buttonX - buttonWidth && x <= buttonX + buttonWidth && y >= buttonY - buttonHeight && y <= buttonY + buttonHeight) { gameReady = true; readyButton.destroy(); levelText.destroy(); } } return; } if (gameEnded) return; throwPackage(x, y); }; // Main game update game.update = function () { if (!gameReady) return; if (!gameStarted) { gameStarted = true; gameTime = 0; // Reset game time when starting lastPackageSpawn = 0; // Reset package spawn timer // Remove infinite button when game starts (level 1 only) if (currentLevel === 1 && infiniteButton && infiniteButton.parent) { infiniteButton.destroy(); infiniteButton = null; } if (currentLevel === 1) { LK.getSound('level1').play(); LK.playMusic('bgmusic'); } else if (currentLevel === 2) { LK.getSound('level2').play(); LK.playMusic('bgmusic'); } else if (currentLevel === 3) { LK.getSound('level3').play(); LK.playMusic('bgmusic3'); } else if (currentLevel === 4) { LK.getSound('final').play(); LK.playMusic('bgmusicfinal'); gameDuration = 240000; // 4 minutes for final level finalLevelStarted = true; } } if (gameEnded) return; // Arena animation trigger at predetermined times - works for all levels var currentGameTimeInSeconds = Math.floor(gameTime / 1000); if (currentArenaAnimationIndex < arenaAnimationTimes.length && currentGameTimeInSeconds >= arenaAnimationTimes[currentArenaAnimationIndex]) { startArenaAnimation(); currentArenaAnimationIndex++; } // Check for insufficient score in final level if (currentLevel === 4) { if (LK.getScore() < -200) { gameEnded = true; LK.showGameOver(); return; } } gameTime += 1000 / 60; // Increment game time only after ready if (isInfiniteMode) { var elapsedTime = Math.floor(gameTime / 1000); timeTxt.setText('Time: ' + elapsedTime); } else { var remainingTime = Math.max(0, Math.ceil((gameDuration - gameTime) / 1000)); timeTxt.setText('Time: ' + remainingTime); } // Infinite mode music timer if (isInfiniteMode) { infiniteMusicTimer += 1000 / 60; if (infiniteMusicTimer >= infiniteMusicInterval) { LK.playMusic('bgmusicinfinite'); infiniteMusicTimer = 0; } } // Check for level completion (skip for infinite mode) if (!isInfiniteMode && gameTime >= gameDuration) { if (currentLevel === 1) { // Level 1 completed, prepare for level 2 currentLevel = 2; levelCompleted = true; gameStarted = false; gameReady = false; gameEnded = false; gameTime = 0; lastPackageSpawn = 0; currentSequenceIndex = 0; currentTimingIndex = 0; currentArenaAnimationIndex = 0; // Reset arena animation timing hellModeSelected = false; // Reset mode selection for next level // Reset bomb mechanics lastBombSpawn = 0; bombHoldTimer = 0; if (bombWarningText) { bombWarningText.destroy(); bombWarningText = null; } // Reset character state character.heldPackage = null; character.x = arenaX; character.y = arenaY; character.rotation = 0; character.targetRotation = 0; // Clear all packages for (var p = packages.length - 1; p >= 0; p--) { packages[p].destroy(); packages.splice(p, 1); } // Clear all confetti for (var c = confettiParticles.length - 1; c >= 0; c--) { confettiParticles[c].destroy(); confettiParticles.splice(c, 1); } // Show level 2 ready screen levelText = new Text2('LEVEL 2', { size: 120, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0.5); levelText.x = gameWidth / 2; levelText.y = gameHeight / 2 - 250; game.addChild(levelText); readyButton = LK.getAsset('ready', { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2, y: gameHeight / 2 }); readyButton.tint = 0x666666; // Dark grey passive effect readyButton.alpha = 0.5; // Additional passive effect game.addChild(readyButton); // Hell mode selection UI for level 2 normalModeButton = new Text2('NORMAL', { size: 120, fill: 0x00FF00 }); normalModeButton.anchor.set(0.5, 0.5); normalModeButton.x = gameWidth / 2 - 220; normalModeButton.y = gameHeight / 2 + 130; game.addChild(normalModeButton); hellModeButton = LK.getAsset('hell', { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2 + 220, y: gameHeight / 2 + 130, scaleX: 2, scaleY: 2 }); game.addChild(hellModeButton); return; } else if (currentLevel === 2) { // Level 2 completed, prepare for level 3 currentLevel = 3; levelCompleted = true; gameStarted = false; gameReady = false; gameEnded = false; gameTime = 0; lastPackageSpawn = 0; currentSequenceIndex = 0; currentTimingIndex = 0; currentArenaAnimationIndex = 0; // Reset arena animation timing hellModeSelected = false; // Reset mode selection for level 3 // Reset bomb mechanics lastBombSpawn = 0; bombHoldTimer = 0; if (bombWarningText) { bombWarningText.destroy(); bombWarningText = null; } // Reset character state character.heldPackage = null; character.x = arenaX; character.y = arenaY; character.rotation = 0; character.targetRotation = 0; // Clear all packages for (var p = packages.length - 1; p >= 0; p--) { packages[p].destroy(); packages.splice(p, 1); } // Clear all confetti for (var c = confettiParticles.length - 1; c >= 0; c--) { confettiParticles[c].destroy(); confettiParticles.splice(c, 1); } // Show level 3 ready screen levelText = new Text2('LEVEL 3', { size: 120, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0.5); levelText.x = gameWidth / 2; levelText.y = gameHeight / 2 - 250; game.addChild(levelText); readyButton = LK.getAsset('ready', { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2, y: gameHeight / 2 }); readyButton.tint = 0x666666; // Dark grey passive effect readyButton.alpha = 0.5; // Additional passive effect game.addChild(readyButton); // Hell mode selection UI for level 3 normalModeButton = new Text2('NORMAL', { size: 120, fill: 0x00FF00 }); normalModeButton.anchor.set(0.5, 0.5); normalModeButton.x = gameWidth / 2 - 220; normalModeButton.y = gameHeight / 2 + 130; game.addChild(normalModeButton); hellModeButton = LK.getAsset('hell', { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2 + 220, y: gameHeight / 2 + 130, scaleX: 2, scaleY: 2 }); game.addChild(hellModeButton); return; } else if (currentLevel === 3) { // Level 3 completed, prepare for final level currentLevel = 4; levelCompleted = true; gameStarted = false; gameReady = false; gameEnded = false; gameTime = 0; lastPackageSpawn = 0; currentSequenceIndex = 0; currentTimingIndex = 0; currentArenaAnimationIndex = 0; // Reset arena animation timing hellModeSelected = false; // Reset mode selection for final level // Reset bomb mechanics lastBombSpawn = 0; bombHoldTimer = 0; if (bombWarningText) { bombWarningText.destroy(); bombWarningText = null; } // Reset character state character.heldPackage = null; character.x = arenaX; character.y = arenaY; character.rotation = 0; character.targetRotation = 0; // Clear all packages for (var p = packages.length - 1; p >= 0; p--) { packages[p].destroy(); packages.splice(p, 1); } // Clear all confetti for (var c = confettiParticles.length - 1; c >= 0; c--) { confettiParticles[c].destroy(); confettiParticles.splice(c, 1); } // Show final level ready screen levelText = new Text2('FINAL LEVEL', { size: 120, fill: 0xFFD700 }); levelText.anchor.set(0.5, 0.5); levelText.x = gameWidth / 2; levelText.y = gameHeight / 2 - 250; game.addChild(levelText); readyButton = LK.getAsset('ready', { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2, y: gameHeight / 2 }); readyButton.tint = 0x666666; // Dark grey passive effect readyButton.alpha = 0.5; // Additional passive effect game.addChild(readyButton); // Hell mode selection UI for final level normalModeButton = new Text2('NORMAL', { size: 120, fill: 0x00FF00 }); normalModeButton.anchor.set(0.5, 0.5); normalModeButton.x = gameWidth / 2 - 220; normalModeButton.y = gameHeight / 2 + 130; game.addChild(normalModeButton); hellModeButton = LK.getAsset('hell', { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2 + 220, y: gameHeight / 2 + 130, scaleX: 2, scaleY: 2 }); game.addChild(hellModeButton); return; } else { // Final level completed - you win with fireworks gameEnded = true; createFireworks(); LK.getSound('gameend').play(); LK.setTimeout(function () { LK.showYouWin(); }, 5000); return; } } // Hell mode and infinite mode bomb spawning for all levels if ((isHellMode || isInfiniteMode) && gameTime - lastBombSpawn >= bombSpawnInterval) { if (Math.random() < 0.25) { // 25% chance spawnBomb(); } lastBombSpawn = gameTime; } // Infinite mode game over condition when score reaches 0 if (isInfiniteMode && LK.getScore() <= 0) { gameEnded = true; LK.showGameOver(); return; } // Play bomb sound continuously when bomb is present in hell mode or infinite mode for all levels if ((isHellMode || isInfiniteMode) && character.heldPackage && character.heldPackage.isBomb) { if (!LK.getSound('bomb').isPlaying) { LK.getSound('bomb').play(); } } // Bomb holding penalty (10 points every 0.1 seconds = every 6 frames at 60fps) if (character.heldPackage && character.heldPackage.isBomb) { bombHoldTimer++; if (bombHoldTimer >= 6) { // 0.1 seconds at 60fps LK.setScore(LK.getScore() - 10); bombHoldTimer = 0; } // Show bomb warning if not already shown if (!bombWarningText) { bombWarningText = new Text2('BOMB! THROW AWAY!', { size: 60, fill: 0xFF0000 }); bombWarningText.anchor.set(0.5, 0.5); bombWarningText.x = gameWidth / 2; bombWarningText.y = 200; game.addChild(bombWarningText); // Flash effect tween(bombWarningText, { alpha: 0.3 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { if (bombWarningText) { tween(bombWarningText, { alpha: 1 }, { duration: 500, easing: tween.easeInOut }); } } }); } } else { bombHoldTimer = 0; // Clear bomb warning if not holding bomb if (bombWarningText && (!character.heldPackage || !character.heldPackage.isBomb)) { bombWarningText.destroy(); bombWarningText = null; } } // Spawn packages var currentColorSequence; if (isInfiniteMode) { // Infinite mode uses completely random colors var randomColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800]; currentColorSequence = randomColors; } else if (currentLevel === 1) { currentColorSequence = colorSequenceLevel1; } else if (currentLevel === 2) { currentColorSequence = colorSequenceLevel2; } else { currentColorSequence = colorSequenceLevel3; } var currentSpawnInterval; if (isInfiniteMode) { // Infinite mode random intervals: 15% - 0.4s, 30% - 0.8s, 54% - 1.2s, 1% - 0.2s var randomValue = Math.random(); if (randomValue < 0.15) { currentSpawnInterval = 400; // 0.4 seconds } else if (randomValue < 0.45) { currentSpawnInterval = 800; // 0.8 seconds } else if (randomValue < 0.99) { currentSpawnInterval = 1200; // 1.2 seconds } else { currentSpawnInterval = 200; // 0.2 seconds } } else if (currentLevel === 1) { currentSpawnInterval = packageSpawnInterval; // Keep 2000ms for level 1 } else if (currentLevel === 2) { // Level 2 uses custom timing intervals if (currentTimingIndex < timingIntervalsLevel2.length) { currentSpawnInterval = timingIntervalsLevel2[currentTimingIndex]; } else { currentSpawnInterval = 1720; // Default fallback } } else if (currentLevel === 3) { // Level 3 uses custom timing intervals if (currentTimingIndex < timingIntervalsLevel3.length) { currentSpawnInterval = timingIntervalsLevel3[currentTimingIndex]; } else { currentSpawnInterval = 1720; // Default fallback } } else if (currentLevel === 4) { // Final level uses progressive timing based on game time var progressiveTiming = [1500, 1875]; // 0-30 seconds if (gameTime >= 30000 && gameTime < 60000) { progressiveTiming = [1125, 1500, 1875]; // 30-60 seconds } else if (gameTime >= 60000 && gameTime < 180000) { progressiveTiming = [1125, 1500]; // 60-180 seconds } else if (gameTime >= 180000) { progressiveTiming = [750, 1125, 1500]; // 180-240 seconds } currentSpawnInterval = progressiveTiming[Math.floor(Math.random() * progressiveTiming.length)]; } if (gameTime - lastPackageSpawn >= currentSpawnInterval) { // For final level, allow sequence to loop when exhausted if (currentLevel === 4 && currentSequenceIndex >= currentColorSequence.length) { currentSequenceIndex = 0; // Reset to beginning of sequence } // Only spawn if we have colors available or it's the final level or infinite mode if (currentSequenceIndex < currentColorSequence.length || currentLevel === 4 || isInfiniteMode) { spawnPackage(); if (currentLevel === 2 || currentLevel === 3) { currentTimingIndex++; } lastPackageSpawn = gameTime; } } // Update packages for (var i = packages.length - 1; i >= 0; i--) { var pkg = packages[i]; if (pkg.lastY === undefined) pkg.lastY = pkg.y; if (pkg.lastCaught === undefined) pkg.lastCaught = false; if (pkg.lastThrown === undefined) pkg.lastThrown = false; // Check if package reached character (catch) if (!pkg.caught && !pkg.thrown) { var distanceToCharacter = Math.sqrt(Math.pow(pkg.x - character.x, 2) + Math.pow(pkg.y - character.y, 2)); if (distanceToCharacter < 75) { if (!character.heldPackage) { pkg.caught = true; character.heldPackage = pkg; LK.getSound('catch').play(); } } } // Check if package fell off screen (drop penalty) if (!pkg.caught && !pkg.thrown && pkg.y > arenaY + arenaSize / 2 + 100) { LK.setScore(LK.getScore() - 150); pkg.destroy(); packages.splice(i, 1); continue; } // Check thrown package collisions with targets if (pkg.thrown) { var hitTarget = false; for (var j = 0; j < targets.length; j++) { var target = targets[j]; if (checkPackageTargetCollision(pkg, target)) { if (pkg.isBomb) { // Bomb hit target - create flame explosion effect and apply penalty LK.setScore(LK.getScore() - 500); createFireExplosion(target.x, target.y); LK.getSound('blast').play(); } else if (pkg.colorValue === target.colorValue) { // Correct color match LK.setScore(LK.getScore() + 100); createConfettiExplosion(target.x, target.y, pkg.colorValue); LK.getSound('hit').play(); } else { // Wrong color penalty LK.setScore(LK.getScore() - 60); LK.getSound('miss').play(); } hitTarget = true; break; } } if (hitTarget || pkg.x < 0 || pkg.x > gameWidth || pkg.y < 0 || pkg.y > gameHeight) { if (!hitTarget) { // Only apply missed throw penalty for non-bomb packages if (!pkg.isBomb) { LK.setScore(LK.getScore() - 60); LK.getSound('miss').play(); } } pkg.destroy(); packages.splice(i, 1); continue; } } pkg.lastY = pkg.y; pkg.lastCaught = pkg.caught; pkg.lastThrown = pkg.thrown; } // Update confetti for (var i = confettiParticles.length - 1; i >= 0; i--) { var confetti = confettiParticles[i]; if (confetti.alpha <= 0) { confetti.destroy(); confettiParticles.splice(i, 1); } } // Update score display scoreTxt.setText('Score: ' + LK.getScore()); }; // Infinite button animation - runs independently of game update var infiniteButtonQueue = []; // Queue to track buttons for delayed destruction LK.on('tick', function () { // Animate infinite button (only in level 1 before game starts) if (currentLevel === 1 && !gameStarted && infiniteButton && infiniteButton.parent) { infiniteAnimationTimer++; if (infiniteAnimationTimer >= infiniteAnimationSpeed) { currentInfiniteTextureIndex = (currentInfiniteTextureIndex + 1) % infiniteTextures.length; // Add current button to queue for delayed destruction infiniteButtonQueue.push(infiniteButton); // Create new button with next texture at 4.76x scale and fixed position infiniteButton = LK.getAsset(infiniteTextures[currentInfiniteTextureIndex], { anchorX: 0.5, anchorY: 0.5, x: gameWidth / 2, y: gameHeight / 2 + 430, scaleX: 4.76, scaleY: 4.76 }); game.addChild(infiniteButton); // If we have 3 or more buttons in queue, destroy the oldest one if (infiniteButtonQueue.length >= 3) { var buttonToDestroy = infiniteButtonQueue.shift(); // Remove first (oldest) button from queue // Fade out and destroy the oldest button with 0.1 second delay tween(buttonToDestroy, { alpha: 0 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { // Remove old button after fade out if (buttonToDestroy.parent) { game.removeChild(buttonToDestroy); } buttonToDestroy.destroy(); } }); } infiniteAnimationTimer = 0; } } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bombGraphics = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.isBomb = true;
self.speed = 172.5;
if (isInfiniteMode) {
self.speed = 172.5 * 3.6; // 3.6x faster than normal speed (20% increase)
} else if (isHellMode) {
self.speed *= 4; // 4x speed in hell mode
}
self.caught = false;
self.thrown = false;
self.throwVelocityX = 0;
self.throwVelocityY = 0;
self.update = function () {
if (self.thrown) {
self.x += self.throwVelocityX;
self.y += self.throwVelocityY;
} else if (!self.caught) {
self.y += self.speed * (1 / 60);
}
};
return self;
});
var Character = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
self.heldPackage = null;
self.targetRotation = 0;
self.update = function () {
var rotationDiff = self.targetRotation - self.rotation;
while (rotationDiff > Math.PI) rotationDiff -= 2 * Math.PI;
while (rotationDiff < -Math.PI) rotationDiff += 2 * Math.PI;
self.rotation += rotationDiff * 0.1;
if (self.heldPackage) {
// Position package in front of character based on rotation
var packageDistance = 90; // Distance in front of character
var packageX = self.x + Math.cos(self.rotation) * packageDistance;
var packageY = self.y + Math.sin(self.rotation) * packageDistance;
// Smoothly tween package to new position for better visual flow
tween(self.heldPackage, {
x: packageX,
y: packageY,
rotation: self.rotation
}, {
duration: 100,
easing: tween.easeOut
});
}
};
return self;
});
var Confetti = Container.expand(function (colorValue) {
var self = Container.call(this);
var confettiGraphics = self.attachAsset('confetti', {
anchorX: 0.5,
anchorY: 0.5
});
confettiGraphics.tint = colorValue;
self.velocityX = (Math.random() - 0.5) * 400;
self.velocityY = (Math.random() - 0.5) * 400;
self.life = 60;
self.update = function () {
self.x += self.velocityX * (1 / 60);
self.y += self.velocityY * (1 / 60);
self.velocityY += 300 * (1 / 60);
self.life--;
if (self.life <= 0) {
self.alpha = 0;
}
};
return self;
});
var Package = Container.expand(function (colorValue) {
var self = Container.call(this);
var assetName = 'yellowpacket';
if (colorValue === 0x0066ff) assetName = 'bluepacket';else if (colorValue === 0xff0000) assetName = 'redpacket';else if (colorValue === 0xff8800) assetName = 'orangepacket';
var packageGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.colorValue = colorValue || 0xffffff;
self.speed = 172.5; // 150 * 1.15 = 15% increase
if (isInfiniteMode) {
self.speed = 172.5 * 3.6; // 3.6x faster than normal speed (20% increase)
} else if (isHellMode) {
self.speed *= 4; // 4x speed in hell mode
}
self.caught = false;
self.thrown = false;
self.throwVelocityX = 0;
self.throwVelocityY = 0;
self.update = function () {
if (self.thrown) {
self.x += self.throwVelocityX;
self.y += self.throwVelocityY;
} else if (!self.caught) {
self.y += self.speed * (1 / 60);
}
};
return self;
});
var TargetBox = Container.expand(function (colorValue) {
var self = Container.call(this);
var assetName = 'targetYellow';
if (colorValue === 0x0066ff) assetName = 'targetBlue';else if (colorValue === 0xff0000) assetName = 'targetRed';else if (colorValue === 0xff8800) assetName = 'targetOrange';
var targetGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.colorValue = colorValue;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
var gameWidth = 2048;
var gameHeight = 2732;
var arenaSize = 1600;
var arenaX = gameWidth / 2;
var arenaY = gameHeight / 2;
// Game arena
var arena = game.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: arenaX,
y: arenaY
}));
// Character
var character = game.addChild(new Character());
character.x = arenaX;
character.y = arenaY;
// Target boxes at corners
var targets = [];
var targetColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800]; // yellow, blue, red, orange
var targetPositions = [{
x: arenaX - arenaSize / 2 + 180,
y: arenaY - arenaSize / 2 + 180
},
// top-left
{
x: arenaX + arenaSize / 2 - 180,
y: arenaY - arenaSize / 2 + 180
},
// top-right
{
x: arenaX - arenaSize / 2 + 180,
y: arenaY + arenaSize / 2 - 180
},
// bottom-left
{
x: arenaX + arenaSize / 2 - 180,
y: arenaY + arenaSize / 2 - 180
} // bottom-right
];
for (var i = 0; i < 4; i++) {
var target = game.addChild(new TargetBox(targetColors[i]));
target.x = targetPositions[i].x;
target.y = targetPositions[i].y;
targets.push(target);
}
// Game state
var packages = [];
var confettiParticles = [];
var gameTime = 0;
var gameDuration = 30000; // 30 seconds for levels 1-3, 240000 for final level
var packageSpawnInterval = 2000; // 2 seconds
var lastPackageSpawn = 0;
var gameStarted = false;
var gameEnded = false;
var gameReady = false;
var currentLevel = 1;
var levelCompleted = false;
var finalLevelStarted = false;
var isHellMode = false;
var hellModeSelected = false;
var isInfiniteMode = false;
var infiniteModeSelected = false;
var infiniteMusicTimer = 0;
var infiniteMusicInterval = 108000; // 108 seconds in milliseconds
// Arena animation variables
var arenaAnimationTimes = [11, 23, 31, 41, 53, 63, 75, 85, 96, 107, 116, 128, 137, 149, 157, 169, 180, 190, 202, 214, 222, 232, 241, 253, 263, 271, 280, 290, 301, 310, 321, 329, 339, 349, 361, 370, 382, 394, 405, 414, 423, 435, 444, 452, 461, 471, 479, 490, 500, 510, 519, 527, 538, 546, 558, 567, 575, 584, 596, 608];
var currentArenaAnimationIndex = 0;
var isArenaAnimating = false;
var arenaAnimationStep = 0;
// Bomb mechanic variables
var lastBombSpawn = 0;
var bombSpawnInterval = 3000; // 3 seconds
var bombHoldTimer = 0;
var bombWarningText = null;
// Predetermined color sequence for level 1
var colorSequenceLevel1 = [0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff0000, 0x0066ff, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xff0000, 0x0066ff, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff8800, 0xff0000, 0xffff00, 0x0066ff];
// Level 2 color sequence and timing intervals (in milliseconds)
var colorSequenceLevel2 = [0xff0000, 0xff8800, 0x0066ff, 0xffff00, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0x0066ff, 0xff8800, 0xff0000, 0x0066ff, 0xffff00, 0xff8800, 0x0066ff, 0xffff00];
var timingIntervalsLevel2 = [1720, 2150, 1290, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 1720, 2150, 1720, 1720, 1290, 1720, 1720, 1720, 1720, 1720, 2150, 1720, 1290];
// Level 3 color sequence and timing intervals (in milliseconds)
var colorSequenceLevel3 = [0x0066ff, 0xffff00, 0xff8800, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0x0066ff, 0xffff00];
var timingIntervalsLevel3 = [1720, 1720, 2150, 1290, 1720, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 2150, 1720, 1290, 1720, 1720, 1720, 1720, 2150, 1290, 1720];
// Final level color sequence (longer sequence for 4 minutes)
var colorSequenceFinal = [0xff0000, 0x0066ff, 0xffff00, 0xff8800, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xff0000, 0x0066ff, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0x0066ff, 0xff0000, 0xff8800, 0xffff00, 0xff8800, 0x0066ff, 0xff0000, 0xffff00, 0x0066ff, 0xff8800, 0xffff00, 0xff0000, 0xff8800, 0xffff00, 0x0066ff, 0xff0000, 0xffff00, 0xff8800, 0x0066ff, 0xff0000];
var currentSequenceIndex = 0;
var currentTimingIndex = 0;
// UI
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var timeTxt = new Text2('Time: 30', {
size: 60,
fill: 0xFFFFFF
});
timeTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(timeTxt);
// Level display
var levelText = new Text2('LEVEL 1', {
size: 120,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.x = gameWidth / 2;
levelText.y = gameHeight / 2 - 250;
game.addChild(levelText);
// Ready button
var readyButton = LK.getAsset('ready', {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2,
y: gameHeight / 2
});
readyButton.tint = 0x666666; // Dark grey passive effect
readyButton.alpha = 0.5; // Additional passive effect
game.addChild(readyButton);
// Hell mode selection UI
var normalModeButton = new Text2('NORMAL', {
size: 120,
fill: 0x00FF00
});
normalModeButton.anchor.set(0.5, 0.5);
normalModeButton.x = gameWidth / 2 - 220;
normalModeButton.y = gameHeight / 2 + 130;
game.addChild(normalModeButton);
var hellModeButton = LK.getAsset('hell', {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2 + 220,
y: gameHeight / 2 + 130,
scaleX: 2,
scaleY: 2
});
game.addChild(hellModeButton);
// Infinite button (only for level 1)
var infiniteButton = LK.getAsset('infinite1', {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2,
y: gameHeight / 2 + 430,
scaleX: 4.76,
scaleY: 4.76
});
game.addChild(infiniteButton);
// Infinite button animation variables
var infiniteTextures = ['infinite1', 'infinite2', 'infinite3', 'infinite4', 'infinite5', 'infinite6', 'infinite7', 'infinite8'];
var currentInfiniteTextureIndex = 0;
var infiniteAnimationTimer = 0;
var infiniteAnimationSpeed = 4; // Change texture every 4 frames (about 15 fps at 60fps)
// Helper functions
function getColorName(colorValue) {
switch (colorValue) {
case 0xffff00:
return 'Yellow';
case 0x0066ff:
return 'Blue';
case 0xff0000:
return 'Red';
case 0xff8800:
return 'Orange';
default:
return 'Unknown';
}
}
function spawnPackage() {
var currentColorSequence;
var packageColor;
if (isInfiniteMode) {
// Infinite mode: completely random colors
var randomColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800];
packageColor = randomColors[Math.floor(Math.random() * randomColors.length)];
} else {
if (currentLevel === 1) {
currentColorSequence = colorSequenceLevel1;
} else if (currentLevel === 2) {
currentColorSequence = colorSequenceLevel2;
} else if (currentLevel === 3) {
currentColorSequence = colorSequenceLevel3;
} else {
currentColorSequence = colorSequenceFinal;
}
if (currentSequenceIndex >= currentColorSequence.length) return;
packageColor = currentColorSequence[currentSequenceIndex];
currentSequenceIndex++;
}
var newPackage = new Package(packageColor);
newPackage.x = character.x; // Spawn directly above character
newPackage.y = arenaY - arenaSize / 2 - 200; // Spawn higher above arena
packages.push(newPackage);
game.addChild(newPackage);
// Hell mode: 20% chance to spawn a second package 0.05 seconds later
if (isHellMode && Math.random() < 0.2) {
LK.setTimeout(function () {
// Get next color from sequence for the second package
var secondPackageColor;
if (currentSequenceIndex < currentColorSequence.length) {
secondPackageColor = currentColorSequence[currentSequenceIndex];
currentSequenceIndex++;
} else if (currentLevel === 4) {
// For final level, loop back to beginning
currentSequenceIndex = 0;
secondPackageColor = currentColorSequence[currentSequenceIndex];
currentSequenceIndex++;
} else {
// Use random color if sequence exhausted
var randomColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800];
secondPackageColor = randomColors[Math.floor(Math.random() * randomColors.length)];
}
var secondPackage = new Package(secondPackageColor);
secondPackage.x = character.x;
secondPackage.y = arenaY - arenaSize / 2 - 200;
packages.push(secondPackage);
game.addChild(secondPackage);
}, 150); // 0.15 seconds = 150ms
}
}
function spawnBomb() {
var newBomb = new Bomb();
newBomb.x = character.x; // Spawn directly above character
newBomb.y = arenaY - arenaSize / 2 - 200; // Spawn higher above arena
packages.push(newBomb);
game.addChild(newBomb);
}
function createConfettiExplosion(x, y, color) {
var allColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800]; // yellow, blue, red, orange
// Create more particles for bigger explosion (25 instead of 15)
for (var i = 0; i < 25; i++) {
var confettiColor;
if (i < 18) {
// Most particles (72%) use the main color
confettiColor = color;
} else {
// Some particles (28%) use random other colors
confettiColor = allColors[Math.floor(Math.random() * allColors.length)];
}
var confetti = new Confetti(confettiColor);
confetti.x = x;
confetti.y = y;
// Scale up confetti particles by 1.5x for bigger effect
tween(confetti, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 50,
easing: tween.easeOut
});
confettiParticles.push(confetti);
game.addChild(confetti);
}
}
function startArenaAnimation() {
if (isArenaAnimating) return;
isArenaAnimating = true;
arenaAnimationStep = 0;
// Start animation sequence
animateArenaStep();
}
function animateArenaStep() {
var arenaAssets = ['arena2', 'arena3', 'arena4'];
if (arenaAnimationStep < arenaAssets.length) {
// Change to next animation frame
var newArena = LK.getAsset(arenaAssets[arenaAnimationStep], {
anchorX: 0.5,
anchorY: 0.5,
x: arenaX,
y: arenaY,
scaleX: 12,
// Scale to match original arena size
scaleY: 12
});
// Add new arena behind all other objects (at index 1, after original arena)
game.addChildAt(newArena, 1);
// Auto-remove after 1.6 seconds
LK.setTimeout(function () {
newArena.destroy();
}, 1600);
arenaAnimationStep++;
// Schedule next step after 400ms
LK.setTimeout(function () {
animateArenaStep();
}, 400);
} else {
// Animation complete
isArenaAnimating = false;
}
}
function createFireExplosion(x, y) {
var flameColors = [0xFF4500, 0xFF6347, 0xFF0000, 0xFFA500, 0xFFD700]; // Orange, tomato, red, orange, gold
// Create 30 flame particles for explosion effect
for (var i = 0; i < 30; i++) {
var flameColor = flameColors[Math.floor(Math.random() * flameColors.length)];
var flame = new Confetti(flameColor);
flame.x = x;
flame.y = y;
// Enhanced velocities for explosive effect
flame.velocityX = (Math.random() - 0.5) * 600;
flame.velocityY = (Math.random() - 0.5) * 600;
flame.life = 90; // Medium life for flames
// Scale and fade effect using tween
tween(flame, {
scaleX: 2,
scaleY: 2
}, {
duration: 80,
easing: tween.easeOut
});
tween(flame, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut
});
confettiParticles.push(flame);
game.addChild(flame);
}
}
function createFireworks() {
var fireworksColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800, 0x00ff00, 0xff00ff, 0x00ffff];
// Create multiple firework explosions across the screen
for (var f = 0; f < 8; f++) {
var fireworkX = Math.random() * gameWidth;
var fireworkY = Math.random() * (gameHeight * 0.6) + gameHeight * 0.2;
var fireworkColor = fireworksColors[Math.floor(Math.random() * fireworksColors.length)];
// Create 40 particles per firework for spectacular effect
for (var i = 0; i < 40; i++) {
var firework = new Confetti(fireworkColor);
firework.x = fireworkX;
firework.y = fireworkY;
// Enhanced velocities for bigger explosion
firework.velocityX = (Math.random() - 0.5) * 800;
firework.velocityY = (Math.random() - 0.5) * 600 - 200;
firework.life = 120; // Longer life for fireworks
// Scale and fade effect using tween
tween(firework, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 100,
easing: tween.easeOut
});
tween(firework, {
alpha: 0
}, {
duration: 2000,
easing: tween.easeOut
});
confettiParticles.push(firework);
game.addChild(firework);
}
}
}
function checkPackageTargetCollision(packageObj, target) {
var dx = packageObj.x - target.x;
var dy = packageObj.y - target.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Orange target gets larger hitbox (50% larger than base 120 = 180)
if (target.colorValue === 0xff8800) {
return distance < 180; // Orange target gets bigger hitbox
}
return distance < 156; // Increased from 104 to 156 (1.5x scale) for other targets
}
function throwPackage(targetX, targetY) {
if (!character.heldPackage) {
// Empty click penalty
LK.setScore(LK.getScore() - 15);
LK.getSound('miss').play();
return;
}
var packageToThrow = character.heldPackage;
character.heldPackage = null;
// Clear bomb warning if it exists
if (bombWarningText) {
bombWarningText.destroy();
bombWarningText = null;
}
var dx = targetX - packageToThrow.x;
var dy = targetY - packageToThrow.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var speed = 800;
packageToThrow.throwVelocityX = dx / distance * speed * (1 / 60);
packageToThrow.throwVelocityY = dy / distance * speed * (1 / 60);
packageToThrow.thrown = true;
LK.getSound('throw').play();
}
// Event handlers
game.move = function (x, y, obj) {
var dx = x - character.x;
var dy = y - character.y;
character.targetRotation = Math.atan2(dy, dx);
};
game.down = function (x, y, obj) {
if (!gameReady) {
// Check infinite button first (only for level 1)
if (currentLevel === 1) {
var infiniteButtonX = gameWidth / 2;
var infiniteButtonY = gameHeight / 2 + 430;
var infiniteButtonWidth = 476; // 4.76x scale of 200px width = 952, so half is 476
var infiniteButtonHeight = 110; // 4.76x scale of 46.1px height = 219, so half is 110
if (x >= infiniteButtonX - infiniteButtonWidth && x <= infiniteButtonX + infiniteButtonWidth && y >= infiniteButtonY - infiniteButtonHeight && y <= infiniteButtonY + infiniteButtonHeight) {
// Start infinite mode
isInfiniteMode = true;
infiniteModeSelected = true;
hellModeSelected = true; // Skip mode selection since infinite mode is already chosen
gameReady = true;
gameStarted = true;
gameTime = 0;
lastPackageSpawn = 0;
// Set score to 10000 for infinite mode
LK.setScore(10000);
// Clean up UI elements and stop animation
if (infiniteButton && infiniteButton.parent) {
infiniteButton.destroy();
infiniteButton = null;
}
// Clean up any queued infinite buttons from animation
for (var q = infiniteButtonQueue.length - 1; q >= 0; q--) {
if (infiniteButtonQueue[q] && infiniteButtonQueue[q].parent) {
infiniteButtonQueue[q].destroy();
}
}
infiniteButtonQueue = []; // Clear the queue
if (levelText && levelText.parent) {
levelText.destroy();
}
if (readyButton && readyButton.parent) {
readyButton.destroy();
}
if (normalModeButton && normalModeButton.parent) {
normalModeButton.destroy();
}
if (hellModeButton && hellModeButton.parent) {
hellModeButton.destroy();
}
// Start infinite mode music
LK.playMusic('bgmusicinfinite');
return;
}
}
// Check mode selection if not selected
if (!hellModeSelected) {
// Check normal mode button
var normalButtonX = gameWidth / 2 - 220;
var normalButtonY = gameHeight / 2 + 130;
var normalButtonWidth = 150;
var normalButtonHeight = 60;
if (x >= normalButtonX - normalButtonWidth && x <= normalButtonX + normalButtonWidth && y >= normalButtonY - normalButtonHeight && y <= normalButtonY + normalButtonHeight) {
isHellMode = false;
hellModeSelected = true;
normalModeButton.destroy();
hellModeButton.destroy();
// Hide infinite button when normal mode is selected
if (infiniteButton && infiniteButton.parent) {
infiniteButton.destroy();
infiniteButton = null;
}
// Clean up any queued infinite buttons from animation
for (var q = infiniteButtonQueue.length - 1; q >= 0; q--) {
if (infiniteButtonQueue[q] && infiniteButtonQueue[q].parent) {
infiniteButtonQueue[q].destroy();
}
}
infiniteButtonQueue = []; // Clear the queue
// Remove passive effect from ready button
readyButton.tint = 0xFFFFFF;
readyButton.alpha = 1;
return;
}
// Check hell mode button
var hellButtonX = gameWidth / 2 + 220;
var hellButtonY = gameHeight / 2 + 130;
var hellButtonWidth = 100;
var hellButtonHeight = 100;
if (x >= hellButtonX - hellButtonWidth && x <= hellButtonX + hellButtonWidth && y >= hellButtonY - hellButtonHeight && y <= hellButtonY + hellButtonHeight) {
isHellMode = true;
hellModeSelected = true;
normalModeButton.destroy();
hellModeButton.destroy();
// Hide infinite button when hell mode is selected
if (infiniteButton && infiniteButton.parent) {
infiniteButton.destroy();
infiniteButton = null;
}
// Clean up any queued infinite buttons from animation
for (var q = infiniteButtonQueue.length - 1; q >= 0; q--) {
if (infiniteButtonQueue[q] && infiniteButtonQueue[q].parent) {
infiniteButtonQueue[q].destroy();
}
}
infiniteButtonQueue = []; // Clear the queue
// Remove passive effect from ready button
readyButton.tint = 0xFFFFFF;
readyButton.alpha = 1;
return;
}
return;
}
// Check if clicked on ready button area (only after mode selected)
if (hellModeSelected) {
var buttonX = gameWidth / 2;
var buttonY = gameHeight / 2;
var buttonWidth = 200;
var buttonHeight = 100;
if (x >= buttonX - buttonWidth && x <= buttonX + buttonWidth && y >= buttonY - buttonHeight && y <= buttonY + buttonHeight) {
gameReady = true;
readyButton.destroy();
levelText.destroy();
}
}
return;
}
if (gameEnded) return;
throwPackage(x, y);
};
// Main game update
game.update = function () {
if (!gameReady) return;
if (!gameStarted) {
gameStarted = true;
gameTime = 0; // Reset game time when starting
lastPackageSpawn = 0; // Reset package spawn timer
// Remove infinite button when game starts (level 1 only)
if (currentLevel === 1 && infiniteButton && infiniteButton.parent) {
infiniteButton.destroy();
infiniteButton = null;
}
if (currentLevel === 1) {
LK.getSound('level1').play();
LK.playMusic('bgmusic');
} else if (currentLevel === 2) {
LK.getSound('level2').play();
LK.playMusic('bgmusic');
} else if (currentLevel === 3) {
LK.getSound('level3').play();
LK.playMusic('bgmusic3');
} else if (currentLevel === 4) {
LK.getSound('final').play();
LK.playMusic('bgmusicfinal');
gameDuration = 240000; // 4 minutes for final level
finalLevelStarted = true;
}
}
if (gameEnded) return;
// Arena animation trigger at predetermined times - works for all levels
var currentGameTimeInSeconds = Math.floor(gameTime / 1000);
if (currentArenaAnimationIndex < arenaAnimationTimes.length && currentGameTimeInSeconds >= arenaAnimationTimes[currentArenaAnimationIndex]) {
startArenaAnimation();
currentArenaAnimationIndex++;
}
// Check for insufficient score in final level
if (currentLevel === 4) {
if (LK.getScore() < -200) {
gameEnded = true;
LK.showGameOver();
return;
}
}
gameTime += 1000 / 60; // Increment game time only after ready
if (isInfiniteMode) {
var elapsedTime = Math.floor(gameTime / 1000);
timeTxt.setText('Time: ' + elapsedTime);
} else {
var remainingTime = Math.max(0, Math.ceil((gameDuration - gameTime) / 1000));
timeTxt.setText('Time: ' + remainingTime);
}
// Infinite mode music timer
if (isInfiniteMode) {
infiniteMusicTimer += 1000 / 60;
if (infiniteMusicTimer >= infiniteMusicInterval) {
LK.playMusic('bgmusicinfinite');
infiniteMusicTimer = 0;
}
}
// Check for level completion (skip for infinite mode)
if (!isInfiniteMode && gameTime >= gameDuration) {
if (currentLevel === 1) {
// Level 1 completed, prepare for level 2
currentLevel = 2;
levelCompleted = true;
gameStarted = false;
gameReady = false;
gameEnded = false;
gameTime = 0;
lastPackageSpawn = 0;
currentSequenceIndex = 0;
currentTimingIndex = 0;
currentArenaAnimationIndex = 0; // Reset arena animation timing
hellModeSelected = false; // Reset mode selection for next level
// Reset bomb mechanics
lastBombSpawn = 0;
bombHoldTimer = 0;
if (bombWarningText) {
bombWarningText.destroy();
bombWarningText = null;
}
// Reset character state
character.heldPackage = null;
character.x = arenaX;
character.y = arenaY;
character.rotation = 0;
character.targetRotation = 0;
// Clear all packages
for (var p = packages.length - 1; p >= 0; p--) {
packages[p].destroy();
packages.splice(p, 1);
}
// Clear all confetti
for (var c = confettiParticles.length - 1; c >= 0; c--) {
confettiParticles[c].destroy();
confettiParticles.splice(c, 1);
}
// Show level 2 ready screen
levelText = new Text2('LEVEL 2', {
size: 120,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.x = gameWidth / 2;
levelText.y = gameHeight / 2 - 250;
game.addChild(levelText);
readyButton = LK.getAsset('ready', {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2,
y: gameHeight / 2
});
readyButton.tint = 0x666666; // Dark grey passive effect
readyButton.alpha = 0.5; // Additional passive effect
game.addChild(readyButton);
// Hell mode selection UI for level 2
normalModeButton = new Text2('NORMAL', {
size: 120,
fill: 0x00FF00
});
normalModeButton.anchor.set(0.5, 0.5);
normalModeButton.x = gameWidth / 2 - 220;
normalModeButton.y = gameHeight / 2 + 130;
game.addChild(normalModeButton);
hellModeButton = LK.getAsset('hell', {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2 + 220,
y: gameHeight / 2 + 130,
scaleX: 2,
scaleY: 2
});
game.addChild(hellModeButton);
return;
} else if (currentLevel === 2) {
// Level 2 completed, prepare for level 3
currentLevel = 3;
levelCompleted = true;
gameStarted = false;
gameReady = false;
gameEnded = false;
gameTime = 0;
lastPackageSpawn = 0;
currentSequenceIndex = 0;
currentTimingIndex = 0;
currentArenaAnimationIndex = 0; // Reset arena animation timing
hellModeSelected = false; // Reset mode selection for level 3
// Reset bomb mechanics
lastBombSpawn = 0;
bombHoldTimer = 0;
if (bombWarningText) {
bombWarningText.destroy();
bombWarningText = null;
}
// Reset character state
character.heldPackage = null;
character.x = arenaX;
character.y = arenaY;
character.rotation = 0;
character.targetRotation = 0;
// Clear all packages
for (var p = packages.length - 1; p >= 0; p--) {
packages[p].destroy();
packages.splice(p, 1);
}
// Clear all confetti
for (var c = confettiParticles.length - 1; c >= 0; c--) {
confettiParticles[c].destroy();
confettiParticles.splice(c, 1);
}
// Show level 3 ready screen
levelText = new Text2('LEVEL 3', {
size: 120,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.x = gameWidth / 2;
levelText.y = gameHeight / 2 - 250;
game.addChild(levelText);
readyButton = LK.getAsset('ready', {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2,
y: gameHeight / 2
});
readyButton.tint = 0x666666; // Dark grey passive effect
readyButton.alpha = 0.5; // Additional passive effect
game.addChild(readyButton);
// Hell mode selection UI for level 3
normalModeButton = new Text2('NORMAL', {
size: 120,
fill: 0x00FF00
});
normalModeButton.anchor.set(0.5, 0.5);
normalModeButton.x = gameWidth / 2 - 220;
normalModeButton.y = gameHeight / 2 + 130;
game.addChild(normalModeButton);
hellModeButton = LK.getAsset('hell', {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2 + 220,
y: gameHeight / 2 + 130,
scaleX: 2,
scaleY: 2
});
game.addChild(hellModeButton);
return;
} else if (currentLevel === 3) {
// Level 3 completed, prepare for final level
currentLevel = 4;
levelCompleted = true;
gameStarted = false;
gameReady = false;
gameEnded = false;
gameTime = 0;
lastPackageSpawn = 0;
currentSequenceIndex = 0;
currentTimingIndex = 0;
currentArenaAnimationIndex = 0; // Reset arena animation timing
hellModeSelected = false; // Reset mode selection for final level
// Reset bomb mechanics
lastBombSpawn = 0;
bombHoldTimer = 0;
if (bombWarningText) {
bombWarningText.destroy();
bombWarningText = null;
}
// Reset character state
character.heldPackage = null;
character.x = arenaX;
character.y = arenaY;
character.rotation = 0;
character.targetRotation = 0;
// Clear all packages
for (var p = packages.length - 1; p >= 0; p--) {
packages[p].destroy();
packages.splice(p, 1);
}
// Clear all confetti
for (var c = confettiParticles.length - 1; c >= 0; c--) {
confettiParticles[c].destroy();
confettiParticles.splice(c, 1);
}
// Show final level ready screen
levelText = new Text2('FINAL LEVEL', {
size: 120,
fill: 0xFFD700
});
levelText.anchor.set(0.5, 0.5);
levelText.x = gameWidth / 2;
levelText.y = gameHeight / 2 - 250;
game.addChild(levelText);
readyButton = LK.getAsset('ready', {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2,
y: gameHeight / 2
});
readyButton.tint = 0x666666; // Dark grey passive effect
readyButton.alpha = 0.5; // Additional passive effect
game.addChild(readyButton);
// Hell mode selection UI for final level
normalModeButton = new Text2('NORMAL', {
size: 120,
fill: 0x00FF00
});
normalModeButton.anchor.set(0.5, 0.5);
normalModeButton.x = gameWidth / 2 - 220;
normalModeButton.y = gameHeight / 2 + 130;
game.addChild(normalModeButton);
hellModeButton = LK.getAsset('hell', {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2 + 220,
y: gameHeight / 2 + 130,
scaleX: 2,
scaleY: 2
});
game.addChild(hellModeButton);
return;
} else {
// Final level completed - you win with fireworks
gameEnded = true;
createFireworks();
LK.getSound('gameend').play();
LK.setTimeout(function () {
LK.showYouWin();
}, 5000);
return;
}
}
// Hell mode and infinite mode bomb spawning for all levels
if ((isHellMode || isInfiniteMode) && gameTime - lastBombSpawn >= bombSpawnInterval) {
if (Math.random() < 0.25) {
// 25% chance
spawnBomb();
}
lastBombSpawn = gameTime;
}
// Infinite mode game over condition when score reaches 0
if (isInfiniteMode && LK.getScore() <= 0) {
gameEnded = true;
LK.showGameOver();
return;
}
// Play bomb sound continuously when bomb is present in hell mode or infinite mode for all levels
if ((isHellMode || isInfiniteMode) && character.heldPackage && character.heldPackage.isBomb) {
if (!LK.getSound('bomb').isPlaying) {
LK.getSound('bomb').play();
}
}
// Bomb holding penalty (10 points every 0.1 seconds = every 6 frames at 60fps)
if (character.heldPackage && character.heldPackage.isBomb) {
bombHoldTimer++;
if (bombHoldTimer >= 6) {
// 0.1 seconds at 60fps
LK.setScore(LK.getScore() - 10);
bombHoldTimer = 0;
}
// Show bomb warning if not already shown
if (!bombWarningText) {
bombWarningText = new Text2('BOMB! THROW AWAY!', {
size: 60,
fill: 0xFF0000
});
bombWarningText.anchor.set(0.5, 0.5);
bombWarningText.x = gameWidth / 2;
bombWarningText.y = 200;
game.addChild(bombWarningText);
// Flash effect
tween(bombWarningText, {
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (bombWarningText) {
tween(bombWarningText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeInOut
});
}
}
});
}
} else {
bombHoldTimer = 0;
// Clear bomb warning if not holding bomb
if (bombWarningText && (!character.heldPackage || !character.heldPackage.isBomb)) {
bombWarningText.destroy();
bombWarningText = null;
}
}
// Spawn packages
var currentColorSequence;
if (isInfiniteMode) {
// Infinite mode uses completely random colors
var randomColors = [0xffff00, 0x0066ff, 0xff0000, 0xff8800];
currentColorSequence = randomColors;
} else if (currentLevel === 1) {
currentColorSequence = colorSequenceLevel1;
} else if (currentLevel === 2) {
currentColorSequence = colorSequenceLevel2;
} else {
currentColorSequence = colorSequenceLevel3;
}
var currentSpawnInterval;
if (isInfiniteMode) {
// Infinite mode random intervals: 15% - 0.4s, 30% - 0.8s, 54% - 1.2s, 1% - 0.2s
var randomValue = Math.random();
if (randomValue < 0.15) {
currentSpawnInterval = 400; // 0.4 seconds
} else if (randomValue < 0.45) {
currentSpawnInterval = 800; // 0.8 seconds
} else if (randomValue < 0.99) {
currentSpawnInterval = 1200; // 1.2 seconds
} else {
currentSpawnInterval = 200; // 0.2 seconds
}
} else if (currentLevel === 1) {
currentSpawnInterval = packageSpawnInterval; // Keep 2000ms for level 1
} else if (currentLevel === 2) {
// Level 2 uses custom timing intervals
if (currentTimingIndex < timingIntervalsLevel2.length) {
currentSpawnInterval = timingIntervalsLevel2[currentTimingIndex];
} else {
currentSpawnInterval = 1720; // Default fallback
}
} else if (currentLevel === 3) {
// Level 3 uses custom timing intervals
if (currentTimingIndex < timingIntervalsLevel3.length) {
currentSpawnInterval = timingIntervalsLevel3[currentTimingIndex];
} else {
currentSpawnInterval = 1720; // Default fallback
}
} else if (currentLevel === 4) {
// Final level uses progressive timing based on game time
var progressiveTiming = [1500, 1875]; // 0-30 seconds
if (gameTime >= 30000 && gameTime < 60000) {
progressiveTiming = [1125, 1500, 1875]; // 30-60 seconds
} else if (gameTime >= 60000 && gameTime < 180000) {
progressiveTiming = [1125, 1500]; // 60-180 seconds
} else if (gameTime >= 180000) {
progressiveTiming = [750, 1125, 1500]; // 180-240 seconds
}
currentSpawnInterval = progressiveTiming[Math.floor(Math.random() * progressiveTiming.length)];
}
if (gameTime - lastPackageSpawn >= currentSpawnInterval) {
// For final level, allow sequence to loop when exhausted
if (currentLevel === 4 && currentSequenceIndex >= currentColorSequence.length) {
currentSequenceIndex = 0; // Reset to beginning of sequence
}
// Only spawn if we have colors available or it's the final level or infinite mode
if (currentSequenceIndex < currentColorSequence.length || currentLevel === 4 || isInfiniteMode) {
spawnPackage();
if (currentLevel === 2 || currentLevel === 3) {
currentTimingIndex++;
}
lastPackageSpawn = gameTime;
}
}
// Update packages
for (var i = packages.length - 1; i >= 0; i--) {
var pkg = packages[i];
if (pkg.lastY === undefined) pkg.lastY = pkg.y;
if (pkg.lastCaught === undefined) pkg.lastCaught = false;
if (pkg.lastThrown === undefined) pkg.lastThrown = false;
// Check if package reached character (catch)
if (!pkg.caught && !pkg.thrown) {
var distanceToCharacter = Math.sqrt(Math.pow(pkg.x - character.x, 2) + Math.pow(pkg.y - character.y, 2));
if (distanceToCharacter < 75) {
if (!character.heldPackage) {
pkg.caught = true;
character.heldPackage = pkg;
LK.getSound('catch').play();
}
}
}
// Check if package fell off screen (drop penalty)
if (!pkg.caught && !pkg.thrown && pkg.y > arenaY + arenaSize / 2 + 100) {
LK.setScore(LK.getScore() - 150);
pkg.destroy();
packages.splice(i, 1);
continue;
}
// Check thrown package collisions with targets
if (pkg.thrown) {
var hitTarget = false;
for (var j = 0; j < targets.length; j++) {
var target = targets[j];
if (checkPackageTargetCollision(pkg, target)) {
if (pkg.isBomb) {
// Bomb hit target - create flame explosion effect and apply penalty
LK.setScore(LK.getScore() - 500);
createFireExplosion(target.x, target.y);
LK.getSound('blast').play();
} else if (pkg.colorValue === target.colorValue) {
// Correct color match
LK.setScore(LK.getScore() + 100);
createConfettiExplosion(target.x, target.y, pkg.colorValue);
LK.getSound('hit').play();
} else {
// Wrong color penalty
LK.setScore(LK.getScore() - 60);
LK.getSound('miss').play();
}
hitTarget = true;
break;
}
}
if (hitTarget || pkg.x < 0 || pkg.x > gameWidth || pkg.y < 0 || pkg.y > gameHeight) {
if (!hitTarget) {
// Only apply missed throw penalty for non-bomb packages
if (!pkg.isBomb) {
LK.setScore(LK.getScore() - 60);
LK.getSound('miss').play();
}
}
pkg.destroy();
packages.splice(i, 1);
continue;
}
}
pkg.lastY = pkg.y;
pkg.lastCaught = pkg.caught;
pkg.lastThrown = pkg.thrown;
}
// Update confetti
for (var i = confettiParticles.length - 1; i >= 0; i--) {
var confetti = confettiParticles[i];
if (confetti.alpha <= 0) {
confetti.destroy();
confettiParticles.splice(i, 1);
}
}
// Update score display
scoreTxt.setText('Score: ' + LK.getScore());
};
// Infinite button animation - runs independently of game update
var infiniteButtonQueue = []; // Queue to track buttons for delayed destruction
LK.on('tick', function () {
// Animate infinite button (only in level 1 before game starts)
if (currentLevel === 1 && !gameStarted && infiniteButton && infiniteButton.parent) {
infiniteAnimationTimer++;
if (infiniteAnimationTimer >= infiniteAnimationSpeed) {
currentInfiniteTextureIndex = (currentInfiniteTextureIndex + 1) % infiniteTextures.length;
// Add current button to queue for delayed destruction
infiniteButtonQueue.push(infiniteButton);
// Create new button with next texture at 4.76x scale and fixed position
infiniteButton = LK.getAsset(infiniteTextures[currentInfiniteTextureIndex], {
anchorX: 0.5,
anchorY: 0.5,
x: gameWidth / 2,
y: gameHeight / 2 + 430,
scaleX: 4.76,
scaleY: 4.76
});
game.addChild(infiniteButton);
// If we have 3 or more buttons in queue, destroy the oldest one
if (infiniteButtonQueue.length >= 3) {
var buttonToDestroy = infiniteButtonQueue.shift(); // Remove first (oldest) button from queue
// Fade out and destroy the oldest button with 0.1 second delay
tween(buttonToDestroy, {
alpha: 0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove old button after fade out
if (buttonToDestroy.parent) {
game.removeChild(buttonToDestroy);
}
buttonToDestroy.destroy();
}
});
}
infiniteAnimationTimer = 0;
}
}
});
bire bir aynı daha açık parlak sarı
birebir aynısı sarı-gri renkleri biraz daha koyu gri ile karıştır mavi-gri renklerin maviliğini biraz arttır. biraz da kırmızı-gri kareleri düzel
birebir aynısı. karelerin yerlerini değiştir dizilimi bozmadan
fitili ateşlenmiş parlak üzerinde yeşil tehlike işareti olan siyah bomba. In-Game asset. 2d. High contrast. No shadows
müzik temalı cool ready yazısı biraz da sprey boya punk tarzı. In-Game asset. 2d. High contrast. No shadows
dehşet saçan bir hell mode yazısı tek line olsun geniş kısa. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
açık mavi dj masası ekipmanı. In-Game asset. 2d. High contrast. No shadows
aynı stil daha parlak ve altınımsı mikrofon ve kulaklığı kaldır
orange cool dj keyboard rgb keys. In-Game asset. 2d. High contrast. No shadows
red cool dj headset rgp neon. In-Game asset. 2d. High contrast. No shadows