/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { coins: 0, speedBoost: 0, extraLives: 0, coinMultiplier: 0, ownedCars: [1], selectedCar: 1 }); /**** * Classes ****/ var EnemyCar = Container.expand(function () { var self = Container.call(this); // Randomly select car type var carTypes = ['enemyCar1', 'enemyCar2', 'enemyCar3']; var selectedType = carTypes[Math.floor(Math.random() * carTypes.length)]; var carGraphics = self.attachAsset(selectedType, { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.checkedNearMiss = false; self.isCrashed = false; self.lateralSpeed = 0; self.lateralDirection = 0; self.moveTimer = 0; self.canMoveLaterally = false; self.update = function () { // Don't move if this specific car crashed if (self.isCrashed) { return; } // Handle lateral movement for medium and hard difficulties if (self.canMoveLaterally && (currentDifficulty === 'medium' || currentDifficulty === 'hard')) { self.moveTimer++; // Change direction every 60-120 frames (1-2 seconds) if (self.moveTimer >= 60 + Math.random() * 60) { self.moveTimer = 0; // Choose new direction: -1 (left), 0 (straight), 1 (right) self.lateralDirection = Math.floor(Math.random() * 3) - 1; self.lateralSpeed = self.lateralDirection * (currentDifficulty === 'hard' ? 3 : 2); } // Apply lateral movement self.x += self.lateralSpeed; // Keep cars within lane boundaries if (self.x < lanes[0]) { self.x = lanes[0]; self.lateralDirection = 1; self.lateralSpeed = currentDifficulty === 'hard' ? 3 : 2; } else if (self.x > lanes[lanes.length - 1]) { self.x = lanes[lanes.length - 1]; self.lateralDirection = -1; self.lateralSpeed = currentDifficulty === 'hard' ? -3 : -2; } } self.y += self.speed; }; return self; }); var PlayerCar = Container.expand(function () { var self = Container.call(this); var selectedCarId = storage.selectedCar || 1; var carAssetId = 'playerCar' + selectedCarId; var carGraphics = self.attachAsset(carAssetId, { anchorX: 0.5, anchorY: 0.5 }); self.targetX = 2048 / 2; self.currentX = 2048 / 2; self.update = function () { // Don't move if crashed if (crashed) { return; } // Smooth movement towards target position var diff = self.targetX - self.currentX; self.currentX += diff * 0.15; self.x = self.currentX; }; return self; }); var RoadLine = Container.expand(function () { var self = Container.call(this); var lineGraphics = self.attachAsset('roadLine', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.update = function () { self.y += self.speed; }; return self; }); var SmokeParticle = Container.expand(function () { var self = Container.call(this); var smokeGraphics = self.attachAsset('smokeParticle', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = (Math.random() - 0.5) * 8; self.speedY = -Math.random() * 5 - 2; self.life = 300; // 5 seconds at 60fps self.maxLife = 300; self.update = function () { self.x += self.speedX; self.y += self.speedY; self.speedY += 0.2; // gravity self.speedX *= 0.98; // air resistance self.life--; var fadeAmount = self.life / self.maxLife; self.alpha = fadeAmount; self.scaleX = 1 + (1 - fadeAmount) * 2; self.scaleY = 1 + (1 - fadeAmount) * 2; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2d2d2d }); /**** * Game Code ****/ // Game variables var player; var enemyCars = []; var roadLines = []; var gameSpeed = 1; var distanceScore = 0; var bonusScore = 0; var totalScore = 0; var spawnTimer = 0; var roadLineTimer = 0; var speedIncreaseTimer = 0; var smokeParticles = []; var crashed = false; var crashTimer = 0; var showingSecondChance = false; var secondChanceUsed = false; // Money system var coins = storage.coins || 0; var coinsEarned = 0; // Market system var showingMarket = false; var marketContainer = new Container(); game.addChild(marketContainer); marketContainer.alpha = 0; // Difficulty system var currentDifficulty = 'medium'; // 'easy', 'medium', 'hard' var gameStarted = false; var difficultySettings = { easy: { initialSpeed: 1.0, speedIncrease: 0.1, spawnRateBase: 80, enemySpeedMultiplier: 1.0, speedIncreaseInterval: 900 // 15 seconds }, medium: { initialSpeed: 2.0, speedIncrease: 0.2, spawnRateBase: 60, enemySpeedMultiplier: 2.0, speedIncreaseInterval: 600 // 10 seconds }, hard: { initialSpeed: 5.0, speedIncrease: 0.3, spawnRateBase: 25, enemySpeedMultiplier: 5.0, speedIncreaseInterval: 300 // 5 seconds } }; // Lane positions var lanes = [400, 700, 1000, 1300, 1648]; var laneCount = 5; // UI Elements var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF, font: "Arial Black" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 100; var speedTxt = new Text2('Speed: 1x', { size: 60, fill: 0xFFFF00, font: "Arial Black" }); speedTxt.anchor.set(1, 0); LK.gui.topRight.addChild(speedTxt); speedTxt.x = -50; speedTxt.y = 50; var coinsTxt = new Text2('Coins: ' + coins, { size: 60, fill: 0xFFD700, font: "Arial Black" }); coinsTxt.anchor.set(1, 0); LK.gui.topRight.addChild(coinsTxt); coinsTxt.x = -50; coinsTxt.y = 120; // Difficulty selection UI var difficultyTxt = new Text2('Select Difficulty', { size: 100, fill: 0xFFFFFF, font: "Arial Black" }); difficultyTxt.anchor.set(0.5, 0.5); difficultyTxt.x = 2048 / 2; difficultyTxt.y = 800; game.addChild(difficultyTxt); var easyBtn = new Text2('EASY', { size: 80, fill: 0x00FF00, font: "Arial Black" }); easyBtn.anchor.set(0.5, 0.5); easyBtn.x = 2048 / 2 - 300; easyBtn.y = 1200; game.addChild(easyBtn); var mediumBtn = new Text2('MEDIUM', { size: 80, fill: 0xFFFF00, font: "Arial Black" }); mediumBtn.anchor.set(0.5, 0.5); mediumBtn.x = 2048 / 2; mediumBtn.y = 1200; game.addChild(mediumBtn); var hardBtn = new Text2('HARD', { size: 80, fill: 0xFF0000, font: "Arial Black" }); hardBtn.anchor.set(0.5, 0.5); hardBtn.x = 2048 / 2 + 300; hardBtn.y = 1200; game.addChild(hardBtn); var instructionTxt = new Text2('Touch a difficulty to start!', { size: 60, fill: 0xCCCCCC, font: "Arial Black" }); instructionTxt.anchor.set(0.5, 0.5); instructionTxt.x = 2048 / 2; instructionTxt.y = 1400; game.addChild(instructionTxt); // Second chance UI elements (initially hidden) var secondChanceContainer = new Container(); game.addChild(secondChanceContainer); secondChanceContainer.alpha = 0; var secondChanceBg = LK.getAsset('roadLine', { width: 1000, height: 500, anchorX: 0.5, anchorY: 0.5 }); secondChanceBg.tint = 0x000000; secondChanceBg.alpha = 0.8; secondChanceBg.x = 2048 / 2; secondChanceBg.y = 1366; secondChanceContainer.addChild(secondChanceBg); var secondChanceTxt = new Text2('SECOND CHANCE!', { size: 80, fill: 0xFFD700, font: "Arial Black" }); secondChanceTxt.anchor.set(0.5, 0.5); secondChanceTxt.x = 2048 / 2; secondChanceTxt.y = 1266; secondChanceContainer.addChild(secondChanceTxt); var secondChanceCostTxt = new Text2('Cost: 25 Coins', { size: 60, fill: 0xFFFFFF, font: "Arial Black" }); secondChanceCostTxt.anchor.set(0.5, 0.5); secondChanceCostTxt.x = 2048 / 2; secondChanceCostTxt.y = 1366; secondChanceContainer.addChild(secondChanceCostTxt); var buySecondChanceBtn = new Text2('EVET', { size: 80, fill: 0x00FF00, font: "Arial Black" }); buySecondChanceBtn.anchor.set(0.5, 0.5); buySecondChanceBtn.x = 2048 / 2 - 150; buySecondChanceBtn.y = 1466; secondChanceContainer.addChild(buySecondChanceBtn); var declineSecondChanceBtn = new Text2('HAYIR', { size: 80, fill: 0xFF0000, font: "Arial Black" }); declineSecondChanceBtn.anchor.set(0.5, 0.5); declineSecondChanceBtn.x = 2048 / 2 + 150; declineSecondChanceBtn.y = 1466; secondChanceContainer.addChild(declineSecondChanceBtn); // Market button var marketBtn = new Text2('MARKET', { size: 80, fill: 0xFFD700, font: "Arial Black" }); marketBtn.anchor.set(0.5, 0.5); marketBtn.x = 2048 / 2; marketBtn.y = 1600; game.addChild(marketBtn); // Market UI elements var marketBg = LK.getAsset('roadLine', { width: 1600, height: 1200, anchorX: 0.5, anchorY: 0.5 }); marketBg.tint = 0x000000; marketBg.alpha = 0.9; marketBg.x = 2048 / 2; marketBg.y = 1366; marketContainer.addChild(marketBg); var marketTitle = new Text2('MARKET', { size: 120, fill: 0xFFD700, font: "Arial Black" }); marketTitle.anchor.set(0.5, 0.5); marketTitle.x = 2048 / 2; marketTitle.y = 900; marketContainer.addChild(marketTitle); var marketCoinsDisplay = new Text2('Your Coins: ' + coins, { size: 60, fill: 0xFFFFFF, font: "Arial Black" }); marketCoinsDisplay.anchor.set(0.5, 0.5); marketCoinsDisplay.x = 2048 / 2; marketCoinsDisplay.y = 1000; marketContainer.addChild(marketCoinsDisplay); // Market items var item1Txt = new Text2('Speed Boost (50 coins) - Owned: ' + (storage.speedBoost || 0), { size: 50, fill: 0x00FF00, font: "Arial Black" }); item1Txt.anchor.set(0.5, 0.5); item1Txt.x = 2048 / 2; item1Txt.y = 1200; marketContainer.addChild(item1Txt); var item2Txt = new Text2('Extra Life (100 coins) - Owned: ' + (storage.extraLives || 0), { size: 50, fill: 0xFF6600, font: "Arial Black" }); item2Txt.anchor.set(0.5, 0.5); item2Txt.x = 2048 / 2; item2Txt.y = 1300; marketContainer.addChild(item2Txt); var item3Txt = new Text2('Coin Multiplier (200 coins) - Owned: ' + (storage.coinMultiplier || 0), { size: 50, fill: 0x9900FF, font: "Arial Black" }); item3Txt.anchor.set(0.5, 0.5); item3Txt.x = 2048 / 2; item3Txt.y = 1400; marketContainer.addChild(item3Txt); // Car market items var car2Txt = new Text2('Araba 2 (20 coins) - ' + (storage.ownedCars.indexOf(2) !== -1 ? 'OWNED' : 'BUY'), { size: 50, fill: storage.ownedCars.indexOf(2) !== -1 ? 0x00FF00 : 0xFF6600, font: "Arial Black" }); car2Txt.anchor.set(0.5, 0.5); car2Txt.x = 2048 / 2; car2Txt.y = 1500; marketContainer.addChild(car2Txt); var car3Txt = new Text2('F1 (20 coins) - ' + (storage.ownedCars.indexOf(3) !== -1 ? 'OWNED' : 'BUY'), { size: 50, fill: storage.ownedCars.indexOf(3) !== -1 ? 0x00FF00 : 0x0066FF, font: "Arial Black" }); car3Txt.anchor.set(0.5, 0.5); car3Txt.x = 2048 / 2; car3Txt.y = 1600; marketContainer.addChild(car3Txt); var selectCarTxt = new Text2('Selected Car: Car ' + (storage.selectedCar || 1), { size: 60, fill: 0xFFD700, font: "Arial Black" }); selectCarTxt.anchor.set(0.5, 0.5); selectCarTxt.x = 2048 / 2; selectCarTxt.y = 1700; marketContainer.addChild(selectCarTxt); var closeMarketBtn = new Text2('CLOSE', { size: 80, fill: 0xFF0000, font: "Arial Black" }); closeMarketBtn.anchor.set(1, 0); closeMarketBtn.x = 1750; closeMarketBtn.y = 800; marketContainer.addChild(closeMarketBtn); // Initialize player player = game.addChild(new PlayerCar()); player.x = 2048 / 2; player.y = 2200; player.alpha = 0.3; // Make player semi-transparent during difficulty selection // Difficulty button handlers easyBtn.down = function (x, y, obj) { startGameWithDifficulty('easy'); }; mediumBtn.down = function (x, y, obj) { startGameWithDifficulty('medium'); }; hardBtn.down = function (x, y, obj) { startGameWithDifficulty('hard'); }; // Market button handler marketBtn.down = function (x, y, obj) { if (!gameStarted) { showingMarket = true; marketContainer.alpha = 1; marketCoinsDisplay.setText('Your Coins: ' + coins); // Hide difficulty selection UI when market opens difficultyTxt.alpha = 0; easyBtn.alpha = 0; mediumBtn.alpha = 0; hardBtn.alpha = 0; instructionTxt.alpha = 0; marketBtn.alpha = 0; } }; // Second chance button handlers buySecondChanceBtn.down = function (x, y, obj) { if (coins >= 25) { // Deduct coins coins -= 25; storage.coins = coins; coinsTxt.setText('Coins: ' + coins); // Reset crash state crashed = false; crashTimer = 0; showingSecondChance = false; secondChanceUsed = true; // Hide second chance UI secondChanceContainer.alpha = 0; // Reset player player.alpha = 1; player.scaleX = 1; player.scaleY = 1; player.x = 2048 / 2; player.targetX = 2048 / 2; player.currentX = 2048 / 2; // Clear all enemy cars for (var i = enemyCars.length - 1; i >= 0; i--) { enemyCars[i].destroy(); enemyCars.splice(i, 1); } // Clear all smoke particles for (var k = smokeParticles.length - 1; k >= 0; k--) { smokeParticles[k].destroy(); smokeParticles.splice(k, 1); } // Reset timers spawnTimer = 0; roadLineTimer = 0; } }; declineSecondChanceBtn.down = function (x, y, obj) { // Hide second chance UI and proceed to game over showingSecondChance = false; secondChanceContainer.alpha = 0; // Save coins to storage before game over storage.coins = coins; LK.showGameOver(); }; // Market item handlers item1Txt.down = function (x, y, obj) { if (coins >= 50) { coins -= 50; storage.coins = coins; storage.speedBoost = (storage.speedBoost || 0) + 1; marketCoinsDisplay.setText('Your Coins: ' + coins); coinsTxt.setText('Coins: ' + coins); item1Txt.setText('Speed Boost (50 coins) - Owned: ' + storage.speedBoost); } }; item2Txt.down = function (x, y, obj) { if (coins >= 100) { coins -= 100; storage.coins = coins; storage.extraLives = (storage.extraLives || 0) + 1; marketCoinsDisplay.setText('Your Coins: ' + coins); coinsTxt.setText('Coins: ' + coins); item2Txt.setText('Extra Life (100 coins) - Owned: ' + storage.extraLives); } }; item3Txt.down = function (x, y, obj) { if (coins >= 200) { coins -= 200; storage.coins = coins; storage.coinMultiplier = (storage.coinMultiplier || 0) + 1; marketCoinsDisplay.setText('Your Coins: ' + coins); coinsTxt.setText('Coins: ' + coins); item3Txt.setText('Coin Multiplier (200 coins) - Owned: ' + storage.coinMultiplier); } }; // Car market handlers car2Txt.down = function (x, y, obj) { if (storage.ownedCars.indexOf(2) === -1) { // Car not owned, try to buy it if (coins >= 20) { coins -= 20; storage.coins = coins; storage.ownedCars.push(2); car2Txt.setText('Araba 2 (20 coins) - OWNED'); car2Txt.fill = 0x00FF00; marketCoinsDisplay.setText('Your Coins: ' + coins); coinsTxt.setText('Coins: ' + coins); // Auto-select car 2 when purchased storage.selectedCar = 2; selectCarTxt.setText('Selected Car: Araba 2'); // Update player car visual immediately player.removeChildren(); var newCarGraphics = player.attachAsset('playerCar2', { anchorX: 0.5, anchorY: 0.5 }); } } else { // Car owned, select it storage.selectedCar = 2; selectCarTxt.setText('Selected Car: Araba 2'); // Update player car visual immediately player.removeChildren(); var newCarGraphics = player.attachAsset('playerCar2', { anchorX: 0.5, anchorY: 0.5 }); } }; car3Txt.down = function (x, y, obj) { if (storage.ownedCars.indexOf(3) === -1) { // Car not owned, try to buy it if (coins >= 20) { coins -= 20; storage.coins = coins; storage.ownedCars.push(3); car3Txt.setText('F1 (20 coins) - OWNED'); car3Txt.fill = 0x00FF00; marketCoinsDisplay.setText('Your Coins: ' + coins); coinsTxt.setText('Coins: ' + coins); } } else { // Car owned, select it storage.selectedCar = 3; selectCarTxt.setText('Selected Car: F1'); // Update player car visual immediately player.removeChildren(); var newCarGraphics = player.attachAsset('playerCar3', { anchorX: 0.5, anchorY: 0.5 }); } }; closeMarketBtn.down = function (x, y, obj) { showingMarket = false; marketContainer.alpha = 0; // Show difficulty selection UI when market closes difficultyTxt.alpha = 1; easyBtn.alpha = 1; mediumBtn.alpha = 1; hardBtn.alpha = 1; instructionTxt.alpha = 1; marketBtn.alpha = 1; }; function startGameWithDifficulty(difficulty) { currentDifficulty = difficulty; gameStarted = true; gameSpeed = difficultySettings[currentDifficulty].initialSpeed; // Reset coins earned this game coinsEarned = 0; // Reset second chance flag secondChanceUsed = false; showingSecondChance = false; secondChanceContainer.alpha = 0; // Hide difficulty selection UI difficultyTxt.alpha = 0; easyBtn.alpha = 0; mediumBtn.alpha = 0; hardBtn.alpha = 0; instructionTxt.alpha = 0; marketBtn.alpha = 0; // Hide market UI showingMarket = false; marketContainer.alpha = 0; // Make player fully visible player.alpha = 1; // Update speed display speedTxt.setText('Speed: ' + gameSpeed.toFixed(1) + 'x'); // Show difficulty indicator var difficultyIndicator = new Text2('Difficulty: ' + currentDifficulty.toUpperCase(), { size: 50, fill: currentDifficulty === 'easy' ? 0x00FF00 : currentDifficulty === 'medium' ? 0xFFFF00 : 0xFF0000, font: "Arial Black" }); difficultyIndicator.anchor.set(0, 0); LK.gui.topLeft.addChild(difficultyIndicator); difficultyIndicator.x = 120; difficultyIndicator.y = 20; } // Touch controls var isDragging = false; game.down = function (x, y, obj) { if (gameStarted) { isDragging = true; player.targetX = x; } }; game.move = function (x, y, obj) { if (isDragging && gameStarted) { // Constrain to lanes var clampedX = Math.max(lanes[0], Math.min(lanes[lanes.length - 1], x)); player.targetX = clampedX; } }; game.up = function (x, y, obj) { if (gameStarted) { isDragging = false; } }; // Helper functions function spawnEnemyCar() { var enemy = new EnemyCar(); var laneIndex = Math.floor(Math.random() * lanes.length); enemy.x = lanes[laneIndex]; enemy.y = -100; enemy.speed = 8 + gameSpeed * difficultySettings[currentDifficulty].enemySpeedMultiplier; // Enable lateral movement for medium and hard difficulties if (currentDifficulty === 'medium' || currentDifficulty === 'hard') { enemy.canMoveLaterally = true; // Random initial lateral movement enemy.lateralDirection = Math.floor(Math.random() * 3) - 1; enemy.lateralSpeed = enemy.lateralDirection * (currentDifficulty === 'hard' ? 3 : 2); enemy.moveTimer = Math.floor(Math.random() * 60); // Random start time } enemyCars.push(enemy); game.addChild(enemy); } function spawnRoadLine() { var line = new RoadLine(); line.x = 2048 / 2; line.y = -50; line.speed = 10 + gameSpeed * 2; roadLines.push(line); game.addChild(line); } function checkNearMiss(enemy) { if (!enemy.checkedNearMiss) { var distance = Math.abs(player.x - enemy.x); var verticalDistance = Math.abs(player.y - enemy.y); if (distance < 150 && verticalDistance < 200) { enemy.checkedNearMiss = true; bonusScore += 10; totalScore += 10; // Earn coins for near miss coinsEarned += 3; coins += 3; // Visual effect for near miss LK.effects.flashObject(enemy, 0xffff00, 200); LK.getSound('nearMiss').play(); return true; } } return false; } function updateScore() { distanceScore = Math.floor(LK.ticks / 10); totalScore = distanceScore + bonusScore; LK.setScore(totalScore); scoreTxt.setText('Score: ' + totalScore); // Earn coins based on score (1 coin per 50 score points) var newCoinsFromScore = Math.floor(totalScore / 50); if (newCoinsFromScore > coinsEarned) { var coinsToAdd = newCoinsFromScore - coinsEarned; coinsEarned = newCoinsFromScore; coins += coinsToAdd; } // Update coins display coinsTxt.setText('Coins: ' + coins); } function createSmokeEffect(x, y) { for (var i = 0; i < 15; i++) { var smoke = new SmokeParticle(); smoke.x = x + (Math.random() - 0.5) * 60; smoke.y = y + (Math.random() - 0.5) * 60; smokeParticles.push(smoke); game.addChild(smoke); } } function updateSpeed() { speedIncreaseTimer++; var interval = difficultySettings[currentDifficulty].speedIncreaseInterval; if (speedIncreaseTimer >= interval) { gameSpeed += difficultySettings[currentDifficulty].speedIncrease; speedIncreaseTimer = 0; speedTxt.setText('Speed: ' + gameSpeed.toFixed(1) + 'x'); } } // Main game loop game.update = function () { if (!gameStarted) { return; // Don't update game logic until difficulty is selected } // Handle crash timer if (crashed) { crashTimer++; // Show second chance offer after 1 second, if not used and player has enough coins if (crashTimer >= 60 && !showingSecondChance && !secondChanceUsed && coins >= 25) { showingSecondChance = true; secondChanceContainer.alpha = 1; } // Only proceed to game over if second chance wasn't shown or was declined if (crashTimer >= 180 && !showingSecondChance) { // Save coins to storage before game over storage.coins = coins; LK.showGameOver(); return; } // Continue updating smoke during crash for (var k = smokeParticles.length - 1; k >= 0; k--) { var smoke = smokeParticles[k]; if (smoke.life <= 0) { smoke.destroy(); smokeParticles.splice(k, 1); } } return; // Don't update other game logic during crash } updateScore(); updateSpeed(); // Spawn enemy cars spawnTimer++; var baseSpawnRate = difficultySettings[currentDifficulty].spawnRateBase; var speedMultiplier = currentDifficulty === 'hard' ? 15 : 10; // More aggressive scaling for hard mode var spawnRate = Math.max(baseSpawnRate - gameSpeed * speedMultiplier, currentDifficulty === 'hard' ? 10 : 20); // Lower minimum for hard mode if (spawnTimer >= spawnRate) { spawnEnemyCar(); spawnTimer = 0; } // Spawn road lines roadLineTimer++; if (roadLineTimer >= 20) { spawnRoadLine(); roadLineTimer = 0; } // Update and check enemy cars for (var i = enemyCars.length - 1; i >= 0; i--) { var enemy = enemyCars[i]; // Check for collision if (enemy.intersects(player) && !crashed) { // Set crash state crashed = true; crashTimer = 0; // Mark both cars as crashed enemy.isCrashed = true; // Create explosion effect on crashed enemy car tween(enemy, { scaleX: 3, scaleY: 3, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Car will fade out completely } }); // Create explosion effect on player car tween(player, { scaleX: 2.5, scaleY: 2.5, alpha: 0.3 }, { duration: 800, easing: tween.easeOut }); // Create smoke effect at crash location createSmokeEffect(player.x, player.y); createSmokeEffect(enemy.x, enemy.y); // Flash screen and play sound LK.effects.flashScreen(0xff0000, 1000); LK.getSound('crash').play(); // Stop player movement player.targetX = player.x; } // Don't update enemy cars if crashed if (!crashed) { // Check for near miss checkNearMiss(enemy); } // Remove off-screen enemies if (enemy.y > 2800) { enemy.destroy(); enemyCars.splice(i, 1); } } // Update and clean up road lines for (var j = roadLines.length - 1; j >= 0; j--) { var line = roadLines[j]; if (line.y > 2800) { line.destroy(); roadLines.splice(j, 1); } } // Update and clean up smoke particles (only when not crashed) if (!crashed) { for (var k = smokeParticles.length - 1; k >= 0; k--) { var smoke = smokeParticles[k]; if (smoke.life <= 0) { smoke.destroy(); smokeParticles.splice(k, 1); } } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
coins: 0,
speedBoost: 0,
extraLives: 0,
coinMultiplier: 0,
ownedCars: [1],
selectedCar: 1
});
/****
* Classes
****/
var EnemyCar = Container.expand(function () {
var self = Container.call(this);
// Randomly select car type
var carTypes = ['enemyCar1', 'enemyCar2', 'enemyCar3'];
var selectedType = carTypes[Math.floor(Math.random() * carTypes.length)];
var carGraphics = self.attachAsset(selectedType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.checkedNearMiss = false;
self.isCrashed = false;
self.lateralSpeed = 0;
self.lateralDirection = 0;
self.moveTimer = 0;
self.canMoveLaterally = false;
self.update = function () {
// Don't move if this specific car crashed
if (self.isCrashed) {
return;
}
// Handle lateral movement for medium and hard difficulties
if (self.canMoveLaterally && (currentDifficulty === 'medium' || currentDifficulty === 'hard')) {
self.moveTimer++;
// Change direction every 60-120 frames (1-2 seconds)
if (self.moveTimer >= 60 + Math.random() * 60) {
self.moveTimer = 0;
// Choose new direction: -1 (left), 0 (straight), 1 (right)
self.lateralDirection = Math.floor(Math.random() * 3) - 1;
self.lateralSpeed = self.lateralDirection * (currentDifficulty === 'hard' ? 3 : 2);
}
// Apply lateral movement
self.x += self.lateralSpeed;
// Keep cars within lane boundaries
if (self.x < lanes[0]) {
self.x = lanes[0];
self.lateralDirection = 1;
self.lateralSpeed = currentDifficulty === 'hard' ? 3 : 2;
} else if (self.x > lanes[lanes.length - 1]) {
self.x = lanes[lanes.length - 1];
self.lateralDirection = -1;
self.lateralSpeed = currentDifficulty === 'hard' ? -3 : -2;
}
}
self.y += self.speed;
};
return self;
});
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
var selectedCarId = storage.selectedCar || 1;
var carAssetId = 'playerCar' + selectedCarId;
var carGraphics = self.attachAsset(carAssetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.targetX = 2048 / 2;
self.currentX = 2048 / 2;
self.update = function () {
// Don't move if crashed
if (crashed) {
return;
}
// Smooth movement towards target position
var diff = self.targetX - self.currentX;
self.currentX += diff * 0.15;
self.x = self.currentX;
};
return self;
});
var RoadLine = Container.expand(function () {
var self = Container.call(this);
var lineGraphics = self.attachAsset('roadLine', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
var SmokeParticle = Container.expand(function () {
var self = Container.call(this);
var smokeGraphics = self.attachAsset('smokeParticle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = (Math.random() - 0.5) * 8;
self.speedY = -Math.random() * 5 - 2;
self.life = 300; // 5 seconds at 60fps
self.maxLife = 300;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.speedY += 0.2; // gravity
self.speedX *= 0.98; // air resistance
self.life--;
var fadeAmount = self.life / self.maxLife;
self.alpha = fadeAmount;
self.scaleX = 1 + (1 - fadeAmount) * 2;
self.scaleY = 1 + (1 - fadeAmount) * 2;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d2d2d
});
/****
* Game Code
****/
// Game variables
var player;
var enemyCars = [];
var roadLines = [];
var gameSpeed = 1;
var distanceScore = 0;
var bonusScore = 0;
var totalScore = 0;
var spawnTimer = 0;
var roadLineTimer = 0;
var speedIncreaseTimer = 0;
var smokeParticles = [];
var crashed = false;
var crashTimer = 0;
var showingSecondChance = false;
var secondChanceUsed = false;
// Money system
var coins = storage.coins || 0;
var coinsEarned = 0;
// Market system
var showingMarket = false;
var marketContainer = new Container();
game.addChild(marketContainer);
marketContainer.alpha = 0;
// Difficulty system
var currentDifficulty = 'medium'; // 'easy', 'medium', 'hard'
var gameStarted = false;
var difficultySettings = {
easy: {
initialSpeed: 1.0,
speedIncrease: 0.1,
spawnRateBase: 80,
enemySpeedMultiplier: 1.0,
speedIncreaseInterval: 900 // 15 seconds
},
medium: {
initialSpeed: 2.0,
speedIncrease: 0.2,
spawnRateBase: 60,
enemySpeedMultiplier: 2.0,
speedIncreaseInterval: 600 // 10 seconds
},
hard: {
initialSpeed: 5.0,
speedIncrease: 0.3,
spawnRateBase: 25,
enemySpeedMultiplier: 5.0,
speedIncreaseInterval: 300 // 5 seconds
}
};
// Lane positions
var lanes = [400, 700, 1000, 1300, 1648];
var laneCount = 5;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF,
font: "Arial Black"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 100;
var speedTxt = new Text2('Speed: 1x', {
size: 60,
fill: 0xFFFF00,
font: "Arial Black"
});
speedTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(speedTxt);
speedTxt.x = -50;
speedTxt.y = 50;
var coinsTxt = new Text2('Coins: ' + coins, {
size: 60,
fill: 0xFFD700,
font: "Arial Black"
});
coinsTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(coinsTxt);
coinsTxt.x = -50;
coinsTxt.y = 120;
// Difficulty selection UI
var difficultyTxt = new Text2('Select Difficulty', {
size: 100,
fill: 0xFFFFFF,
font: "Arial Black"
});
difficultyTxt.anchor.set(0.5, 0.5);
difficultyTxt.x = 2048 / 2;
difficultyTxt.y = 800;
game.addChild(difficultyTxt);
var easyBtn = new Text2('EASY', {
size: 80,
fill: 0x00FF00,
font: "Arial Black"
});
easyBtn.anchor.set(0.5, 0.5);
easyBtn.x = 2048 / 2 - 300;
easyBtn.y = 1200;
game.addChild(easyBtn);
var mediumBtn = new Text2('MEDIUM', {
size: 80,
fill: 0xFFFF00,
font: "Arial Black"
});
mediumBtn.anchor.set(0.5, 0.5);
mediumBtn.x = 2048 / 2;
mediumBtn.y = 1200;
game.addChild(mediumBtn);
var hardBtn = new Text2('HARD', {
size: 80,
fill: 0xFF0000,
font: "Arial Black"
});
hardBtn.anchor.set(0.5, 0.5);
hardBtn.x = 2048 / 2 + 300;
hardBtn.y = 1200;
game.addChild(hardBtn);
var instructionTxt = new Text2('Touch a difficulty to start!', {
size: 60,
fill: 0xCCCCCC,
font: "Arial Black"
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.x = 2048 / 2;
instructionTxt.y = 1400;
game.addChild(instructionTxt);
// Second chance UI elements (initially hidden)
var secondChanceContainer = new Container();
game.addChild(secondChanceContainer);
secondChanceContainer.alpha = 0;
var secondChanceBg = LK.getAsset('roadLine', {
width: 1000,
height: 500,
anchorX: 0.5,
anchorY: 0.5
});
secondChanceBg.tint = 0x000000;
secondChanceBg.alpha = 0.8;
secondChanceBg.x = 2048 / 2;
secondChanceBg.y = 1366;
secondChanceContainer.addChild(secondChanceBg);
var secondChanceTxt = new Text2('SECOND CHANCE!', {
size: 80,
fill: 0xFFD700,
font: "Arial Black"
});
secondChanceTxt.anchor.set(0.5, 0.5);
secondChanceTxt.x = 2048 / 2;
secondChanceTxt.y = 1266;
secondChanceContainer.addChild(secondChanceTxt);
var secondChanceCostTxt = new Text2('Cost: 25 Coins', {
size: 60,
fill: 0xFFFFFF,
font: "Arial Black"
});
secondChanceCostTxt.anchor.set(0.5, 0.5);
secondChanceCostTxt.x = 2048 / 2;
secondChanceCostTxt.y = 1366;
secondChanceContainer.addChild(secondChanceCostTxt);
var buySecondChanceBtn = new Text2('EVET', {
size: 80,
fill: 0x00FF00,
font: "Arial Black"
});
buySecondChanceBtn.anchor.set(0.5, 0.5);
buySecondChanceBtn.x = 2048 / 2 - 150;
buySecondChanceBtn.y = 1466;
secondChanceContainer.addChild(buySecondChanceBtn);
var declineSecondChanceBtn = new Text2('HAYIR', {
size: 80,
fill: 0xFF0000,
font: "Arial Black"
});
declineSecondChanceBtn.anchor.set(0.5, 0.5);
declineSecondChanceBtn.x = 2048 / 2 + 150;
declineSecondChanceBtn.y = 1466;
secondChanceContainer.addChild(declineSecondChanceBtn);
// Market button
var marketBtn = new Text2('MARKET', {
size: 80,
fill: 0xFFD700,
font: "Arial Black"
});
marketBtn.anchor.set(0.5, 0.5);
marketBtn.x = 2048 / 2;
marketBtn.y = 1600;
game.addChild(marketBtn);
// Market UI elements
var marketBg = LK.getAsset('roadLine', {
width: 1600,
height: 1200,
anchorX: 0.5,
anchorY: 0.5
});
marketBg.tint = 0x000000;
marketBg.alpha = 0.9;
marketBg.x = 2048 / 2;
marketBg.y = 1366;
marketContainer.addChild(marketBg);
var marketTitle = new Text2('MARKET', {
size: 120,
fill: 0xFFD700,
font: "Arial Black"
});
marketTitle.anchor.set(0.5, 0.5);
marketTitle.x = 2048 / 2;
marketTitle.y = 900;
marketContainer.addChild(marketTitle);
var marketCoinsDisplay = new Text2('Your Coins: ' + coins, {
size: 60,
fill: 0xFFFFFF,
font: "Arial Black"
});
marketCoinsDisplay.anchor.set(0.5, 0.5);
marketCoinsDisplay.x = 2048 / 2;
marketCoinsDisplay.y = 1000;
marketContainer.addChild(marketCoinsDisplay);
// Market items
var item1Txt = new Text2('Speed Boost (50 coins) - Owned: ' + (storage.speedBoost || 0), {
size: 50,
fill: 0x00FF00,
font: "Arial Black"
});
item1Txt.anchor.set(0.5, 0.5);
item1Txt.x = 2048 / 2;
item1Txt.y = 1200;
marketContainer.addChild(item1Txt);
var item2Txt = new Text2('Extra Life (100 coins) - Owned: ' + (storage.extraLives || 0), {
size: 50,
fill: 0xFF6600,
font: "Arial Black"
});
item2Txt.anchor.set(0.5, 0.5);
item2Txt.x = 2048 / 2;
item2Txt.y = 1300;
marketContainer.addChild(item2Txt);
var item3Txt = new Text2('Coin Multiplier (200 coins) - Owned: ' + (storage.coinMultiplier || 0), {
size: 50,
fill: 0x9900FF,
font: "Arial Black"
});
item3Txt.anchor.set(0.5, 0.5);
item3Txt.x = 2048 / 2;
item3Txt.y = 1400;
marketContainer.addChild(item3Txt);
// Car market items
var car2Txt = new Text2('Araba 2 (20 coins) - ' + (storage.ownedCars.indexOf(2) !== -1 ? 'OWNED' : 'BUY'), {
size: 50,
fill: storage.ownedCars.indexOf(2) !== -1 ? 0x00FF00 : 0xFF6600,
font: "Arial Black"
});
car2Txt.anchor.set(0.5, 0.5);
car2Txt.x = 2048 / 2;
car2Txt.y = 1500;
marketContainer.addChild(car2Txt);
var car3Txt = new Text2('F1 (20 coins) - ' + (storage.ownedCars.indexOf(3) !== -1 ? 'OWNED' : 'BUY'), {
size: 50,
fill: storage.ownedCars.indexOf(3) !== -1 ? 0x00FF00 : 0x0066FF,
font: "Arial Black"
});
car3Txt.anchor.set(0.5, 0.5);
car3Txt.x = 2048 / 2;
car3Txt.y = 1600;
marketContainer.addChild(car3Txt);
var selectCarTxt = new Text2('Selected Car: Car ' + (storage.selectedCar || 1), {
size: 60,
fill: 0xFFD700,
font: "Arial Black"
});
selectCarTxt.anchor.set(0.5, 0.5);
selectCarTxt.x = 2048 / 2;
selectCarTxt.y = 1700;
marketContainer.addChild(selectCarTxt);
var closeMarketBtn = new Text2('CLOSE', {
size: 80,
fill: 0xFF0000,
font: "Arial Black"
});
closeMarketBtn.anchor.set(1, 0);
closeMarketBtn.x = 1750;
closeMarketBtn.y = 800;
marketContainer.addChild(closeMarketBtn);
// Initialize player
player = game.addChild(new PlayerCar());
player.x = 2048 / 2;
player.y = 2200;
player.alpha = 0.3; // Make player semi-transparent during difficulty selection
// Difficulty button handlers
easyBtn.down = function (x, y, obj) {
startGameWithDifficulty('easy');
};
mediumBtn.down = function (x, y, obj) {
startGameWithDifficulty('medium');
};
hardBtn.down = function (x, y, obj) {
startGameWithDifficulty('hard');
};
// Market button handler
marketBtn.down = function (x, y, obj) {
if (!gameStarted) {
showingMarket = true;
marketContainer.alpha = 1;
marketCoinsDisplay.setText('Your Coins: ' + coins);
// Hide difficulty selection UI when market opens
difficultyTxt.alpha = 0;
easyBtn.alpha = 0;
mediumBtn.alpha = 0;
hardBtn.alpha = 0;
instructionTxt.alpha = 0;
marketBtn.alpha = 0;
}
};
// Second chance button handlers
buySecondChanceBtn.down = function (x, y, obj) {
if (coins >= 25) {
// Deduct coins
coins -= 25;
storage.coins = coins;
coinsTxt.setText('Coins: ' + coins);
// Reset crash state
crashed = false;
crashTimer = 0;
showingSecondChance = false;
secondChanceUsed = true;
// Hide second chance UI
secondChanceContainer.alpha = 0;
// Reset player
player.alpha = 1;
player.scaleX = 1;
player.scaleY = 1;
player.x = 2048 / 2;
player.targetX = 2048 / 2;
player.currentX = 2048 / 2;
// Clear all enemy cars
for (var i = enemyCars.length - 1; i >= 0; i--) {
enemyCars[i].destroy();
enemyCars.splice(i, 1);
}
// Clear all smoke particles
for (var k = smokeParticles.length - 1; k >= 0; k--) {
smokeParticles[k].destroy();
smokeParticles.splice(k, 1);
}
// Reset timers
spawnTimer = 0;
roadLineTimer = 0;
}
};
declineSecondChanceBtn.down = function (x, y, obj) {
// Hide second chance UI and proceed to game over
showingSecondChance = false;
secondChanceContainer.alpha = 0;
// Save coins to storage before game over
storage.coins = coins;
LK.showGameOver();
};
// Market item handlers
item1Txt.down = function (x, y, obj) {
if (coins >= 50) {
coins -= 50;
storage.coins = coins;
storage.speedBoost = (storage.speedBoost || 0) + 1;
marketCoinsDisplay.setText('Your Coins: ' + coins);
coinsTxt.setText('Coins: ' + coins);
item1Txt.setText('Speed Boost (50 coins) - Owned: ' + storage.speedBoost);
}
};
item2Txt.down = function (x, y, obj) {
if (coins >= 100) {
coins -= 100;
storage.coins = coins;
storage.extraLives = (storage.extraLives || 0) + 1;
marketCoinsDisplay.setText('Your Coins: ' + coins);
coinsTxt.setText('Coins: ' + coins);
item2Txt.setText('Extra Life (100 coins) - Owned: ' + storage.extraLives);
}
};
item3Txt.down = function (x, y, obj) {
if (coins >= 200) {
coins -= 200;
storage.coins = coins;
storage.coinMultiplier = (storage.coinMultiplier || 0) + 1;
marketCoinsDisplay.setText('Your Coins: ' + coins);
coinsTxt.setText('Coins: ' + coins);
item3Txt.setText('Coin Multiplier (200 coins) - Owned: ' + storage.coinMultiplier);
}
};
// Car market handlers
car2Txt.down = function (x, y, obj) {
if (storage.ownedCars.indexOf(2) === -1) {
// Car not owned, try to buy it
if (coins >= 20) {
coins -= 20;
storage.coins = coins;
storage.ownedCars.push(2);
car2Txt.setText('Araba 2 (20 coins) - OWNED');
car2Txt.fill = 0x00FF00;
marketCoinsDisplay.setText('Your Coins: ' + coins);
coinsTxt.setText('Coins: ' + coins);
// Auto-select car 2 when purchased
storage.selectedCar = 2;
selectCarTxt.setText('Selected Car: Araba 2');
// Update player car visual immediately
player.removeChildren();
var newCarGraphics = player.attachAsset('playerCar2', {
anchorX: 0.5,
anchorY: 0.5
});
}
} else {
// Car owned, select it
storage.selectedCar = 2;
selectCarTxt.setText('Selected Car: Araba 2');
// Update player car visual immediately
player.removeChildren();
var newCarGraphics = player.attachAsset('playerCar2', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
car3Txt.down = function (x, y, obj) {
if (storage.ownedCars.indexOf(3) === -1) {
// Car not owned, try to buy it
if (coins >= 20) {
coins -= 20;
storage.coins = coins;
storage.ownedCars.push(3);
car3Txt.setText('F1 (20 coins) - OWNED');
car3Txt.fill = 0x00FF00;
marketCoinsDisplay.setText('Your Coins: ' + coins);
coinsTxt.setText('Coins: ' + coins);
}
} else {
// Car owned, select it
storage.selectedCar = 3;
selectCarTxt.setText('Selected Car: F1');
// Update player car visual immediately
player.removeChildren();
var newCarGraphics = player.attachAsset('playerCar3', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
closeMarketBtn.down = function (x, y, obj) {
showingMarket = false;
marketContainer.alpha = 0;
// Show difficulty selection UI when market closes
difficultyTxt.alpha = 1;
easyBtn.alpha = 1;
mediumBtn.alpha = 1;
hardBtn.alpha = 1;
instructionTxt.alpha = 1;
marketBtn.alpha = 1;
};
function startGameWithDifficulty(difficulty) {
currentDifficulty = difficulty;
gameStarted = true;
gameSpeed = difficultySettings[currentDifficulty].initialSpeed;
// Reset coins earned this game
coinsEarned = 0;
// Reset second chance flag
secondChanceUsed = false;
showingSecondChance = false;
secondChanceContainer.alpha = 0;
// Hide difficulty selection UI
difficultyTxt.alpha = 0;
easyBtn.alpha = 0;
mediumBtn.alpha = 0;
hardBtn.alpha = 0;
instructionTxt.alpha = 0;
marketBtn.alpha = 0;
// Hide market UI
showingMarket = false;
marketContainer.alpha = 0;
// Make player fully visible
player.alpha = 1;
// Update speed display
speedTxt.setText('Speed: ' + gameSpeed.toFixed(1) + 'x');
// Show difficulty indicator
var difficultyIndicator = new Text2('Difficulty: ' + currentDifficulty.toUpperCase(), {
size: 50,
fill: currentDifficulty === 'easy' ? 0x00FF00 : currentDifficulty === 'medium' ? 0xFFFF00 : 0xFF0000,
font: "Arial Black"
});
difficultyIndicator.anchor.set(0, 0);
LK.gui.topLeft.addChild(difficultyIndicator);
difficultyIndicator.x = 120;
difficultyIndicator.y = 20;
}
// Touch controls
var isDragging = false;
game.down = function (x, y, obj) {
if (gameStarted) {
isDragging = true;
player.targetX = x;
}
};
game.move = function (x, y, obj) {
if (isDragging && gameStarted) {
// Constrain to lanes
var clampedX = Math.max(lanes[0], Math.min(lanes[lanes.length - 1], x));
player.targetX = clampedX;
}
};
game.up = function (x, y, obj) {
if (gameStarted) {
isDragging = false;
}
};
// Helper functions
function spawnEnemyCar() {
var enemy = new EnemyCar();
var laneIndex = Math.floor(Math.random() * lanes.length);
enemy.x = lanes[laneIndex];
enemy.y = -100;
enemy.speed = 8 + gameSpeed * difficultySettings[currentDifficulty].enemySpeedMultiplier;
// Enable lateral movement for medium and hard difficulties
if (currentDifficulty === 'medium' || currentDifficulty === 'hard') {
enemy.canMoveLaterally = true;
// Random initial lateral movement
enemy.lateralDirection = Math.floor(Math.random() * 3) - 1;
enemy.lateralSpeed = enemy.lateralDirection * (currentDifficulty === 'hard' ? 3 : 2);
enemy.moveTimer = Math.floor(Math.random() * 60); // Random start time
}
enemyCars.push(enemy);
game.addChild(enemy);
}
function spawnRoadLine() {
var line = new RoadLine();
line.x = 2048 / 2;
line.y = -50;
line.speed = 10 + gameSpeed * 2;
roadLines.push(line);
game.addChild(line);
}
function checkNearMiss(enemy) {
if (!enemy.checkedNearMiss) {
var distance = Math.abs(player.x - enemy.x);
var verticalDistance = Math.abs(player.y - enemy.y);
if (distance < 150 && verticalDistance < 200) {
enemy.checkedNearMiss = true;
bonusScore += 10;
totalScore += 10;
// Earn coins for near miss
coinsEarned += 3;
coins += 3;
// Visual effect for near miss
LK.effects.flashObject(enemy, 0xffff00, 200);
LK.getSound('nearMiss').play();
return true;
}
}
return false;
}
function updateScore() {
distanceScore = Math.floor(LK.ticks / 10);
totalScore = distanceScore + bonusScore;
LK.setScore(totalScore);
scoreTxt.setText('Score: ' + totalScore);
// Earn coins based on score (1 coin per 50 score points)
var newCoinsFromScore = Math.floor(totalScore / 50);
if (newCoinsFromScore > coinsEarned) {
var coinsToAdd = newCoinsFromScore - coinsEarned;
coinsEarned = newCoinsFromScore;
coins += coinsToAdd;
}
// Update coins display
coinsTxt.setText('Coins: ' + coins);
}
function createSmokeEffect(x, y) {
for (var i = 0; i < 15; i++) {
var smoke = new SmokeParticle();
smoke.x = x + (Math.random() - 0.5) * 60;
smoke.y = y + (Math.random() - 0.5) * 60;
smokeParticles.push(smoke);
game.addChild(smoke);
}
}
function updateSpeed() {
speedIncreaseTimer++;
var interval = difficultySettings[currentDifficulty].speedIncreaseInterval;
if (speedIncreaseTimer >= interval) {
gameSpeed += difficultySettings[currentDifficulty].speedIncrease;
speedIncreaseTimer = 0;
speedTxt.setText('Speed: ' + gameSpeed.toFixed(1) + 'x');
}
}
// Main game loop
game.update = function () {
if (!gameStarted) {
return; // Don't update game logic until difficulty is selected
}
// Handle crash timer
if (crashed) {
crashTimer++;
// Show second chance offer after 1 second, if not used and player has enough coins
if (crashTimer >= 60 && !showingSecondChance && !secondChanceUsed && coins >= 25) {
showingSecondChance = true;
secondChanceContainer.alpha = 1;
}
// Only proceed to game over if second chance wasn't shown or was declined
if (crashTimer >= 180 && !showingSecondChance) {
// Save coins to storage before game over
storage.coins = coins;
LK.showGameOver();
return;
}
// Continue updating smoke during crash
for (var k = smokeParticles.length - 1; k >= 0; k--) {
var smoke = smokeParticles[k];
if (smoke.life <= 0) {
smoke.destroy();
smokeParticles.splice(k, 1);
}
}
return; // Don't update other game logic during crash
}
updateScore();
updateSpeed();
// Spawn enemy cars
spawnTimer++;
var baseSpawnRate = difficultySettings[currentDifficulty].spawnRateBase;
var speedMultiplier = currentDifficulty === 'hard' ? 15 : 10; // More aggressive scaling for hard mode
var spawnRate = Math.max(baseSpawnRate - gameSpeed * speedMultiplier, currentDifficulty === 'hard' ? 10 : 20); // Lower minimum for hard mode
if (spawnTimer >= spawnRate) {
spawnEnemyCar();
spawnTimer = 0;
}
// Spawn road lines
roadLineTimer++;
if (roadLineTimer >= 20) {
spawnRoadLine();
roadLineTimer = 0;
}
// Update and check enemy cars
for (var i = enemyCars.length - 1; i >= 0; i--) {
var enemy = enemyCars[i];
// Check for collision
if (enemy.intersects(player) && !crashed) {
// Set crash state
crashed = true;
crashTimer = 0;
// Mark both cars as crashed
enemy.isCrashed = true;
// Create explosion effect on crashed enemy car
tween(enemy, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Car will fade out completely
}
});
// Create explosion effect on player car
tween(player, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0.3
}, {
duration: 800,
easing: tween.easeOut
});
// Create smoke effect at crash location
createSmokeEffect(player.x, player.y);
createSmokeEffect(enemy.x, enemy.y);
// Flash screen and play sound
LK.effects.flashScreen(0xff0000, 1000);
LK.getSound('crash').play();
// Stop player movement
player.targetX = player.x;
}
// Don't update enemy cars if crashed
if (!crashed) {
// Check for near miss
checkNearMiss(enemy);
}
// Remove off-screen enemies
if (enemy.y > 2800) {
enemy.destroy();
enemyCars.splice(i, 1);
}
}
// Update and clean up road lines
for (var j = roadLines.length - 1; j >= 0; j--) {
var line = roadLines[j];
if (line.y > 2800) {
line.destroy();
roadLines.splice(j, 1);
}
}
// Update and clean up smoke particles (only when not crashed)
if (!crashed) {
for (var k = smokeParticles.length - 1; k >= 0; k--) {
var smoke = smokeParticles[k];
if (smoke.life <= 0) {
smoke.destroy();
smokeParticles.splice(k, 1);
}
}
}
};
üstten çekilmiş mavi araba. In-Game asset. 2d. High contrast. No shadows
yeşil renk üstten çekilmiş araba resmi. In-Game asset. 2d. High contrast. No shadows
pembe renk araba üstten çekilmiş. In-Game asset. 2d. High contrast. No shadows
duman. In-Game asset. 2d. High contrast. No shadows
formula 1 arabası üsten çekilmiş. In-Game asset. 2d. High contrast. No shadows
lamborghini üstten çekilmiş. In-Game asset. 2d. High contrast. No shadows