/**** * Classes ****/ var Background = Container.expand(function () { var self = Container.call(this); var backgroundGraphics1 = self.attachAsset('background_1', { anchorX: 0.5, anchorY: 0.5, visible: true }); var backgroundGraphics2 = self.attachAsset('background_2', { anchorX: 0.5, anchorY: 0.5, visible: false }); var backgroundGraphics3 = self.attachAsset('background_3', { anchorX: 0.5, anchorY: 0.5, visible: false }); self.updateForLevel = function (level) { backgroundGraphics1.visible = level === 1; backgroundGraphics2.visible = level === 2; backgroundGraphics3.visible = level === 3; }; }); var Bonus = Container.expand(function (index) { var self = Container.call(this); self.index = index; var bonusHalo = self.attachAsset('bonusHalo', { anchorX: 0.5, anchorY: 0.5, visible: false }); var assets = ['bonus_1', 'bonus_2', 'bonus_3']; self.assetIndex = index % assets.length; var randomAsset = assets[self.assetIndex]; var bonusGraphics = self.attachAsset(randomAsset, { anchorX: 0.5, anchorY: 0.5 }); var speed = 5; var startY = roadTop - 20; var endY = startY + roadHeight; var leftStartX = 1024 - 100; var leftEndX = 1024 - 650; var rightStartX = 1024 + 100; var rightEndX = 1024 + 650; var startSize = 1; var endSize = 200; var assetHeightRatio = 1; // Adjusted for bonus asset ratio bonusGraphics.width = startSize; bonusGraphics.height = startSize; bonusHalo.width = startSize * 3; bonusHalo.height = startSize * 3; self.pathIndex = 0; self.inactive = true; self.inactiveStartTime = Date.now(); self.update = function () { if (!isPlaying || isKilled) { return; } if (self.inactive) { return; } if (!isKilled && player && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) { // Handle bonus collection logic here bonusManager.applyBonus(self.index); self.reset(); return; } self.progress = Math.max(0, self.y - startY) / (endY - startY); bonusGraphics.width = startSize + (endSize - startSize) * self.progress; bonusGraphics.height = assetHeightRatio * bonusGraphics.width; bonusHalo.visible = true; bonusHalo.rotation += 0.01 + (self.progress * 100 % 3 == 0); // Rotate bonusHalo sequentially bonusHalo.width = bonusGraphics.width * 3; bonusHalo.height = bonusGraphics.height * 3; var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3); var newSpeed = currentSpeed * 1; newSpeed = tempSpeed * 1; self.y += newSpeed; if (self.pathIndex == 0 && self.x != leftEndX) { self.x = leftStartX + (leftEndX - leftStartX) * self.progress; } if (self.pathIndex == 2 && self.x != rightEndX) { self.x = rightStartX + (rightEndX - rightStartX) * self.progress; } if (self.y > endY + endSize / 2) { self.reset(); } }; self.reset = function () { bonusHalo.rotation = 0; // Initialize bonusHalo rotation self.y = startY; self.progress = 0; bonusGraphics.width = startSize; bonusGraphics.height = startSize; bonusHalo.width = startSize * 3; bonusHalo.height = startSize * 3; bonusHalo.visible = false; self.pathIndex = Math.floor(Math.random() * 3); if (self.pathIndex === 0) { self.x = leftStartX; } else if (self.pathIndex === 2) { self.x = rightStartX; } else { self.x = 1024; } self.inactive = true; self.inactiveStartTime = Date.now(); }; }); var BonusManager = Container.expand(function () { var self = Container.call(this); self.bonuses = []; self.bonusIcon = null; self.currentBonusIndex = 0; self.currentActiveBonus = 0; self.lastBonusUpdate = 0; self.bonusDelay = 16000; // Delay in milliseconds before updating bonus self.addBonus = function (bonus) { self.bonuses.push(bonus); }; self.update = function () { if (!isGameStarted || !isPlaying || isKilled) { self.lastBonusUpdate = Date.now(); // Reset the last bonus update time when the game starts return; } if (self.currentActiveBonus > 0) { if (!self.bonusIcon) { self.bonusIcon = LK.getAsset('bonus_' + self.currentActiveBonus, { anchorX: 0.5, anchorY: 0.5, x: scoreTxt.x, y: scoreTxt.y + scoreTxt.height + 50 }); LK.gui.top.addChild(self.bonusIcon); } } else if (self.bonusIcon) { self.bonusIcon.visible = false; self.bonusIcon = null; } var currentTime = Date.now(); var currentDelay = currentTime - self.lastBonusUpdate; if (currentDelay >= self.bonusDelay) { LK.getSound('bonus_approaching').play(); self.currentBonusIndex = (self.currentBonusIndex + 1) % self.bonuses.length; self.bonuses[self.currentBonusIndex].inactive = false; self.lastBonusUpdate = currentTime; } }; self.resetBonuses = function () { self.bonuses.forEach(function (bonus) { bonus.reset(); }); self.currentBonusIndex = 0; self.lastBonusUpdate = Date.now(); }; self.updateForLevel = function (level) { if (level === 1) { self.bonusDelay = 8000; // Delay in milliseconds for level 1 } else if (level === 2) { self.bonusDelay = 12000; // Delay in milliseconds for level 2 } else if (level === 3) { self.bonusDelay = 16000; // Delay in milliseconds for level 3 } }; self.applyBonus = function (index) { self.currentActiveBonus = index + 1; LK.getSound('bonus_take').play(); self.lastBonusUpdate = Date.now(); LK.setTimeout(function () { // Start blinking effect 3 seconds before bonus ends var blinkStartTime = Date.now(); var blinkInterval = LK.setInterval(function () { var elapsed = Date.now() - blinkStartTime; if (elapsed >= 3000) { LK.clearInterval(blinkInterval); self.stopBonus(); } else { if (self.bonusIcon) { self.bonusIcon.alpha = self.bonusIcon.alpha === 1 ? 0.5 : 1; } } }, 150); // Blink every 500ms }, baseBonusDelay - 3000); }; self.stopBonus = function () { self.currentActiveBonus = 0; if (self.bonusIcon) { LK.gui.top.removeChild(self.bonusIcon); } if (self.bonusIcon) { self.bonusIcon.destroy(); } self.bonusIcon = null; self.lastBonusUpdate = Date.now(); }; }); // Assets will be automatically created and loaded during gameplay // Coin class var Coin = Container.expand(function (index) { var self = Container.call(this); self.index = index; var coinGraphics = self.attachAsset('coin1', { anchorX: 0.5, anchorY: 0.5 }); var coinGraphics2 = self.attachAsset('coin2', { //'dollarsBundle' anchorX: 0.5, anchorY: 0.5, visible: false }); var coinGraphics3 = self.attachAsset('dollarsBundle', { //'dollarsBundle' anchorX: 0.5, anchorY: 0.5, visible: false }); var coinGraphicsClone = self.attachAsset('coin1', { anchorX: 0.5, anchorY: 0.5, x: -20, visible: false }); var coinGraphics2Clone = self.attachAsset('coin2', { //'dollarsBundle' anchorX: 0.5, anchorY: 0.5, x: -20, visible: false }); var coinGraphics3Clone = self.attachAsset('dollarsBundle', { anchorX: 0.5, anchorY: 0.5, x: -20, visible: false }); var speed = 5; var startY = roadTop + 50; var endY = startY + roadHeight; var leftStartX = 1024 - 100; var leftEndX = 1024 - 650; var rightStartX = 1024 + 100; var rightEndX = 1024 + 650; var startSize = 2; var endSize = 140; coinGraphics.width = startSize; coinGraphics.height = startSize; coinGraphics2.width = startSize; coinGraphics2.height = startSize; coinGraphics3.width = startSize; coinGraphics3.height = startSize; self.pathIndex = 0; self.update = function () { if (!isGameStarted) { return; } // Road should animate even if the game hasn't started if (!isPlaying || isKilled) { return; } ; obstacleManager.updateObstacles(); self.progress = Math.max(0, self.y - startY) / (endY - startY); // Update progress property coinGraphics.width = startSize + (endSize - startSize) * self.progress; coinGraphics.height = startSize + (endSize - startSize) * self.progress; coinGraphics2.width = startSize + (endSize - startSize) * self.progress; coinGraphics2.height = startSize + (endSize - startSize) * self.progress; coinGraphics3.width = startSize + (endSize - startSize) * self.progress; coinGraphics3.height = startSize + (endSize - startSize) * self.progress; if (bonusManager.currentActiveBonus == 2) { coinGraphicsClone.width = coinGraphics.width; coinGraphicsClone.height = coinGraphics.height; coinGraphics2Clone.width = coinGraphics2.width; coinGraphics2Clone.height = coinGraphics2.height; coinGraphics3Clone.width = coinGraphics3.width; coinGraphics3Clone.height = coinGraphics3.height; coinGraphicsClone.visible = currentLevel === 1; coinGraphics2Clone.visible = currentLevel === 2; coinGraphics3Clone.visible = currentLevel === 3; coinGraphics.x = 20; coinGraphics2.x = 20; coinGraphics3.x = 20; } else { coinGraphics.x = 0; coinGraphics2.x = 0; coinGraphics3.x = 0; coinGraphicsClone.visible = false; coinGraphics2Clone.visible = false; coinGraphics3Clone.visible = false; } if (bonusManager.currentActiveBonus == 3 && self.y > 1500) { // Magnet bonus logic var distanceX = player.x - self.x; var distanceY = player.y - self.y; var distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY); if (distance < 1500) { var attractionSpeed = 20; self.x += distanceX / distance * attractionSpeed; self.y += distanceY / distance * attractionSpeed; } distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY); if (distance < 100) { LK.getSound('coin_1').play(); updateScore(false); // coinsCollected increment moved to increaseScore function LK.effects.flashObject(player, 0x00ff00, 500); // Flash green for 0.5 seconds self.reset(); } } else { var newSpeed = currentSpeed; // + 10 * self.progress; var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3); newSpeed = tempSpeed; self.y += newSpeed; // Move innerLineLeft x progressively to innerLeftLineEndX if (self.pathIndex == 0 && self.x != leftEndX) { self.x = leftStartX + (leftEndX - leftStartX) * self.progress; } if (self.pathIndex == 2 && self.x != rightEndX) { self.x = rightStartX + (rightEndX - rightStartX) * self.progress; } } if (self.y > endY + endSize / 2) { self.reset(); } // Check for collision with player if (!player.isJumping && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) { LK.getSound('coin_1').play(); updateScore(false); // coinsCollected increment moved to increaseScore function LK.effects.flashObject(player, 0x00ff00, 500); // Flash green for 0.5 seconds self.reset(); // Increase speed every 3 coins collected /* if (coinsCollected % nextCoinTypeThreshold === 0 && currentSpeed < maxSpeed) { currentSpeed += 3; // Increase speed by 3 } */ } }; self.reset = function () { self.y = startY; self.progress = 0; // Initialize progress property coinGraphics.width = startSize; coinGraphics.height = startSize; coinGraphics2.width = startSize; coinGraphics2.height = startSize; coinGraphics3.width = startSize; coinGraphics3.height = startSize; coinGraphicsClone.visible = false; coinGraphics2Clone.visible = false; coinGraphics3Clone.visible = false; self.pathIndex = Math.floor(Math.random() * 3); if (self.pathIndex === 0) { self.x = leftStartX; } else if (self.pathIndex === 2) { self.x = rightStartX; } else { self.x = 1024; } }; self.updateForLevel = function (level) { coinGraphics.visible = level === 1; coinGraphics2.visible = level === 2; coinGraphics3.visible = level === 3; }; }); // CoinAnimation class var CoinAnimation = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin1', { anchorX: 0.5, anchorY: 0.5, visible: currentLevel === 1 }); var coinGraphics2 = self.attachAsset('coin2', { anchorX: 0.5, anchorY: 0.5, visible: currentLevel === 2 }); var coinGraphics3 = self.attachAsset('dollarsBundle', { anchorX: 0.5, anchorY: 0.5, visible: currentLevel === 3 }); // Initialize velocity and gravity self.vx = (Math.random() < 0.5 ? -1 : 1) * 5; // Random horizontal velocity self.vy = -15; // Initial vertical velocity self.gravity = 0.5; // Gravity effect self.update = function () { self.vy += self.gravity; // Apply gravity to vertical velocity self.x += self.vx; // Update horizontal position self.y += self.vy; // Update vertical position self.alpha -= 0.0035; // Fade out the coin coinGraphics.visible = currentLevel === 1; coinGraphics2.visible = currentLevel === 2; coinGraphics3.visible = currentLevel === 3; if (self.alpha <= 0) { self.destroy(); // Remove the coin when it becomes invisible } }; }); // Decoration class var Decoration = Container.expand(function (decoIndex) { var self = Container.call(this); self.index = decoIndex; var assets = ['decoration_1_1', 'decoration_1_2', 'decoration_1_3', 'decoration_2_1', 'decoration_2_2', 'decoration_2_3', 'decoration_3_1', 'decoration_3_2', 'decoration_3_3']; self.assets = assets.map(function (assetId) { return self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5, visible: false }); }); self.ready = false; var speed = 5; var startY = roadTop + 50; var endY = startY + roadHeight; var xOffset = 1024; var baseLeftStartX = 780; var rand = Math.random(); self.leftStartX = baseLeftStartX; // - rand * xOffset; self.leftEndX = self.leftStartX - xOffset * (1.5 + rand); var baseRightStartX = 1280; self.rightStartX = baseRightStartX; // + rand * xOffset / 2; self.rightEndX = self.rightStartX + xOffset * (1.5 + rand); self.assetWidthRatios = [0.33, 1, 1, 1, 1, 1, 1, 1, 1]; self.endSizes = [600, 600, 600, 600, 600, 600, 600, 600, 600]; var startSize = 1; self.assetIndex = Math.floor(Math.random() * 3) + (currentLevel - 1) * 3; mainGraphics = self.assets[self.assetIndex]; mainGraphics.width = startSize; mainGraphics.height = startSize; self.pathIndex = 0; self.update = function () { if (isKilled) { return; } var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf; //mainGraphics.tint = newTint; var tempSpeed = currentSpeed * 0.055 + currentSpeed * (self.progress * 3); var newSpeed = currentSpeed; // + 10 * self.progress; newSpeed = tempSpeed * 1; // TEMP DEBUG !!! self.y += newSpeed; self.progress = Math.max(0, self.y - startY) / (endY - startY); // Update progress property // Move innerLineLeft x progressively to innerLeftLineEndX if (self.index == 7) { //log("Decoration " + self.index + " update - p=", self.progress, "x:", Math.round(self.x), "y:", Math.round(self.y)); //log(self.progress); } if (self.pathIndex == 0 && self.x > self.leftEndX) { self.x = self.leftStartX + (self.leftEndX - self.leftStartX) * self.progress * 3; } if (self.pathIndex == 1 && self.x < self.rightEndX) { self.x = self.rightStartX + (self.rightEndX - self.rightStartX) * self.progress * 3; } if (self.y > endY + self.endSizes[self.assetIndex] / 2) { //self.y = -startSize; // Move obstacle back to the top self.reset(); } //mainGraphics = self.assets[self.assetIndex]; mainGraphics.height = startSize + (self.endSizes[self.assetIndex] - startSize) * self.progress * 2; mainGraphics.width = mainGraphics.height * self.assetWidthRatios[self.assetIndex]; if (self.index == 8 && mainGraphics.width > 200) { //log("Decoration " + self.index + " update - assetIndex:", self.assetIndex, "width:", mainGraphics.width, "x:", Math.round(self.x), "y:", Math.round(self.y)); } if (self.index == 7 && mainGraphics.width > 200) { //log("Decoration " + self.index + " update - assetIndex:", self.assetIndex, "width:", mainGraphics.width, "x:", Math.round(self.x), "y:", Math.round(self.y)); } if (!self.ready) { //log("Decoration " + self.index + " ready =" + self.ready); } //log("Decoration " + self.index + " update width:", Math.round(mainGraphics.width), "x:", Math.round(self.x), "y:", Math.round(self.y)); }; self.reset = function () { self.ready = false; //log("Decoration reset" + self.index); self.y = startY; self.progress = 0; // Initialize progress property rand = Math.random(); self.assetIndex = Math.floor(Math.random() * 3) + (currentLevel - 1) * 3; self.assets.forEach(function (asset, index) { asset.visible = index === self.assetIndex; }); mainGraphics = self.assets[self.assetIndex]; mainGraphics.height = startSize; mainGraphics.width = mainGraphics.height * self.assetWidthRatios[self.assetIndex]; if (self.index == 1 && mainGraphics.width > 200) { //log("=== Decoration " + self.index + " reset - assetIndex:", self.assetIndex, "width:", mainGraphics.width, "y:", self.y, " ==="); } self.leftStartX = baseLeftStartX; // - rand * xOffset; self.leftEndX = self.leftStartX - xOffset * (1 + rand); self.rightStartX = baseRightStartX; // + rand * xOffset; self.rightEndX = self.rightStartX + xOffset * (1 + rand); if (self.index == 1) { //log("=== Decoration " + self.index); //log("Left StartX:", self.leftStartX, "Left EndX:", self.leftEndX); //log("Right StartX:", self.rightStartX, "Right EndX:", self.rightEndX); } self.pathIndex = Math.floor(rand * 2); if (self.pathIndex === 0) { self.x = self.leftStartX; } else { self.x = self.rightStartX; } self.ready = true; }; }); var Killer = Container.expand(function (index) { var self = Container.call(this); self.index = index; var assets = ['killer1', 'killer2', 'killer3']; self.assetIndex = index % assets.length; var randomAsset = assets[self.assetIndex]; var killerGraphics = self.attachAsset(randomAsset, { anchorX: 0.5, anchorY: 0.5 }); var speed = 5; var startY = roadTop - 20; var endY = startY + roadHeight; var leftStartX = 1024 - 100; var leftEndX = 1024 - 650; var rightStartX = 1024 + 100; var rightEndX = 1024 + 650; var startSize = 1; var endSize = 800; var assetHeightRatio = 500 / 400; killerGraphics.width = startSize; killerGraphics.height = startSize; self.pathIndex = 0; self.inactive = true; self.inactiveStartTime = Date.now(); self.update = function () { if (!isPlaying) { return; } if (self.inactive) { return; } if (!isKilled && player && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) { LK.getSound('accident_1').play(); if (bonusManager.currentActiveBonus == 1) { // Have Helmet! LK.effects.flashScreen(0xffffff, 2000); self.reset(); bonusManager.stopBonus(); return; } isKilled = true; player.visible = false; LK.stopMusic(); LK.setTimeout(function () { LK.getSound('killed_1').play(); }, 100); // Adjust the delay as needed LK.setTimeout(function () { LK.getSound('rip_1').play(); }, 1000); // Play rip_1 sound 1 second after killed LK.effects.flashScreen(0xff0000, 4000); // Spawn MurderShape at player's last position var murderShape = new MurderShape(); murderShape.x = player.x; murderShape.y = playerBaseY; murderShape.fixPosition(); game.addChildAt(murderShape, game.getChildIndex(road) + 1); // Store the score in LK score before game over LK.setScore(score * 100); LK.setTimeout(function () { LK.showGameOver(); }, 5000); return; } self.progress = Math.max(0, self.y - startY) / (endY - startY); killerGraphics.width = startSize + (endSize - startSize) * self.progress; debugTxt.setText(self.progress.toFixed(2)); killerGraphics.height = assetHeightRatio * killerGraphics.width; var tempSpeed = currentSpeed * 0.5 + currentSpeed * (self.progress * 3); var newSpeed = currentSpeed * 3 + (currentLevel - 1); newSpeed = tempSpeed * 1; self.y += newSpeed; if (self.pathIndex == 0 && self.x != leftEndX) { self.x = leftStartX + (leftEndX - leftStartX) * self.progress; } if (self.pathIndex == 2 && self.x != rightEndX) { self.x = rightStartX + (rightEndX - rightStartX) * self.progress; } if (self.y > endY + endSize / 2) { self.reset(); } }; self.reset = function () { self.y = startY; self.progress = 0; killerGraphics.width = startSize; killerGraphics.height = startSize; self.pathIndex = Math.floor(Math.random() * 3); if (self.pathIndex === 0) { self.x = leftStartX; } else if (self.pathIndex === 2) { self.x = rightStartX; } else { self.x = 1024; } self.inactive = true; self.inactiveStartTime = Date.now(); }; }); var KillerManager = Container.expand(function () { var self = Container.call(this); self.killers = []; self.currentKillerIndex = 0; self.lastKillerUpdate = 0; self.killerDelay = 10000; // Delay in milliseconds before updating killer self.addKiller = function (killer) { self.killers.push(killer); }; self.update = function () { if (!isGameStarted) { self.lastKillerUpdate = Date.now(); // Reset the last killer update time when the game starts return; } var currentTime = Date.now(); var currentDelay = currentTime - self.lastKillerUpdate; if (currentDelay >= self.killerDelay) { self.killers[self.currentKillerIndex].inactive = false; if (self.currentKillerIndex === 0) { LK.getSound('car_1').play(); } else if (self.currentKillerIndex === 1) { LK.getSound('police_1').play(); } else if (self.currentKillerIndex === 2) { LK.getSound('ambulance_1').play(); } self.currentKillerIndex = (self.currentKillerIndex + 1) % self.killers.length; self.lastKillerUpdate = currentTime; } }; self.resetKillers = function () { self.killers.forEach(function (killer) { killer.reset(); }); self.currentKillerIndex = 0; self.lastKillerUpdate = Date.now(); }; self.updateForLevel = function (level) { if (level === 1) { self.killerDelay = 12000; // Delay in milliseconds for level 1 } else if (level === 2) { self.killerDelay = 10000; // Delay in milliseconds for level 2 } else if (level === 3) { self.killerDelay = 8000; // Delay in milliseconds for level 3 } }; }); var Landscape = Container.expand(function () { var self = Container.call(this); var landscapeGraphics = self.attachAsset('landscape_1', { anchorX: 0.5, anchorY: 0.0 }); var landscapeGraphics2 = self.attachAsset('landscape_2', { anchorX: 0.5, anchorY: 0.0, visible: false }); var landscapeGraphics3 = self.attachAsset('landscape_3', { anchorX: 0.5, anchorY: 0.0, visible: false }); var gradientGraphics = self.attachAsset('gradient', { anchorX: 0.5, anchorY: 0.0, scaleY: -1, y: 1024, blendMode: 2, alpha: 0.5, tint: 0xFEFEFE, height: 15 }); self.x = 2048 / 2; // Center horizontally self.y = 0; // Position at the top self.update = function () { var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf; landscapeGraphics.tint = newTint; // Apply reduced tint to the road based on the intensity }; self.updateForLevel = function (level) { landscapeGraphics.visible = level === 1; landscapeGraphics2.visible = level === 2; landscapeGraphics3.visible = level === 3; }; }); var MurderShape = Container.expand(function () { var self = Container.call(this); var murderShapeGraphics = self.attachAsset('murderShape', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // MurderShape does not need to update its position or behavior }; self.fixPosition = function () { if (self.x < 600) { self.x += 150; } else if (self.x > 1400) { self.x -= 150; } }; }); // Obstacle class var Obstacle = Container.expand(function (index) { var self = Container.call(this); self.active = true; self.index = index; var assets = []; if (currentLevel === 1) { assets = ['obstacle_1_1', 'obstacle_1_2', 'obstacle_1_3']; } else if (currentLevel === 2) { assets = ['obstacle_2_1', 'obstacle_2_2', 'obstacle_2_3']; } else if (currentLevel === 3) { assets = ['obstacle_3_1', 'obstacle_3_2', 'obstacle_3_3']; } self.assetIndex = Math.floor(Math.random() * assets.length); var randomAsset = assets[self.assetIndex]; var obstacleGraphics = self.attachAsset(randomAsset, { anchorX: 0.5, anchorY: 0.5 }); var speed = 5; var startY = roadTop + 50; var endY = startY + roadHeight; var leftStartX = 1024 - 100; var leftEndX = 1024 - 650; var rightStartX = 1024 + 100; var rightEndX = 1024 + 650; var innerLeftLineStartX = -150; var innerLeftLineEndX = -390; self.assetWidthRatios = [1, 1, 1.5, 1.8, 1.8, 1.6, 1, 0.8, 1.1]; var startSize, endSize; if (self.assetIndex == 0) { startSize = 3; endSize = 200; } else if (self.assetIndex == 1) { startSize = 1; endSize = 250; } else if (self.assetIndex == 2) { startSize = 2; endSize = 300; } obstacleGraphics.width = startSize; obstacleGraphics.height = startSize; self.pathIndex = 0; self.update = function () { if (!isPlaying || isKilled) { return; } // coinsCollected increment moved to updateScore function var currentTime = Date.now(); if (currentTime - lastObstacleHitTime > immunityDelay && player && !player.isJumping && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) { lastObstacleHitTime = currentTime; // Update the last hit time if (bonusManager.currentActiveBonus != 1) { // Without helmet playHit(); // Make player flash red for 1 second LK.effects.flashObject(player, 0xff0000, 1000); // Add coin animation only if score is greater than 0 if (score > 0) { var coinAnimation = new CoinAnimation(); coinAnimation.x = player.x; coinAnimation.y = player.y; game.addChild(coinAnimation); } // Reduce score by 1 updateScore(true); //log("Obstacle y:", self.y); // Reduce currentSpeed by a factor (e.g., 0.8) //log("Old speed :", currentSpeed); //currentSpeed = Math.max(10, Math.min(20, Math.round(currentSpeed * 0.8))); //log("New speed :", currentSpeed); } } self.progress = Math.max(0, self.y - startY) / (endY - startY); // Update progress property //self.assetWidthRatios[self.assetIndex] obstacleGraphics.height = startSize + (endSize - startSize) * self.progress; obstacleGraphics.width = obstacleGraphics.height * self.assetWidthRatios[self.assetIndex + 3 * (currentLevel - 1)]; var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3); var newSpeed = currentSpeed; // + 10 * self.progress; newSpeed = tempSpeed * 1; // TEMP DEBUG !!! self.y += newSpeed; // Move innerLineLeft x progressively to innerLeftLineEndX if (self.pathIndex == 0 && self.x != leftEndX) { self.x = leftStartX + (leftEndX - leftStartX) * self.progress; } if (self.pathIndex == 2 && self.x != rightEndX) { self.x = rightStartX + (rightEndX - rightStartX) * self.progress; } if (self.y > endY + endSize / 2) { self.reset(); } }; self.reset = function () { obstacleManager.freePath(self.pathIndex); // Mark the path as unoccupied self.active = false; self.y = startY; self.progress = 0; // Initialize progress property obstacleGraphics.width = startSize; obstacleGraphics.height = startSize; }; self.setPath = function (newPathIndex) { self.pathIndex = newPathIndex; //Math.floor(Math.random() * 3); if (self.pathIndex === 0) { self.x = leftStartX; } else if (self.pathIndex === 2) { self.x = rightStartX; } else { self.x = 1024; } }; self.updateForLevel = function (level) { log("Obstacle updateForLevel", level); var assets = []; if (level === 1) { assets = ['obstacle_1_1', 'obstacle_1_2', 'obstacle_1_3']; } else if (level === 2) { assets = ['obstacle_2_1', 'obstacle_2_2', 'obstacle_2_3']; } else if (level === 3) { assets = ['obstacle_3_1', 'obstacle_3_2', 'obstacle_3_3']; } self.assetIndex = Math.floor(Math.random() * 3); var randomAsset = assets[self.assetIndex]; log("Obstacle asset =>", randomAsset); obstacleGraphics.destroy(); obstacleGraphics = self.attachAsset(randomAsset, { anchorX: 0.5, anchorY: 0.5 }); self.reset(); }; }); var ObstacleManager = Container.expand(function () { var self = Container.call(this); self.obstacles = []; self.occupiedPaths = [false, false, false]; self.addObstacle = function (obstacle) { self.obstacles.push(obstacle); }; self.resetObstacles = function () { self.occupiedPaths = [false, false, false]; self.obstacles.forEach(function (obstacle) { obstacle.reset(); }); }; self.updateObstacles = function () { self.obstacles.forEach(function (obstacle) { if (!obstacle.active) { obstacle.reset(); } }); }; self.update = function () { if (!isPlaying || isKilled) { return; } // Activate obstacles regularly in random path var currentTime = Date.now(); log("ObstacleManager update..."); if (currentTime - lastObstacleSpawnTime > baseObstacleSpawnDelay * 0.75) { log("Attempting to spawn obstacle. Current time:", currentTime, "Last spawn time:", lastObstacleSpawnTime); var availablePaths = self.occupiedPaths.map(function (occupied, index) { return occupied ? null : index; }).filter(function (index) { return index !== null; }); log("Available paths for obstacle activation:", availablePaths); if (availablePaths.length > 0) { var randomPathIndex = availablePaths[Math.floor(Math.random() * availablePaths.length)]; var inactiveObstacles = self.obstacles.filter(function (obstacle) { return !obstacle.active; }); log("Inactive obstacles available for activation:", inactiveObstacles.length); if (inactiveObstacles.length > 0) { var obstacleToActivate = inactiveObstacles[Math.floor(Math.random() * inactiveObstacles.length)]; log("Activating obstacle in path:", randomPathIndex); obstacleToActivate.setPath(randomPathIndex); log("Obstacle activated:", obstacleToActivate); obstacleToActivate.active = true; self.setPathOccupied(randomPathIndex, true); log("Path occupied status updated. Path:", randomPathIndex, "Occupied:", self.isPathOccupied(randomPathIndex)); lastObstacleSpawnTime = currentTime; // Update the last spawn time } } } }; self.isPathOccupied = function (pathIndex) { return self.occupiedPaths[pathIndex]; }; self.setPathOccupied = function (pathIndex, occupied) { self.occupiedPaths[pathIndex] = occupied; }; self.freePath = function (pathIndex) { self.setPathOccupied(pathIndex, false); }; self.updateForLevel = function (level) { self.obstacles.forEach(function (obstacle) { obstacle.updateForLevel(level); }); }; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); self.shadow = self.attachAsset('shadow', { anchorX: 0.5, anchorY: 0.5 }); self.isJumping = false; // Initialize isJumping to false self.shadow.alpha = 0.5; // Make the shadow semi-transparent self.shadow.y = 270; // Offset the shadow slightly below the player var playerGraphics1_1 = self.attachAsset('player_1_1', { anchorX: 0.5, anchorY: 0.5, x: -5 }); var playerGraphics1_2 = self.attachAsset('player_1_2', { anchorX: 0.5, anchorY: 0.5, x: 5 }); var playerGraphics2_1 = self.attachAsset('player_2_1', { anchorX: 0.5, anchorY: 0.5, x: -5, visible: false // Initially hide player2_1 asset }); var playerGraphics2_2 = self.attachAsset('player_2_2', { anchorX: 0.5, anchorY: 0.5, x: 5, visible: false // Initially hide player2_2 asset }); var playerGraphics3_1 = self.attachAsset('player_3_1', { anchorX: 0.5, anchorY: 0.5, x: -5, visible: false // Initially hide player3_1 asset }); var playerGraphics3_2 = self.attachAsset('player_3_2', { anchorX: 0.5, anchorY: 0.5, x: 5, visible: false // Initially hide player3_2 asset }); self.helmet = self.attachAsset('helmet', { anchorX: 0.5, anchorY: 0.5, x: -4, visible: false }); self.helmet.y = -210; var frame = 0; self.update = function () { if (!self.isJumping) { frame += Math.min(currentSpeed, 20); // Add a max limit to avoid optical effects if (frame >= 100) { frame = 0; // Swap frames every 10 game ticks if (currentLevel <= 1) { var visible = playerGraphics1_1.visible; playerGraphics1_1.visible = !visible; playerGraphics1_2.visible = visible; } if (currentLevel === 2) { var visible = playerGraphics2_1.visible; playerGraphics2_1.visible = !visible; playerGraphics2_2.visible = visible; } if (currentLevel === 3) { var visible = playerGraphics3_1.visible; playerGraphics3_1.visible = !visible; playerGraphics3_2.visible = visible; } self.helmet.visible = bonusManager.currentActiveBonus == 1; if (self.helmet.visible) { self.helmet.scale.x *= -1; self.helmet.x *= -1; self.helmet.y = currentLevel == 2 ? -170 : -210; self.helmet.scale.x = currentLevel == 3 ? 1.1 : 1; self.helmet.scale.y = currentLevel == 3 ? 1.1 : 1; } } } }; self.updateForLevel = function (level) { playerGraphics1_1.visible = level === 1; playerGraphics1_2.visible = level === 1; playerGraphics2_1.visible = level === 2; playerGraphics2_2.visible = level === 2; playerGraphics3_1.visible = level === 3; playerGraphics3_2.visible = level === 3; }; self.jump = function () { if (!self.isJumping) { self.isJumping = true; LK.getSound('jump_1').play(); var initialY = self.y; var initialShadowY = self.shadow.y; var jumpHeight = 300; var jumpDuration = 30; var jumpStep = jumpHeight / jumpDuration; var fallStep = jumpHeight / jumpDuration; var jumpStartTime = Date.now(); var jumpInterval = LK.setInterval(function () { var elapsed = Date.now() - jumpStartTime; var progress = elapsed / (jumpDuration * 1000 / 60); if (progress < 1) { var easeProgress = Math.sin(progress * Math.PI / 2); self.y = initialY - jumpHeight * easeProgress; self.shadow.y = initialShadowY + jumpHeight * easeProgress; // Move shadow inversely self.shadow.width = 240 * (1 - 0.5 * easeProgress); // Reduce shadow width self.shadow.height = 100 * (1 - 0.5 * easeProgress); // Reduce shadow height } else { LK.clearInterval(jumpInterval); var fallStartTime = Date.now(); var fallInterval = LK.setInterval(function () { var elapsed = Date.now() - fallStartTime; var progress = elapsed / (jumpDuration * 1000 / 60); if (progress < 1) { var easeProgress = Math.sin(progress * Math.PI / 2); self.y = initialY - jumpHeight + jumpHeight * easeProgress; self.shadow.y = initialShadowY + jumpHeight - jumpHeight * easeProgress; // Move shadow inversely self.shadow.width = 120 + 120 * easeProgress; // Reset shadow width self.shadow.height = 50 + 50 * easeProgress; // Reset shadow height } else { self.y = initialY; self.shadow.y = initialShadowY; // Reset shadow position self.isJumping = false; LK.clearInterval(fallInterval); } }, 1000 / 60); } }, 1000 / 60); } }; }); // Road class var Road = Container.expand(function () { var self = Container.call(this); var baseY = 750; var roadGraphics = self.attachAsset('triangle', { tint: 0x555555, // Initialize tint to white anchorX: 0.5, anchorY: 0, width: 2048, height: roadHeight, y: baseY }); var speed = 5; var lineOffset = -150; // Inner lines var innerLineStartY = roadTop; var innerLineEndY = roadTop + roadHeight + 200; // Left var innerLeftLineStartX = -50; var innerLeftLineEndX = -412; var innerLeftLineStartW = 3; var innerLeftLineEndW = 80; var innerLeftLineStartH = 3; var innerLeftLineEndH = 500; var innerLeftLineStartR = 0.22; //0.075; var innerLeftLineEndR = 0.275; // Right var innerRightLineStartX = 50; var innerRightLineEndX = 412; var innerRightLineStartW = 3; var innerRightLineEndW = 80; var innerRightLineStartH = 3; var innerRightLineEndH = 500; var innerRightLineStartR = -0.22; var innerRightLineEndR = -0.275; // Lamp posts // Left Lamp var leftLampStartX = -130; var leftLampEndX = -1600; var leftLampStartY = roadTop; var leftLampEndY = roadTop + roadHeight + 0; // Define leftLampEndY variable var leftLampStartH = 2; var leftLampEndH = 900; var leftLampWRatio = 1 / 3; // Right Lamp var rightLampStartX = 130; var rightLampEndX = 1600; var rightLampStartY = roadTop; var rightLampEndY = roadTop + roadHeight + 0; // Define leftLampEndY variable var rightLampStartH = 2; var rightLampEndH = 900; var rightLampWRatio = 1 / 3; var nbInnerLines = 6; var leftLine = self.attachAsset('triangle', { anchorX: 0.5, anchorY: 0, width: 100, height: 1950, rotation: 0.45 }); leftLine.x = lineOffset; // Position the left line on the left side of the road leftLine.y = roadTop + 45; // Center the left line vertically var rightLine = self.attachAsset('triangle', { anchorX: 0.5, anchorY: 0, width: 100, height: 1950, rotation: -0.45 }); rightLine.x = -lineOffset; // Position the right line on the right side of the road rightLine.y = roadTop + 45; // Center the right line vertically self.innerLeftLines = []; self.innerRightLines = []; self.leftLampPosts = []; self.rightLampPosts = []; // Define arrays to store assets for each level var leftLampPostAssets = ['lampPost_1', // Level 1 asset 'lampPost_2', // Level 2 asset 'lampPost_3' // Level 3 asset ]; var rightLampPostAssets = ['lampPost_1', // Level 1 asset 'lampPost_2', // Level 2 asset 'lampPost_3' // Level 3 asset ]; for (var i = 0; i < nbInnerLines; i++) { var innerLineLeft = self.attachAsset('line', { anchorX: 0.5, anchorY: 0.5, width: innerLeftLineStartW, height: innerLeftLineStartH, rotation: innerLeftLineStartR, alpha: 1 }); innerLineLeft.x = innerLeftLineStartX; innerLineLeft.y = innerLineStartY - 0.1 * i * roadHeight / nbInnerLines; //log(i + " : " + innerLineStartY + " + " + i * roadHeight / nbInnerLines + " => " + innerLineLeft.y); innerLineLeft.progress = 0; // Initialize progress property self.innerLeftLines.push(innerLineLeft); var innerLineRight = self.attachAsset('line', { anchorX: 0.5, anchorY: 0.5, width: innerRightLineStartW, height: innerRightLineStartH, rotation: innerRightLineStartR, alpha: 1 }); innerLineRight.x = innerRightLineStartX; innerLineRight.y = innerLineStartY - 0.1 * i * roadHeight / nbInnerLines; innerLineRight.progress = 0; // Initialize progress property self.innerRightLines.push(innerLineRight); if (i % 2 == 0) { continue; } var leftLampPost = self.attachAsset(leftLampPostAssets[currentLevel - 1], { anchorX: 0.5, anchorY: 0.5, height: leftLampStartH, width: leftLampStartH * leftLampWRatio }); var leftLampShadow = self.attachAsset('shadow', { anchorX: 0.5, anchorY: 0.5, width: leftLampPost.width * 0.8, height: leftLampPost.height * 0.1, y: leftLampPost.height * 0.5 + 10 // Offset shadow slightly below the lamp post }); leftLampPost.addChild(leftLampShadow); leftLampPost.x = leftLampStartX; leftLampPost.y = leftLampStartY - (i - 1) * 40; self.addChild(leftLampPost); self.leftLampPosts.push(leftLampPost); var rightLampPost = self.attachAsset(rightLampPostAssets[currentLevel - 1], { anchorX: 0.5, anchorY: 0.5, scaleX: -1, height: rightLampStartH, width: rightLampStartH * rightLampWRatio }); var rightLampShadow = self.attachAsset('shadow', { anchorX: 0.5, anchorY: 0.5, width: rightLampPost.width * 0.8, height: rightLampPost.height * 0.1, y: rightLampPost.height * 0.5 + 10 // Offset shadow slightly below the lamp post }); rightLampPost.addChild(rightLampShadow); rightLampPost.x = rightLampStartX; rightLampPost.y = rightLampStartY - (i - 1) * 40; self.addChild(rightLampPost); self.rightLampPosts.push(rightLampPost); } self.update = function () { if (isKilled) { return; } var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf; //roadGraphics.tint = newTint; // Apply reduced tint to the road based on the intensity leftLine.tint = newTint; rightLine.tint = newTint; // Add any update logic for the road if needed for (var i = 0; i < self.innerLeftLines.length; i++) { innerLineLeft = self.innerLeftLines[i]; innerLineLeft.tint = newTint; if (innerLineLeft.y > innerLineEndY) { self.resetInnerLine(innerLineLeft, true); } else { innerLineLeft.progress = Math.max(0, innerLineLeft.y - innerLineStartY) / (innerLineEndY - innerLineStartY); // Update progress property } var tempSpeed = currentSpeed * 0.05 + currentSpeed * (innerLineLeft.progress * 3); var newSpeed = currentSpeed; // + 10 * self.progress; newSpeed = tempSpeed * 1; // TEMP DEBUG !!! innerLineLeft.y += newSpeed; // Move innerLineLeft x progressively to innerLeftLineEndX if (innerLineLeft.x != innerLeftLineEndX) { innerLineLeft.x = innerLeftLineStartX + (innerLeftLineEndX - innerLeftLineStartX) * innerLineLeft.progress; } // Move innerLineLeft x progressively if (innerLineLeft.rotation != innerLeftLineEndR) { //innerLineLeft.rotation = innerLeftLineStartR + (innerLeftLineEndR - innerLeftLineStartR) * innerLineLeft.progress; } // Move innerLineLeft x progressively if (innerLineLeft.width != innerLeftLineEndW) { innerLineLeft.width = innerLeftLineStartW + (innerLeftLineEndW - innerLeftLineStartW) * innerLineLeft.progress; } // Move innerLineLeft x progressively if (innerLineLeft.height != innerLeftLineEndH) { innerLineLeft.height = innerLeftLineStartH + (innerLeftLineEndH - innerLeftLineStartH) * innerLineLeft.progress; } } for (var i = 0; i < self.innerRightLines.length; i++) { innerLineRight = self.innerRightLines[i]; innerLineRight.tint = newTint; if (innerLineRight.y > innerLineEndY) { self.resetInnerLine(innerLineRight, false); } else { innerLineRight.progress = Math.max(0, innerLineRight.y - innerLineStartY) / (innerLineEndY - innerLineStartY); } var tempSpeed = currentSpeed * 0.05 + currentSpeed * (innerLineRight.progress * 3); var newSpeed = currentSpeed; // + 10 * self.progress; newSpeed = tempSpeed * 1; // TEMP DEBUG !!! innerLineRight.y += newSpeed; // Move innerLineRight x progressively to innerRightLineEndX if (innerLineRight.x != innerRightLineEndX) { innerLineRight.x = innerRightLineStartX + (innerRightLineEndX - innerRightLineStartX) * innerLineRight.progress; } // Move innerLineRight x progressively if (innerLineRight.rotation != innerRightLineEndR) { //innerLineRight.rotation = innerRightLineStartR + (innerRightLineEndR - innerRightLineStartR) * innerLineRight.progress; } // Move innerLineRight x progressively if (innerLineRight.width != innerRightLineEndW) { innerLineRight.width = innerRightLineStartW + (innerRightLineEndW - innerRightLineStartW) * innerLineRight.progress; } // Move innerLineRight x progressively if (innerLineRight.height != innerRightLineEndH) { innerLineRight.height = innerRightLineStartH + (innerRightLineEndH - innerRightLineStartH) * innerLineRight.progress; } } // Lamp posts for (var i = 0; i < self.leftLampPosts.length; i++) { var leftLampPost = self.leftLampPosts[i]; //leftLampPost.tint = newTint; var tempProgress = Math.max(0, leftLampPost.y - leftLampStartY) / (leftLampEndY - leftLampStartY); var tempSpeed = currentSpeed * 0.05 + currentSpeed * (tempProgress * 3); leftLampPost.y += tempSpeed; //leftLampPost.visible = currentLevel !== 1; // Make lampPost not visible when level is 1 if (leftLampPost.y > leftLampEndY) { leftLampPost.y = leftLampStartY; leftLampPost.x = leftLampStartX; leftLampPost.height = leftLampStartH; } leftLampPost.progress = Math.max(0, leftLampPost.y - leftLampStartY) / (leftLampEndY - leftLampStartY); // Update progress property leftLampPost.alpha = 0.75 + Math.min(0.25, leftLampPost.progress); if (i == 0) { //debugTxt.setText(leftLampPost.progress.toFixed(2)); } if (leftLampPost.x != leftLampEndX) { leftLampPost.x = leftLampStartX + (leftLampEndX - leftLampStartX) * Math.min(1, leftLampPost.progress * 1); } if (leftLampPost.height != leftLampEndH) { leftLampPost.height = Math.min(1, leftLampPost.progress * 2) * leftLampEndH; // leftLampStartH + (leftLampEndH - leftLampStartH) * Math.min(1, leftLampPost.progress * 1); leftLampPost.width = leftLampPost.height * leftLampWRatio; } } for (var i = 0; i < self.rightLampPosts.length; i++) { var rightLampPost = self.rightLampPosts[i]; var tempProgress = Math.max(0, rightLampPost.y - rightLampStartY) / (rightLampEndY - rightLampStartY); var tempSpeed = currentSpeed * 0.05 + currentSpeed * (tempProgress * 3); rightLampPost.y += tempSpeed; //rightLampPost.visible = currentLevel !== 1; // Make right lampPost not visible when level is 1 if (rightLampPost.y > rightLampEndY) { rightLampPost.y = rightLampStartY; rightLampPost.x = rightLampStartX; rightLampPost.height = rightLampStartH; } rightLampPost.progress = Math.max(0, rightLampPost.y - rightLampStartY) / (rightLampEndY - rightLampStartY); rightLampPost.alpha = 0.75 + Math.min(0.25, rightLampPost.progress); if (rightLampPost.x != rightLampEndX) { rightLampPost.x = rightLampStartX + (rightLampEndX - rightLampStartX) * rightLampPost.progress; } if (rightLampPost.height != leftLampEndH) { rightLampPost.height = rightLampStartH + (rightLampEndH - rightLampStartH) * Math.min(1, rightLampPost.progress * 2); rightLampPost.width = rightLampPost.height * rightLampWRatio; } } }; self.updateForLevel = function (level) { // Iterate through left lamp posts for (var i = 0; i < self.leftLampPosts.length; i++) { var leftLampPost = self.leftLampPosts[i]; var newLeftLampPost = self.attachAsset(leftLampPostAssets[level - 1], { anchorX: 0.5, anchorY: 0.5, height: leftLampPost.height, width: leftLampPost.width }); newLeftLampPost.visible = leftLampPost.visible; newLeftLampPost.x = leftLampPost.x; newLeftLampPost.y = leftLampPost.y; self.leftLampPosts[i] = newLeftLampPost; leftLampPost.destroy(); } for (var i = 0; i < self.rightLampPosts.length; i++) { var rightLampPost = self.rightLampPosts[i]; rightLampPost.children.forEach(function (child) { child.visible = false; }); var newRightLampPost = self.attachAsset(rightLampPostAssets[level - 1], { anchorX: 0.5, anchorY: 0.5, scaleX: -1, height: rightLampPost.height, width: rightLampPost.width }); newRightLampPost.visible = rightLampPost.visible; newRightLampPost.x = rightLampPost.x; newRightLampPost.y = rightLampPost.y; self.rightLampPosts[i] = newRightLampPost; rightLampPost.destroy(); } }; self.resetInnerLine = function (innerLine, isLeft) { if (isLeft) { innerLine.x = innerLeftLineStartX; innerLine.rotation = innerLeftLineStartR; innerLine.width = innerLeftLineStartW; innerLine.height = innerLeftLineStartH; } else { innerLine.x = innerRightLineStartX; innerLine.rotation = innerRightLineStartR; innerLine.width = innerRightLineStartW; innerLine.height = innerRightLineStartH; } innerLine.y = innerLineStartY - 0.2 * roadHeight / nbInnerLines; innerLine.progress = 0; // Reset progress property }; }); var StartButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5 }); self.interactive = true; self.buttonMode = true; self.on('down', function () { LK.playMusic('bgMusic', { loop: true }); self.visible = false; updateGoalForLevel(1); // Call updateGoalForLevel(1) when start button is pressed LK.setTimeout(function () { goalText.visible = false; scoreTxt.visible = true; isPlaying = true; isGameStarted = true; }, goalAnnounceDelay); }); }); var Stripe = Container.expand(function () { var self = Container.call(this); self.stripeGraphics = self.attachAsset('stripe_1', { anchorX: 0, anchorY: 1, height: 1 }); self.stripeGraphics2 = self.attachAsset('stripe_2', { anchorX: 0, anchorY: 1, height: 1, visible: false }); self.stripeGraphics3 = self.attachAsset('stripe_3', { anchorX: 0, anchorY: 1, height: 1, visible: false }); self.progress = 0; // Initialize progress property self.update = function () { if (isKilled) { return; } self.progress = Math.max(0, self.y - roadTop) / roadHeight; // Update progress property var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf; self.stripeGraphics.tint = newTint; self.stripeGraphics2.tint = newTint; self.stripeGraphics3.tint = newTint; var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3); self.y += tempSpeed; self.stripeGraphics.height = 400 * self.progress; // Adjust height based on progress self.stripeGraphics2.height = 400 * self.progress; // Adjust height based on progress self.stripeGraphics3.height = 400 * self.progress; // Adjust height based on progress if (self.y > roadTop + roadHeight) { self.y = roadTop; self.stripeGraphics.height = 0; // Reset height to initial value self.stripeGraphics.tint = 0xFFFFFF; // Reset tint to initial value self.stripeGraphics2.height = 0; self.stripeGraphics2.tint = 0xFFFFFF; self.stripeGraphics3.height = 0; self.stripeGraphics3.tint = 0xFFFFFF; } }; self.updateForLevel = function (level) { self.stripeGraphics.visible = level === 1; self.stripeGraphics2.visible = level === 2; self.stripeGraphics3.visible = level === 3; }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 // Init game with black background }); /**** * Game Code ****/ function updateGoalForLevel(level) { if (level === 1) { goalText.setText('COLLECT\r\n$10'); } else if (level === 2) { goalText.setText('COLLECT\r\n$100'); } else if (level === 3) { goalText.setText('COLLECT\r\n$1 000 000+'); bonusManager.update(); // Update bonuses every game tick } ; goalText.visible = true; LK.setTimeout(function () { goalText.visible = false; }, goalAnnounceDelay); } var moneyLost = 0; // Initialize global moneyLost variable var isDebug = false; // Define global isDebug variable var occupiedPaths = [false, false, false]; // Initialize an array to track occupied paths var baseObstacleSpawnDelay = 1500; // Define global baseObstacleSpawnDelay var obstacleManager; // Define obstacleManager in the global scope var killerManager = new KillerManager(); // Initialize killerManager in the global scope var bonusManager = new BonusManager(); // Initialize killerManager in the global scope var bonusIcon = null; // Variable to store the bonus icon var lastObstacleSpawnTime = 0; // Track the last time an obstacle was spawned var bonusManager = new BonusManager(); // Initialize bonusManager in the global scope var levelConfigs = [{}, { name: "Level 1", backgroundTint: 0xeda716, coinValue: 0.10, baseSpeed: 10, nextLevelScore: 10 }, { name: "Level 2", backgroundTint: 0x2faf1d, coinValue: 1, baseSpeed: 15, nextLevelScore: 100 }, { name: "Level 3", backgroundTint: 0x6c6060, coinValue: 100, baseSpeed: 20, nextLevelScore: Infinity // Endless Runner ;) }]; var stripes = []; var nbDecorations = 10; var decorations = []; // Initialize arrays and variables var currentLevel = 1; var road = new Road(); var isPlaying = false; var isGameStarted = false; var isMouseDown = false; // Flag to track if the mouse/finger is down var isMoveAboveThreshold = false; // Flag to track if a move above threshold has been detected var isKilled = false; var killerDelay = 10000; // Delay in milliseconds before updating killer var lastKillerUpdate = 0; // Timestamp of the last killer update var currentCoinType = 0; var nextCoinTypeThreshold = 1000; var isNight = false; var roadHeight = 2000; var roadTop = 1000; // ~= road.height/2 - baseY var background; var landscape; var nbStripes = 33; var baseNbCoins = 10; var baseNbObstacles = 10; var baseBonusDelay = 10000; var coins = []; var obstacles = []; var killers = []; var road; var score = 0; var scoreTxt; var goalText; var goalAnnounceDelay = 3000; var startX = 0; var startY = 0; var endX = 0; var endY = 0; var intensity = 0; var intensityHalf = 0; var leftLampPosts = []; var rightLampPosts = []; var leftDecorations = []; var rightDecorationss = []; var maxSpeed = 70; // Define a maximum speed limit var currentSpeed = 15; //20; // Initialize currentSpeed var coinsCollected = 0; // Initialize coins collected counter var isIntersectingObstacle = false; // Flag to track if the player is currently intersecting an obstacle var lastObstacleHitTime = 0; // Timestamp of the last obstacle hit var immunityDelay = 500; // Immunity delay in milliseconds var playerPositionIndex = 1; // Initialize player position index var playerBaseY = 2732 - 300; // Define the three fixed x positions for the player var playerPositions = [2048 / 5, 2048 / 2, 4 * 2048 / 5]; // Create player var player; var debugMarker; var debugText; var debugTxt; /****************************************************************************************** */ /************************************** GAME FUNCTIONS ************************************ */ /****************************************************************************************** */ function updateScore() { var negative = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; if (negative) { if (score > 0) { moneyLost += Math.min(levelConfigs[currentLevel].coinValue || 1, score); } score -= levelConfigs[currentLevel].coinValue || 1; score = parseFloat(score.toFixed(1)); score = Math.max(0, score); // Ensure score doesn't go below 0 } else { var gain = levelConfigs[currentLevel].coinValue || 1; if (bonusManager.currentActiveBonus == 2) { // Multiplier bonus gain *= 2; } score += gain; score = parseFloat(score.toFixed(1)); coinsCollected += 1; // Increment coins collected counter } if (score >= levelConfigs[currentLevel].nextLevelScore) { changeLevel(currentLevel + 1); } // Format score log("score=", score, " => ", (score * 100).toFixed(0) + "¢"); if (score < 1) { scoreTxt.setText((score * 100).toFixed(0) + "¢"); } else if (score < 10) { scoreTxt.setText("$" + score.toFixed(2)); } else { scoreTxt.setText("$" + Math.floor(score)); } } // Function to change the level function changeLevel(newLevel) { log("changeLevel:", newLevel); newLevel = Math.max(1, Math.min(levelConfigs.length, newLevel)); currentLevel = newLevel; obstacleManager.updateForLevel(newLevel); currentSpeed = levelConfigs[currentLevel].baseSpeed; console.log("Level changed to:", currentLevel); // Add a big white flash effect LK.effects.flashScreen(0xFFFFFF, 1000); // Flash white for 1 second // Change background tint using levelConfig background.updateForLevel(currentLevel); // Update stripe graphics visibility based on the level stripes.forEach(function (stripe) { stripe.updateForLevel(currentLevel); }); // Update landscape based on the level landscape.updateForLevel(currentLevel); // Update player graphics based on the level player.updateForLevel(currentLevel); if (road) { road.updateForLevel(currentLevel); } coins.forEach(function (coin) { coin.updateForLevel(currentLevel); }); LK.getSound('levelWin_1').play(); updateGoalForLevel(currentLevel); bonusManager.updateForLevel(newLevel); killerManager.updateForLevel(newLevel); killerManager.lastKillerUpdate = Date.now(); // Reset the last killer update time when level changes } function easeInOutQuad(t) { return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; } function playHit() { var hitSounds = ['hit_1', 'hit_2', 'hit_3']; var randomIndex = Math.floor(Math.random() * hitSounds.length); LK.getSound(hitSounds[randomIndex]).play(); } function updateBackgroundColor() { var time = 1000 + new Date().getTime() * 0.0002; intensity = Math.sin(time) * 127 + 128; var baseColor = levelConfigs[currentLevel].backgroundTint; var r = (baseColor >> 16 & 0xFF) + intensity; var g = (baseColor >> 8 & 0xFF) + intensity; var b = (baseColor & 0xFF) + intensity; r = Math.min(255, Math.max(0, r)); g = Math.min(255, Math.max(0, g)); b = Math.min(255, Math.max(0, b)); var color = r << 16 | g << 8 | b; background.tint = color; isNight = intensity < 128; intensityHalf = 128 + Math.floor(intensity * 0.5); } function log() { if (isDebug) { var _console; (_console = console).log.apply(_console, arguments); } } /****************************************************************************************** */ /************************************** INPUT HANDLERS ************************************ */ /****************************************************************************************** */ // Handle move events game.down = function (x, y, obj) { if (!isPlaying) { return; } startX = x; startY = y; isMouseDown = true; // Set flag to true when mouse/finger is down }; game.move = function (x, y, obj) { if (!isPlaying || !isMouseDown) { return; } var deltaX = x - startX; var deltaY = startY - y; var threshold = 10; // Define a threshold for movement if ((Math.abs(deltaX) > threshold || deltaY > threshold) && !isMoveAboveThreshold) { isMoveAboveThreshold = true; if (Math.abs(deltaX) > deltaY) { if (deltaX > 0) { // Swipe right if (playerPositionIndex < 2) { playerPositionIndex++; } } else { // Swipe left if (playerPositionIndex > 0) { playerPositionIndex--; } } // Make the player move progressively to the next path var targetX = playerPositions[playerPositionIndex]; var initialX = player.x; var moveDuration = 20; var moveStartTime = Date.now(); var moveInterval = LK.setInterval(function () { var elapsed = Date.now() - moveStartTime; var progress = elapsed / (moveDuration * 1000 / 60); if (progress < 1) { var easeProgress = easeInOutQuad(progress); player.x = initialX + (targetX - initialX) * easeProgress; } else { player.x = targetX; LK.clearInterval(moveInterval); } }, 1000 / 60); } else { if (deltaY > threshold) { // Swipe up player.jump(); } } } }; game.up = function (x, y, obj) { isMouseDown = false; // Set flag to false when mouse/finger is up isMoveAboveThreshold = false; // Reset flag when the move ends if (isKilled) { LK.setScore(score * 100); // Store the score in LK score before game over LK.setTimeout(function () { LK.stopMusic(); LK.showGameOver(); }, 500); return; } if (!isPlaying) { return; } }; // Update game every tick game.update = function () { updateBackgroundColor(); if (!isPlaying || isKilled) { return; } }; // Initialize game function gameInitialize() { bonusManager.resetBonuses(); // Reset bonuses when initializing the game killerManager.resetKillers(); killerManager.lastKillerUpdate = Date.now(); // Reset the last killer update time when initializing the game // Initialize arrays and variables // Attach the background asset to the game background = game.addChild(new Background()); background.updateForLevel(currentLevel); // Add a series of Stripe instances to cover the bottom half of the screen for (var i = 0; i < nbStripes; i++) { var stripe = new Stripe(); stripe.y = i === 0 ? roadTop : stripes[i - 1].y + stripes[i - 1].stripeGraphics.height; // Position stripe under the previous one using previous stripe y and height stripe.progress = Math.max(0, stripe.y - roadTop) / roadHeight; // Calculate progress stripes.push(stripe); game.addChild(stripe); stripe.stripeGraphics.height = 1 + 400 * stripe.progress; // Adjust height based on progress //log("Stripe ", i, " y=", stripe.y, " h=", stripe.stripeGraphics.height, " p=", stripe.progress); } for (var i = 0; i < stripes.length; i++) { stripes[i].update(); } // Create and attach decoration instances to the game for (var i = 0; i < nbDecorations; i++) { var newDecoration = new Decoration(i); newDecoration.reset(); decorations.push(newDecoration); game.addChild(newDecoration); } // Create and attach the road instance to the game road = game.addChild(new Road()); road.x = 2048 / 2; road.y = 0; if (road) { //road.updateForLevel(currentLevel); } score = 0; scoreTxt = new Text2('0¢', { size: 150, fill: "#ffffff", dropShadow: true, dropShadowColor: "#000000", dropShadowBlur: 5, dropShadowDistance: 5 }); scoreTxt.anchor.set(0.5, 0); scoreTxt.visible = false; goalText = new Text2('', { size: 150, fill: "#ffffff", dropShadow: true, dropShadowColor: "#111111", dropShadowBlur: 10, dropShadowDistance: 10, align: 'center', weight: 1000 }); goalText.anchor.set(0.5, 1); LK.gui.center.addChild(goalText); //goalText.x = 2048 / 2; //goalText.y = 100; //goalText.visible = true; LK.gui.top.addChild(scoreTxt); coins = []; for (var i = 0; i < baseNbCoins; i++) { var newCoin = new Coin(i); newCoin.reset(); newCoin.y = roadTop - i * 50; coins.push(newCoin); game.addChild(newCoin); } // Create a variable to store the current player position index playerPositionIndex = 1; // Create and attach obstacle instances to the game obstacleManager = new ObstacleManager(); var numObstacles = Math.floor(Math.random() * baseNbObstacles) + 1; // Randomize number of obstacles (1 to baseNbObstacles) for (var i = 0; i < numObstacles; i++) { var newObstacle = new Obstacle(i); obstacleManager.addObstacle(newObstacle); game.addChild(newObstacle); } obstacleManager.resetObstacles(); game.addChild(obstacleManager); // Create and attach the killer instance to the game // killerManager is already initialized in the global scope for (var i = 0; i < 3; i++) { var newKiller = new Killer(i); // Pass index for each killer killerManager.addKiller(newKiller); game.addChild(newKiller); } killerManager.resetKillers(); game.addChild(killerManager); // Create and attach the bonus instance to the game // bonusManager is already initialized in the global scope for (var i = 0; i < 3; i++) { var newBonus = new Bonus(i); // Pass index for each killer bonusManager.addBonus(newBonus); game.addChild(newBonus); } bonusManager.resetBonuses(); game.addChild(bonusManager); // Create player player = game.addChild(new Player()); player.frame = 0; player.x = playerPositions[playerPositionIndex]; // Start at the center position player.y = playerBaseY; // Create and attach the landscape instance to the game landscape = game.addChild(new Landscape()); var startButton = game.addChild(new StartButton()); startButton.x = 2048 / 2; startButton.y = 2732 / 4; // TEMP DEBUG !!! //startButton.width = 100; //startButton.height = 100; // Attach a debugMarker asset to the game at position (1000, 0) debugMarker = game.attachAsset('debugMarker', { anchorX: 0.5, anchorY: 0.5, visible: isDebug }); debugMarker.x = 1280; debugMarker.y = roadTop; debugTxt = new Text2('Debug Info', { size: 50, fill: "#ff0000" }); debugTxt.anchor.set(1, 1); // Set anchor to the bottom right corner debugTxt.visible = isDebug; LK.gui.bottomRight.addChild(debugTxt); isPlaying = false; } gameInitialize();
/****
* Classes
****/
var Background = Container.expand(function () {
var self = Container.call(this);
var backgroundGraphics1 = self.attachAsset('background_1', {
anchorX: 0.5,
anchorY: 0.5,
visible: true
});
var backgroundGraphics2 = self.attachAsset('background_2', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var backgroundGraphics3 = self.attachAsset('background_3', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
self.updateForLevel = function (level) {
backgroundGraphics1.visible = level === 1;
backgroundGraphics2.visible = level === 2;
backgroundGraphics3.visible = level === 3;
};
});
var Bonus = Container.expand(function (index) {
var self = Container.call(this);
self.index = index;
var bonusHalo = self.attachAsset('bonusHalo', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var assets = ['bonus_1', 'bonus_2', 'bonus_3'];
self.assetIndex = index % assets.length;
var randomAsset = assets[self.assetIndex];
var bonusGraphics = self.attachAsset(randomAsset, {
anchorX: 0.5,
anchorY: 0.5
});
var speed = 5;
var startY = roadTop - 20;
var endY = startY + roadHeight;
var leftStartX = 1024 - 100;
var leftEndX = 1024 - 650;
var rightStartX = 1024 + 100;
var rightEndX = 1024 + 650;
var startSize = 1;
var endSize = 200;
var assetHeightRatio = 1; // Adjusted for bonus asset ratio
bonusGraphics.width = startSize;
bonusGraphics.height = startSize;
bonusHalo.width = startSize * 3;
bonusHalo.height = startSize * 3;
self.pathIndex = 0;
self.inactive = true;
self.inactiveStartTime = Date.now();
self.update = function () {
if (!isPlaying || isKilled) {
return;
}
if (self.inactive) {
return;
}
if (!isKilled && player && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) {
// Handle bonus collection logic here
bonusManager.applyBonus(self.index);
self.reset();
return;
}
self.progress = Math.max(0, self.y - startY) / (endY - startY);
bonusGraphics.width = startSize + (endSize - startSize) * self.progress;
bonusGraphics.height = assetHeightRatio * bonusGraphics.width;
bonusHalo.visible = true;
bonusHalo.rotation += 0.01 + (self.progress * 100 % 3 == 0); // Rotate bonusHalo sequentially
bonusHalo.width = bonusGraphics.width * 3;
bonusHalo.height = bonusGraphics.height * 3;
var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3);
var newSpeed = currentSpeed * 1;
newSpeed = tempSpeed * 1;
self.y += newSpeed;
if (self.pathIndex == 0 && self.x != leftEndX) {
self.x = leftStartX + (leftEndX - leftStartX) * self.progress;
}
if (self.pathIndex == 2 && self.x != rightEndX) {
self.x = rightStartX + (rightEndX - rightStartX) * self.progress;
}
if (self.y > endY + endSize / 2) {
self.reset();
}
};
self.reset = function () {
bonusHalo.rotation = 0; // Initialize bonusHalo rotation
self.y = startY;
self.progress = 0;
bonusGraphics.width = startSize;
bonusGraphics.height = startSize;
bonusHalo.width = startSize * 3;
bonusHalo.height = startSize * 3;
bonusHalo.visible = false;
self.pathIndex = Math.floor(Math.random() * 3);
if (self.pathIndex === 0) {
self.x = leftStartX;
} else if (self.pathIndex === 2) {
self.x = rightStartX;
} else {
self.x = 1024;
}
self.inactive = true;
self.inactiveStartTime = Date.now();
};
});
var BonusManager = Container.expand(function () {
var self = Container.call(this);
self.bonuses = [];
self.bonusIcon = null;
self.currentBonusIndex = 0;
self.currentActiveBonus = 0;
self.lastBonusUpdate = 0;
self.bonusDelay = 16000; // Delay in milliseconds before updating bonus
self.addBonus = function (bonus) {
self.bonuses.push(bonus);
};
self.update = function () {
if (!isGameStarted || !isPlaying || isKilled) {
self.lastBonusUpdate = Date.now(); // Reset the last bonus update time when the game starts
return;
}
if (self.currentActiveBonus > 0) {
if (!self.bonusIcon) {
self.bonusIcon = LK.getAsset('bonus_' + self.currentActiveBonus, {
anchorX: 0.5,
anchorY: 0.5,
x: scoreTxt.x,
y: scoreTxt.y + scoreTxt.height + 50
});
LK.gui.top.addChild(self.bonusIcon);
}
} else if (self.bonusIcon) {
self.bonusIcon.visible = false;
self.bonusIcon = null;
}
var currentTime = Date.now();
var currentDelay = currentTime - self.lastBonusUpdate;
if (currentDelay >= self.bonusDelay) {
LK.getSound('bonus_approaching').play();
self.currentBonusIndex = (self.currentBonusIndex + 1) % self.bonuses.length;
self.bonuses[self.currentBonusIndex].inactive = false;
self.lastBonusUpdate = currentTime;
}
};
self.resetBonuses = function () {
self.bonuses.forEach(function (bonus) {
bonus.reset();
});
self.currentBonusIndex = 0;
self.lastBonusUpdate = Date.now();
};
self.updateForLevel = function (level) {
if (level === 1) {
self.bonusDelay = 8000; // Delay in milliseconds for level 1
} else if (level === 2) {
self.bonusDelay = 12000; // Delay in milliseconds for level 2
} else if (level === 3) {
self.bonusDelay = 16000; // Delay in milliseconds for level 3
}
};
self.applyBonus = function (index) {
self.currentActiveBonus = index + 1;
LK.getSound('bonus_take').play();
self.lastBonusUpdate = Date.now();
LK.setTimeout(function () {
// Start blinking effect 3 seconds before bonus ends
var blinkStartTime = Date.now();
var blinkInterval = LK.setInterval(function () {
var elapsed = Date.now() - blinkStartTime;
if (elapsed >= 3000) {
LK.clearInterval(blinkInterval);
self.stopBonus();
} else {
if (self.bonusIcon) {
self.bonusIcon.alpha = self.bonusIcon.alpha === 1 ? 0.5 : 1;
}
}
}, 150); // Blink every 500ms
}, baseBonusDelay - 3000);
};
self.stopBonus = function () {
self.currentActiveBonus = 0;
if (self.bonusIcon) {
LK.gui.top.removeChild(self.bonusIcon);
}
if (self.bonusIcon) {
self.bonusIcon.destroy();
}
self.bonusIcon = null;
self.lastBonusUpdate = Date.now();
};
});
// Assets will be automatically created and loaded during gameplay
// Coin class
var Coin = Container.expand(function (index) {
var self = Container.call(this);
self.index = index;
var coinGraphics = self.attachAsset('coin1', {
anchorX: 0.5,
anchorY: 0.5
});
var coinGraphics2 = self.attachAsset('coin2', {
//'dollarsBundle'
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var coinGraphics3 = self.attachAsset('dollarsBundle', {
//'dollarsBundle'
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var coinGraphicsClone = self.attachAsset('coin1', {
anchorX: 0.5,
anchorY: 0.5,
x: -20,
visible: false
});
var coinGraphics2Clone = self.attachAsset('coin2', {
//'dollarsBundle'
anchorX: 0.5,
anchorY: 0.5,
x: -20,
visible: false
});
var coinGraphics3Clone = self.attachAsset('dollarsBundle', {
anchorX: 0.5,
anchorY: 0.5,
x: -20,
visible: false
});
var speed = 5;
var startY = roadTop + 50;
var endY = startY + roadHeight;
var leftStartX = 1024 - 100;
var leftEndX = 1024 - 650;
var rightStartX = 1024 + 100;
var rightEndX = 1024 + 650;
var startSize = 2;
var endSize = 140;
coinGraphics.width = startSize;
coinGraphics.height = startSize;
coinGraphics2.width = startSize;
coinGraphics2.height = startSize;
coinGraphics3.width = startSize;
coinGraphics3.height = startSize;
self.pathIndex = 0;
self.update = function () {
if (!isGameStarted) {
return;
}
// Road should animate even if the game hasn't started
if (!isPlaying || isKilled) {
return;
}
;
obstacleManager.updateObstacles();
self.progress = Math.max(0, self.y - startY) / (endY - startY); // Update progress property
coinGraphics.width = startSize + (endSize - startSize) * self.progress;
coinGraphics.height = startSize + (endSize - startSize) * self.progress;
coinGraphics2.width = startSize + (endSize - startSize) * self.progress;
coinGraphics2.height = startSize + (endSize - startSize) * self.progress;
coinGraphics3.width = startSize + (endSize - startSize) * self.progress;
coinGraphics3.height = startSize + (endSize - startSize) * self.progress;
if (bonusManager.currentActiveBonus == 2) {
coinGraphicsClone.width = coinGraphics.width;
coinGraphicsClone.height = coinGraphics.height;
coinGraphics2Clone.width = coinGraphics2.width;
coinGraphics2Clone.height = coinGraphics2.height;
coinGraphics3Clone.width = coinGraphics3.width;
coinGraphics3Clone.height = coinGraphics3.height;
coinGraphicsClone.visible = currentLevel === 1;
coinGraphics2Clone.visible = currentLevel === 2;
coinGraphics3Clone.visible = currentLevel === 3;
coinGraphics.x = 20;
coinGraphics2.x = 20;
coinGraphics3.x = 20;
} else {
coinGraphics.x = 0;
coinGraphics2.x = 0;
coinGraphics3.x = 0;
coinGraphicsClone.visible = false;
coinGraphics2Clone.visible = false;
coinGraphics3Clone.visible = false;
}
if (bonusManager.currentActiveBonus == 3 && self.y > 1500) {
// Magnet bonus logic
var distanceX = player.x - self.x;
var distanceY = player.y - self.y;
var distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
if (distance < 1500) {
var attractionSpeed = 20;
self.x += distanceX / distance * attractionSpeed;
self.y += distanceY / distance * attractionSpeed;
}
distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
if (distance < 100) {
LK.getSound('coin_1').play();
updateScore(false);
// coinsCollected increment moved to increaseScore function
LK.effects.flashObject(player, 0x00ff00, 500); // Flash green for 0.5 seconds
self.reset();
}
} else {
var newSpeed = currentSpeed; // + 10 * self.progress;
var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3);
newSpeed = tempSpeed;
self.y += newSpeed;
// Move innerLineLeft x progressively to innerLeftLineEndX
if (self.pathIndex == 0 && self.x != leftEndX) {
self.x = leftStartX + (leftEndX - leftStartX) * self.progress;
}
if (self.pathIndex == 2 && self.x != rightEndX) {
self.x = rightStartX + (rightEndX - rightStartX) * self.progress;
}
}
if (self.y > endY + endSize / 2) {
self.reset();
}
// Check for collision with player
if (!player.isJumping && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) {
LK.getSound('coin_1').play();
updateScore(false);
// coinsCollected increment moved to increaseScore function
LK.effects.flashObject(player, 0x00ff00, 500); // Flash green for 0.5 seconds
self.reset();
// Increase speed every 3 coins collected
/*
if (coinsCollected % nextCoinTypeThreshold === 0 && currentSpeed < maxSpeed) {
currentSpeed += 3; // Increase speed by 3
}
*/
}
};
self.reset = function () {
self.y = startY;
self.progress = 0; // Initialize progress property
coinGraphics.width = startSize;
coinGraphics.height = startSize;
coinGraphics2.width = startSize;
coinGraphics2.height = startSize;
coinGraphics3.width = startSize;
coinGraphics3.height = startSize;
coinGraphicsClone.visible = false;
coinGraphics2Clone.visible = false;
coinGraphics3Clone.visible = false;
self.pathIndex = Math.floor(Math.random() * 3);
if (self.pathIndex === 0) {
self.x = leftStartX;
} else if (self.pathIndex === 2) {
self.x = rightStartX;
} else {
self.x = 1024;
}
};
self.updateForLevel = function (level) {
coinGraphics.visible = level === 1;
coinGraphics2.visible = level === 2;
coinGraphics3.visible = level === 3;
};
});
// CoinAnimation class
var CoinAnimation = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin1', {
anchorX: 0.5,
anchorY: 0.5,
visible: currentLevel === 1
});
var coinGraphics2 = self.attachAsset('coin2', {
anchorX: 0.5,
anchorY: 0.5,
visible: currentLevel === 2
});
var coinGraphics3 = self.attachAsset('dollarsBundle', {
anchorX: 0.5,
anchorY: 0.5,
visible: currentLevel === 3
});
// Initialize velocity and gravity
self.vx = (Math.random() < 0.5 ? -1 : 1) * 5; // Random horizontal velocity
self.vy = -15; // Initial vertical velocity
self.gravity = 0.5; // Gravity effect
self.update = function () {
self.vy += self.gravity; // Apply gravity to vertical velocity
self.x += self.vx; // Update horizontal position
self.y += self.vy; // Update vertical position
self.alpha -= 0.0035; // Fade out the coin
coinGraphics.visible = currentLevel === 1;
coinGraphics2.visible = currentLevel === 2;
coinGraphics3.visible = currentLevel === 3;
if (self.alpha <= 0) {
self.destroy(); // Remove the coin when it becomes invisible
}
};
});
// Decoration class
var Decoration = Container.expand(function (decoIndex) {
var self = Container.call(this);
self.index = decoIndex;
var assets = ['decoration_1_1', 'decoration_1_2', 'decoration_1_3', 'decoration_2_1', 'decoration_2_2', 'decoration_2_3', 'decoration_3_1', 'decoration_3_2', 'decoration_3_3'];
self.assets = assets.map(function (assetId) {
return self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
});
self.ready = false;
var speed = 5;
var startY = roadTop + 50;
var endY = startY + roadHeight;
var xOffset = 1024;
var baseLeftStartX = 780;
var rand = Math.random();
self.leftStartX = baseLeftStartX; // - rand * xOffset;
self.leftEndX = self.leftStartX - xOffset * (1.5 + rand);
var baseRightStartX = 1280;
self.rightStartX = baseRightStartX; // + rand * xOffset / 2;
self.rightEndX = self.rightStartX + xOffset * (1.5 + rand);
self.assetWidthRatios = [0.33, 1, 1, 1, 1, 1, 1, 1, 1];
self.endSizes = [600, 600, 600, 600, 600, 600, 600, 600, 600];
var startSize = 1;
self.assetIndex = Math.floor(Math.random() * 3) + (currentLevel - 1) * 3;
mainGraphics = self.assets[self.assetIndex];
mainGraphics.width = startSize;
mainGraphics.height = startSize;
self.pathIndex = 0;
self.update = function () {
if (isKilled) {
return;
}
var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf;
//mainGraphics.tint = newTint;
var tempSpeed = currentSpeed * 0.055 + currentSpeed * (self.progress * 3);
var newSpeed = currentSpeed; // + 10 * self.progress;
newSpeed = tempSpeed * 1; // TEMP DEBUG !!!
self.y += newSpeed;
self.progress = Math.max(0, self.y - startY) / (endY - startY); // Update progress property
// Move innerLineLeft x progressively to innerLeftLineEndX
if (self.index == 7) {
//log("Decoration " + self.index + " update - p=", self.progress, "x:", Math.round(self.x), "y:", Math.round(self.y));
//log(self.progress);
}
if (self.pathIndex == 0 && self.x > self.leftEndX) {
self.x = self.leftStartX + (self.leftEndX - self.leftStartX) * self.progress * 3;
}
if (self.pathIndex == 1 && self.x < self.rightEndX) {
self.x = self.rightStartX + (self.rightEndX - self.rightStartX) * self.progress * 3;
}
if (self.y > endY + self.endSizes[self.assetIndex] / 2) {
//self.y = -startSize; // Move obstacle back to the top
self.reset();
}
//mainGraphics = self.assets[self.assetIndex];
mainGraphics.height = startSize + (self.endSizes[self.assetIndex] - startSize) * self.progress * 2;
mainGraphics.width = mainGraphics.height * self.assetWidthRatios[self.assetIndex];
if (self.index == 8 && mainGraphics.width > 200) {
//log("Decoration " + self.index + " update - assetIndex:", self.assetIndex, "width:", mainGraphics.width, "x:", Math.round(self.x), "y:", Math.round(self.y));
}
if (self.index == 7 && mainGraphics.width > 200) {
//log("Decoration " + self.index + " update - assetIndex:", self.assetIndex, "width:", mainGraphics.width, "x:", Math.round(self.x), "y:", Math.round(self.y));
}
if (!self.ready) {
//log("Decoration " + self.index + " ready =" + self.ready);
}
//log("Decoration " + self.index + " update width:", Math.round(mainGraphics.width), "x:", Math.round(self.x), "y:", Math.round(self.y));
};
self.reset = function () {
self.ready = false;
//log("Decoration reset" + self.index);
self.y = startY;
self.progress = 0; // Initialize progress property
rand = Math.random();
self.assetIndex = Math.floor(Math.random() * 3) + (currentLevel - 1) * 3;
self.assets.forEach(function (asset, index) {
asset.visible = index === self.assetIndex;
});
mainGraphics = self.assets[self.assetIndex];
mainGraphics.height = startSize;
mainGraphics.width = mainGraphics.height * self.assetWidthRatios[self.assetIndex];
if (self.index == 1 && mainGraphics.width > 200) {
//log("=== Decoration " + self.index + " reset - assetIndex:", self.assetIndex, "width:", mainGraphics.width, "y:", self.y, " ===");
}
self.leftStartX = baseLeftStartX; // - rand * xOffset;
self.leftEndX = self.leftStartX - xOffset * (1 + rand);
self.rightStartX = baseRightStartX; // + rand * xOffset;
self.rightEndX = self.rightStartX + xOffset * (1 + rand);
if (self.index == 1) {
//log("=== Decoration " + self.index);
//log("Left StartX:", self.leftStartX, "Left EndX:", self.leftEndX);
//log("Right StartX:", self.rightStartX, "Right EndX:", self.rightEndX);
}
self.pathIndex = Math.floor(rand * 2);
if (self.pathIndex === 0) {
self.x = self.leftStartX;
} else {
self.x = self.rightStartX;
}
self.ready = true;
};
});
var Killer = Container.expand(function (index) {
var self = Container.call(this);
self.index = index;
var assets = ['killer1', 'killer2', 'killer3'];
self.assetIndex = index % assets.length;
var randomAsset = assets[self.assetIndex];
var killerGraphics = self.attachAsset(randomAsset, {
anchorX: 0.5,
anchorY: 0.5
});
var speed = 5;
var startY = roadTop - 20;
var endY = startY + roadHeight;
var leftStartX = 1024 - 100;
var leftEndX = 1024 - 650;
var rightStartX = 1024 + 100;
var rightEndX = 1024 + 650;
var startSize = 1;
var endSize = 800;
var assetHeightRatio = 500 / 400;
killerGraphics.width = startSize;
killerGraphics.height = startSize;
self.pathIndex = 0;
self.inactive = true;
self.inactiveStartTime = Date.now();
self.update = function () {
if (!isPlaying) {
return;
}
if (self.inactive) {
return;
}
if (!isKilled && player && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) {
LK.getSound('accident_1').play();
if (bonusManager.currentActiveBonus == 1) {
// Have Helmet!
LK.effects.flashScreen(0xffffff, 2000);
self.reset();
bonusManager.stopBonus();
return;
}
isKilled = true;
player.visible = false;
LK.stopMusic();
LK.setTimeout(function () {
LK.getSound('killed_1').play();
}, 100); // Adjust the delay as needed
LK.setTimeout(function () {
LK.getSound('rip_1').play();
}, 1000); // Play rip_1 sound 1 second after killed
LK.effects.flashScreen(0xff0000, 4000);
// Spawn MurderShape at player's last position
var murderShape = new MurderShape();
murderShape.x = player.x;
murderShape.y = playerBaseY;
murderShape.fixPosition();
game.addChildAt(murderShape, game.getChildIndex(road) + 1);
// Store the score in LK score before game over
LK.setScore(score * 100);
LK.setTimeout(function () {
LK.showGameOver();
}, 5000);
return;
}
self.progress = Math.max(0, self.y - startY) / (endY - startY);
killerGraphics.width = startSize + (endSize - startSize) * self.progress;
debugTxt.setText(self.progress.toFixed(2));
killerGraphics.height = assetHeightRatio * killerGraphics.width;
var tempSpeed = currentSpeed * 0.5 + currentSpeed * (self.progress * 3);
var newSpeed = currentSpeed * 3 + (currentLevel - 1);
newSpeed = tempSpeed * 1;
self.y += newSpeed;
if (self.pathIndex == 0 && self.x != leftEndX) {
self.x = leftStartX + (leftEndX - leftStartX) * self.progress;
}
if (self.pathIndex == 2 && self.x != rightEndX) {
self.x = rightStartX + (rightEndX - rightStartX) * self.progress;
}
if (self.y > endY + endSize / 2) {
self.reset();
}
};
self.reset = function () {
self.y = startY;
self.progress = 0;
killerGraphics.width = startSize;
killerGraphics.height = startSize;
self.pathIndex = Math.floor(Math.random() * 3);
if (self.pathIndex === 0) {
self.x = leftStartX;
} else if (self.pathIndex === 2) {
self.x = rightStartX;
} else {
self.x = 1024;
}
self.inactive = true;
self.inactiveStartTime = Date.now();
};
});
var KillerManager = Container.expand(function () {
var self = Container.call(this);
self.killers = [];
self.currentKillerIndex = 0;
self.lastKillerUpdate = 0;
self.killerDelay = 10000; // Delay in milliseconds before updating killer
self.addKiller = function (killer) {
self.killers.push(killer);
};
self.update = function () {
if (!isGameStarted) {
self.lastKillerUpdate = Date.now(); // Reset the last killer update time when the game starts
return;
}
var currentTime = Date.now();
var currentDelay = currentTime - self.lastKillerUpdate;
if (currentDelay >= self.killerDelay) {
self.killers[self.currentKillerIndex].inactive = false;
if (self.currentKillerIndex === 0) {
LK.getSound('car_1').play();
} else if (self.currentKillerIndex === 1) {
LK.getSound('police_1').play();
} else if (self.currentKillerIndex === 2) {
LK.getSound('ambulance_1').play();
}
self.currentKillerIndex = (self.currentKillerIndex + 1) % self.killers.length;
self.lastKillerUpdate = currentTime;
}
};
self.resetKillers = function () {
self.killers.forEach(function (killer) {
killer.reset();
});
self.currentKillerIndex = 0;
self.lastKillerUpdate = Date.now();
};
self.updateForLevel = function (level) {
if (level === 1) {
self.killerDelay = 12000; // Delay in milliseconds for level 1
} else if (level === 2) {
self.killerDelay = 10000; // Delay in milliseconds for level 2
} else if (level === 3) {
self.killerDelay = 8000; // Delay in milliseconds for level 3
}
};
});
var Landscape = Container.expand(function () {
var self = Container.call(this);
var landscapeGraphics = self.attachAsset('landscape_1', {
anchorX: 0.5,
anchorY: 0.0
});
var landscapeGraphics2 = self.attachAsset('landscape_2', {
anchorX: 0.5,
anchorY: 0.0,
visible: false
});
var landscapeGraphics3 = self.attachAsset('landscape_3', {
anchorX: 0.5,
anchorY: 0.0,
visible: false
});
var gradientGraphics = self.attachAsset('gradient', {
anchorX: 0.5,
anchorY: 0.0,
scaleY: -1,
y: 1024,
blendMode: 2,
alpha: 0.5,
tint: 0xFEFEFE,
height: 15
});
self.x = 2048 / 2; // Center horizontally
self.y = 0; // Position at the top
self.update = function () {
var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf;
landscapeGraphics.tint = newTint; // Apply reduced tint to the road based on the intensity
};
self.updateForLevel = function (level) {
landscapeGraphics.visible = level === 1;
landscapeGraphics2.visible = level === 2;
landscapeGraphics3.visible = level === 3;
};
});
var MurderShape = Container.expand(function () {
var self = Container.call(this);
var murderShapeGraphics = self.attachAsset('murderShape', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// MurderShape does not need to update its position or behavior
};
self.fixPosition = function () {
if (self.x < 600) {
self.x += 150;
} else if (self.x > 1400) {
self.x -= 150;
}
};
});
// Obstacle class
var Obstacle = Container.expand(function (index) {
var self = Container.call(this);
self.active = true;
self.index = index;
var assets = [];
if (currentLevel === 1) {
assets = ['obstacle_1_1', 'obstacle_1_2', 'obstacle_1_3'];
} else if (currentLevel === 2) {
assets = ['obstacle_2_1', 'obstacle_2_2', 'obstacle_2_3'];
} else if (currentLevel === 3) {
assets = ['obstacle_3_1', 'obstacle_3_2', 'obstacle_3_3'];
}
self.assetIndex = Math.floor(Math.random() * assets.length);
var randomAsset = assets[self.assetIndex];
var obstacleGraphics = self.attachAsset(randomAsset, {
anchorX: 0.5,
anchorY: 0.5
});
var speed = 5;
var startY = roadTop + 50;
var endY = startY + roadHeight;
var leftStartX = 1024 - 100;
var leftEndX = 1024 - 650;
var rightStartX = 1024 + 100;
var rightEndX = 1024 + 650;
var innerLeftLineStartX = -150;
var innerLeftLineEndX = -390;
self.assetWidthRatios = [1, 1, 1.5, 1.8, 1.8, 1.6, 1, 0.8, 1.1];
var startSize, endSize;
if (self.assetIndex == 0) {
startSize = 3;
endSize = 200;
} else if (self.assetIndex == 1) {
startSize = 1;
endSize = 250;
} else if (self.assetIndex == 2) {
startSize = 2;
endSize = 300;
}
obstacleGraphics.width = startSize;
obstacleGraphics.height = startSize;
self.pathIndex = 0;
self.update = function () {
if (!isPlaying || isKilled) {
return;
}
// coinsCollected increment moved to updateScore function
var currentTime = Date.now();
if (currentTime - lastObstacleHitTime > immunityDelay && player && !player.isJumping && self.y > 2500 && self.y < 2732 && player.shadow.intersects(self)) {
lastObstacleHitTime = currentTime; // Update the last hit time
if (bonusManager.currentActiveBonus != 1) {
// Without helmet
playHit();
// Make player flash red for 1 second
LK.effects.flashObject(player, 0xff0000, 1000);
// Add coin animation only if score is greater than 0
if (score > 0) {
var coinAnimation = new CoinAnimation();
coinAnimation.x = player.x;
coinAnimation.y = player.y;
game.addChild(coinAnimation);
}
// Reduce score by 1
updateScore(true);
//log("Obstacle y:", self.y);
// Reduce currentSpeed by a factor (e.g., 0.8)
//log("Old speed :", currentSpeed);
//currentSpeed = Math.max(10, Math.min(20, Math.round(currentSpeed * 0.8)));
//log("New speed :", currentSpeed);
}
}
self.progress = Math.max(0, self.y - startY) / (endY - startY); // Update progress property
//self.assetWidthRatios[self.assetIndex]
obstacleGraphics.height = startSize + (endSize - startSize) * self.progress;
obstacleGraphics.width = obstacleGraphics.height * self.assetWidthRatios[self.assetIndex + 3 * (currentLevel - 1)];
var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3);
var newSpeed = currentSpeed; // + 10 * self.progress;
newSpeed = tempSpeed * 1; // TEMP DEBUG !!!
self.y += newSpeed;
// Move innerLineLeft x progressively to innerLeftLineEndX
if (self.pathIndex == 0 && self.x != leftEndX) {
self.x = leftStartX + (leftEndX - leftStartX) * self.progress;
}
if (self.pathIndex == 2 && self.x != rightEndX) {
self.x = rightStartX + (rightEndX - rightStartX) * self.progress;
}
if (self.y > endY + endSize / 2) {
self.reset();
}
};
self.reset = function () {
obstacleManager.freePath(self.pathIndex); // Mark the path as unoccupied
self.active = false;
self.y = startY;
self.progress = 0; // Initialize progress property
obstacleGraphics.width = startSize;
obstacleGraphics.height = startSize;
};
self.setPath = function (newPathIndex) {
self.pathIndex = newPathIndex; //Math.floor(Math.random() * 3);
if (self.pathIndex === 0) {
self.x = leftStartX;
} else if (self.pathIndex === 2) {
self.x = rightStartX;
} else {
self.x = 1024;
}
};
self.updateForLevel = function (level) {
log("Obstacle updateForLevel", level);
var assets = [];
if (level === 1) {
assets = ['obstacle_1_1', 'obstacle_1_2', 'obstacle_1_3'];
} else if (level === 2) {
assets = ['obstacle_2_1', 'obstacle_2_2', 'obstacle_2_3'];
} else if (level === 3) {
assets = ['obstacle_3_1', 'obstacle_3_2', 'obstacle_3_3'];
}
self.assetIndex = Math.floor(Math.random() * 3);
var randomAsset = assets[self.assetIndex];
log("Obstacle asset =>", randomAsset);
obstacleGraphics.destroy();
obstacleGraphics = self.attachAsset(randomAsset, {
anchorX: 0.5,
anchorY: 0.5
});
self.reset();
};
});
var ObstacleManager = Container.expand(function () {
var self = Container.call(this);
self.obstacles = [];
self.occupiedPaths = [false, false, false];
self.addObstacle = function (obstacle) {
self.obstacles.push(obstacle);
};
self.resetObstacles = function () {
self.occupiedPaths = [false, false, false];
self.obstacles.forEach(function (obstacle) {
obstacle.reset();
});
};
self.updateObstacles = function () {
self.obstacles.forEach(function (obstacle) {
if (!obstacle.active) {
obstacle.reset();
}
});
};
self.update = function () {
if (!isPlaying || isKilled) {
return;
}
// Activate obstacles regularly in random path
var currentTime = Date.now();
log("ObstacleManager update...");
if (currentTime - lastObstacleSpawnTime > baseObstacleSpawnDelay * 0.75) {
log("Attempting to spawn obstacle. Current time:", currentTime, "Last spawn time:", lastObstacleSpawnTime);
var availablePaths = self.occupiedPaths.map(function (occupied, index) {
return occupied ? null : index;
}).filter(function (index) {
return index !== null;
});
log("Available paths for obstacle activation:", availablePaths);
if (availablePaths.length > 0) {
var randomPathIndex = availablePaths[Math.floor(Math.random() * availablePaths.length)];
var inactiveObstacles = self.obstacles.filter(function (obstacle) {
return !obstacle.active;
});
log("Inactive obstacles available for activation:", inactiveObstacles.length);
if (inactiveObstacles.length > 0) {
var obstacleToActivate = inactiveObstacles[Math.floor(Math.random() * inactiveObstacles.length)];
log("Activating obstacle in path:", randomPathIndex);
obstacleToActivate.setPath(randomPathIndex);
log("Obstacle activated:", obstacleToActivate);
obstacleToActivate.active = true;
self.setPathOccupied(randomPathIndex, true);
log("Path occupied status updated. Path:", randomPathIndex, "Occupied:", self.isPathOccupied(randomPathIndex));
lastObstacleSpawnTime = currentTime; // Update the last spawn time
}
}
}
};
self.isPathOccupied = function (pathIndex) {
return self.occupiedPaths[pathIndex];
};
self.setPathOccupied = function (pathIndex, occupied) {
self.occupiedPaths[pathIndex] = occupied;
};
self.freePath = function (pathIndex) {
self.setPathOccupied(pathIndex, false);
};
self.updateForLevel = function (level) {
self.obstacles.forEach(function (obstacle) {
obstacle.updateForLevel(level);
});
};
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
self.shadow = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.isJumping = false; // Initialize isJumping to false
self.shadow.alpha = 0.5; // Make the shadow semi-transparent
self.shadow.y = 270; // Offset the shadow slightly below the player
var playerGraphics1_1 = self.attachAsset('player_1_1', {
anchorX: 0.5,
anchorY: 0.5,
x: -5
});
var playerGraphics1_2 = self.attachAsset('player_1_2', {
anchorX: 0.5,
anchorY: 0.5,
x: 5
});
var playerGraphics2_1 = self.attachAsset('player_2_1', {
anchorX: 0.5,
anchorY: 0.5,
x: -5,
visible: false // Initially hide player2_1 asset
});
var playerGraphics2_2 = self.attachAsset('player_2_2', {
anchorX: 0.5,
anchorY: 0.5,
x: 5,
visible: false // Initially hide player2_2 asset
});
var playerGraphics3_1 = self.attachAsset('player_3_1', {
anchorX: 0.5,
anchorY: 0.5,
x: -5,
visible: false // Initially hide player3_1 asset
});
var playerGraphics3_2 = self.attachAsset('player_3_2', {
anchorX: 0.5,
anchorY: 0.5,
x: 5,
visible: false // Initially hide player3_2 asset
});
self.helmet = self.attachAsset('helmet', {
anchorX: 0.5,
anchorY: 0.5,
x: -4,
visible: false
});
self.helmet.y = -210;
var frame = 0;
self.update = function () {
if (!self.isJumping) {
frame += Math.min(currentSpeed, 20); // Add a max limit to avoid optical effects
if (frame >= 100) {
frame = 0;
// Swap frames every 10 game ticks
if (currentLevel <= 1) {
var visible = playerGraphics1_1.visible;
playerGraphics1_1.visible = !visible;
playerGraphics1_2.visible = visible;
}
if (currentLevel === 2) {
var visible = playerGraphics2_1.visible;
playerGraphics2_1.visible = !visible;
playerGraphics2_2.visible = visible;
}
if (currentLevel === 3) {
var visible = playerGraphics3_1.visible;
playerGraphics3_1.visible = !visible;
playerGraphics3_2.visible = visible;
}
self.helmet.visible = bonusManager.currentActiveBonus == 1;
if (self.helmet.visible) {
self.helmet.scale.x *= -1;
self.helmet.x *= -1;
self.helmet.y = currentLevel == 2 ? -170 : -210;
self.helmet.scale.x = currentLevel == 3 ? 1.1 : 1;
self.helmet.scale.y = currentLevel == 3 ? 1.1 : 1;
}
}
}
};
self.updateForLevel = function (level) {
playerGraphics1_1.visible = level === 1;
playerGraphics1_2.visible = level === 1;
playerGraphics2_1.visible = level === 2;
playerGraphics2_2.visible = level === 2;
playerGraphics3_1.visible = level === 3;
playerGraphics3_2.visible = level === 3;
};
self.jump = function () {
if (!self.isJumping) {
self.isJumping = true;
LK.getSound('jump_1').play();
var initialY = self.y;
var initialShadowY = self.shadow.y;
var jumpHeight = 300;
var jumpDuration = 30;
var jumpStep = jumpHeight / jumpDuration;
var fallStep = jumpHeight / jumpDuration;
var jumpStartTime = Date.now();
var jumpInterval = LK.setInterval(function () {
var elapsed = Date.now() - jumpStartTime;
var progress = elapsed / (jumpDuration * 1000 / 60);
if (progress < 1) {
var easeProgress = Math.sin(progress * Math.PI / 2);
self.y = initialY - jumpHeight * easeProgress;
self.shadow.y = initialShadowY + jumpHeight * easeProgress; // Move shadow inversely
self.shadow.width = 240 * (1 - 0.5 * easeProgress); // Reduce shadow width
self.shadow.height = 100 * (1 - 0.5 * easeProgress); // Reduce shadow height
} else {
LK.clearInterval(jumpInterval);
var fallStartTime = Date.now();
var fallInterval = LK.setInterval(function () {
var elapsed = Date.now() - fallStartTime;
var progress = elapsed / (jumpDuration * 1000 / 60);
if (progress < 1) {
var easeProgress = Math.sin(progress * Math.PI / 2);
self.y = initialY - jumpHeight + jumpHeight * easeProgress;
self.shadow.y = initialShadowY + jumpHeight - jumpHeight * easeProgress; // Move shadow inversely
self.shadow.width = 120 + 120 * easeProgress; // Reset shadow width
self.shadow.height = 50 + 50 * easeProgress; // Reset shadow height
} else {
self.y = initialY;
self.shadow.y = initialShadowY; // Reset shadow position
self.isJumping = false;
LK.clearInterval(fallInterval);
}
}, 1000 / 60);
}
}, 1000 / 60);
}
};
});
// Road class
var Road = Container.expand(function () {
var self = Container.call(this);
var baseY = 750;
var roadGraphics = self.attachAsset('triangle', {
tint: 0x555555,
// Initialize tint to white
anchorX: 0.5,
anchorY: 0,
width: 2048,
height: roadHeight,
y: baseY
});
var speed = 5;
var lineOffset = -150;
// Inner lines
var innerLineStartY = roadTop;
var innerLineEndY = roadTop + roadHeight + 200;
// Left
var innerLeftLineStartX = -50;
var innerLeftLineEndX = -412;
var innerLeftLineStartW = 3;
var innerLeftLineEndW = 80;
var innerLeftLineStartH = 3;
var innerLeftLineEndH = 500;
var innerLeftLineStartR = 0.22; //0.075;
var innerLeftLineEndR = 0.275;
// Right
var innerRightLineStartX = 50;
var innerRightLineEndX = 412;
var innerRightLineStartW = 3;
var innerRightLineEndW = 80;
var innerRightLineStartH = 3;
var innerRightLineEndH = 500;
var innerRightLineStartR = -0.22;
var innerRightLineEndR = -0.275;
// Lamp posts
// Left Lamp
var leftLampStartX = -130;
var leftLampEndX = -1600;
var leftLampStartY = roadTop;
var leftLampEndY = roadTop + roadHeight + 0; // Define leftLampEndY variable
var leftLampStartH = 2;
var leftLampEndH = 900;
var leftLampWRatio = 1 / 3;
// Right Lamp
var rightLampStartX = 130;
var rightLampEndX = 1600;
var rightLampStartY = roadTop;
var rightLampEndY = roadTop + roadHeight + 0; // Define leftLampEndY variable
var rightLampStartH = 2;
var rightLampEndH = 900;
var rightLampWRatio = 1 / 3;
var nbInnerLines = 6;
var leftLine = self.attachAsset('triangle', {
anchorX: 0.5,
anchorY: 0,
width: 100,
height: 1950,
rotation: 0.45
});
leftLine.x = lineOffset; // Position the left line on the left side of the road
leftLine.y = roadTop + 45; // Center the left line vertically
var rightLine = self.attachAsset('triangle', {
anchorX: 0.5,
anchorY: 0,
width: 100,
height: 1950,
rotation: -0.45
});
rightLine.x = -lineOffset; // Position the right line on the right side of the road
rightLine.y = roadTop + 45; // Center the right line vertically
self.innerLeftLines = [];
self.innerRightLines = [];
self.leftLampPosts = [];
self.rightLampPosts = [];
// Define arrays to store assets for each level
var leftLampPostAssets = ['lampPost_1',
// Level 1 asset
'lampPost_2',
// Level 2 asset
'lampPost_3' // Level 3 asset
];
var rightLampPostAssets = ['lampPost_1',
// Level 1 asset
'lampPost_2',
// Level 2 asset
'lampPost_3' // Level 3 asset
];
for (var i = 0; i < nbInnerLines; i++) {
var innerLineLeft = self.attachAsset('line', {
anchorX: 0.5,
anchorY: 0.5,
width: innerLeftLineStartW,
height: innerLeftLineStartH,
rotation: innerLeftLineStartR,
alpha: 1
});
innerLineLeft.x = innerLeftLineStartX;
innerLineLeft.y = innerLineStartY - 0.1 * i * roadHeight / nbInnerLines;
//log(i + " : " + innerLineStartY + " + " + i * roadHeight / nbInnerLines + " => " + innerLineLeft.y);
innerLineLeft.progress = 0; // Initialize progress property
self.innerLeftLines.push(innerLineLeft);
var innerLineRight = self.attachAsset('line', {
anchorX: 0.5,
anchorY: 0.5,
width: innerRightLineStartW,
height: innerRightLineStartH,
rotation: innerRightLineStartR,
alpha: 1
});
innerLineRight.x = innerRightLineStartX;
innerLineRight.y = innerLineStartY - 0.1 * i * roadHeight / nbInnerLines;
innerLineRight.progress = 0; // Initialize progress property
self.innerRightLines.push(innerLineRight);
if (i % 2 == 0) {
continue;
}
var leftLampPost = self.attachAsset(leftLampPostAssets[currentLevel - 1], {
anchorX: 0.5,
anchorY: 0.5,
height: leftLampStartH,
width: leftLampStartH * leftLampWRatio
});
var leftLampShadow = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
width: leftLampPost.width * 0.8,
height: leftLampPost.height * 0.1,
y: leftLampPost.height * 0.5 + 10 // Offset shadow slightly below the lamp post
});
leftLampPost.addChild(leftLampShadow);
leftLampPost.x = leftLampStartX;
leftLampPost.y = leftLampStartY - (i - 1) * 40;
self.addChild(leftLampPost);
self.leftLampPosts.push(leftLampPost);
var rightLampPost = self.attachAsset(rightLampPostAssets[currentLevel - 1], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: -1,
height: rightLampStartH,
width: rightLampStartH * rightLampWRatio
});
var rightLampShadow = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
width: rightLampPost.width * 0.8,
height: rightLampPost.height * 0.1,
y: rightLampPost.height * 0.5 + 10 // Offset shadow slightly below the lamp post
});
rightLampPost.addChild(rightLampShadow);
rightLampPost.x = rightLampStartX;
rightLampPost.y = rightLampStartY - (i - 1) * 40;
self.addChild(rightLampPost);
self.rightLampPosts.push(rightLampPost);
}
self.update = function () {
if (isKilled) {
return;
}
var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf;
//roadGraphics.tint = newTint; // Apply reduced tint to the road based on the intensity
leftLine.tint = newTint;
rightLine.tint = newTint;
// Add any update logic for the road if needed
for (var i = 0; i < self.innerLeftLines.length; i++) {
innerLineLeft = self.innerLeftLines[i];
innerLineLeft.tint = newTint;
if (innerLineLeft.y > innerLineEndY) {
self.resetInnerLine(innerLineLeft, true);
} else {
innerLineLeft.progress = Math.max(0, innerLineLeft.y - innerLineStartY) / (innerLineEndY - innerLineStartY); // Update progress property
}
var tempSpeed = currentSpeed * 0.05 + currentSpeed * (innerLineLeft.progress * 3);
var newSpeed = currentSpeed; // + 10 * self.progress;
newSpeed = tempSpeed * 1; // TEMP DEBUG !!!
innerLineLeft.y += newSpeed;
// Move innerLineLeft x progressively to innerLeftLineEndX
if (innerLineLeft.x != innerLeftLineEndX) {
innerLineLeft.x = innerLeftLineStartX + (innerLeftLineEndX - innerLeftLineStartX) * innerLineLeft.progress;
}
// Move innerLineLeft x progressively
if (innerLineLeft.rotation != innerLeftLineEndR) {
//innerLineLeft.rotation = innerLeftLineStartR + (innerLeftLineEndR - innerLeftLineStartR) * innerLineLeft.progress;
}
// Move innerLineLeft x progressively
if (innerLineLeft.width != innerLeftLineEndW) {
innerLineLeft.width = innerLeftLineStartW + (innerLeftLineEndW - innerLeftLineStartW) * innerLineLeft.progress;
}
// Move innerLineLeft x progressively
if (innerLineLeft.height != innerLeftLineEndH) {
innerLineLeft.height = innerLeftLineStartH + (innerLeftLineEndH - innerLeftLineStartH) * innerLineLeft.progress;
}
}
for (var i = 0; i < self.innerRightLines.length; i++) {
innerLineRight = self.innerRightLines[i];
innerLineRight.tint = newTint;
if (innerLineRight.y > innerLineEndY) {
self.resetInnerLine(innerLineRight, false);
} else {
innerLineRight.progress = Math.max(0, innerLineRight.y - innerLineStartY) / (innerLineEndY - innerLineStartY);
}
var tempSpeed = currentSpeed * 0.05 + currentSpeed * (innerLineRight.progress * 3);
var newSpeed = currentSpeed; // + 10 * self.progress;
newSpeed = tempSpeed * 1; // TEMP DEBUG !!!
innerLineRight.y += newSpeed;
// Move innerLineRight x progressively to innerRightLineEndX
if (innerLineRight.x != innerRightLineEndX) {
innerLineRight.x = innerRightLineStartX + (innerRightLineEndX - innerRightLineStartX) * innerLineRight.progress;
}
// Move innerLineRight x progressively
if (innerLineRight.rotation != innerRightLineEndR) {
//innerLineRight.rotation = innerRightLineStartR + (innerRightLineEndR - innerRightLineStartR) * innerLineRight.progress;
}
// Move innerLineRight x progressively
if (innerLineRight.width != innerRightLineEndW) {
innerLineRight.width = innerRightLineStartW + (innerRightLineEndW - innerRightLineStartW) * innerLineRight.progress;
}
// Move innerLineRight x progressively
if (innerLineRight.height != innerRightLineEndH) {
innerLineRight.height = innerRightLineStartH + (innerRightLineEndH - innerRightLineStartH) * innerLineRight.progress;
}
}
// Lamp posts
for (var i = 0; i < self.leftLampPosts.length; i++) {
var leftLampPost = self.leftLampPosts[i];
//leftLampPost.tint = newTint;
var tempProgress = Math.max(0, leftLampPost.y - leftLampStartY) / (leftLampEndY - leftLampStartY);
var tempSpeed = currentSpeed * 0.05 + currentSpeed * (tempProgress * 3);
leftLampPost.y += tempSpeed;
//leftLampPost.visible = currentLevel !== 1; // Make lampPost not visible when level is 1
if (leftLampPost.y > leftLampEndY) {
leftLampPost.y = leftLampStartY;
leftLampPost.x = leftLampStartX;
leftLampPost.height = leftLampStartH;
}
leftLampPost.progress = Math.max(0, leftLampPost.y - leftLampStartY) / (leftLampEndY - leftLampStartY); // Update progress property
leftLampPost.alpha = 0.75 + Math.min(0.25, leftLampPost.progress);
if (i == 0) {
//debugTxt.setText(leftLampPost.progress.toFixed(2));
}
if (leftLampPost.x != leftLampEndX) {
leftLampPost.x = leftLampStartX + (leftLampEndX - leftLampStartX) * Math.min(1, leftLampPost.progress * 1);
}
if (leftLampPost.height != leftLampEndH) {
leftLampPost.height = Math.min(1, leftLampPost.progress * 2) * leftLampEndH; // leftLampStartH + (leftLampEndH - leftLampStartH) * Math.min(1, leftLampPost.progress * 1);
leftLampPost.width = leftLampPost.height * leftLampWRatio;
}
}
for (var i = 0; i < self.rightLampPosts.length; i++) {
var rightLampPost = self.rightLampPosts[i];
var tempProgress = Math.max(0, rightLampPost.y - rightLampStartY) / (rightLampEndY - rightLampStartY);
var tempSpeed = currentSpeed * 0.05 + currentSpeed * (tempProgress * 3);
rightLampPost.y += tempSpeed;
//rightLampPost.visible = currentLevel !== 1; // Make right lampPost not visible when level is 1
if (rightLampPost.y > rightLampEndY) {
rightLampPost.y = rightLampStartY;
rightLampPost.x = rightLampStartX;
rightLampPost.height = rightLampStartH;
}
rightLampPost.progress = Math.max(0, rightLampPost.y - rightLampStartY) / (rightLampEndY - rightLampStartY);
rightLampPost.alpha = 0.75 + Math.min(0.25, rightLampPost.progress);
if (rightLampPost.x != rightLampEndX) {
rightLampPost.x = rightLampStartX + (rightLampEndX - rightLampStartX) * rightLampPost.progress;
}
if (rightLampPost.height != leftLampEndH) {
rightLampPost.height = rightLampStartH + (rightLampEndH - rightLampStartH) * Math.min(1, rightLampPost.progress * 2);
rightLampPost.width = rightLampPost.height * rightLampWRatio;
}
}
};
self.updateForLevel = function (level) {
// Iterate through left lamp posts
for (var i = 0; i < self.leftLampPosts.length; i++) {
var leftLampPost = self.leftLampPosts[i];
var newLeftLampPost = self.attachAsset(leftLampPostAssets[level - 1], {
anchorX: 0.5,
anchorY: 0.5,
height: leftLampPost.height,
width: leftLampPost.width
});
newLeftLampPost.visible = leftLampPost.visible;
newLeftLampPost.x = leftLampPost.x;
newLeftLampPost.y = leftLampPost.y;
self.leftLampPosts[i] = newLeftLampPost;
leftLampPost.destroy();
}
for (var i = 0; i < self.rightLampPosts.length; i++) {
var rightLampPost = self.rightLampPosts[i];
rightLampPost.children.forEach(function (child) {
child.visible = false;
});
var newRightLampPost = self.attachAsset(rightLampPostAssets[level - 1], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: -1,
height: rightLampPost.height,
width: rightLampPost.width
});
newRightLampPost.visible = rightLampPost.visible;
newRightLampPost.x = rightLampPost.x;
newRightLampPost.y = rightLampPost.y;
self.rightLampPosts[i] = newRightLampPost;
rightLampPost.destroy();
}
};
self.resetInnerLine = function (innerLine, isLeft) {
if (isLeft) {
innerLine.x = innerLeftLineStartX;
innerLine.rotation = innerLeftLineStartR;
innerLine.width = innerLeftLineStartW;
innerLine.height = innerLeftLineStartH;
} else {
innerLine.x = innerRightLineStartX;
innerLine.rotation = innerRightLineStartR;
innerLine.width = innerRightLineStartW;
innerLine.height = innerRightLineStartH;
}
innerLine.y = innerLineStartY - 0.2 * roadHeight / nbInnerLines;
innerLine.progress = 0; // Reset progress property
};
});
var StartButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.interactive = true;
self.buttonMode = true;
self.on('down', function () {
LK.playMusic('bgMusic', {
loop: true
});
self.visible = false;
updateGoalForLevel(1); // Call updateGoalForLevel(1) when start button is pressed
LK.setTimeout(function () {
goalText.visible = false;
scoreTxt.visible = true;
isPlaying = true;
isGameStarted = true;
}, goalAnnounceDelay);
});
});
var Stripe = Container.expand(function () {
var self = Container.call(this);
self.stripeGraphics = self.attachAsset('stripe_1', {
anchorX: 0,
anchorY: 1,
height: 1
});
self.stripeGraphics2 = self.attachAsset('stripe_2', {
anchorX: 0,
anchorY: 1,
height: 1,
visible: false
});
self.stripeGraphics3 = self.attachAsset('stripe_3', {
anchorX: 0,
anchorY: 1,
height: 1,
visible: false
});
self.progress = 0; // Initialize progress property
self.update = function () {
if (isKilled) {
return;
}
self.progress = Math.max(0, self.y - roadTop) / roadHeight; // Update progress property
var newTint = intensityHalf << 16 | intensityHalf << 8 | intensityHalf;
self.stripeGraphics.tint = newTint;
self.stripeGraphics2.tint = newTint;
self.stripeGraphics3.tint = newTint;
var tempSpeed = currentSpeed * 0.05 + currentSpeed * (self.progress * 3);
self.y += tempSpeed;
self.stripeGraphics.height = 400 * self.progress; // Adjust height based on progress
self.stripeGraphics2.height = 400 * self.progress; // Adjust height based on progress
self.stripeGraphics3.height = 400 * self.progress; // Adjust height based on progress
if (self.y > roadTop + roadHeight) {
self.y = roadTop;
self.stripeGraphics.height = 0; // Reset height to initial value
self.stripeGraphics.tint = 0xFFFFFF; // Reset tint to initial value
self.stripeGraphics2.height = 0;
self.stripeGraphics2.tint = 0xFFFFFF;
self.stripeGraphics3.height = 0;
self.stripeGraphics3.tint = 0xFFFFFF;
}
};
self.updateForLevel = function (level) {
self.stripeGraphics.visible = level === 1;
self.stripeGraphics2.visible = level === 2;
self.stripeGraphics3.visible = level === 3;
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Init game with black background
});
/****
* Game Code
****/
function updateGoalForLevel(level) {
if (level === 1) {
goalText.setText('COLLECT\r\n$10');
} else if (level === 2) {
goalText.setText('COLLECT\r\n$100');
} else if (level === 3) {
goalText.setText('COLLECT\r\n$1 000 000+');
bonusManager.update(); // Update bonuses every game tick
}
;
goalText.visible = true;
LK.setTimeout(function () {
goalText.visible = false;
}, goalAnnounceDelay);
}
var moneyLost = 0; // Initialize global moneyLost variable
var isDebug = false; // Define global isDebug variable
var occupiedPaths = [false, false, false]; // Initialize an array to track occupied paths
var baseObstacleSpawnDelay = 1500; // Define global baseObstacleSpawnDelay
var obstacleManager; // Define obstacleManager in the global scope
var killerManager = new KillerManager(); // Initialize killerManager in the global scope
var bonusManager = new BonusManager(); // Initialize killerManager in the global scope
var bonusIcon = null; // Variable to store the bonus icon
var lastObstacleSpawnTime = 0; // Track the last time an obstacle was spawned
var bonusManager = new BonusManager(); // Initialize bonusManager in the global scope
var levelConfigs = [{}, {
name: "Level 1",
backgroundTint: 0xeda716,
coinValue: 0.10,
baseSpeed: 10,
nextLevelScore: 10
}, {
name: "Level 2",
backgroundTint: 0x2faf1d,
coinValue: 1,
baseSpeed: 15,
nextLevelScore: 100
}, {
name: "Level 3",
backgroundTint: 0x6c6060,
coinValue: 100,
baseSpeed: 20,
nextLevelScore: Infinity // Endless Runner ;)
}];
var stripes = [];
var nbDecorations = 10;
var decorations = [];
// Initialize arrays and variables
var currentLevel = 1;
var road = new Road();
var isPlaying = false;
var isGameStarted = false;
var isMouseDown = false; // Flag to track if the mouse/finger is down
var isMoveAboveThreshold = false; // Flag to track if a move above threshold has been detected
var isKilled = false;
var killerDelay = 10000; // Delay in milliseconds before updating killer
var lastKillerUpdate = 0; // Timestamp of the last killer update
var currentCoinType = 0;
var nextCoinTypeThreshold = 1000;
var isNight = false;
var roadHeight = 2000;
var roadTop = 1000; // ~= road.height/2 - baseY
var background;
var landscape;
var nbStripes = 33;
var baseNbCoins = 10;
var baseNbObstacles = 10;
var baseBonusDelay = 10000;
var coins = [];
var obstacles = [];
var killers = [];
var road;
var score = 0;
var scoreTxt;
var goalText;
var goalAnnounceDelay = 3000;
var startX = 0;
var startY = 0;
var endX = 0;
var endY = 0;
var intensity = 0;
var intensityHalf = 0;
var leftLampPosts = [];
var rightLampPosts = [];
var leftDecorations = [];
var rightDecorationss = [];
var maxSpeed = 70; // Define a maximum speed limit
var currentSpeed = 15; //20; // Initialize currentSpeed
var coinsCollected = 0; // Initialize coins collected counter
var isIntersectingObstacle = false; // Flag to track if the player is currently intersecting an obstacle
var lastObstacleHitTime = 0; // Timestamp of the last obstacle hit
var immunityDelay = 500; // Immunity delay in milliseconds
var playerPositionIndex = 1; // Initialize player position index
var playerBaseY = 2732 - 300;
// Define the three fixed x positions for the player
var playerPositions = [2048 / 5, 2048 / 2, 4 * 2048 / 5];
// Create player
var player;
var debugMarker;
var debugText;
var debugTxt;
/****************************************************************************************** */
/************************************** GAME FUNCTIONS ************************************ */
/****************************************************************************************** */
function updateScore() {
var negative = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
if (negative) {
if (score > 0) {
moneyLost += Math.min(levelConfigs[currentLevel].coinValue || 1, score);
}
score -= levelConfigs[currentLevel].coinValue || 1;
score = parseFloat(score.toFixed(1));
score = Math.max(0, score); // Ensure score doesn't go below 0
} else {
var gain = levelConfigs[currentLevel].coinValue || 1;
if (bonusManager.currentActiveBonus == 2) {
// Multiplier bonus
gain *= 2;
}
score += gain;
score = parseFloat(score.toFixed(1));
coinsCollected += 1; // Increment coins collected counter
}
if (score >= levelConfigs[currentLevel].nextLevelScore) {
changeLevel(currentLevel + 1);
}
// Format score
log("score=", score, " => ", (score * 100).toFixed(0) + "¢");
if (score < 1) {
scoreTxt.setText((score * 100).toFixed(0) + "¢");
} else if (score < 10) {
scoreTxt.setText("$" + score.toFixed(2));
} else {
scoreTxt.setText("$" + Math.floor(score));
}
}
// Function to change the level
function changeLevel(newLevel) {
log("changeLevel:", newLevel);
newLevel = Math.max(1, Math.min(levelConfigs.length, newLevel));
currentLevel = newLevel;
obstacleManager.updateForLevel(newLevel);
currentSpeed = levelConfigs[currentLevel].baseSpeed;
console.log("Level changed to:", currentLevel);
// Add a big white flash effect
LK.effects.flashScreen(0xFFFFFF, 1000); // Flash white for 1 second
// Change background tint using levelConfig
background.updateForLevel(currentLevel);
// Update stripe graphics visibility based on the level
stripes.forEach(function (stripe) {
stripe.updateForLevel(currentLevel);
});
// Update landscape based on the level
landscape.updateForLevel(currentLevel);
// Update player graphics based on the level
player.updateForLevel(currentLevel);
if (road) {
road.updateForLevel(currentLevel);
}
coins.forEach(function (coin) {
coin.updateForLevel(currentLevel);
});
LK.getSound('levelWin_1').play();
updateGoalForLevel(currentLevel);
bonusManager.updateForLevel(newLevel);
killerManager.updateForLevel(newLevel);
killerManager.lastKillerUpdate = Date.now(); // Reset the last killer update time when level changes
}
function easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
function playHit() {
var hitSounds = ['hit_1', 'hit_2', 'hit_3'];
var randomIndex = Math.floor(Math.random() * hitSounds.length);
LK.getSound(hitSounds[randomIndex]).play();
}
function updateBackgroundColor() {
var time = 1000 + new Date().getTime() * 0.0002;
intensity = Math.sin(time) * 127 + 128;
var baseColor = levelConfigs[currentLevel].backgroundTint;
var r = (baseColor >> 16 & 0xFF) + intensity;
var g = (baseColor >> 8 & 0xFF) + intensity;
var b = (baseColor & 0xFF) + intensity;
r = Math.min(255, Math.max(0, r));
g = Math.min(255, Math.max(0, g));
b = Math.min(255, Math.max(0, b));
var color = r << 16 | g << 8 | b;
background.tint = color;
isNight = intensity < 128;
intensityHalf = 128 + Math.floor(intensity * 0.5);
}
function log() {
if (isDebug) {
var _console;
(_console = console).log.apply(_console, arguments);
}
}
/****************************************************************************************** */
/************************************** INPUT HANDLERS ************************************ */
/****************************************************************************************** */
// Handle move events
game.down = function (x, y, obj) {
if (!isPlaying) {
return;
}
startX = x;
startY = y;
isMouseDown = true; // Set flag to true when mouse/finger is down
};
game.move = function (x, y, obj) {
if (!isPlaying || !isMouseDown) {
return;
}
var deltaX = x - startX;
var deltaY = startY - y;
var threshold = 10; // Define a threshold for movement
if ((Math.abs(deltaX) > threshold || deltaY > threshold) && !isMoveAboveThreshold) {
isMoveAboveThreshold = true;
if (Math.abs(deltaX) > deltaY) {
if (deltaX > 0) {
// Swipe right
if (playerPositionIndex < 2) {
playerPositionIndex++;
}
} else {
// Swipe left
if (playerPositionIndex > 0) {
playerPositionIndex--;
}
}
// Make the player move progressively to the next path
var targetX = playerPositions[playerPositionIndex];
var initialX = player.x;
var moveDuration = 20;
var moveStartTime = Date.now();
var moveInterval = LK.setInterval(function () {
var elapsed = Date.now() - moveStartTime;
var progress = elapsed / (moveDuration * 1000 / 60);
if (progress < 1) {
var easeProgress = easeInOutQuad(progress);
player.x = initialX + (targetX - initialX) * easeProgress;
} else {
player.x = targetX;
LK.clearInterval(moveInterval);
}
}, 1000 / 60);
} else {
if (deltaY > threshold) {
// Swipe up
player.jump();
}
}
}
};
game.up = function (x, y, obj) {
isMouseDown = false; // Set flag to false when mouse/finger is up
isMoveAboveThreshold = false; // Reset flag when the move ends
if (isKilled) {
LK.setScore(score * 100); // Store the score in LK score before game over
LK.setTimeout(function () {
LK.stopMusic();
LK.showGameOver();
}, 500);
return;
}
if (!isPlaying) {
return;
}
};
// Update game every tick
game.update = function () {
updateBackgroundColor();
if (!isPlaying || isKilled) {
return;
}
};
// Initialize game
function gameInitialize() {
bonusManager.resetBonuses(); // Reset bonuses when initializing the game
killerManager.resetKillers();
killerManager.lastKillerUpdate = Date.now(); // Reset the last killer update time when initializing the game
// Initialize arrays and variables
// Attach the background asset to the game
background = game.addChild(new Background());
background.updateForLevel(currentLevel);
// Add a series of Stripe instances to cover the bottom half of the screen
for (var i = 0; i < nbStripes; i++) {
var stripe = new Stripe();
stripe.y = i === 0 ? roadTop : stripes[i - 1].y + stripes[i - 1].stripeGraphics.height; // Position stripe under the previous one using previous stripe y and height
stripe.progress = Math.max(0, stripe.y - roadTop) / roadHeight; // Calculate progress
stripes.push(stripe);
game.addChild(stripe);
stripe.stripeGraphics.height = 1 + 400 * stripe.progress; // Adjust height based on progress
//log("Stripe ", i, " y=", stripe.y, " h=", stripe.stripeGraphics.height, " p=", stripe.progress);
}
for (var i = 0; i < stripes.length; i++) {
stripes[i].update();
}
// Create and attach decoration instances to the game
for (var i = 0; i < nbDecorations; i++) {
var newDecoration = new Decoration(i);
newDecoration.reset();
decorations.push(newDecoration);
game.addChild(newDecoration);
}
// Create and attach the road instance to the game
road = game.addChild(new Road());
road.x = 2048 / 2;
road.y = 0;
if (road) {
//road.updateForLevel(currentLevel);
}
score = 0;
scoreTxt = new Text2('0¢', {
size: 150,
fill: "#ffffff",
dropShadow: true,
dropShadowColor: "#000000",
dropShadowBlur: 5,
dropShadowDistance: 5
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.visible = false;
goalText = new Text2('', {
size: 150,
fill: "#ffffff",
dropShadow: true,
dropShadowColor: "#111111",
dropShadowBlur: 10,
dropShadowDistance: 10,
align: 'center',
weight: 1000
});
goalText.anchor.set(0.5, 1);
LK.gui.center.addChild(goalText);
//goalText.x = 2048 / 2;
//goalText.y = 100;
//goalText.visible = true;
LK.gui.top.addChild(scoreTxt);
coins = [];
for (var i = 0; i < baseNbCoins; i++) {
var newCoin = new Coin(i);
newCoin.reset();
newCoin.y = roadTop - i * 50;
coins.push(newCoin);
game.addChild(newCoin);
}
// Create a variable to store the current player position index
playerPositionIndex = 1;
// Create and attach obstacle instances to the game
obstacleManager = new ObstacleManager();
var numObstacles = Math.floor(Math.random() * baseNbObstacles) + 1; // Randomize number of obstacles (1 to baseNbObstacles)
for (var i = 0; i < numObstacles; i++) {
var newObstacle = new Obstacle(i);
obstacleManager.addObstacle(newObstacle);
game.addChild(newObstacle);
}
obstacleManager.resetObstacles();
game.addChild(obstacleManager);
// Create and attach the killer instance to the game
// killerManager is already initialized in the global scope
for (var i = 0; i < 3; i++) {
var newKiller = new Killer(i); // Pass index for each killer
killerManager.addKiller(newKiller);
game.addChild(newKiller);
}
killerManager.resetKillers();
game.addChild(killerManager);
// Create and attach the bonus instance to the game
// bonusManager is already initialized in the global scope
for (var i = 0; i < 3; i++) {
var newBonus = new Bonus(i); // Pass index for each killer
bonusManager.addBonus(newBonus);
game.addChild(newBonus);
}
bonusManager.resetBonuses();
game.addChild(bonusManager);
// Create player
player = game.addChild(new Player());
player.frame = 0;
player.x = playerPositions[playerPositionIndex]; // Start at the center position
player.y = playerBaseY;
// Create and attach the landscape instance to the game
landscape = game.addChild(new Landscape());
var startButton = game.addChild(new StartButton());
startButton.x = 2048 / 2;
startButton.y = 2732 / 4;
// TEMP DEBUG !!!
//startButton.width = 100;
//startButton.height = 100;
// Attach a debugMarker asset to the game at position (1000, 0)
debugMarker = game.attachAsset('debugMarker', {
anchorX: 0.5,
anchorY: 0.5,
visible: isDebug
});
debugMarker.x = 1280;
debugMarker.y = roadTop;
debugTxt = new Text2('Debug Info', {
size: 50,
fill: "#ff0000"
});
debugTxt.anchor.set(1, 1); // Set anchor to the bottom right corner
debugTxt.visible = isDebug;
LK.gui.bottomRight.addChild(debugTxt);
isPlaying = false;
}
gameInitialize();
Directly overhead, plumb view of a beggar heading top (we see his back).. Zenith view, directly overhead, plumb view. NOT PERSPECTIVE! Fantasy theme. Pixel art
a traffic cone. video game sprite
face view of a big start button in the shape of a dollar bill. video game style
a tree. video game style
a black garbage bag. video game style
Dollar bill. Perspective. video game sprite
perspective of a simple snake rolled up on itself.. video game sprite
Ball of dry desert bushes. video game sprite
tractor. high definition video game sprite
street ad billboard with 1 or 2 posts with "Get rich!" on it. high definition video game sprite
a dog sleeping on a street. video game sprite
desert bush. video game sprite
profile view of an empty motorcycle helmet. black with a white vertical central band and another thiner orange band on the center. NOT PERSPECTIVE!. Pixel art high definition
simple red and white magnet. video game style
gold sign with a "X" and a "2". video game style
bgMusic
Music
coin_1
Sound effect
hit_1
Sound effect
hit_2
Sound effect
hit_3
Sound effect
levelWin_1
Sound effect
car_1
Sound effect
police_1
Sound effect
ambulance_1
Sound effect
accident_1
Sound effect
killed_1
Sound effect
jump_1
Sound effect
rip_1
Sound effect
bonus_take
Sound effect
bonus_approaching
Sound effect