/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BackgroundStar = Container.expand(function () { var self = Container.call(this); var starGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5 }); self.twinkleSpeed = 0.02 + Math.random() * 0.03; self.twinkleOffset = Math.random() * Math.PI * 2; self.baseAlpha = 0.3 + Math.random() * 0.7; self.update = function () { // Direct property updates instead of creating tweens every frame var twinkle = Math.sin(LK.ticks * self.twinkleSpeed + self.twinkleOffset) * 0.3 + 0.7; self.alpha = self.baseAlpha * twinkle; // Direct position updates for smooth movement self.x += Math.sin(LK.ticks * 0.01 + self.twinkleOffset) * 0.02; self.y += Math.cos(LK.ticks * 0.008 + self.twinkleOffset) * 0.015; }; return self; }); var InterferenceField = Container.expand(function () { var self = Container.call(this); var fieldGraphics = self.attachAsset('interferenceField', { anchorX: 0.5, anchorY: 0.5, tint: 0xff4444 }); self.dimension = 0; self.pulseDirection = 1; self.setDimension = function (dim) { self.dimension = dim; self.alpha = 0.8; }; self.update = function () { // Direct rotation update fieldGraphics.rotation += 0.015; // Direct alpha updates instead of creating tweens every frame if (self.dimension === currentDimension) { self.alpha = 0.9 + Math.sin(LK.ticks * 0.05) * 0.3; // Add bright glow effect with color cycling var glowIntensity = Math.sin(LK.ticks * 0.08) * 0.5 + 0.5; fieldGraphics.tint = 0xff0000 + Math.floor(glowIntensity * 0x4444); } else { self.alpha = 0.4; fieldGraphics.tint = 0xff4444; } // Direct position updates for moving fields - reduced speeds for easier gameplay if (self.moveDirection !== undefined) { var moveSpeed = 2.5; // Reduced from 4 to 2.5 // Increase speed for level 8+ if (level >= 8) { moveSpeed = 3.5; // Reduced from 6 to 3.5 } // Ultra-fast speed for level 16+ if (level >= 16) { moveSpeed = 5; // Reduced from 9 to 5 } // Extreme speed for level 11+ if (level >= 11) { moveSpeed = 4; // Reduced from 7 to 4 } self.x += self.moveDirection * moveSpeed; if (self.x <= self.minX || self.x >= self.maxX) { self.moveDirection *= -1; } } }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); self.dimension = 0; self.originalPosition = { x: 0, y: 0 }; self.isBeingDragged = false; self.isCollected = false; self.entangledWith = null; self.setDimension = function (dim) { self.dimension = dim; self.alpha = 1.0; }; self.startDrag = function () { self.isBeingDragged = true; tween(particleGraphics, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200 }); }; self.stopDrag = function () { self.isBeingDragged = false; tween(particleGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); }; self.collect = function () { self.isCollected = true; // Enhanced collection animation with bounce effect tween(self, { scaleX: 1.5, scaleY: 1.5 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { self.visible = false; } }); } }); // Tutorial step progression for particle collection if (isTutorial) { if (tutorialStep === 1 || tutorialStep === 2) { tutorialStep = 3; // Move to "great job" step LK.setTimeout(function () { updateTutorialStep(); }, 800); } else if (tutorialStep === 5) { tutorialStep = 6; LK.setTimeout(function () { updateTutorialStep(); }, 800); } } }; self.update = function () { if (self.isCollected) return; // Initialize collision tracking if (self.lastCoreIntersecting === undefined) { self.lastCoreIntersecting = false; } // Check collision with quantum core - only trigger on first contact var currentCoreIntersecting = false; if (self.dimension === currentDimension && quantumCore) { // Use actual asset dimensions for accurate collision detection var particleHalfWidth = particleGraphics.width / 2; // Use actual particle asset width var particleHalfHeight = particleGraphics.height / 2; // Use actual particle asset height var coreHalfWidth = quantumCore.width / 2; // Use actual quantum core asset width var coreHalfHeight = quantumCore.height / 2; // Use actual quantum core asset height currentCoreIntersecting = Math.abs(self.x - quantumCore.x) < particleHalfWidth + coreHalfWidth && Math.abs(self.y - quantumCore.y) < particleHalfHeight + coreHalfHeight; } if (!self.lastCoreIntersecting && currentCoreIntersecting) { self.collect(); LK.getSound('collectSound').play(); particlesCollected++; checkWinCondition(); } self.lastCoreIntersecting = currentCoreIntersecting; // Check collision with interference fields for (var i = 0; i < interferenceFields.length; i++) { var field = interferenceFields[i]; if (field.dimension === self.dimension) { // Use actual asset dimensions for accurate collision detection var particleHalfWidth = particleGraphics.width / 2; // Use actual particle asset width var particleHalfHeight = particleGraphics.height / 2; // Use actual particle asset height var fieldHalfWidth = field.children[0].width / 2; // Use actual interference field asset width var fieldHalfHeight = field.children[0].height / 2; // Use actual interference field asset height var isColliding = Math.abs(self.x - field.x) < particleHalfWidth + fieldHalfWidth && Math.abs(self.y - field.y) < particleHalfHeight + fieldHalfHeight; if (isColliding) { if (isTutorial) { // In tutorial, just show educational message instead of resetting if (tutorialStep >= 7) { tutorialText.setText('You touched an interference field!\nIn real levels, this would reset the level.'); LK.effects.flashObject(self, 0xff0000, 500); } } else { resetLevel(); return; } } } } // Handle entanglement if (self.entangledWith && !self.isBeingDragged && self.entangledWith.isBeingDragged) { self.x = self.entangledWith.x + 150; self.y = self.entangledWith.y; // Maintain proper alpha based on current dimension var targetAlpha = self.dimension === currentDimension ? 1.0 : 0.15; self.alpha = targetAlpha; } }; self.down = function (x, y, obj) { // Drag handling is now managed by game.down event handler }; return self; }); var Portal = Container.expand(function () { var self = Container.call(this); var portalGraphics = self.attachAsset('portal', { anchorX: 0.5, anchorY: 0.5 }); self.dimension = 0; self.targetDimension = 1; self.setDimension = function (dim) { self.dimension = dim; self.alpha = 1.0; }; self.update = function () { // Direct rotation update portalGraphics.rotation += 0.02; // Check if particles are transported through portal for (var i = 0; i < particles.length; i++) { var particle = particles[i]; if (particle.dimension === self.dimension && !particle.isBeingDragged) { // Use actual asset dimensions for accurate collision detection var portalHalfWidth = portalGraphics.width / 2; // Use actual portal asset width var portalHalfHeight = portalGraphics.height / 2; // Use actual portal asset height var particleHalfWidth = particle.children[0].width / 2; // Use actual particle asset width var particleHalfHeight = particle.children[0].height / 2; // Use actual particle asset height var isColliding = Math.abs(self.x - particle.x) < portalHalfWidth + particleHalfWidth && Math.abs(self.y - particle.y) < portalHalfHeight + particleHalfHeight; if (isColliding) { particle.setDimension(self.targetDimension); LK.getSound('portalSound').play(); LK.effects.flashObject(self, 0xffffff, 300); } } } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); self.type = 'timeBoost'; // Default type self.dimension = 0; self.isCollected = false; self.powerUpGraphics = null; self.floatOffset = Math.random() * Math.PI * 2; self.floatSpeed = 0.02 + Math.random() * 0.01; self.glowDirection = 1; self.glowIntensity = 1.0; self.setType = function (type) { self.type = type; if (self.powerUpGraphics) { self.powerUpGraphics.destroy(); } var assetName = type === 'timeBoost' ? 'timeBoost' : type === 'shield' ? 'shieldPower' : 'slowMotion'; self.powerUpGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); }; self.setDimension = function (dim) { self.dimension = dim; self.alpha = 1.0; }; self.collect = function () { self.isCollected = true; LK.getSound('powerUpSound').play(); // Collect animation with burst effect tween(self, { scaleX: 2.0, scaleY: 2.0, alpha: 0 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { self.visible = false; } }); // Apply power-up effect self.applyEffect(); }; self.applyEffect = function () { if (self.type === 'timeBoost') { timeRemaining += 15000; // Add 15 seconds (increased from 10) LK.effects.flashScreen(0x00ff00, 300); showPowerUpSpec('TIME BOOST', '+15 seconds', 0x00ff00); } else if (self.type === 'shield') { shieldActive = true; shieldTimeRemaining = 12000; // 12 seconds of shield (increased from 8) LK.effects.flashScreen(0x0088ff, 300); showPowerUpSpec('SHIELD', '12 seconds protection', 0x0088ff); } else if (self.type === 'slowMotion') { slowMotionActive = true; slowMotionTimeRemaining = 10000; // 10 seconds of slow motion (increased from 6) LK.effects.flashScreen(0xff8800, 300); showPowerUpSpec('SLOW MOTION', '10 seconds effect', 0xff8800); } }; self.update = function () { if (self.isCollected) return; // Initialize collision tracking if (self.lastPlayerIntersecting === undefined) { self.lastPlayerIntersecting = false; } // Floating animation self.y += Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 0.5; // Glow effect self.glowIntensity += self.glowDirection * 0.02; if (self.glowIntensity > 1.3) { self.glowIntensity = 1.3; self.glowDirection = -1; } else if (self.glowIntensity < 0.7) { self.glowIntensity = 0.7; self.glowDirection = 1; } self.scaleX = self.glowIntensity; self.scaleY = self.glowIntensity; // Rotation for visual appeal if (self.powerUpGraphics) { self.powerUpGraphics.rotation += 0.03; } // Update visibility based on current dimension var targetAlpha = self.dimension === currentDimension ? self.glowIntensity : 0.15; if (Math.abs(self.alpha - targetAlpha) > 0.05) { self.alpha = targetAlpha; } // Check collision with all particles in current dimension var currentPlayerIntersecting = false; for (var p = 0; p < particles.length; p++) { var particle = particles[p]; if (particle.dimension === self.dimension && particle.dimension === currentDimension && !particle.isCollected) { // Use actual asset dimensions for accurate collision detection var powerUpHalfWidth = self.powerUpGraphics.width / 2; // Use actual power-up asset width var powerUpHalfHeight = self.powerUpGraphics.height / 2; // Use actual power-up asset height var particleHalfWidth = particle.children[0].width / 2; // Use actual particle asset width var particleHalfHeight = particle.children[0].height / 2; // Use actual particle asset height var isColliding = Math.abs(self.x - particle.x) < powerUpHalfWidth + particleHalfWidth && Math.abs(self.y - particle.y) < powerUpHalfHeight + particleHalfHeight; if (isColliding) { currentPlayerIntersecting = true; break; } } } if (!self.lastPlayerIntersecting && currentPlayerIntersecting) { self.collect(); } self.lastPlayerIntersecting = currentPlayerIntersecting; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000033 }); /**** * Game Code ****/ var currentDimension = 0; var totalDimensions = 2; var particles = []; var portals = []; var interferenceFields = []; var quantumCore; var draggedParticle = null; var dragOffset = { x: 0, y: 0 }; var particlesCollected = 0; var totalParticles = 0; var level = 0; // Start with tutorial level (level 0) var timeLimit = 25000; // 25 seconds in milliseconds var timeRemaining = timeLimit; var timerActive = false; var dimensionSwitches = 0; var maxDimensionSwitches = 5; var backgroundStars = []; var powerUps = []; var shieldActive = false; var shieldTimeRemaining = 0; var slowMotionActive = false; var slowMotionTimeRemaining = 0; var powerUpSpawnTimer = 0; var powerUpSpawnInterval = 8000; // Spawn power-up every 8 seconds var isTutorial = true; var tutorialStep = 0; var tutorialComplete = false; var tutorialText = null; // UI Elements var dimensionText = new Text2('Dimension: 0', { size: 60, fill: 0xFFFFFF }); dimensionText.anchor.set(0.5, 0); LK.gui.top.addChild(dimensionText); var levelText = new Text2('Level: 1', { size: 50, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); levelText.y = 100; LK.gui.top.addChild(levelText); var instructionText = new Text2('Tap to switch dimensions', { size: 40, fill: 0xCCCCCC }); instructionText.anchor.set(0.5, 1); LK.gui.bottom.addChild(instructionText); var timerText = new Text2('Time: 25s', { size: 50, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); timerText.y = 160; LK.gui.top.addChild(timerText); var shieldText = new Text2('SHIELD ACTIVE', { size: 45, fill: 0x0088ff }); shieldText.anchor.set(0.5, 0); shieldText.y = 220; shieldText.visible = false; LK.gui.top.addChild(shieldText); var slowMotionText = new Text2('SLOW MOTION', { size: 45, fill: 0xff8800 }); slowMotionText.anchor.set(0.5, 0); slowMotionText.y = 280; slowMotionText.visible = false; LK.gui.top.addChild(slowMotionText); // Tutorial text - larger and more visible tutorialText = new Text2('Welcome to Quantum Dimensions!', { size: 55, fill: 0x00ff88 }); tutorialText.anchor.set(0.5, 0.5); tutorialText.x = 1024; tutorialText.y = 500; // Better positioning tutorialText.visible = false; game.addChild(tutorialText); // Create dimension indicators var dimensionIndicators = []; for (var d = 0; d < totalDimensions; d++) { var indicator = LK.getAsset('dimensionIndicator', { anchorX: 0.5, anchorY: 0.5, x: 1024 + d * 60, y: 150 }); dimensionIndicators.push(indicator); LK.gui.addChild(indicator); } function initializeLevel() { // Clear existing elements for (var i = 0; i < particles.length; i++) { particles[i].destroy(); } for (var i = 0; i < portals.length; i++) { portals[i].destroy(); } for (var i = 0; i < interferenceFields.length; i++) { interferenceFields[i].destroy(); } for (var i = 0; i < backgroundStars.length; i++) { backgroundStars[i].destroy(); } for (var i = 0; i < powerUps.length; i++) { powerUps[i].destroy(); } backgroundStars = []; particles = []; portals = []; interferenceFields = []; powerUps = []; particlesCollected = 0; currentDimension = 0; // Reset and start timer - reduced time penalty for easier gameplay var timeReduction = (level - 1) * 800; // Reduced from 1500 to 800 // Extra time reduction for extreme levels - less harsh if (level >= 11) { timeReduction += (level - 10) * 200; // Reduced from 500 to 200 } if (level >= 16) { timeReduction += (level - 15) * 100; // Reduced from 300 to 100 } timeRemaining = Math.max(12000, timeLimit - timeReduction); // Increased minimum from 6 to 12 seconds timerActive = true; dimensionSwitches = 0; maxDimensionSwitches = Math.max(12, 18 - Math.min(level, 4)); // More switches allowed, minimum 12 (increased from 8) // Reset power-up system shieldActive = false; shieldTimeRemaining = 0; slowMotionActive = false; slowMotionTimeRemaining = 0; powerUpSpawnTimer = 0; shieldText.visible = false; slowMotionText.visible = false; // Create quantum core if (quantumCore) { quantumCore.destroy(); } quantumCore = game.addChild(LK.getAsset('quantumCore', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 800 })); // Create background star field var numStars = 80 + level * 15; for (var i = 0; i < numStars; i++) { var star = game.addChild(new BackgroundStar()); star.x = Math.random() * 2048; star.y = Math.random() * 2732; star.scaleX = 0.5 + Math.random() * 1.5; star.scaleY = star.scaleX; backgroundStars.push(star); } // Create orbital particles around quantum core for (var i = 0; i < 8; i++) { var orbitalStar = game.addChild(new BackgroundStar()); var angle = i / 8 * Math.PI * 2; var radius = 200 + Math.random() * 100; orbitalStar.x = quantumCore.x + Math.cos(angle) * radius; orbitalStar.y = quantumCore.y + Math.sin(angle) * radius; orbitalStar.scaleX = 1.5; orbitalStar.scaleY = 1.5; orbitalStar.orbitalAngle = angle; orbitalStar.orbitalRadius = radius; orbitalStar.orbitalSpeed = 0.01 + Math.random() * 0.02; backgroundStars.push(orbitalStar); } // Tutorial level setup (Level 0) if (level === 0) { isTutorial = true; tutorialStep = 0; tutorialComplete = false; timerActive = false; // No timer pressure in tutorial maxDimensionSwitches = 999; // Unlimited switches for tutorial tutorialText.visible = true; tutorialText.setText('Welcome to Quantum Dimensions!'); // Single particle in dimension 0 for simple drag tutorial var tutorialParticle = game.addChild(new Particle()); tutorialParticle.x = 300; tutorialParticle.y = 1800; tutorialParticle.setDimension(0); tutorialParticle.lastCoreIntersecting = false; tutorialParticle.isBeingDragged = false; tutorialParticle.isCollected = false; tutorialParticle.dimension = 0; // Ensure dimension is properly set particles.push(tutorialParticle); // Add a second particle in dimension 1 to demonstrate dimension switching var tutorialParticle2 = game.addChild(new Particle()); tutorialParticle2.x = 1700; tutorialParticle2.y = 1800; tutorialParticle2.setDimension(1); tutorialParticle2.lastCoreIntersecting = false; tutorialParticle2.isBeingDragged = false; tutorialParticle2.isCollected = false; tutorialParticle2.dimension = 1; // Ensure dimension is properly set particles.push(tutorialParticle2); // Add a safe interference field for demonstration (not dangerous in tutorial) var demoField = game.addChild(new InterferenceField()); demoField.x = 1024; demoField.y = 2200; demoField.setDimension(0); demoField.alpha = 0.3; // Make it less threatening interferenceFields.push(demoField); // Add a portal for demonstration var demoPortal = game.addChild(new Portal()); demoPortal.x = 1024; demoPortal.y = 1400; demoPortal.dimension = 0; demoPortal.targetDimension = 1; demoPortal.setDimension(0); demoPortal.alpha = 0.5; // Make it visible but not distracting portals.push(demoPortal); totalParticles = 2; // Count both particles for tutorial completion // Show tutorial instructions immediately LK.setTimeout(function () { updateTutorialStep(); }, 500); } else if (level === 1) { // Reset tutorial flags for actual gameplay isTutorial = false; tutorialText.visible = false; timerActive = true; // Simple particles in different dimensions var particle1 = game.addChild(new Particle()); particle1.x = 300; particle1.y = 1600; particle1.setDimension(0); particle1.lastCoreIntersecting = false; particle1.isBeingDragged = false; particle1.isCollected = false; particles.push(particle1); var particle2 = game.addChild(new Particle()); particle2.x = 1700; particle2.y = 1600; particle2.setDimension(1); particle2.lastCoreIntersecting = false; particle2.isBeingDragged = false; particle2.isCollected = false; particles.push(particle2); // Portal to connect dimensions var portal1 = game.addChild(new Portal()); portal1.x = 1024; portal1.y = 1600; portal1.dimension = 0; portal1.targetDimension = 1; portal1.setDimension(0); portals.push(portal1); totalParticles = 2; } else { // Progressive levels with more complexity - reduced interference fields var numParticles = Math.min(level + 1, 4); var numFields = Math.min(Math.max(0, level - 1), 4); // Fewer interference fields, starting from level 2 for (var i = 0; i < numParticles; i++) { var particle = game.addChild(new Particle()); particle.x = 200 + i * 400; particle.y = 1800 + i % 2 * 400; particle.setDimension(i % totalDimensions); particle.lastCoreIntersecting = false; particle.isBeingDragged = false; particle.isCollected = false; particles.push(particle); } // Create entangled pairs for higher levels if (level >= 3 && particles.length >= 2) { particles[0].entangledWith = particles[1]; particles[1].entangledWith = particles[0]; } // Create portals for (var i = 0; i < 2; i++) { var portal = game.addChild(new Portal()); portal.x = 400 + i * 1200; portal.y = 1200; portal.dimension = i; portal.targetDimension = (i + 1) % totalDimensions; portal.setDimension(i); portals.push(portal); } // Create interference fields for (var i = 0; i < numFields; i++) { var field = game.addChild(new InterferenceField()); field.x = 300 + i * 600; field.y = 1000 + i % 2 * 400; field.setDimension(i % totalDimensions); // Add movement to interference fields for higher levels if (level >= 2) { field.moveDirection = i % 2 === 0 ? 1 : -1; field.minX = 100; field.maxX = 1948; } interferenceFields.push(field); } // Add additional moving barriers for higher levels if (level >= 2) { var movingField = game.addChild(new InterferenceField()); movingField.x = 1024; movingField.y = 1400; movingField.setDimension(0); movingField.moveDirection = 1; movingField.minX = 200; movingField.maxX = 1848; interferenceFields.push(movingField); } // Add second moving barrier for level 3+ if (level >= 3) { var movingField2 = game.addChild(new InterferenceField()); movingField2.x = 500; movingField2.y = 2000; movingField2.setDimension(1); movingField2.moveDirection = -1; movingField2.minX = 100; movingField2.maxX = 1948; interferenceFields.push(movingField2); } // Add third moving barrier for level 4+ if (level >= 4) { var movingField3 = game.addChild(new InterferenceField()); movingField3.x = 1500; movingField3.y = 1600; movingField3.setDimension(0); movingField3.moveDirection = 1; movingField3.minX = 300; movingField3.maxX = 1700; interferenceFields.push(movingField3); } // Add fourth moving barrier for level 5+ if (level >= 5) { var movingField4 = game.addChild(new InterferenceField()); movingField4.x = 800; movingField4.y = 1800; movingField4.setDimension(1); movingField4.moveDirection = -1; movingField4.minX = 200; movingField4.maxX = 1800; interferenceFields.push(movingField4); } // Advanced levels 6-10 with additional challenges if (level >= 6) { // Add more particles for higher levels var extraParticles = Math.min(level - 5, 3); for (var j = 0; j < extraParticles; j++) { var extraParticle = game.addChild(new Particle()); extraParticle.x = 400 + j * 300; extraParticle.y = 2200 + j % 2 * 200; extraParticle.setDimension(j % totalDimensions); extraParticle.lastCoreIntersecting = false; extraParticle.isBeingDragged = false; extraParticle.isCollected = false; particles.push(extraParticle); } totalParticles += extraParticles; // Add additional moving barriers var numExtraFields = Math.min(level - 5, 4); for (var k = 0; k < numExtraFields; k++) { var extraField = game.addChild(new InterferenceField()); extraField.x = 200 + k * 400; extraField.y = 1300 + k % 2 * 300; extraField.setDimension(k % totalDimensions); extraField.moveDirection = k % 2 === 0 ? 1 : -1; extraField.minX = 100; extraField.maxX = 1948; interferenceFields.push(extraField); } } // Level 8+ speed increase is now handled in the InterferenceField update method // Level 10 gets entangled triplets if (level >= 10 && particles.length >= 3) { particles[0].entangledWith = particles[1]; particles[1].entangledWith = particles[2]; particles[2].entangledWith = particles[0]; } // Advanced levels 11-15 with extreme challenges if (level >= 11) { // Add even more particles for extreme levels var extremeParticles = Math.min(level - 10, 5); for (var m = 0; m < extremeParticles; m++) { var extremeParticle = game.addChild(new Particle()); extremeParticle.x = 150 + m * 250; extremeParticle.y = 2400 + m % 2 * 150; extremeParticle.setDimension(m % totalDimensions); extremeParticle.lastCoreIntersecting = false; extremeParticle.isBeingDragged = false; extremeParticle.isCollected = false; particles.push(extremeParticle); } totalParticles += extremeParticles; // Add maze-like interference field patterns var mazeFields = Math.min(level - 10, 6); for (var n = 0; n < mazeFields; n++) { var mazeField = game.addChild(new InterferenceField()); mazeField.x = 300 + n * 200; mazeField.y = 1100 + n % 3 * 200; mazeField.setDimension(n % totalDimensions); mazeField.moveDirection = n % 2 === 0 ? 1 : -1; mazeField.minX = 50; mazeField.maxX = 1998; interferenceFields.push(mazeField); } } // Master levels 16-20 with ultimate difficulty if (level >= 16) { // Add master-level particles var masterParticles = Math.min(level - 15, 4); for (var p = 0; p < masterParticles; p++) { var masterParticle = game.addChild(new Particle()); masterParticle.x = 200 + p * 400; masterParticle.y = 2500 + p % 2 * 100; masterParticle.setDimension(p % totalDimensions); masterParticle.lastCoreIntersecting = false; masterParticle.isBeingDragged = false; masterParticle.isCollected = false; particles.push(masterParticle); } totalParticles += masterParticles; // Create complex entanglement networks if (particles.length >= 4) { for (var q = 0; q < Math.min(particles.length - 1, 6); q++) { if (q + 1 < particles.length) { particles[q].entangledWith = particles[q + 1]; } } } // Add ultra-fast moving barriers var ultraFields = Math.min(level - 15, 8); for (var r = 0; r < ultraFields; r++) { var ultraField = game.addChild(new InterferenceField()); ultraField.x = 100 + r * 180; ultraField.y = 1200 + r % 4 * 150; ultraField.setDimension(r % totalDimensions); ultraField.moveDirection = r % 2 === 0 ? 1 : -1; ultraField.minX = 50; ultraField.maxX = 1998; interferenceFields.push(ultraField); } } // Calculate total particles correctly for all levels totalParticles = particles.length; } updateDimensionDisplay(); if (level === 0) { levelText.setText('Tutorial'); } else { levelText.setText('Level: ' + level); } } function updateDimensionDisplay() { dimensionText.setText('Dimension: ' + currentDimension); instructionText.setText('Switches: ' + dimensionSwitches + '/' + maxDimensionSwitches + ' - Tap to switch'); for (var i = 0; i < dimensionIndicators.length; i++) { var indicator = dimensionIndicators[i]; tween(indicator, { alpha: i === currentDimension ? 1.0 : 0.3, scaleX: i === currentDimension ? 1.5 : 1.0, scaleY: i === currentDimension ? 1.5 : 1.0 }, { duration: 300, easing: tween.easeOut }); } // Update all objects for dimension visibility for (var i = 0; i < particles.length; i++) { var targetAlpha = particles[i].dimension === currentDimension ? 1.0 : 0.15; tween(particles[i], { alpha: targetAlpha }, { duration: 200, easing: tween.easeInOut }); } for (var i = 0; i < portals.length; i++) { var targetAlpha = portals[i].dimension === currentDimension ? 1.0 : 0.1; tween(portals[i], { alpha: targetAlpha }, { duration: 200, easing: tween.easeInOut }); } for (var i = 0; i < interferenceFields.length; i++) { var targetAlpha = interferenceFields[i].dimension === currentDimension ? 0.8 : 0.1; tween(interferenceFields[i], { alpha: targetAlpha }, { duration: 200, easing: tween.easeInOut }); } for (var i = 0; i < powerUps.length; i++) { var targetAlpha = powerUps[i].dimension === currentDimension ? 1.0 : 0.15; tween(powerUps[i], { alpha: targetAlpha }, { duration: 200, easing: tween.easeInOut }); } } function switchDimension() { if (dimensionSwitches >= maxDimensionSwitches && !isTutorial) { LK.effects.flashScreen(0xFF0000, 200); return; // No more switches allowed (except in tutorial) } dimensionSwitches++; // Remove time penalty to make dimension switching more accessible currentDimension = (currentDimension + 1) % totalDimensions; updateDimensionDisplay(); LK.getSound('dimensionShift').play(); LK.effects.flashScreen(0x440088, 200); // Tutorial progress tracking if (isTutorial) { if (tutorialStep === 3) { tutorialStep = 4; // Add celebratory flash for successful dimension switch LK.effects.flashScreen(0x00ff88, 300); LK.setTimeout(function () { updateTutorialStep(); }, 800); } else if (tutorialStep === 4 && currentDimension === 1) { // Player successfully switched to dimension 1 tutorialStep = 5; LK.setTimeout(function () { updateTutorialStep(); }, 1200); } } } function checkWinCondition() { if (particlesCollected >= totalParticles) { timerActive = false; // Stop timer when level complete if (isTutorial) { if (particlesCollected === 1 && tutorialStep <= 3) { // First particle collected, advance tutorial tutorialStep = 3; updateTutorialStep(); return; } else if (particlesCollected >= 2) { // All particles collected in tutorial, complete it if (tutorialStep < 6) { tutorialStep = 6; updateTutorialStep(); } else if (tutorialComplete || tutorialStep >= 10) { // Tutorial is complete, move to level 1 level = 1; isTutorial = false; tutorialText.visible = false; initializeLevel(); } return; } } level++; LK.setTimeout(function () { if (level > 20) { LK.showYouWin(); } else { initializeLevel(); } }, 1000); } } function resetLevel() { // Check if shield is active to prevent death if (shieldActive) { shieldActive = false; shieldTimeRemaining = 0; shieldText.visible = false; LK.effects.flashScreen(0x0088ff, 300); return; // Shield absorbed the hit } LK.effects.flashScreen(0xff0000, 500); LK.setTimeout(function () { initializeLevel(); }, 600); } function spawnPowerUp() { if (powerUps.length >= 2) return; // Maximum 2 power-ups on screen var powerUp = game.addChild(new PowerUp()); // Ensure power-ups spawn in safe areas away from interference fields var safePosition = false; var attempts = 0; var spawnX, spawnY; while (!safePosition && attempts < 10) { spawnX = 300 + Math.random() * 1448; spawnY = 600 + Math.random() * 800; // Check distance from interference fields safePosition = true; for (var f = 0; f < interferenceFields.length; f++) { var field = interferenceFields[f]; var distance = Math.sqrt((spawnX - field.x) * (spawnX - field.x) + (spawnY - field.y) * (spawnY - field.y)); if (distance < 200) { safePosition = false; break; } } attempts++; } powerUp.x = spawnX || 300 + Math.random() * 1448; powerUp.y = spawnY || 600 + Math.random() * 800; powerUp.setDimension(currentDimension); // Always spawn in current dimension for better accessibility // Random power-up type var types = ['timeBoost', 'shield', 'slowMotion']; var randomType = types[Math.floor(Math.random() * types.length)]; powerUp.setType(randomType); powerUp.lastPlayerIntersecting = false; powerUps.push(powerUp); } // Event handlers game.down = function (x, y, obj) { var hitParticle = false; for (var i = 0; i < particles.length; i++) { var particle = particles[i]; if (particle.dimension === currentDimension && !particle.isCollected && particle.alpha > 0.5) { // Use actual asset dimensions for accurate touch detection var halfWidth = particle.children[0].width / 2; // Use actual particle asset width var halfHeight = particle.children[0].height / 2; // Use actual particle asset height // Check if touch point is within particle bounds if (x >= particle.x - halfWidth && x <= particle.x + halfWidth && y >= particle.y - halfHeight && y <= particle.y + halfHeight) { draggedParticle = particle; particle.startDrag(); dragOffset.x = x - particle.x; dragOffset.y = y - particle.y; hitParticle = true; break; } } } if (!hitParticle) { switchDimension(); } }; game.move = function (x, y, obj) { if (draggedParticle && !draggedParticle.isCollected) { var targetX = x - dragOffset.x; var targetY = y - dragOffset.y; // Keep particle within bounds targetX = Math.max(80, Math.min(1968, targetX)); targetY = Math.max(80, Math.min(2652, targetY)); // Direct position update for responsive dragging draggedParticle.x = targetX; draggedParticle.y = targetY; // Reduce trail effect frequency to improve performance if (LK.ticks % 10 === 0) { var trailStar = game.addChild(new BackgroundStar()); trailStar.x = draggedParticle.x + (Math.random() - 0.5) * 20; trailStar.y = draggedParticle.y + (Math.random() - 0.5) * 20; trailStar.scaleX = 0.8; trailStar.scaleY = 0.8; trailStar.alpha = 0.8; // Fade out trail particle tween(trailStar, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { trailStar.destroy(); } }); } // Handle entangled particle movement with direct updates if (draggedParticle.entangledWith) { // Only move entangled particles when BOTH the dragged particle AND the entangled particle are in the current dimension // This prevents cross-dimensional interference where particles in other dimensions move unexpectedly if (draggedParticle.dimension === currentDimension && draggedParticle.entangledWith.dimension === currentDimension) { draggedParticle.entangledWith.x = targetX + 150; draggedParticle.entangledWith.y = targetY; } // Ensure entangled particles maintain proper alpha based on current dimension var entangledTargetAlpha = draggedParticle.entangledWith.dimension === currentDimension ? 1.0 : 0.15; draggedParticle.entangledWith.alpha = entangledTargetAlpha; } } }; game.up = function (x, y, obj) { if (draggedParticle) { draggedParticle.stopDrag(); draggedParticle = null; } }; game.update = function () { // Handle timer countdown if (timerActive) { var timeDecrement = slowMotionActive ? 8.33 : 16.67; // Slow motion halves time consumption timeRemaining -= timeDecrement; if (timeRemaining <= 0) { resetLevel(); return; } var seconds = Math.ceil(timeRemaining / 1000); timerText.setText('Time: ' + seconds + 's'); // Smooth color transitions when time is running out if (seconds <= 5) { tween(timerText, { tint: 0xFF0000 }, { duration: 200, easing: tween.easeOut }); } else if (seconds <= 10) { tween(timerText, { tint: 0xFFFF00 }, { duration: 200, easing: tween.easeOut }); } else { tween(timerText, { tint: 0xFFFFFF }, { duration: 200, easing: tween.easeOut }); } } // Animate quantum core with direct property updates if (quantumCore) { // Direct rotation update quantumCore.rotation += 0.02; // Direct pulsing animation var pulse = Math.sin(LK.ticks * 0.08) * 0.15 + 1.0; quantumCore.scaleX = pulse; quantumCore.scaleY = pulse; // Reduced frequency color cycling if (LK.ticks % 60 === 0) { var colorPhase = LK.ticks * 0.015; var r = Math.sin(colorPhase) * 0.4 + 0.6; var g = Math.sin(colorPhase + 2) * 0.4 + 0.6; var b = Math.sin(colorPhase + 4) * 0.4 + 0.6; var color = Math.floor(r * 255) << 16 | Math.floor(g * 255) << 8 | Math.floor(b * 255); quantumCore.tint = color; } } // Update all particles for (var i = 0; i < particles.length; i++) { if (particles[i].update) { particles[i].update(); } } // Update all portals for (var i = 0; i < portals.length; i++) { if (portals[i].update) { portals[i].update(); } } // Update all interference fields for (var i = 0; i < interferenceFields.length; i++) { if (interferenceFields[i].update) { interferenceFields[i].update(); } } // Handle power-up spawning if (timerActive) { powerUpSpawnTimer += 16.67; // Calculate dynamic spawn interval based on level - more frequent power-ups var dynamicSpawnInterval = powerUpSpawnInterval; if (level >= 5) { dynamicSpawnInterval = Math.max(3000, powerUpSpawnInterval - (level - 4) * 300); // Faster spawning for higher levels, minimum 3 seconds (reduced from 4) } if (powerUpSpawnTimer >= dynamicSpawnInterval) { spawnPowerUp(); powerUpSpawnTimer = 0; } } // Handle shield duration if (shieldActive) { shieldTimeRemaining -= 16.67; if (shieldTimeRemaining <= 0) { shieldActive = false; shieldText.visible = false; } else { shieldText.visible = true; shieldText.setText('SHIELD: ' + Math.ceil(shieldTimeRemaining / 1000) + 's'); } } // Handle slow motion duration if (slowMotionActive) { slowMotionTimeRemaining -= 16.67; if (slowMotionTimeRemaining <= 0) { slowMotionActive = false; slowMotionText.visible = false; } else { slowMotionText.visible = true; slowMotionText.setText('SLOW MOTION: ' + Math.ceil(slowMotionTimeRemaining / 1000) + 's'); } } // Update power-ups for (var i = powerUps.length - 1; i >= 0; i--) { if (powerUps[i].update) { powerUps[i].update(); } // Remove collected power-ups if (powerUps[i].isCollected && !powerUps[i].visible) { powerUps[i].destroy(); powerUps.splice(i, 1); } } // Update background stars for (var i = 0; i < backgroundStars.length; i++) { var star = backgroundStars[i]; if (star.update) { star.update(); } // Handle orbital motion for core particles if (star.orbitalAngle !== undefined && quantumCore) { star.orbitalAngle += star.orbitalSpeed; star.x = quantumCore.x + Math.cos(star.orbitalAngle) * star.orbitalRadius; star.y = quantumCore.y + Math.sin(star.orbitalAngle) * star.orbitalRadius; } } }; function updateTutorialStep() { if (!isTutorial) return; // Ensure tutorial text is visible and properly positioned tutorialText.visible = true; tutorialText.alpha = 1.0; // Position tutorial text in center area for better visibility tutorialText.x = 1024; tutorialText.y = 500; // Better positioning for readability // Ensure text is on top and visible game.removeChild(tutorialText); game.addChild(tutorialText); switch (tutorialStep) { case 0: tutorialText.setText('Welcome to Quantum Dimensions!\nMove particles to the center core to collect them.'); LK.setTimeout(function () { tutorialStep = 1; updateTutorialStep(); }, 2500); break; case 1: tutorialText.setText('STEP 1: DRAG A PARTICLE\nTouch and drag the glowing particle below.'); // Add visual hint by pulsing the particle if (particles.length > 0 && particles[0].dimension === currentDimension) { LK.effects.flashObject(particles[0], 0x00ff00, 1500); // Keep flashing until moved LK.setInterval(function () { if (tutorialStep === 1 && !particles[0].isBeingDragged) { LK.effects.flashObject(particles[0], 0x00ff00, 800); } }, 1000); } break; case 2: tutorialText.setText('STEP 2: MOVE TO CENTER\nDrag the particle to the quantum core (glowing center).'); // Add visual hint by flashing the quantum core if (quantumCore) { LK.effects.flashObject(quantumCore, 0x00ffff, 2000); // Keep flashing until collected LK.setInterval(function () { if (tutorialStep === 2 && quantumCore) { LK.effects.flashObject(quantumCore, 0x00ffff, 1000); } }, 1500); } break; case 3: tutorialText.setText('GREAT! Particle collected!\nNow tap empty space to switch dimensions.'); break; case 4: tutorialText.setText('STEP 3: DIMENSION SWITCHING\nYou switched to Dimension 1! See the other particle?'); if (particles.length > 1 && particles[1].dimension === currentDimension) { LK.effects.flashObject(particles[1], 0x00ff00, 1500); } LK.setTimeout(function () { tutorialStep = 5; updateTutorialStep(); }, 2500); break; case 5: tutorialText.setText('STEP 4: COLLECT SECOND PARTICLE\nDrag this particle to the center too.'); if (particles.length > 1 && particles[1].dimension === currentDimension) { LK.effects.flashObject(particles[1], 0x00ff00, 1500); // Keep flashing until collected LK.setInterval(function () { if (tutorialStep === 5 && particles.length > 1 && !particles[1].isCollected) { LK.effects.flashObject(particles[1], 0x00ff00, 800); } }, 1200); } break; case 6: tutorialText.setText('PERFECT! You mastered the basics!\nRemember: Limited dimension switches in real levels.'); LK.setTimeout(function () { tutorialStep = 7; updateTutorialStep(); }, 2500); break; case 7: tutorialText.setText('WARNING: RED FIELDS = DANGER\nAvoid red interference fields - they reset the level!'); // Flash the demo interference field to show danger for (var i = 0; i < interferenceFields.length; i++) { LK.effects.flashObject(interferenceFields[i], 0xff0000, 2000); } LK.setTimeout(function () { tutorialStep = 8; updateTutorialStep(); }, 3000); break; case 8: tutorialText.setText('BLUE PORTALS = TRANSPORT\nPortals move particles between dimensions.'); // Flash the demo portal for (var i = 0; i < portals.length; i++) { LK.effects.flashObject(portals[i], 0x0088ff, 2000); } LK.setTimeout(function () { tutorialStep = 9; updateTutorialStep(); }, 3000); break; case 9: tutorialText.setText('POWER-UPS HELP YOU:\n🟢 Time Boost 🔵 Shield 🟡 Slow Motion'); LK.setTimeout(function () { tutorialStep = 10; updateTutorialStep(); }, 3500); break; case 10: tutorialText.setText('🎉 TUTORIAL COMPLETE! 🎉\nReady for the real challenge? Starting Level 1...'); LK.setTimeout(function () { tutorialComplete = true; checkWinCondition(); // Use existing function to transition properly }, 3000); break; } } function showPowerUpSpec(title, description, color) { // Create power-up specification display var specContainer = new Container(); // Title text var titleText = new Text2(title, { size: 60, fill: color }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 1300; specContainer.addChild(titleText); // Description text var descText = new Text2(description, { size: 45, fill: 0xFFFFFF }); descText.anchor.set(0.5, 0.5); descText.x = 1024; descText.y = 1380; specContainer.addChild(descText); // Add to game game.addChild(specContainer); // Initial state specContainer.alpha = 0; specContainer.scaleX = 0.3; specContainer.scaleY = 0.3; // Animation: fade in and scale up tween(specContainer, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Hold for a moment then fade out LK.setTimeout(function () { tween(specContainer, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { specContainer.destroy(); } }); }, 2000); } }); } // Initialize first level initializeLevel();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BackgroundStar = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.twinkleSpeed = 0.02 + Math.random() * 0.03;
self.twinkleOffset = Math.random() * Math.PI * 2;
self.baseAlpha = 0.3 + Math.random() * 0.7;
self.update = function () {
// Direct property updates instead of creating tweens every frame
var twinkle = Math.sin(LK.ticks * self.twinkleSpeed + self.twinkleOffset) * 0.3 + 0.7;
self.alpha = self.baseAlpha * twinkle;
// Direct position updates for smooth movement
self.x += Math.sin(LK.ticks * 0.01 + self.twinkleOffset) * 0.02;
self.y += Math.cos(LK.ticks * 0.008 + self.twinkleOffset) * 0.015;
};
return self;
});
var InterferenceField = Container.expand(function () {
var self = Container.call(this);
var fieldGraphics = self.attachAsset('interferenceField', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff4444
});
self.dimension = 0;
self.pulseDirection = 1;
self.setDimension = function (dim) {
self.dimension = dim;
self.alpha = 0.8;
};
self.update = function () {
// Direct rotation update
fieldGraphics.rotation += 0.015;
// Direct alpha updates instead of creating tweens every frame
if (self.dimension === currentDimension) {
self.alpha = 0.9 + Math.sin(LK.ticks * 0.05) * 0.3;
// Add bright glow effect with color cycling
var glowIntensity = Math.sin(LK.ticks * 0.08) * 0.5 + 0.5;
fieldGraphics.tint = 0xff0000 + Math.floor(glowIntensity * 0x4444);
} else {
self.alpha = 0.4;
fieldGraphics.tint = 0xff4444;
}
// Direct position updates for moving fields - reduced speeds for easier gameplay
if (self.moveDirection !== undefined) {
var moveSpeed = 2.5; // Reduced from 4 to 2.5
// Increase speed for level 8+
if (level >= 8) {
moveSpeed = 3.5; // Reduced from 6 to 3.5
}
// Ultra-fast speed for level 16+
if (level >= 16) {
moveSpeed = 5; // Reduced from 9 to 5
}
// Extreme speed for level 11+
if (level >= 11) {
moveSpeed = 4; // Reduced from 7 to 4
}
self.x += self.moveDirection * moveSpeed;
if (self.x <= self.minX || self.x >= self.maxX) {
self.moveDirection *= -1;
}
}
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.dimension = 0;
self.originalPosition = {
x: 0,
y: 0
};
self.isBeingDragged = false;
self.isCollected = false;
self.entangledWith = null;
self.setDimension = function (dim) {
self.dimension = dim;
self.alpha = 1.0;
};
self.startDrag = function () {
self.isBeingDragged = true;
tween(particleGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200
});
};
self.stopDrag = function () {
self.isBeingDragged = false;
tween(particleGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
};
self.collect = function () {
self.isCollected = true;
// Enhanced collection animation with bounce effect
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
self.visible = false;
}
});
}
});
// Tutorial step progression for particle collection
if (isTutorial) {
if (tutorialStep === 1 || tutorialStep === 2) {
tutorialStep = 3; // Move to "great job" step
LK.setTimeout(function () {
updateTutorialStep();
}, 800);
} else if (tutorialStep === 5) {
tutorialStep = 6;
LK.setTimeout(function () {
updateTutorialStep();
}, 800);
}
}
};
self.update = function () {
if (self.isCollected) return;
// Initialize collision tracking
if (self.lastCoreIntersecting === undefined) {
self.lastCoreIntersecting = false;
}
// Check collision with quantum core - only trigger on first contact
var currentCoreIntersecting = false;
if (self.dimension === currentDimension && quantumCore) {
// Use actual asset dimensions for accurate collision detection
var particleHalfWidth = particleGraphics.width / 2; // Use actual particle asset width
var particleHalfHeight = particleGraphics.height / 2; // Use actual particle asset height
var coreHalfWidth = quantumCore.width / 2; // Use actual quantum core asset width
var coreHalfHeight = quantumCore.height / 2; // Use actual quantum core asset height
currentCoreIntersecting = Math.abs(self.x - quantumCore.x) < particleHalfWidth + coreHalfWidth && Math.abs(self.y - quantumCore.y) < particleHalfHeight + coreHalfHeight;
}
if (!self.lastCoreIntersecting && currentCoreIntersecting) {
self.collect();
LK.getSound('collectSound').play();
particlesCollected++;
checkWinCondition();
}
self.lastCoreIntersecting = currentCoreIntersecting;
// Check collision with interference fields
for (var i = 0; i < interferenceFields.length; i++) {
var field = interferenceFields[i];
if (field.dimension === self.dimension) {
// Use actual asset dimensions for accurate collision detection
var particleHalfWidth = particleGraphics.width / 2; // Use actual particle asset width
var particleHalfHeight = particleGraphics.height / 2; // Use actual particle asset height
var fieldHalfWidth = field.children[0].width / 2; // Use actual interference field asset width
var fieldHalfHeight = field.children[0].height / 2; // Use actual interference field asset height
var isColliding = Math.abs(self.x - field.x) < particleHalfWidth + fieldHalfWidth && Math.abs(self.y - field.y) < particleHalfHeight + fieldHalfHeight;
if (isColliding) {
if (isTutorial) {
// In tutorial, just show educational message instead of resetting
if (tutorialStep >= 7) {
tutorialText.setText('You touched an interference field!\nIn real levels, this would reset the level.');
LK.effects.flashObject(self, 0xff0000, 500);
}
} else {
resetLevel();
return;
}
}
}
}
// Handle entanglement
if (self.entangledWith && !self.isBeingDragged && self.entangledWith.isBeingDragged) {
self.x = self.entangledWith.x + 150;
self.y = self.entangledWith.y;
// Maintain proper alpha based on current dimension
var targetAlpha = self.dimension === currentDimension ? 1.0 : 0.15;
self.alpha = targetAlpha;
}
};
self.down = function (x, y, obj) {
// Drag handling is now managed by game.down event handler
};
return self;
});
var Portal = Container.expand(function () {
var self = Container.call(this);
var portalGraphics = self.attachAsset('portal', {
anchorX: 0.5,
anchorY: 0.5
});
self.dimension = 0;
self.targetDimension = 1;
self.setDimension = function (dim) {
self.dimension = dim;
self.alpha = 1.0;
};
self.update = function () {
// Direct rotation update
portalGraphics.rotation += 0.02;
// Check if particles are transported through portal
for (var i = 0; i < particles.length; i++) {
var particle = particles[i];
if (particle.dimension === self.dimension && !particle.isBeingDragged) {
// Use actual asset dimensions for accurate collision detection
var portalHalfWidth = portalGraphics.width / 2; // Use actual portal asset width
var portalHalfHeight = portalGraphics.height / 2; // Use actual portal asset height
var particleHalfWidth = particle.children[0].width / 2; // Use actual particle asset width
var particleHalfHeight = particle.children[0].height / 2; // Use actual particle asset height
var isColliding = Math.abs(self.x - particle.x) < portalHalfWidth + particleHalfWidth && Math.abs(self.y - particle.y) < portalHalfHeight + particleHalfHeight;
if (isColliding) {
particle.setDimension(self.targetDimension);
LK.getSound('portalSound').play();
LK.effects.flashObject(self, 0xffffff, 300);
}
}
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
self.type = 'timeBoost'; // Default type
self.dimension = 0;
self.isCollected = false;
self.powerUpGraphics = null;
self.floatOffset = Math.random() * Math.PI * 2;
self.floatSpeed = 0.02 + Math.random() * 0.01;
self.glowDirection = 1;
self.glowIntensity = 1.0;
self.setType = function (type) {
self.type = type;
if (self.powerUpGraphics) {
self.powerUpGraphics.destroy();
}
var assetName = type === 'timeBoost' ? 'timeBoost' : type === 'shield' ? 'shieldPower' : 'slowMotion';
self.powerUpGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.setDimension = function (dim) {
self.dimension = dim;
self.alpha = 1.0;
};
self.collect = function () {
self.isCollected = true;
LK.getSound('powerUpSound').play();
// Collect animation with burst effect
tween(self, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
self.visible = false;
}
});
// Apply power-up effect
self.applyEffect();
};
self.applyEffect = function () {
if (self.type === 'timeBoost') {
timeRemaining += 15000; // Add 15 seconds (increased from 10)
LK.effects.flashScreen(0x00ff00, 300);
showPowerUpSpec('TIME BOOST', '+15 seconds', 0x00ff00);
} else if (self.type === 'shield') {
shieldActive = true;
shieldTimeRemaining = 12000; // 12 seconds of shield (increased from 8)
LK.effects.flashScreen(0x0088ff, 300);
showPowerUpSpec('SHIELD', '12 seconds protection', 0x0088ff);
} else if (self.type === 'slowMotion') {
slowMotionActive = true;
slowMotionTimeRemaining = 10000; // 10 seconds of slow motion (increased from 6)
LK.effects.flashScreen(0xff8800, 300);
showPowerUpSpec('SLOW MOTION', '10 seconds effect', 0xff8800);
}
};
self.update = function () {
if (self.isCollected) return;
// Initialize collision tracking
if (self.lastPlayerIntersecting === undefined) {
self.lastPlayerIntersecting = false;
}
// Floating animation
self.y += Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 0.5;
// Glow effect
self.glowIntensity += self.glowDirection * 0.02;
if (self.glowIntensity > 1.3) {
self.glowIntensity = 1.3;
self.glowDirection = -1;
} else if (self.glowIntensity < 0.7) {
self.glowIntensity = 0.7;
self.glowDirection = 1;
}
self.scaleX = self.glowIntensity;
self.scaleY = self.glowIntensity;
// Rotation for visual appeal
if (self.powerUpGraphics) {
self.powerUpGraphics.rotation += 0.03;
}
// Update visibility based on current dimension
var targetAlpha = self.dimension === currentDimension ? self.glowIntensity : 0.15;
if (Math.abs(self.alpha - targetAlpha) > 0.05) {
self.alpha = targetAlpha;
}
// Check collision with all particles in current dimension
var currentPlayerIntersecting = false;
for (var p = 0; p < particles.length; p++) {
var particle = particles[p];
if (particle.dimension === self.dimension && particle.dimension === currentDimension && !particle.isCollected) {
// Use actual asset dimensions for accurate collision detection
var powerUpHalfWidth = self.powerUpGraphics.width / 2; // Use actual power-up asset width
var powerUpHalfHeight = self.powerUpGraphics.height / 2; // Use actual power-up asset height
var particleHalfWidth = particle.children[0].width / 2; // Use actual particle asset width
var particleHalfHeight = particle.children[0].height / 2; // Use actual particle asset height
var isColliding = Math.abs(self.x - particle.x) < powerUpHalfWidth + particleHalfWidth && Math.abs(self.y - particle.y) < powerUpHalfHeight + particleHalfHeight;
if (isColliding) {
currentPlayerIntersecting = true;
break;
}
}
}
if (!self.lastPlayerIntersecting && currentPlayerIntersecting) {
self.collect();
}
self.lastPlayerIntersecting = currentPlayerIntersecting;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000033
});
/****
* Game Code
****/
var currentDimension = 0;
var totalDimensions = 2;
var particles = [];
var portals = [];
var interferenceFields = [];
var quantumCore;
var draggedParticle = null;
var dragOffset = {
x: 0,
y: 0
};
var particlesCollected = 0;
var totalParticles = 0;
var level = 0; // Start with tutorial level (level 0)
var timeLimit = 25000; // 25 seconds in milliseconds
var timeRemaining = timeLimit;
var timerActive = false;
var dimensionSwitches = 0;
var maxDimensionSwitches = 5;
var backgroundStars = [];
var powerUps = [];
var shieldActive = false;
var shieldTimeRemaining = 0;
var slowMotionActive = false;
var slowMotionTimeRemaining = 0;
var powerUpSpawnTimer = 0;
var powerUpSpawnInterval = 8000; // Spawn power-up every 8 seconds
var isTutorial = true;
var tutorialStep = 0;
var tutorialComplete = false;
var tutorialText = null;
// UI Elements
var dimensionText = new Text2('Dimension: 0', {
size: 60,
fill: 0xFFFFFF
});
dimensionText.anchor.set(0.5, 0);
LK.gui.top.addChild(dimensionText);
var levelText = new Text2('Level: 1', {
size: 50,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
levelText.y = 100;
LK.gui.top.addChild(levelText);
var instructionText = new Text2('Tap to switch dimensions', {
size: 40,
fill: 0xCCCCCC
});
instructionText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionText);
var timerText = new Text2('Time: 25s', {
size: 50,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
timerText.y = 160;
LK.gui.top.addChild(timerText);
var shieldText = new Text2('SHIELD ACTIVE', {
size: 45,
fill: 0x0088ff
});
shieldText.anchor.set(0.5, 0);
shieldText.y = 220;
shieldText.visible = false;
LK.gui.top.addChild(shieldText);
var slowMotionText = new Text2('SLOW MOTION', {
size: 45,
fill: 0xff8800
});
slowMotionText.anchor.set(0.5, 0);
slowMotionText.y = 280;
slowMotionText.visible = false;
LK.gui.top.addChild(slowMotionText);
// Tutorial text - larger and more visible
tutorialText = new Text2('Welcome to Quantum Dimensions!', {
size: 55,
fill: 0x00ff88
});
tutorialText.anchor.set(0.5, 0.5);
tutorialText.x = 1024;
tutorialText.y = 500; // Better positioning
tutorialText.visible = false;
game.addChild(tutorialText);
// Create dimension indicators
var dimensionIndicators = [];
for (var d = 0; d < totalDimensions; d++) {
var indicator = LK.getAsset('dimensionIndicator', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024 + d * 60,
y: 150
});
dimensionIndicators.push(indicator);
LK.gui.addChild(indicator);
}
function initializeLevel() {
// Clear existing elements
for (var i = 0; i < particles.length; i++) {
particles[i].destroy();
}
for (var i = 0; i < portals.length; i++) {
portals[i].destroy();
}
for (var i = 0; i < interferenceFields.length; i++) {
interferenceFields[i].destroy();
}
for (var i = 0; i < backgroundStars.length; i++) {
backgroundStars[i].destroy();
}
for (var i = 0; i < powerUps.length; i++) {
powerUps[i].destroy();
}
backgroundStars = [];
particles = [];
portals = [];
interferenceFields = [];
powerUps = [];
particlesCollected = 0;
currentDimension = 0;
// Reset and start timer - reduced time penalty for easier gameplay
var timeReduction = (level - 1) * 800; // Reduced from 1500 to 800
// Extra time reduction for extreme levels - less harsh
if (level >= 11) {
timeReduction += (level - 10) * 200; // Reduced from 500 to 200
}
if (level >= 16) {
timeReduction += (level - 15) * 100; // Reduced from 300 to 100
}
timeRemaining = Math.max(12000, timeLimit - timeReduction); // Increased minimum from 6 to 12 seconds
timerActive = true;
dimensionSwitches = 0;
maxDimensionSwitches = Math.max(12, 18 - Math.min(level, 4)); // More switches allowed, minimum 12 (increased from 8)
// Reset power-up system
shieldActive = false;
shieldTimeRemaining = 0;
slowMotionActive = false;
slowMotionTimeRemaining = 0;
powerUpSpawnTimer = 0;
shieldText.visible = false;
slowMotionText.visible = false;
// Create quantum core
if (quantumCore) {
quantumCore.destroy();
}
quantumCore = game.addChild(LK.getAsset('quantumCore', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 800
}));
// Create background star field
var numStars = 80 + level * 15;
for (var i = 0; i < numStars; i++) {
var star = game.addChild(new BackgroundStar());
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
star.scaleX = 0.5 + Math.random() * 1.5;
star.scaleY = star.scaleX;
backgroundStars.push(star);
}
// Create orbital particles around quantum core
for (var i = 0; i < 8; i++) {
var orbitalStar = game.addChild(new BackgroundStar());
var angle = i / 8 * Math.PI * 2;
var radius = 200 + Math.random() * 100;
orbitalStar.x = quantumCore.x + Math.cos(angle) * radius;
orbitalStar.y = quantumCore.y + Math.sin(angle) * radius;
orbitalStar.scaleX = 1.5;
orbitalStar.scaleY = 1.5;
orbitalStar.orbitalAngle = angle;
orbitalStar.orbitalRadius = radius;
orbitalStar.orbitalSpeed = 0.01 + Math.random() * 0.02;
backgroundStars.push(orbitalStar);
}
// Tutorial level setup (Level 0)
if (level === 0) {
isTutorial = true;
tutorialStep = 0;
tutorialComplete = false;
timerActive = false; // No timer pressure in tutorial
maxDimensionSwitches = 999; // Unlimited switches for tutorial
tutorialText.visible = true;
tutorialText.setText('Welcome to Quantum Dimensions!');
// Single particle in dimension 0 for simple drag tutorial
var tutorialParticle = game.addChild(new Particle());
tutorialParticle.x = 300;
tutorialParticle.y = 1800;
tutorialParticle.setDimension(0);
tutorialParticle.lastCoreIntersecting = false;
tutorialParticle.isBeingDragged = false;
tutorialParticle.isCollected = false;
tutorialParticle.dimension = 0; // Ensure dimension is properly set
particles.push(tutorialParticle);
// Add a second particle in dimension 1 to demonstrate dimension switching
var tutorialParticle2 = game.addChild(new Particle());
tutorialParticle2.x = 1700;
tutorialParticle2.y = 1800;
tutorialParticle2.setDimension(1);
tutorialParticle2.lastCoreIntersecting = false;
tutorialParticle2.isBeingDragged = false;
tutorialParticle2.isCollected = false;
tutorialParticle2.dimension = 1; // Ensure dimension is properly set
particles.push(tutorialParticle2);
// Add a safe interference field for demonstration (not dangerous in tutorial)
var demoField = game.addChild(new InterferenceField());
demoField.x = 1024;
demoField.y = 2200;
demoField.setDimension(0);
demoField.alpha = 0.3; // Make it less threatening
interferenceFields.push(demoField);
// Add a portal for demonstration
var demoPortal = game.addChild(new Portal());
demoPortal.x = 1024;
demoPortal.y = 1400;
demoPortal.dimension = 0;
demoPortal.targetDimension = 1;
demoPortal.setDimension(0);
demoPortal.alpha = 0.5; // Make it visible but not distracting
portals.push(demoPortal);
totalParticles = 2; // Count both particles for tutorial completion
// Show tutorial instructions immediately
LK.setTimeout(function () {
updateTutorialStep();
}, 500);
} else if (level === 1) {
// Reset tutorial flags for actual gameplay
isTutorial = false;
tutorialText.visible = false;
timerActive = true;
// Simple particles in different dimensions
var particle1 = game.addChild(new Particle());
particle1.x = 300;
particle1.y = 1600;
particle1.setDimension(0);
particle1.lastCoreIntersecting = false;
particle1.isBeingDragged = false;
particle1.isCollected = false;
particles.push(particle1);
var particle2 = game.addChild(new Particle());
particle2.x = 1700;
particle2.y = 1600;
particle2.setDimension(1);
particle2.lastCoreIntersecting = false;
particle2.isBeingDragged = false;
particle2.isCollected = false;
particles.push(particle2);
// Portal to connect dimensions
var portal1 = game.addChild(new Portal());
portal1.x = 1024;
portal1.y = 1600;
portal1.dimension = 0;
portal1.targetDimension = 1;
portal1.setDimension(0);
portals.push(portal1);
totalParticles = 2;
} else {
// Progressive levels with more complexity - reduced interference fields
var numParticles = Math.min(level + 1, 4);
var numFields = Math.min(Math.max(0, level - 1), 4); // Fewer interference fields, starting from level 2
for (var i = 0; i < numParticles; i++) {
var particle = game.addChild(new Particle());
particle.x = 200 + i * 400;
particle.y = 1800 + i % 2 * 400;
particle.setDimension(i % totalDimensions);
particle.lastCoreIntersecting = false;
particle.isBeingDragged = false;
particle.isCollected = false;
particles.push(particle);
}
// Create entangled pairs for higher levels
if (level >= 3 && particles.length >= 2) {
particles[0].entangledWith = particles[1];
particles[1].entangledWith = particles[0];
}
// Create portals
for (var i = 0; i < 2; i++) {
var portal = game.addChild(new Portal());
portal.x = 400 + i * 1200;
portal.y = 1200;
portal.dimension = i;
portal.targetDimension = (i + 1) % totalDimensions;
portal.setDimension(i);
portals.push(portal);
}
// Create interference fields
for (var i = 0; i < numFields; i++) {
var field = game.addChild(new InterferenceField());
field.x = 300 + i * 600;
field.y = 1000 + i % 2 * 400;
field.setDimension(i % totalDimensions);
// Add movement to interference fields for higher levels
if (level >= 2) {
field.moveDirection = i % 2 === 0 ? 1 : -1;
field.minX = 100;
field.maxX = 1948;
}
interferenceFields.push(field);
}
// Add additional moving barriers for higher levels
if (level >= 2) {
var movingField = game.addChild(new InterferenceField());
movingField.x = 1024;
movingField.y = 1400;
movingField.setDimension(0);
movingField.moveDirection = 1;
movingField.minX = 200;
movingField.maxX = 1848;
interferenceFields.push(movingField);
}
// Add second moving barrier for level 3+
if (level >= 3) {
var movingField2 = game.addChild(new InterferenceField());
movingField2.x = 500;
movingField2.y = 2000;
movingField2.setDimension(1);
movingField2.moveDirection = -1;
movingField2.minX = 100;
movingField2.maxX = 1948;
interferenceFields.push(movingField2);
}
// Add third moving barrier for level 4+
if (level >= 4) {
var movingField3 = game.addChild(new InterferenceField());
movingField3.x = 1500;
movingField3.y = 1600;
movingField3.setDimension(0);
movingField3.moveDirection = 1;
movingField3.minX = 300;
movingField3.maxX = 1700;
interferenceFields.push(movingField3);
}
// Add fourth moving barrier for level 5+
if (level >= 5) {
var movingField4 = game.addChild(new InterferenceField());
movingField4.x = 800;
movingField4.y = 1800;
movingField4.setDimension(1);
movingField4.moveDirection = -1;
movingField4.minX = 200;
movingField4.maxX = 1800;
interferenceFields.push(movingField4);
}
// Advanced levels 6-10 with additional challenges
if (level >= 6) {
// Add more particles for higher levels
var extraParticles = Math.min(level - 5, 3);
for (var j = 0; j < extraParticles; j++) {
var extraParticle = game.addChild(new Particle());
extraParticle.x = 400 + j * 300;
extraParticle.y = 2200 + j % 2 * 200;
extraParticle.setDimension(j % totalDimensions);
extraParticle.lastCoreIntersecting = false;
extraParticle.isBeingDragged = false;
extraParticle.isCollected = false;
particles.push(extraParticle);
}
totalParticles += extraParticles;
// Add additional moving barriers
var numExtraFields = Math.min(level - 5, 4);
for (var k = 0; k < numExtraFields; k++) {
var extraField = game.addChild(new InterferenceField());
extraField.x = 200 + k * 400;
extraField.y = 1300 + k % 2 * 300;
extraField.setDimension(k % totalDimensions);
extraField.moveDirection = k % 2 === 0 ? 1 : -1;
extraField.minX = 100;
extraField.maxX = 1948;
interferenceFields.push(extraField);
}
}
// Level 8+ speed increase is now handled in the InterferenceField update method
// Level 10 gets entangled triplets
if (level >= 10 && particles.length >= 3) {
particles[0].entangledWith = particles[1];
particles[1].entangledWith = particles[2];
particles[2].entangledWith = particles[0];
}
// Advanced levels 11-15 with extreme challenges
if (level >= 11) {
// Add even more particles for extreme levels
var extremeParticles = Math.min(level - 10, 5);
for (var m = 0; m < extremeParticles; m++) {
var extremeParticle = game.addChild(new Particle());
extremeParticle.x = 150 + m * 250;
extremeParticle.y = 2400 + m % 2 * 150;
extremeParticle.setDimension(m % totalDimensions);
extremeParticle.lastCoreIntersecting = false;
extremeParticle.isBeingDragged = false;
extremeParticle.isCollected = false;
particles.push(extremeParticle);
}
totalParticles += extremeParticles;
// Add maze-like interference field patterns
var mazeFields = Math.min(level - 10, 6);
for (var n = 0; n < mazeFields; n++) {
var mazeField = game.addChild(new InterferenceField());
mazeField.x = 300 + n * 200;
mazeField.y = 1100 + n % 3 * 200;
mazeField.setDimension(n % totalDimensions);
mazeField.moveDirection = n % 2 === 0 ? 1 : -1;
mazeField.minX = 50;
mazeField.maxX = 1998;
interferenceFields.push(mazeField);
}
}
// Master levels 16-20 with ultimate difficulty
if (level >= 16) {
// Add master-level particles
var masterParticles = Math.min(level - 15, 4);
for (var p = 0; p < masterParticles; p++) {
var masterParticle = game.addChild(new Particle());
masterParticle.x = 200 + p * 400;
masterParticle.y = 2500 + p % 2 * 100;
masterParticle.setDimension(p % totalDimensions);
masterParticle.lastCoreIntersecting = false;
masterParticle.isBeingDragged = false;
masterParticle.isCollected = false;
particles.push(masterParticle);
}
totalParticles += masterParticles;
// Create complex entanglement networks
if (particles.length >= 4) {
for (var q = 0; q < Math.min(particles.length - 1, 6); q++) {
if (q + 1 < particles.length) {
particles[q].entangledWith = particles[q + 1];
}
}
}
// Add ultra-fast moving barriers
var ultraFields = Math.min(level - 15, 8);
for (var r = 0; r < ultraFields; r++) {
var ultraField = game.addChild(new InterferenceField());
ultraField.x = 100 + r * 180;
ultraField.y = 1200 + r % 4 * 150;
ultraField.setDimension(r % totalDimensions);
ultraField.moveDirection = r % 2 === 0 ? 1 : -1;
ultraField.minX = 50;
ultraField.maxX = 1998;
interferenceFields.push(ultraField);
}
}
// Calculate total particles correctly for all levels
totalParticles = particles.length;
}
updateDimensionDisplay();
if (level === 0) {
levelText.setText('Tutorial');
} else {
levelText.setText('Level: ' + level);
}
}
function updateDimensionDisplay() {
dimensionText.setText('Dimension: ' + currentDimension);
instructionText.setText('Switches: ' + dimensionSwitches + '/' + maxDimensionSwitches + ' - Tap to switch');
for (var i = 0; i < dimensionIndicators.length; i++) {
var indicator = dimensionIndicators[i];
tween(indicator, {
alpha: i === currentDimension ? 1.0 : 0.3,
scaleX: i === currentDimension ? 1.5 : 1.0,
scaleY: i === currentDimension ? 1.5 : 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
// Update all objects for dimension visibility
for (var i = 0; i < particles.length; i++) {
var targetAlpha = particles[i].dimension === currentDimension ? 1.0 : 0.15;
tween(particles[i], {
alpha: targetAlpha
}, {
duration: 200,
easing: tween.easeInOut
});
}
for (var i = 0; i < portals.length; i++) {
var targetAlpha = portals[i].dimension === currentDimension ? 1.0 : 0.1;
tween(portals[i], {
alpha: targetAlpha
}, {
duration: 200,
easing: tween.easeInOut
});
}
for (var i = 0; i < interferenceFields.length; i++) {
var targetAlpha = interferenceFields[i].dimension === currentDimension ? 0.8 : 0.1;
tween(interferenceFields[i], {
alpha: targetAlpha
}, {
duration: 200,
easing: tween.easeInOut
});
}
for (var i = 0; i < powerUps.length; i++) {
var targetAlpha = powerUps[i].dimension === currentDimension ? 1.0 : 0.15;
tween(powerUps[i], {
alpha: targetAlpha
}, {
duration: 200,
easing: tween.easeInOut
});
}
}
function switchDimension() {
if (dimensionSwitches >= maxDimensionSwitches && !isTutorial) {
LK.effects.flashScreen(0xFF0000, 200);
return; // No more switches allowed (except in tutorial)
}
dimensionSwitches++;
// Remove time penalty to make dimension switching more accessible
currentDimension = (currentDimension + 1) % totalDimensions;
updateDimensionDisplay();
LK.getSound('dimensionShift').play();
LK.effects.flashScreen(0x440088, 200);
// Tutorial progress tracking
if (isTutorial) {
if (tutorialStep === 3) {
tutorialStep = 4;
// Add celebratory flash for successful dimension switch
LK.effects.flashScreen(0x00ff88, 300);
LK.setTimeout(function () {
updateTutorialStep();
}, 800);
} else if (tutorialStep === 4 && currentDimension === 1) {
// Player successfully switched to dimension 1
tutorialStep = 5;
LK.setTimeout(function () {
updateTutorialStep();
}, 1200);
}
}
}
function checkWinCondition() {
if (particlesCollected >= totalParticles) {
timerActive = false; // Stop timer when level complete
if (isTutorial) {
if (particlesCollected === 1 && tutorialStep <= 3) {
// First particle collected, advance tutorial
tutorialStep = 3;
updateTutorialStep();
return;
} else if (particlesCollected >= 2) {
// All particles collected in tutorial, complete it
if (tutorialStep < 6) {
tutorialStep = 6;
updateTutorialStep();
} else if (tutorialComplete || tutorialStep >= 10) {
// Tutorial is complete, move to level 1
level = 1;
isTutorial = false;
tutorialText.visible = false;
initializeLevel();
}
return;
}
}
level++;
LK.setTimeout(function () {
if (level > 20) {
LK.showYouWin();
} else {
initializeLevel();
}
}, 1000);
}
}
function resetLevel() {
// Check if shield is active to prevent death
if (shieldActive) {
shieldActive = false;
shieldTimeRemaining = 0;
shieldText.visible = false;
LK.effects.flashScreen(0x0088ff, 300);
return; // Shield absorbed the hit
}
LK.effects.flashScreen(0xff0000, 500);
LK.setTimeout(function () {
initializeLevel();
}, 600);
}
function spawnPowerUp() {
if (powerUps.length >= 2) return; // Maximum 2 power-ups on screen
var powerUp = game.addChild(new PowerUp());
// Ensure power-ups spawn in safe areas away from interference fields
var safePosition = false;
var attempts = 0;
var spawnX, spawnY;
while (!safePosition && attempts < 10) {
spawnX = 300 + Math.random() * 1448;
spawnY = 600 + Math.random() * 800;
// Check distance from interference fields
safePosition = true;
for (var f = 0; f < interferenceFields.length; f++) {
var field = interferenceFields[f];
var distance = Math.sqrt((spawnX - field.x) * (spawnX - field.x) + (spawnY - field.y) * (spawnY - field.y));
if (distance < 200) {
safePosition = false;
break;
}
}
attempts++;
}
powerUp.x = spawnX || 300 + Math.random() * 1448;
powerUp.y = spawnY || 600 + Math.random() * 800;
powerUp.setDimension(currentDimension); // Always spawn in current dimension for better accessibility
// Random power-up type
var types = ['timeBoost', 'shield', 'slowMotion'];
var randomType = types[Math.floor(Math.random() * types.length)];
powerUp.setType(randomType);
powerUp.lastPlayerIntersecting = false;
powerUps.push(powerUp);
}
// Event handlers
game.down = function (x, y, obj) {
var hitParticle = false;
for (var i = 0; i < particles.length; i++) {
var particle = particles[i];
if (particle.dimension === currentDimension && !particle.isCollected && particle.alpha > 0.5) {
// Use actual asset dimensions for accurate touch detection
var halfWidth = particle.children[0].width / 2; // Use actual particle asset width
var halfHeight = particle.children[0].height / 2; // Use actual particle asset height
// Check if touch point is within particle bounds
if (x >= particle.x - halfWidth && x <= particle.x + halfWidth && y >= particle.y - halfHeight && y <= particle.y + halfHeight) {
draggedParticle = particle;
particle.startDrag();
dragOffset.x = x - particle.x;
dragOffset.y = y - particle.y;
hitParticle = true;
break;
}
}
}
if (!hitParticle) {
switchDimension();
}
};
game.move = function (x, y, obj) {
if (draggedParticle && !draggedParticle.isCollected) {
var targetX = x - dragOffset.x;
var targetY = y - dragOffset.y;
// Keep particle within bounds
targetX = Math.max(80, Math.min(1968, targetX));
targetY = Math.max(80, Math.min(2652, targetY));
// Direct position update for responsive dragging
draggedParticle.x = targetX;
draggedParticle.y = targetY;
// Reduce trail effect frequency to improve performance
if (LK.ticks % 10 === 0) {
var trailStar = game.addChild(new BackgroundStar());
trailStar.x = draggedParticle.x + (Math.random() - 0.5) * 20;
trailStar.y = draggedParticle.y + (Math.random() - 0.5) * 20;
trailStar.scaleX = 0.8;
trailStar.scaleY = 0.8;
trailStar.alpha = 0.8;
// Fade out trail particle
tween(trailStar, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
trailStar.destroy();
}
});
}
// Handle entangled particle movement with direct updates
if (draggedParticle.entangledWith) {
// Only move entangled particles when BOTH the dragged particle AND the entangled particle are in the current dimension
// This prevents cross-dimensional interference where particles in other dimensions move unexpectedly
if (draggedParticle.dimension === currentDimension && draggedParticle.entangledWith.dimension === currentDimension) {
draggedParticle.entangledWith.x = targetX + 150;
draggedParticle.entangledWith.y = targetY;
}
// Ensure entangled particles maintain proper alpha based on current dimension
var entangledTargetAlpha = draggedParticle.entangledWith.dimension === currentDimension ? 1.0 : 0.15;
draggedParticle.entangledWith.alpha = entangledTargetAlpha;
}
}
};
game.up = function (x, y, obj) {
if (draggedParticle) {
draggedParticle.stopDrag();
draggedParticle = null;
}
};
game.update = function () {
// Handle timer countdown
if (timerActive) {
var timeDecrement = slowMotionActive ? 8.33 : 16.67; // Slow motion halves time consumption
timeRemaining -= timeDecrement;
if (timeRemaining <= 0) {
resetLevel();
return;
}
var seconds = Math.ceil(timeRemaining / 1000);
timerText.setText('Time: ' + seconds + 's');
// Smooth color transitions when time is running out
if (seconds <= 5) {
tween(timerText, {
tint: 0xFF0000
}, {
duration: 200,
easing: tween.easeOut
});
} else if (seconds <= 10) {
tween(timerText, {
tint: 0xFFFF00
}, {
duration: 200,
easing: tween.easeOut
});
} else {
tween(timerText, {
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeOut
});
}
}
// Animate quantum core with direct property updates
if (quantumCore) {
// Direct rotation update
quantumCore.rotation += 0.02;
// Direct pulsing animation
var pulse = Math.sin(LK.ticks * 0.08) * 0.15 + 1.0;
quantumCore.scaleX = pulse;
quantumCore.scaleY = pulse;
// Reduced frequency color cycling
if (LK.ticks % 60 === 0) {
var colorPhase = LK.ticks * 0.015;
var r = Math.sin(colorPhase) * 0.4 + 0.6;
var g = Math.sin(colorPhase + 2) * 0.4 + 0.6;
var b = Math.sin(colorPhase + 4) * 0.4 + 0.6;
var color = Math.floor(r * 255) << 16 | Math.floor(g * 255) << 8 | Math.floor(b * 255);
quantumCore.tint = color;
}
}
// Update all particles
for (var i = 0; i < particles.length; i++) {
if (particles[i].update) {
particles[i].update();
}
}
// Update all portals
for (var i = 0; i < portals.length; i++) {
if (portals[i].update) {
portals[i].update();
}
}
// Update all interference fields
for (var i = 0; i < interferenceFields.length; i++) {
if (interferenceFields[i].update) {
interferenceFields[i].update();
}
}
// Handle power-up spawning
if (timerActive) {
powerUpSpawnTimer += 16.67;
// Calculate dynamic spawn interval based on level - more frequent power-ups
var dynamicSpawnInterval = powerUpSpawnInterval;
if (level >= 5) {
dynamicSpawnInterval = Math.max(3000, powerUpSpawnInterval - (level - 4) * 300); // Faster spawning for higher levels, minimum 3 seconds (reduced from 4)
}
if (powerUpSpawnTimer >= dynamicSpawnInterval) {
spawnPowerUp();
powerUpSpawnTimer = 0;
}
}
// Handle shield duration
if (shieldActive) {
shieldTimeRemaining -= 16.67;
if (shieldTimeRemaining <= 0) {
shieldActive = false;
shieldText.visible = false;
} else {
shieldText.visible = true;
shieldText.setText('SHIELD: ' + Math.ceil(shieldTimeRemaining / 1000) + 's');
}
}
// Handle slow motion duration
if (slowMotionActive) {
slowMotionTimeRemaining -= 16.67;
if (slowMotionTimeRemaining <= 0) {
slowMotionActive = false;
slowMotionText.visible = false;
} else {
slowMotionText.visible = true;
slowMotionText.setText('SLOW MOTION: ' + Math.ceil(slowMotionTimeRemaining / 1000) + 's');
}
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
if (powerUps[i].update) {
powerUps[i].update();
}
// Remove collected power-ups
if (powerUps[i].isCollected && !powerUps[i].visible) {
powerUps[i].destroy();
powerUps.splice(i, 1);
}
}
// Update background stars
for (var i = 0; i < backgroundStars.length; i++) {
var star = backgroundStars[i];
if (star.update) {
star.update();
}
// Handle orbital motion for core particles
if (star.orbitalAngle !== undefined && quantumCore) {
star.orbitalAngle += star.orbitalSpeed;
star.x = quantumCore.x + Math.cos(star.orbitalAngle) * star.orbitalRadius;
star.y = quantumCore.y + Math.sin(star.orbitalAngle) * star.orbitalRadius;
}
}
};
function updateTutorialStep() {
if (!isTutorial) return;
// Ensure tutorial text is visible and properly positioned
tutorialText.visible = true;
tutorialText.alpha = 1.0;
// Position tutorial text in center area for better visibility
tutorialText.x = 1024;
tutorialText.y = 500; // Better positioning for readability
// Ensure text is on top and visible
game.removeChild(tutorialText);
game.addChild(tutorialText);
switch (tutorialStep) {
case 0:
tutorialText.setText('Welcome to Quantum Dimensions!\nMove particles to the center core to collect them.');
LK.setTimeout(function () {
tutorialStep = 1;
updateTutorialStep();
}, 2500);
break;
case 1:
tutorialText.setText('STEP 1: DRAG A PARTICLE\nTouch and drag the glowing particle below.');
// Add visual hint by pulsing the particle
if (particles.length > 0 && particles[0].dimension === currentDimension) {
LK.effects.flashObject(particles[0], 0x00ff00, 1500);
// Keep flashing until moved
LK.setInterval(function () {
if (tutorialStep === 1 && !particles[0].isBeingDragged) {
LK.effects.flashObject(particles[0], 0x00ff00, 800);
}
}, 1000);
}
break;
case 2:
tutorialText.setText('STEP 2: MOVE TO CENTER\nDrag the particle to the quantum core (glowing center).');
// Add visual hint by flashing the quantum core
if (quantumCore) {
LK.effects.flashObject(quantumCore, 0x00ffff, 2000);
// Keep flashing until collected
LK.setInterval(function () {
if (tutorialStep === 2 && quantumCore) {
LK.effects.flashObject(quantumCore, 0x00ffff, 1000);
}
}, 1500);
}
break;
case 3:
tutorialText.setText('GREAT! Particle collected!\nNow tap empty space to switch dimensions.');
break;
case 4:
tutorialText.setText('STEP 3: DIMENSION SWITCHING\nYou switched to Dimension 1! See the other particle?');
if (particles.length > 1 && particles[1].dimension === currentDimension) {
LK.effects.flashObject(particles[1], 0x00ff00, 1500);
}
LK.setTimeout(function () {
tutorialStep = 5;
updateTutorialStep();
}, 2500);
break;
case 5:
tutorialText.setText('STEP 4: COLLECT SECOND PARTICLE\nDrag this particle to the center too.');
if (particles.length > 1 && particles[1].dimension === currentDimension) {
LK.effects.flashObject(particles[1], 0x00ff00, 1500);
// Keep flashing until collected
LK.setInterval(function () {
if (tutorialStep === 5 && particles.length > 1 && !particles[1].isCollected) {
LK.effects.flashObject(particles[1], 0x00ff00, 800);
}
}, 1200);
}
break;
case 6:
tutorialText.setText('PERFECT! You mastered the basics!\nRemember: Limited dimension switches in real levels.');
LK.setTimeout(function () {
tutorialStep = 7;
updateTutorialStep();
}, 2500);
break;
case 7:
tutorialText.setText('WARNING: RED FIELDS = DANGER\nAvoid red interference fields - they reset the level!');
// Flash the demo interference field to show danger
for (var i = 0; i < interferenceFields.length; i++) {
LK.effects.flashObject(interferenceFields[i], 0xff0000, 2000);
}
LK.setTimeout(function () {
tutorialStep = 8;
updateTutorialStep();
}, 3000);
break;
case 8:
tutorialText.setText('BLUE PORTALS = TRANSPORT\nPortals move particles between dimensions.');
// Flash the demo portal
for (var i = 0; i < portals.length; i++) {
LK.effects.flashObject(portals[i], 0x0088ff, 2000);
}
LK.setTimeout(function () {
tutorialStep = 9;
updateTutorialStep();
}, 3000);
break;
case 9:
tutorialText.setText('POWER-UPS HELP YOU:\n🟢 Time Boost 🔵 Shield 🟡 Slow Motion');
LK.setTimeout(function () {
tutorialStep = 10;
updateTutorialStep();
}, 3500);
break;
case 10:
tutorialText.setText('🎉 TUTORIAL COMPLETE! 🎉\nReady for the real challenge? Starting Level 1...');
LK.setTimeout(function () {
tutorialComplete = true;
checkWinCondition(); // Use existing function to transition properly
}, 3000);
break;
}
}
function showPowerUpSpec(title, description, color) {
// Create power-up specification display
var specContainer = new Container();
// Title text
var titleText = new Text2(title, {
size: 60,
fill: color
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1300;
specContainer.addChild(titleText);
// Description text
var descText = new Text2(description, {
size: 45,
fill: 0xFFFFFF
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 1380;
specContainer.addChild(descText);
// Add to game
game.addChild(specContainer);
// Initial state
specContainer.alpha = 0;
specContainer.scaleX = 0.3;
specContainer.scaleY = 0.3;
// Animation: fade in and scale up
tween(specContainer, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Hold for a moment then fade out
LK.setTimeout(function () {
tween(specContainer, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
specContainer.destroy();
}
});
}, 2000);
}
});
}
// Initialize first level
initializeLevel();