/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { currentLevel: 1, highestLevel: 1 }); /**** * Classes ****/ var Bridge = Container.expand(function (direction) { var self = Container.call(this); var bridgeGraphic = self.attachAsset('bridge', { anchorX: 0.5, anchorY: 0.5 }); if (direction === 'vertical') { bridgeGraphic.rotation = Math.PI / 2; } // Bridge disappears after some time self.lifespan = 5000; // 5 seconds self.creationTime = Date.now(); self.update = function () { var elapsedTime = Date.now() - self.creationTime; var timeLeft = self.lifespan - elapsedTime; if (timeLeft <= 0) { self.destroy(); var index = bridges.indexOf(self); if (index > -1) { bridges.splice(index, 1); } } else if (timeLeft < 1000) { // Fade out when almost gone bridgeGraphic.alpha = timeLeft / 1000; } }; return self; }); var LevelButton = Container.expand(function (levelNum, unlocked) { var self = Container.call(this); // Create button background var bgColor = unlocked ? 0x3498db : 0x7f8c8d; var bg = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 150 }); bg.tint = bgColor; // Create level text var levelText = new Text2(levelNum.toString(), { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0.5); self.addChild(levelText); self.levelNum = levelNum; self.unlocked = unlocked; // Interaction handlers self.down = function (x, y, obj) { if (self.unlocked) { tween(bg, { tint: 0x2980b9 }, { duration: 100 }); } }; self.up = function (x, y, obj) { if (self.unlocked) { tween(bg, { tint: bgColor }, { duration: 100 }); currentLevel = self.levelNum; showGame(); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphic = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.isInvincible = false; self.hasBridge = false; self.makeInvincible = function (duration) { self.isInvincible = true; // Visual feedback for invincibility tween(playerGraphic, { tint: 0xFFD700 }, { duration: 300 }); LK.setTimeout(function () { self.isInvincible = false; tween(playerGraphic, { tint: 0xFFFFFF }, { duration: 300 }); }, duration); }; self.giveBridge = function () { self.hasBridge = true; // Visual feedback for bridge ability tween(playerGraphic, { tint: 0x9b59b6 }, { duration: 300 }); }; self.useBridge = function () { if (self.hasBridge) { self.hasBridge = false; tween(playerGraphic, { tint: 0xFFFFFF }, { duration: 300 }); return true; } return false; }; return self; }); var PowerOrb = Container.expand(function (type) { var self = Container.call(this); var orbGraphic = self.attachAsset('powerOrb', { anchorX: 0.5, anchorY: 0.5 }); self.type = type || 'invincibility'; // Default type is invincibility // Visual differentiation based on type if (self.type === 'bridge') { orbGraphic.tint = 0x9b59b6; // Purple for bridge } else { orbGraphic.tint = 0xf1c40f; // Yellow for invincibility } // Floating animation self.update = function () { self.rotation += 0.01; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xecf0f1 }); /**** * Game Code ****/ // Game state variables var currentLevel = storage.currentLevel || 1; var highestLevel = storage.highestLevel || 1; var gameActive = false; var levelComplete = false; var player = null; var goal = null; var walls = []; var negativeZones = []; var powerOrbs = []; var bridges = []; var dragNode = null; var levelMenu = null; var currentLevelText = null; var totalLevels = 5; var dragStartPos = { x: 0, y: 0 }; // Create level selection menu function createLevelMenu() { if (levelMenu) { game.removeChild(levelMenu); } levelMenu = new Container(); game.addChild(levelMenu); // Title var titleText = new Text2("Positive Path", { size: 120, fill: 0x2C3E50 }); titleText.anchor.set(0.5, 0); titleText.x = 2048 / 2; titleText.y = 200; levelMenu.addChild(titleText); // Subtitle var subtitleText = new Text2("Select a Level", { size: 80, fill: 0x7F8C8D }); subtitleText.anchor.set(0.5, 0); subtitleText.x = 2048 / 2; subtitleText.y = 350; levelMenu.addChild(subtitleText); // Level buttons var buttonsPerRow = 3; var buttonSize = 200; var spacing = 50; var startX = (2048 - (buttonsPerRow * buttonSize + (buttonsPerRow - 1) * spacing)) / 2 + buttonSize / 2; var startY = 500; for (var i = 1; i <= totalLevels; i++) { var row = Math.floor((i - 1) / buttonsPerRow); var col = (i - 1) % buttonsPerRow; var x = startX + col * (buttonSize + spacing); var y = startY + row * (buttonSize + spacing); var button = new LevelButton(i, i <= highestLevel); button.x = x; button.y = y; levelMenu.addChild(button); } } // Create level function createLevel(levelNumber) { clearLevel(); // Create player player = new Player(); game.addChild(player); // Create goal goal = game.addChild(LK.getAsset('goal', { anchorX: 0.5, anchorY: 0.5 })); // Setup level-specific layout switch (levelNumber) { case 1: createLevel1(); break; case 2: createLevel2(); break; case 3: createLevel3(); break; case 4: createLevel4(); break; case 5: createLevel5(); break; default: createLevel1(); } // Create level text if (currentLevelText) { LK.gui.topRight.removeChild(currentLevelText); } currentLevelText = new Text2("Level " + levelNumber, { size: 60, fill: 0x34495E }); currentLevelText.anchor.set(1, 0); currentLevelText.x = -50; currentLevelText.y = 50; LK.gui.topRight.addChild(currentLevelText); gameActive = true; } function clearLevel() { if (player) { player.destroy(); player = null; } if (goal) { goal.destroy(); goal = null; } // Clear walls for (var i = 0; i < walls.length; i++) { walls[i].destroy(); } walls = []; // Clear negative zones for (var i = 0; i < negativeZones.length; i++) { negativeZones[i].destroy(); } negativeZones = []; // Clear power orbs for (var i = 0; i < powerOrbs.length; i++) { powerOrbs[i].destroy(); } powerOrbs = []; // Clear bridges for (var i = 0; i < bridges.length; i++) { bridges[i].destroy(); } bridges = []; gameActive = false; levelComplete = false; } function createWall(x, y, width, height) { var wall = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: width / 100, scaleY: height / 100 }); wall.x = x; wall.y = y; game.addChild(wall); walls.push(wall); return wall; } function createNegativeZone(x, y, width, height) { var zone = LK.getAsset('negative', { anchorX: 0.5, anchorY: 0.5, scaleX: width / 100, scaleY: height / 100 }); zone.x = x; zone.y = y; game.addChild(zone); negativeZones.push(zone); return zone; } function createPowerOrb(x, y, type) { var orb = new PowerOrb(type); orb.x = x; orb.y = y; game.addChild(orb); powerOrbs.push(orb); return orb; } function createBridge(x, y, direction) { var bridge = new Bridge(direction); bridge.x = x; bridge.y = y; game.addChild(bridge); bridges.push(bridge); return bridge; } // Level layouts function createLevel1() { // Tutorial level - simple path with one negative zone player.x = 400; player.y = 1366; goal.x = 1648; goal.y = 1366; // Walls to create a path createWall(1024, 1066, 1600, 100); // Top wall createWall(1024, 1666, 1600, 100); // Bottom wall // One negative zone to avoid createNegativeZone(1024, 1366, 300, 300); // Instructions var instructionText = new Text2("Drag the blue ball to the green goal.\nAvoid the red areas!", { size: 60, fill: 0x34495E }); instructionText.anchor.set(0.5, 0); instructionText.x = 1024; instructionText.y = 800; game.addChild(instructionText); walls.push(instructionText); // Add to walls array to be cleared properly } function createLevel2() { // More complex path with multiple negative zones player.x = 300; player.y = 500; goal.x = 1748; goal.y = 2200; // Create maze walls createWall(1024, 300, 1600, 100); // Top wall createWall(1024, 2400, 1600, 100); // Bottom wall createWall(300, 1350, 100, 2000); // Left wall createWall(1748, 1350, 100, 2000); // Right wall // Create inner walls createWall(800, 800, 800, 100); createWall(1300, 1200, 800, 100); createWall(800, 1600, 800, 100); createWall(1300, 2000, 800, 100); // Create negative zones createNegativeZone(800, 1200, 300, 300); createNegativeZone(1300, 1600, 300, 300); createNegativeZone(800, 2000, 300, 300); // Add a power orb createPowerOrb(1024, 600, 'invincibility'); } function createLevel3() { // Introduce bridge power-up player.x = 300; player.y = 400; goal.x = 1748; goal.y = 2300; // Create outer walls createWall(1024, 250, 1600, 100); // Top wall createWall(1024, 2500, 1600, 100); // Bottom wall createWall(250, 1375, 100, 2250); // Left wall createWall(1798, 1375, 100, 2250); // Right wall // Create gaps with negative zones createNegativeZone(700, 800, 900, 200); createNegativeZone(1350, 1400, 900, 200); createNegativeZone(700, 2000, 900, 200); // Add bridge power-up createPowerOrb(1024, 600, 'bridge'); // Instructions var instructionText = new Text2("Yellow orbs give you special powers.\nPurple orbs let you create bridges!", { size: 50, fill: 0x34495E }); instructionText.anchor.set(0.5, 0); instructionText.x = 1024; instructionText.y = 300; game.addChild(instructionText); walls.push(instructionText); } function createLevel4() { // Complex level with both power-ups player.x = 300; player.y = 400; goal.x = 1748; goal.y = 2300; // Create outer walls createWall(1024, 250, 1600, 100); // Top wall createWall(1024, 2500, 1600, 100); // Bottom wall createWall(250, 1375, 100, 2250); // Left wall createWall(1798, 1375, 100, 2250); // Right wall // Create maze structure createWall(700, 800, 100, 700); createWall(1350, 800, 100, 700); createWall(700, 1800, 100, 700); createWall(1350, 1800, 100, 700); // Create negative zones - forming a checkerboard pattern createNegativeZone(500, 600, 200, 200); createNegativeZone(900, 600, 200, 200); createNegativeZone(1300, 600, 200, 200); createNegativeZone(1700, 600, 200, 200); createNegativeZone(700, 1000, 200, 200); createNegativeZone(1100, 1000, 200, 200); createNegativeZone(1500, 1000, 200, 200); createNegativeZone(500, 1400, 200, 200); createNegativeZone(900, 1400, 200, 200); createNegativeZone(1300, 1400, 200, 200); createNegativeZone(1700, 1400, 200, 200); createNegativeZone(700, 1800, 200, 200); createNegativeZone(1100, 1800, 200, 200); createNegativeZone(1500, 1800, 200, 200); createNegativeZone(500, 2200, 200, 200); createNegativeZone(900, 2200, 200, 200); createNegativeZone(1300, 2200, 200, 200); createNegativeZone(1700, 2200, 200, 200); // Add power-ups createPowerOrb(500, 1000, 'invincibility'); createPowerOrb(1500, 1000, 'bridge'); createPowerOrb(1100, 1400, 'invincibility'); createPowerOrb(500, 1800, 'bridge'); } function createLevel5() { // Final challenge level player.x = 1024; player.y = 400; goal.x = 1024; goal.y = 2300; // Create outer walls createWall(1024, 250, 1600, 100); // Top wall createWall(1024, 2500, 1600, 100); // Bottom wall createWall(250, 1375, 100, 2250); // Left wall createWall(1798, 1375, 100, 2250); // Right wall // Create a spiral of negative zones var center = { x: 1024, y: 1375 }; var spiralRadius = 800; var spiralWidth = 150; var angleStep = Math.PI / 8; for (var angle = 0; angle < 4 * Math.PI; angle += angleStep) { var radius = spiralRadius * (1 - angle / (4 * Math.PI)); var x = center.x + radius * Math.cos(angle); var y = center.y + radius * Math.sin(angle); createNegativeZone(x, y, spiralWidth, spiralWidth); } // Add power-ups strategically createPowerOrb(1024, 600, 'invincibility'); createPowerOrb(600, 1000, 'bridge'); createPowerOrb(1450, 1800, 'invincibility'); createPowerOrb(800, 2100, 'bridge'); } // Game mechanics function checkCollisions() { if (!gameActive || levelComplete) { return; } // Check if player reached goal if (player.intersects(goal)) { levelComplete = true; LK.getSound('win').play(); // Update highest level if needed if (currentLevel >= highestLevel) { highestLevel = currentLevel + 1; if (highestLevel > totalLevels) { highestLevel = totalLevels; } storage.highestLevel = highestLevel; } // Show completion message and proceed to next level var completionText = new Text2("Level Complete!", { size: 100, fill: 0x2ECC71 }); completionText.anchor.set(0.5, 0.5); completionText.x = 1024; completionText.y = 1366; game.addChild(completionText); LK.setTimeout(function () { completionText.destroy(); if (currentLevel < totalLevels) { currentLevel++; storage.currentLevel = currentLevel; createLevel(currentLevel); } else { // Game completed LK.showYouWin(); } }, 2000); return; } // Check collision with negative zones for (var i = 0; i < negativeZones.length; i++) { if (player.intersects(negativeZones[i]) && !player.isInvincible) { gameActive = false; LK.getSound('lose').play(); // Visual feedback LK.effects.flashScreen(0xe74c3c, 1000); // Restart level after a delay LK.setTimeout(function () { createLevel(currentLevel); }, 1500); return; } } // Check collision with power orbs for (var i = powerOrbs.length - 1; i >= 0; i--) { if (player.intersects(powerOrbs[i])) { // Apply power-up effect if (powerOrbs[i].type === 'invincibility') { player.makeInvincible(5000); // 5 seconds of invincibility } else if (powerOrbs[i].type === 'bridge') { player.giveBridge(); } // Remove the orb LK.getSound('collect').play(); powerOrbs[i].destroy(); powerOrbs.splice(i, 1); } } // Check if player is trying to cross a wall if (dragNode) { for (var i = 0; i < walls.length; i++) { if (player.intersects(walls[i])) { // Move player back to valid position player.x = dragStartPos.x; player.y = dragStartPos.y; return; } } } } // Bridge placement function placeBridge(x, y) { if (!player.hasBridge) { return false; } // Determine bridge direction based on player position var direction = 'horizontal'; var minDistanceToWall = 9999; var nearestWall = null; for (var i = 0; i < walls.length; i++) { var wall = walls[i]; var dx = Math.abs(wall.x - player.x); var dy = Math.abs(wall.y - player.y); var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistanceToWall) { minDistanceToWall = distance; nearestWall = wall; } } if (nearestWall) { // Determine orientation based on nearest wall position var dx = Math.abs(nearestWall.x - player.x); var dy = Math.abs(nearestWall.y - player.y); direction = dx > dy ? 'horizontal' : 'vertical'; } // Place bridge slightly ahead of player in the direction of drag var placeX = x; var placeY = y; createBridge(placeX, placeY, direction); return player.useBridge(); } // Game state management function showMenu() { clearLevel(); createLevelMenu(); gameActive = false; } function showGame() { if (levelMenu) { game.removeChild(levelMenu); levelMenu = null; } createLevel(currentLevel); // Play background music when starting the game LK.playMusic('bgmusic', { loop: true, fade: { start: 0, end: 0.4, duration: 1000 } }); } // Event handlers game.down = function (x, y, obj) { if (!gameActive) { return; } if (player) { // Check if we're clicking on player var playerBounds = { left: player.x - player.width / 2, right: player.x + player.width / 2, top: player.y - player.height / 2, bottom: player.y + player.height / 2 }; if (x >= playerBounds.left && x <= playerBounds.right && y >= playerBounds.top && y <= playerBounds.bottom) { dragNode = player; dragStartPos = { x: player.x, y: player.y }; } else if (player.hasBridge) { // Try to place a bridge placeBridge(x, y); } } }; game.up = function (x, y, obj) { dragNode = null; }; game.move = function (x, y, obj) { if (dragNode && gameActive && !levelComplete) { // Store the current position in case we need to revert var oldX = dragNode.x; var oldY = dragNode.y; // Update position dragNode.x = x; dragNode.y = y; // Check for wall collisions for (var i = 0; i < walls.length; i++) { if (dragNode.intersects(walls[i])) { // Revert position dragNode.x = oldX; dragNode.y = oldY; return; } } // Check if we can cross with a bridge for (var i = 0; i < bridges.length; i++) { if (dragNode.intersects(bridges[i])) { return; // We're on a bridge, allow movement } } } }; game.update = function () { if (!gameActive) { return; } // Update all objects with update methods for (var i = 0; i < powerOrbs.length; i++) { powerOrbs[i].update(); } for (var i = 0; i < bridges.length; i++) { bridges[i].update(); } // Check for collisions checkCollisions(); }; // Initialize the game showMenu();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currentLevel: 1,
highestLevel: 1
});
/****
* Classes
****/
var Bridge = Container.expand(function (direction) {
var self = Container.call(this);
var bridgeGraphic = self.attachAsset('bridge', {
anchorX: 0.5,
anchorY: 0.5
});
if (direction === 'vertical') {
bridgeGraphic.rotation = Math.PI / 2;
}
// Bridge disappears after some time
self.lifespan = 5000; // 5 seconds
self.creationTime = Date.now();
self.update = function () {
var elapsedTime = Date.now() - self.creationTime;
var timeLeft = self.lifespan - elapsedTime;
if (timeLeft <= 0) {
self.destroy();
var index = bridges.indexOf(self);
if (index > -1) {
bridges.splice(index, 1);
}
} else if (timeLeft < 1000) {
// Fade out when almost gone
bridgeGraphic.alpha = timeLeft / 1000;
}
};
return self;
});
var LevelButton = Container.expand(function (levelNum, unlocked) {
var self = Container.call(this);
// Create button background
var bgColor = unlocked ? 0x3498db : 0x7f8c8d;
var bg = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 150
});
bg.tint = bgColor;
// Create level text
var levelText = new Text2(levelNum.toString(), {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
self.addChild(levelText);
self.levelNum = levelNum;
self.unlocked = unlocked;
// Interaction handlers
self.down = function (x, y, obj) {
if (self.unlocked) {
tween(bg, {
tint: 0x2980b9
}, {
duration: 100
});
}
};
self.up = function (x, y, obj) {
if (self.unlocked) {
tween(bg, {
tint: bgColor
}, {
duration: 100
});
currentLevel = self.levelNum;
showGame();
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphic = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.isInvincible = false;
self.hasBridge = false;
self.makeInvincible = function (duration) {
self.isInvincible = true;
// Visual feedback for invincibility
tween(playerGraphic, {
tint: 0xFFD700
}, {
duration: 300
});
LK.setTimeout(function () {
self.isInvincible = false;
tween(playerGraphic, {
tint: 0xFFFFFF
}, {
duration: 300
});
}, duration);
};
self.giveBridge = function () {
self.hasBridge = true;
// Visual feedback for bridge ability
tween(playerGraphic, {
tint: 0x9b59b6
}, {
duration: 300
});
};
self.useBridge = function () {
if (self.hasBridge) {
self.hasBridge = false;
tween(playerGraphic, {
tint: 0xFFFFFF
}, {
duration: 300
});
return true;
}
return false;
};
return self;
});
var PowerOrb = Container.expand(function (type) {
var self = Container.call(this);
var orbGraphic = self.attachAsset('powerOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type || 'invincibility'; // Default type is invincibility
// Visual differentiation based on type
if (self.type === 'bridge') {
orbGraphic.tint = 0x9b59b6; // Purple for bridge
} else {
orbGraphic.tint = 0xf1c40f; // Yellow for invincibility
}
// Floating animation
self.update = function () {
self.rotation += 0.01;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xecf0f1
});
/****
* Game Code
****/
// Game state variables
var currentLevel = storage.currentLevel || 1;
var highestLevel = storage.highestLevel || 1;
var gameActive = false;
var levelComplete = false;
var player = null;
var goal = null;
var walls = [];
var negativeZones = [];
var powerOrbs = [];
var bridges = [];
var dragNode = null;
var levelMenu = null;
var currentLevelText = null;
var totalLevels = 5;
var dragStartPos = {
x: 0,
y: 0
};
// Create level selection menu
function createLevelMenu() {
if (levelMenu) {
game.removeChild(levelMenu);
}
levelMenu = new Container();
game.addChild(levelMenu);
// Title
var titleText = new Text2("Positive Path", {
size: 120,
fill: 0x2C3E50
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 200;
levelMenu.addChild(titleText);
// Subtitle
var subtitleText = new Text2("Select a Level", {
size: 80,
fill: 0x7F8C8D
});
subtitleText.anchor.set(0.5, 0);
subtitleText.x = 2048 / 2;
subtitleText.y = 350;
levelMenu.addChild(subtitleText);
// Level buttons
var buttonsPerRow = 3;
var buttonSize = 200;
var spacing = 50;
var startX = (2048 - (buttonsPerRow * buttonSize + (buttonsPerRow - 1) * spacing)) / 2 + buttonSize / 2;
var startY = 500;
for (var i = 1; i <= totalLevels; i++) {
var row = Math.floor((i - 1) / buttonsPerRow);
var col = (i - 1) % buttonsPerRow;
var x = startX + col * (buttonSize + spacing);
var y = startY + row * (buttonSize + spacing);
var button = new LevelButton(i, i <= highestLevel);
button.x = x;
button.y = y;
levelMenu.addChild(button);
}
}
// Create level
function createLevel(levelNumber) {
clearLevel();
// Create player
player = new Player();
game.addChild(player);
// Create goal
goal = game.addChild(LK.getAsset('goal', {
anchorX: 0.5,
anchorY: 0.5
}));
// Setup level-specific layout
switch (levelNumber) {
case 1:
createLevel1();
break;
case 2:
createLevel2();
break;
case 3:
createLevel3();
break;
case 4:
createLevel4();
break;
case 5:
createLevel5();
break;
default:
createLevel1();
}
// Create level text
if (currentLevelText) {
LK.gui.topRight.removeChild(currentLevelText);
}
currentLevelText = new Text2("Level " + levelNumber, {
size: 60,
fill: 0x34495E
});
currentLevelText.anchor.set(1, 0);
currentLevelText.x = -50;
currentLevelText.y = 50;
LK.gui.topRight.addChild(currentLevelText);
gameActive = true;
}
function clearLevel() {
if (player) {
player.destroy();
player = null;
}
if (goal) {
goal.destroy();
goal = null;
}
// Clear walls
for (var i = 0; i < walls.length; i++) {
walls[i].destroy();
}
walls = [];
// Clear negative zones
for (var i = 0; i < negativeZones.length; i++) {
negativeZones[i].destroy();
}
negativeZones = [];
// Clear power orbs
for (var i = 0; i < powerOrbs.length; i++) {
powerOrbs[i].destroy();
}
powerOrbs = [];
// Clear bridges
for (var i = 0; i < bridges.length; i++) {
bridges[i].destroy();
}
bridges = [];
gameActive = false;
levelComplete = false;
}
function createWall(x, y, width, height) {
var wall = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: width / 100,
scaleY: height / 100
});
wall.x = x;
wall.y = y;
game.addChild(wall);
walls.push(wall);
return wall;
}
function createNegativeZone(x, y, width, height) {
var zone = LK.getAsset('negative', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: width / 100,
scaleY: height / 100
});
zone.x = x;
zone.y = y;
game.addChild(zone);
negativeZones.push(zone);
return zone;
}
function createPowerOrb(x, y, type) {
var orb = new PowerOrb(type);
orb.x = x;
orb.y = y;
game.addChild(orb);
powerOrbs.push(orb);
return orb;
}
function createBridge(x, y, direction) {
var bridge = new Bridge(direction);
bridge.x = x;
bridge.y = y;
game.addChild(bridge);
bridges.push(bridge);
return bridge;
}
// Level layouts
function createLevel1() {
// Tutorial level - simple path with one negative zone
player.x = 400;
player.y = 1366;
goal.x = 1648;
goal.y = 1366;
// Walls to create a path
createWall(1024, 1066, 1600, 100); // Top wall
createWall(1024, 1666, 1600, 100); // Bottom wall
// One negative zone to avoid
createNegativeZone(1024, 1366, 300, 300);
// Instructions
var instructionText = new Text2("Drag the blue ball to the green goal.\nAvoid the red areas!", {
size: 60,
fill: 0x34495E
});
instructionText.anchor.set(0.5, 0);
instructionText.x = 1024;
instructionText.y = 800;
game.addChild(instructionText);
walls.push(instructionText); // Add to walls array to be cleared properly
}
function createLevel2() {
// More complex path with multiple negative zones
player.x = 300;
player.y = 500;
goal.x = 1748;
goal.y = 2200;
// Create maze walls
createWall(1024, 300, 1600, 100); // Top wall
createWall(1024, 2400, 1600, 100); // Bottom wall
createWall(300, 1350, 100, 2000); // Left wall
createWall(1748, 1350, 100, 2000); // Right wall
// Create inner walls
createWall(800, 800, 800, 100);
createWall(1300, 1200, 800, 100);
createWall(800, 1600, 800, 100);
createWall(1300, 2000, 800, 100);
// Create negative zones
createNegativeZone(800, 1200, 300, 300);
createNegativeZone(1300, 1600, 300, 300);
createNegativeZone(800, 2000, 300, 300);
// Add a power orb
createPowerOrb(1024, 600, 'invincibility');
}
function createLevel3() {
// Introduce bridge power-up
player.x = 300;
player.y = 400;
goal.x = 1748;
goal.y = 2300;
// Create outer walls
createWall(1024, 250, 1600, 100); // Top wall
createWall(1024, 2500, 1600, 100); // Bottom wall
createWall(250, 1375, 100, 2250); // Left wall
createWall(1798, 1375, 100, 2250); // Right wall
// Create gaps with negative zones
createNegativeZone(700, 800, 900, 200);
createNegativeZone(1350, 1400, 900, 200);
createNegativeZone(700, 2000, 900, 200);
// Add bridge power-up
createPowerOrb(1024, 600, 'bridge');
// Instructions
var instructionText = new Text2("Yellow orbs give you special powers.\nPurple orbs let you create bridges!", {
size: 50,
fill: 0x34495E
});
instructionText.anchor.set(0.5, 0);
instructionText.x = 1024;
instructionText.y = 300;
game.addChild(instructionText);
walls.push(instructionText);
}
function createLevel4() {
// Complex level with both power-ups
player.x = 300;
player.y = 400;
goal.x = 1748;
goal.y = 2300;
// Create outer walls
createWall(1024, 250, 1600, 100); // Top wall
createWall(1024, 2500, 1600, 100); // Bottom wall
createWall(250, 1375, 100, 2250); // Left wall
createWall(1798, 1375, 100, 2250); // Right wall
// Create maze structure
createWall(700, 800, 100, 700);
createWall(1350, 800, 100, 700);
createWall(700, 1800, 100, 700);
createWall(1350, 1800, 100, 700);
// Create negative zones - forming a checkerboard pattern
createNegativeZone(500, 600, 200, 200);
createNegativeZone(900, 600, 200, 200);
createNegativeZone(1300, 600, 200, 200);
createNegativeZone(1700, 600, 200, 200);
createNegativeZone(700, 1000, 200, 200);
createNegativeZone(1100, 1000, 200, 200);
createNegativeZone(1500, 1000, 200, 200);
createNegativeZone(500, 1400, 200, 200);
createNegativeZone(900, 1400, 200, 200);
createNegativeZone(1300, 1400, 200, 200);
createNegativeZone(1700, 1400, 200, 200);
createNegativeZone(700, 1800, 200, 200);
createNegativeZone(1100, 1800, 200, 200);
createNegativeZone(1500, 1800, 200, 200);
createNegativeZone(500, 2200, 200, 200);
createNegativeZone(900, 2200, 200, 200);
createNegativeZone(1300, 2200, 200, 200);
createNegativeZone(1700, 2200, 200, 200);
// Add power-ups
createPowerOrb(500, 1000, 'invincibility');
createPowerOrb(1500, 1000, 'bridge');
createPowerOrb(1100, 1400, 'invincibility');
createPowerOrb(500, 1800, 'bridge');
}
function createLevel5() {
// Final challenge level
player.x = 1024;
player.y = 400;
goal.x = 1024;
goal.y = 2300;
// Create outer walls
createWall(1024, 250, 1600, 100); // Top wall
createWall(1024, 2500, 1600, 100); // Bottom wall
createWall(250, 1375, 100, 2250); // Left wall
createWall(1798, 1375, 100, 2250); // Right wall
// Create a spiral of negative zones
var center = {
x: 1024,
y: 1375
};
var spiralRadius = 800;
var spiralWidth = 150;
var angleStep = Math.PI / 8;
for (var angle = 0; angle < 4 * Math.PI; angle += angleStep) {
var radius = spiralRadius * (1 - angle / (4 * Math.PI));
var x = center.x + radius * Math.cos(angle);
var y = center.y + radius * Math.sin(angle);
createNegativeZone(x, y, spiralWidth, spiralWidth);
}
// Add power-ups strategically
createPowerOrb(1024, 600, 'invincibility');
createPowerOrb(600, 1000, 'bridge');
createPowerOrb(1450, 1800, 'invincibility');
createPowerOrb(800, 2100, 'bridge');
}
// Game mechanics
function checkCollisions() {
if (!gameActive || levelComplete) {
return;
}
// Check if player reached goal
if (player.intersects(goal)) {
levelComplete = true;
LK.getSound('win').play();
// Update highest level if needed
if (currentLevel >= highestLevel) {
highestLevel = currentLevel + 1;
if (highestLevel > totalLevels) {
highestLevel = totalLevels;
}
storage.highestLevel = highestLevel;
}
// Show completion message and proceed to next level
var completionText = new Text2("Level Complete!", {
size: 100,
fill: 0x2ECC71
});
completionText.anchor.set(0.5, 0.5);
completionText.x = 1024;
completionText.y = 1366;
game.addChild(completionText);
LK.setTimeout(function () {
completionText.destroy();
if (currentLevel < totalLevels) {
currentLevel++;
storage.currentLevel = currentLevel;
createLevel(currentLevel);
} else {
// Game completed
LK.showYouWin();
}
}, 2000);
return;
}
// Check collision with negative zones
for (var i = 0; i < negativeZones.length; i++) {
if (player.intersects(negativeZones[i]) && !player.isInvincible) {
gameActive = false;
LK.getSound('lose').play();
// Visual feedback
LK.effects.flashScreen(0xe74c3c, 1000);
// Restart level after a delay
LK.setTimeout(function () {
createLevel(currentLevel);
}, 1500);
return;
}
}
// Check collision with power orbs
for (var i = powerOrbs.length - 1; i >= 0; i--) {
if (player.intersects(powerOrbs[i])) {
// Apply power-up effect
if (powerOrbs[i].type === 'invincibility') {
player.makeInvincible(5000); // 5 seconds of invincibility
} else if (powerOrbs[i].type === 'bridge') {
player.giveBridge();
}
// Remove the orb
LK.getSound('collect').play();
powerOrbs[i].destroy();
powerOrbs.splice(i, 1);
}
}
// Check if player is trying to cross a wall
if (dragNode) {
for (var i = 0; i < walls.length; i++) {
if (player.intersects(walls[i])) {
// Move player back to valid position
player.x = dragStartPos.x;
player.y = dragStartPos.y;
return;
}
}
}
}
// Bridge placement
function placeBridge(x, y) {
if (!player.hasBridge) {
return false;
}
// Determine bridge direction based on player position
var direction = 'horizontal';
var minDistanceToWall = 9999;
var nearestWall = null;
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
var dx = Math.abs(wall.x - player.x);
var dy = Math.abs(wall.y - player.y);
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistanceToWall) {
minDistanceToWall = distance;
nearestWall = wall;
}
}
if (nearestWall) {
// Determine orientation based on nearest wall position
var dx = Math.abs(nearestWall.x - player.x);
var dy = Math.abs(nearestWall.y - player.y);
direction = dx > dy ? 'horizontal' : 'vertical';
}
// Place bridge slightly ahead of player in the direction of drag
var placeX = x;
var placeY = y;
createBridge(placeX, placeY, direction);
return player.useBridge();
}
// Game state management
function showMenu() {
clearLevel();
createLevelMenu();
gameActive = false;
}
function showGame() {
if (levelMenu) {
game.removeChild(levelMenu);
levelMenu = null;
}
createLevel(currentLevel);
// Play background music when starting the game
LK.playMusic('bgmusic', {
loop: true,
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
}
// Event handlers
game.down = function (x, y, obj) {
if (!gameActive) {
return;
}
if (player) {
// Check if we're clicking on player
var playerBounds = {
left: player.x - player.width / 2,
right: player.x + player.width / 2,
top: player.y - player.height / 2,
bottom: player.y + player.height / 2
};
if (x >= playerBounds.left && x <= playerBounds.right && y >= playerBounds.top && y <= playerBounds.bottom) {
dragNode = player;
dragStartPos = {
x: player.x,
y: player.y
};
} else if (player.hasBridge) {
// Try to place a bridge
placeBridge(x, y);
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
game.move = function (x, y, obj) {
if (dragNode && gameActive && !levelComplete) {
// Store the current position in case we need to revert
var oldX = dragNode.x;
var oldY = dragNode.y;
// Update position
dragNode.x = x;
dragNode.y = y;
// Check for wall collisions
for (var i = 0; i < walls.length; i++) {
if (dragNode.intersects(walls[i])) {
// Revert position
dragNode.x = oldX;
dragNode.y = oldY;
return;
}
}
// Check if we can cross with a bridge
for (var i = 0; i < bridges.length; i++) {
if (dragNode.intersects(bridges[i])) {
return; // We're on a bridge, allow movement
}
}
}
};
game.update = function () {
if (!gameActive) {
return;
}
// Update all objects with update methods
for (var i = 0; i < powerOrbs.length; i++) {
powerOrbs[i].update();
}
for (var i = 0; i < bridges.length; i++) {
bridges[i].update();
}
// Check for collisions
checkCollisions();
};
// Initialize the game
showMenu();