/****
* 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();