/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bush = Container.expand(function () {
var self = Container.call(this);
var bushGraphics = self.attachAsset('bush', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 6;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Car = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.targetX = 0;
self.lane = 1; // 0=left, 1=center, 2=right
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
coinGraphics.rotation += 0.1;
};
return self;
});
var EnemyCar = Container.expand(function () {
var self = Container.call(this);
var carTypes = ['enemyCar1', 'enemyCar2', 'enemyCar3'];
var randomType = carTypes[Math.floor(Math.random() * carTypes.length)];
var carGraphics = self.attachAsset(randomType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var FuelTank = Container.expand(function () {
var self = Container.call(this);
var fuelTankGraphics = self.attachAsset('fuelTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
fuelTankGraphics.rotation += 0.05;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Random power-up type: 0=speed boost, 1=shield
self.powerType = Math.floor(Math.random() * 2);
var powerUpGraphics;
if (self.powerType === 0) {
// Speed boost power-up (blue)
powerUpGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
powerUpGraphics.tint = 0x0099ff; // Blue tint
} else {
// Shield power-up (purple)
powerUpGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
powerUpGraphics.tint = 0x9900ff; // Purple tint
}
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
powerUpGraphics.rotation += 0.15;
// Pulsing effect
powerUpGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.2) * 0.3;
powerUpGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.2) * 0.3;
};
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 = 6;
self.update = function () {
self.y += self.speed;
};
return self;
});
var SpilledBox = Container.expand(function () {
var self = Container.call(this);
var boxGraphics = self.attachAsset('spilledBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var SpilledFuel = Container.expand(function () {
var self = Container.call(this);
var spillGraphics = self.attachAsset('spilledFuel', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Tree = Container.expand(function () {
var self = Container.call(this);
var treeGraphics = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 6;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
// Game variables
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var playerCar;
var enemyCars = [];
var coins = [];
var roadLines = [];
var trees = [];
var bushes = [];
var gameSpeed = 6;
var lanes = [2048 / 4, 2048 / 2, 3 * 2048 / 4]; // Three lanes
var spawnTimer = 0;
var coinSpawnTimer = 0;
var roadLineSpawnTimer = 0;
var treeSpawnTimer = 0;
var bushSpawnTimer = 0;
var distanceScore = 0;
var fuelTanks = [];
var fuelTankSpawnTimer = 0;
var currentFuel = 100;
var maxFuel = 100;
var fuelConsumptionRate = 0.1;
var dragActive = false;
var showingLeaderboard = false;
var leaderboardContainer;
var leaderboardScores = storage.leaderboard || [];
var gameStartTime = Date.now();
var gameTime = 0;
var spilledFuels = [];
var spilledFuelSpawnTimer = 0;
var spilledBoxes = [];
var spilledBoxSpawnTimer = 0;
var isSliding = false;
var slideDirection = 0;
var slideTimer = 0;
var powerUps = [];
var powerUpSpawnTimer = 0;
var hasShield = false;
var shieldTimer = 0;
var speedBoostTimer = 0;
var hasSpeedBoost = false;
var comboMultiplier = 1;
var comboTimer = 0;
var lastCollectTime = 0;
// Create score display using asset
var scoreDisplay = LK.getAsset('Score', {
anchorX: 0.5,
anchorY: 0
});
LK.gui.top.addChild(scoreDisplay);
// Create score text display
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = scoreDisplay.x + 60; // Position next to score image
scoreTxt.y = scoreDisplay.y;
LK.gui.top.addChild(scoreTxt);
// Create score button to show/hide score
var scoreButton = new Text2('📊', {
size: 80,
fill: 0x00FF00
});
scoreButton.anchor.set(0.5, 0);
scoreButton.x = 2048 - 200;
scoreButton.y = 20;
LK.gui.top.addChild(scoreButton);
// Create leaderboard button
var leaderboardButton = new Text2('🏆', {
size: 80,
fill: 0xFFD700
});
leaderboardButton.anchor.set(0.5, 0);
leaderboardButton.x = 2048 - 100;
leaderboardButton.y = 20;
LK.gui.top.addChild(leaderboardButton);
// Score visibility state
var showScore = true;
// Create distance display
var distanceTxt = new Text2('Distance: 0m', {
size: 60,
fill: 0xFFFFFF
});
distanceTxt.anchor.set(0.5, 0);
distanceTxt.y = 100;
LK.gui.top.addChild(distanceTxt);
// Create speedometer display
var speedometerTxt = new Text2('Speed: 0 km/h', {
size: 60,
fill: 0xFFFFFF
});
speedometerTxt.anchor.set(0.5, 0);
speedometerTxt.y = 170;
LK.gui.top.addChild(speedometerTxt);
// Create fuel display
var fuelTxt = new Text2('Fuel: 100%', {
size: 60,
fill: 0x00FF00
});
fuelTxt.anchor.set(0.5, 0);
fuelTxt.y = 240;
LK.gui.top.addChild(fuelTxt);
// Create time display
var timeTxt = new Text2('Time: 0:00', {
size: 60,
fill: 0xFFFFFF
});
timeTxt.anchor.set(0.5, 0);
timeTxt.y = 310;
LK.gui.top.addChild(timeTxt);
// Create shield indicator
var shieldTxt = new Text2('', {
size: 60,
fill: 0x9900ff
});
shieldTxt.anchor.set(0.5, 0);
shieldTxt.y = 380;
LK.gui.top.addChild(shieldTxt);
// Create speed boost indicator
var speedBoostTxt = new Text2('', {
size: 60,
fill: 0x0099ff
});
speedBoostTxt.anchor.set(0.5, 0);
speedBoostTxt.y = 450;
LK.gui.top.addChild(speedBoostTxt);
// Create combo multiplier display
var comboTxt = new Text2('', {
size: 70,
fill: 0xFFD700
});
comboTxt.anchor.set(0.5, 0);
comboTxt.y = 520;
LK.gui.top.addChild(comboTxt);
// Create left arrow button
var leftArrow = LK.getAsset('Oktusu', {
width: 300,
height: 300,
anchorX: 0.5,
anchorY: 0.5
});
leftArrow.x = 200;
leftArrow.y = 2732 - 200;
game.addChild(leftArrow);
// Create left arrow text
var leftArrowTxt = new Text2('←', {
size: 80,
fill: 0xFFFFFF
});
leftArrowTxt.anchor.set(0.5, 0.5);
leftArrowTxt.x = leftArrow.x;
leftArrowTxt.y = leftArrow.y;
game.addChild(leftArrowTxt);
// Create right arrow button
var rightArrow = LK.getAsset('Oktusu', {
width: 300,
height: 300,
anchorX: 0.5,
anchorY: 0.5
});
rightArrow.x = 2048 - 200;
rightArrow.y = 2732 - 200;
game.addChild(rightArrow);
// Create right arrow text
var rightArrowTxt = new Text2('→', {
size: 80,
fill: 0xFFFFFF
});
rightArrowTxt.anchor.set(0.5, 0.5);
rightArrowTxt.x = rightArrow.x;
rightArrowTxt.y = rightArrow.y;
game.addChild(rightArrowTxt);
// Gas pedal variables (keeping for boost system)
var isGasPedalPressed = false;
var boostMultiplier = 1.0;
// Function to show leaderboard
function showLeaderboard() {
if (showingLeaderboard) return;
showingLeaderboard = true;
leaderboardContainer = new Container();
game.addChild(leaderboardContainer);
// Semi-transparent background
var background = LK.getAsset('highway', {
width: 1800,
height: 2200,
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
background.alpha = 0.8;
background.tint = 0x000000;
leaderboardContainer.addChild(background);
// Title
var titleText = new Text2('🏆 TOP SCORES 🏆', {
size: 100,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 400;
leaderboardContainer.addChild(titleText);
// Display top 10 scores
var sortedScores = leaderboardScores.slice().sort(function (a, b) {
return b - a;
});
for (var i = 0; i < Math.min(10, sortedScores.length); i++) {
var rankText = new Text2(i + 1 + '. ' + sortedScores[i] + ' points', {
size: 80,
fill: i < 3 ? 0xFFD700 : 0xFFFFFF
});
rankText.anchor.set(0.5, 0);
rankText.x = 2048 / 2;
rankText.y = 600 + i * 120;
leaderboardContainer.addChild(rankText);
}
// Close button
var closeButton = new Text2('❌ CLOSE', {
size: 80,
fill: 0xFF4444
});
closeButton.anchor.set(0.5, 0);
closeButton.x = 2048 / 2;
closeButton.y = 2200;
leaderboardContainer.addChild(closeButton);
}
// Function to hide leaderboard
function hideLeaderboard() {
if (!showingLeaderboard) return;
showingLeaderboard = false;
if (leaderboardContainer) {
leaderboardContainer.destroy();
leaderboardContainer = null;
}
}
// Function to save score to leaderboard
function saveScore(score) {
leaderboardScores.push(score);
leaderboardScores.sort(function (a, b) {
return b - a;
});
// Keep only top 20 scores
if (leaderboardScores.length > 20) {
leaderboardScores = leaderboardScores.slice(0, 20);
}
storage.leaderboard = leaderboardScores;
}
// Create player car
playerCar = game.addChild(new Car());
playerCar.x = lanes[1]; // Start in middle lane
playerCar.y = 2732 - 300;
playerCar.targetX = playerCar.x;
// Touch controls
game.down = function (x, y, obj) {
// Check if leaderboard is showing and handle close button
if (showingLeaderboard) {
var closeButtonBounds = {
left: 2048 / 2 - 150,
right: 2048 / 2 + 150,
top: 2200 - 50,
bottom: 2200 + 50
};
if (x >= closeButtonBounds.left && x <= closeButtonBounds.right && y >= closeButtonBounds.top && y <= closeButtonBounds.bottom) {
hideLeaderboard();
return;
}
// Ignore other touches when leaderboard is showing
return;
}
// Check if score button is pressed
var scoreBounds = {
left: scoreButton.x - 50,
right: scoreButton.x + 50,
top: scoreButton.y,
bottom: scoreButton.y + 80
};
if (x >= scoreBounds.left && x <= scoreBounds.right && y >= scoreBounds.top && y <= scoreBounds.bottom) {
showScore = !showScore;
if (showScore) {
scoreDisplay.alpha = 1;
scoreTxt.alpha = 1;
} else {
scoreDisplay.alpha = 0;
scoreTxt.alpha = 0;
}
return;
}
// Check if leaderboard button is pressed
var leaderboardBounds = {
left: leaderboardButton.x - 50,
right: leaderboardButton.x + 50,
top: leaderboardButton.y,
bottom: leaderboardButton.y + 80
};
if (x >= leaderboardBounds.left && x <= leaderboardBounds.right && y >= leaderboardBounds.top && y <= leaderboardBounds.bottom) {
showLeaderboard();
return;
}
// Check if left arrow is pressed
var leftArrowBounds = {
left: leftArrow.x - 150,
right: leftArrow.x + 150,
top: leftArrow.y - 150,
bottom: leftArrow.y + 150
};
if (x >= leftArrowBounds.left && x <= leftArrowBounds.right && y >= leftArrowBounds.top && y <= leftArrowBounds.bottom) {
// Move car to left lane
if (playerCar.lane > 0) {
playerCar.lane--;
playerCar.targetX = lanes[playerCar.lane];
}
leftArrow.tint = 0xffff00; // Yellow when pressed
}
// Check if right arrow is pressed
var rightArrowBounds = {
left: rightArrow.x - 150,
right: rightArrow.x + 150,
top: rightArrow.y - 150,
bottom: rightArrow.y + 150
};
if (x >= rightArrowBounds.left && x <= rightArrowBounds.right && y >= rightArrowBounds.top && y <= rightArrowBounds.bottom) {
// Move car to right lane
if (playerCar.lane < 2) {
playerCar.lane++;
playerCar.targetX = lanes[playerCar.lane];
}
rightArrow.tint = 0xffff00; // Yellow when pressed
}
};
game.move = function (x, y, obj) {
// Don't allow movement when leaderboard is showing
if (showingLeaderboard) return;
var leftArrowBounds = {
left: leftArrow.x - 150,
right: leftArrow.x + 150,
top: leftArrow.y - 150,
bottom: leftArrow.y + 150
};
var rightArrowBounds = {
left: rightArrow.x - 150,
right: rightArrow.x + 150,
top: rightArrow.y - 150,
bottom: rightArrow.y + 150
};
};
game.up = function (x, y, obj) {
// Don't process touches when leaderboard is showing
if (showingLeaderboard) return;
// Reset arrow button colors
leftArrow.tint = 0xffffff;
rightArrow.tint = 0xffffff;
};
// Main game loop
game.update = function () {
// Don't update game when leaderboard is showing
if (showingLeaderboard) return;
// Update game time
gameTime = Math.floor((Date.now() - gameStartTime) / 1000);
var minutes = Math.floor(gameTime / 60);
var seconds = gameTime % 60;
var timeString = minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
timeTxt.setText('Time: ' + timeString);
// Update power-up timers
if (hasShield) {
shieldTimer--;
shieldTxt.setText('🛡️ Shield: ' + Math.ceil(shieldTimer / 60) + 's');
if (shieldTimer <= 0) {
hasShield = false;
shieldTxt.setText('');
// Remove shield visual effect
playerCar.tint = 0xffffff;
}
} else {
shieldTxt.setText('');
}
if (hasSpeedBoost) {
speedBoostTimer--;
speedBoostTxt.setText('⚡ Boost: ' + Math.ceil(speedBoostTimer / 60) + 's');
if (speedBoostTimer <= 0) {
hasSpeedBoost = false;
speedBoostTxt.setText('');
}
} else {
speedBoostTxt.setText('');
}
// Update combo system
if (comboTimer > 0) {
comboTimer--;
comboTxt.setText('Combo x' + comboMultiplier);
if (comboTimer <= 0) {
comboMultiplier = 1;
comboTxt.setText('');
}
} else {
comboTxt.setText('');
}
// Reset combo if too much time passed since last collect
if (Date.now() - lastCollectTime > 3000) {
comboMultiplier = 1;
comboTimer = 0;
}
// Handle sliding mechanics
if (isSliding) {
slideTimer--;
// Apply sliding movement with tween for smooth effect
var slideAmount = slideDirection * 8;
playerCar.x += slideAmount;
// Constrain car to stay within road bounds
playerCar.x = Math.max(lanes[0] - 100, Math.min(lanes[2] + 100, playerCar.x));
// Add visual sliding effect
tween(playerCar, {
rotation: slideDirection * 0.3
}, {
duration: 100,
easing: tween.easeOut
});
if (slideTimer <= 0) {
isSliding = false;
slideDirection = 0;
// Return car to normal rotation
tween(playerCar, {
rotation: 0
}, {
duration: 500,
easing: tween.easeOut
});
// Snap back to nearest lane
var closestLane = 1;
var minDistance = Math.abs(playerCar.x - lanes[1]);
for (var i = 0; i < lanes.length; i++) {
var distance = Math.abs(playerCar.x - lanes[i]);
if (distance < minDistance) {
minDistance = distance;
closestLane = i;
}
}
playerCar.lane = closestLane;
playerCar.targetX = lanes[closestLane];
}
} else {
// Normal smooth car movement to target lane
var moveSpeed = 15;
if (Math.abs(playerCar.x - playerCar.targetX) > moveSpeed) {
if (playerCar.x < playerCar.targetX) {
playerCar.x += moveSpeed;
} else {
playerCar.x -= moveSpeed;
}
} else {
playerCar.x = playerCar.targetX;
}
}
// Increase game speed over time
gameSpeed += 0.002;
// Player car accelerates 3 units per second (3/60 = 0.05 per frame at 60fps)
playerCar.speed += 0.05;
// Calculate base boost from speed boost power-up only
var targetBoost = 1.0;
if (hasSpeedBoost) {
targetBoost *= 1.5; // Additional 50% speed from power-up
}
// Apply boost with smooth transition
if (boostMultiplier < targetBoost) {
// Smoothly increase speed
tween(this, {
boostMultiplier: targetBoost
}, {
duration: 1000,
easing: tween.easeOut
});
} else if (boostMultiplier > targetBoost) {
// Smoothly decrease speed
tween(this, {
boostMultiplier: targetBoost
}, {
duration: 500,
easing: tween.easeOut
});
}
// Limit effective speed to prevent exceeding 150 km/h
var maxEffectiveSpeed = 15; // 15 * 10 = 150 km/h display limit
var effectiveSpeed = Math.min(gameSpeed * boostMultiplier, maxEffectiveSpeed);
var speedLimitRatio = effectiveSpeed / (gameSpeed * boostMultiplier);
// Update distance score
distanceScore += effectiveSpeed * 0.1;
distanceTxt.setText('Distance: ' + Math.floor(distanceScore) + 'm');
// Update speedometer display
var currentSpeed = Math.floor(gameSpeed * boostMultiplier * 10); // Convert to km/h scale
// Limit maximum displayed speed to 150 km/h
currentSpeed = Math.min(currentSpeed, 150);
speedometerTxt.setText('Speed: ' + currentSpeed + ' km/h');
// Spawn road lines
roadLineSpawnTimer++;
if (roadLineSpawnTimer >= 20) {
roadLineSpawnTimer = 0;
for (var i = 0; i < 2; i++) {
var roadLine = new RoadLine();
roadLine.x = lanes[0] + i * (lanes[2] - lanes[0]);
roadLine.y = -50;
roadLine.speed = effectiveSpeed;
roadLines.push(roadLine);
game.addChild(roadLine);
}
}
// Spawn enemy cars
spawnTimer++;
// Increase spawn rate based on score and distance
var spawnRateBonus = Math.floor(LK.getScore() / 100) + Math.floor(distanceScore / 1000);
var baseSpawnRate = Math.max(20, 90 - Math.floor(gameSpeed) - spawnRateBonus);
if (spawnTimer >= baseSpawnRate) {
spawnTimer = 0;
var enemyCar = new EnemyCar();
var randomLane = Math.floor(Math.random() * 3);
enemyCar.x = lanes[randomLane];
enemyCar.y = -100;
enemyCar.speed = (gameSpeed + Math.random() * 3) * boostMultiplier;
enemyCar.lastY = enemyCar.y;
enemyCar.lastIntersecting = enemyCar.intersects(playerCar);
enemyCars.push(enemyCar);
game.addChild(enemyCar);
}
// Spawn trees
treeSpawnTimer++;
if (treeSpawnTimer >= 60) {
treeSpawnTimer = 0;
// Spawn trees on left side
if (Math.random() < 0.8) {
var leftTree = new Tree();
leftTree.x = Math.random() * (lanes[0] - 100); // Random position on left side
leftTree.y = -100;
leftTree.speed = effectiveSpeed;
trees.push(leftTree);
game.addChild(leftTree);
}
// Spawn trees on right side
if (Math.random() < 0.8) {
var rightTree = new Tree();
rightTree.x = lanes[2] + 100 + Math.random() * (2048 - lanes[2] - 200); // Random position on right side
rightTree.y = -100;
rightTree.speed = effectiveSpeed;
trees.push(rightTree);
game.addChild(rightTree);
}
}
// Spawn bushes
bushSpawnTimer++;
if (bushSpawnTimer >= 40) {
bushSpawnTimer = 0;
// Spawn bushes on left side between trees
if (Math.random() < 0.6) {
var leftBush = new Bush();
leftBush.x = Math.random() * (lanes[0] - 50); // Random position on left side
leftBush.y = -50;
leftBush.speed = effectiveSpeed;
bushes.push(leftBush);
game.addChild(leftBush);
}
// Spawn bushes on right side between trees
if (Math.random() < 0.6) {
var rightBush = new Bush();
rightBush.x = lanes[2] + 50 + Math.random() * (2048 - lanes[2] - 150); // Random position on right side
rightBush.y = -50;
rightBush.speed = effectiveSpeed;
bushes.push(rightBush);
game.addChild(rightBush);
}
}
// Spawn coins
coinSpawnTimer++;
if (coinSpawnTimer >= 120) {
coinSpawnTimer = 0;
if (Math.random() < 0.7) {
var coin = new Coin();
var randomLane = Math.floor(Math.random() * 3);
coin.x = lanes[randomLane];
coin.y = -50;
coin.speed = effectiveSpeed;
coin.lastY = coin.y;
coin.lastIntersecting = coin.intersects(playerCar);
coins.push(coin);
game.addChild(coin);
}
}
// Spawn fuel tanks
fuelTankSpawnTimer++;
if (fuelTankSpawnTimer >= 150) {
fuelTankSpawnTimer = 0;
if (Math.random() < 0.7) {
var fuelTank = new FuelTank();
var randomLane = Math.floor(Math.random() * 3);
fuelTank.x = lanes[randomLane];
fuelTank.y = -50;
fuelTank.speed = effectiveSpeed;
fuelTank.lastY = fuelTank.y;
fuelTank.lastIntersecting = fuelTank.intersects(playerCar);
fuelTanks.push(fuelTank);
game.addChild(fuelTank);
}
}
// Spawn spilled fuel
spilledFuelSpawnTimer++;
if (spilledFuelSpawnTimer >= 200) {
spilledFuelSpawnTimer = 0;
if (Math.random() < 0.4) {
var spilledFuel = new SpilledFuel();
var randomLane = Math.floor(Math.random() * 3);
spilledFuel.x = lanes[randomLane];
spilledFuel.y = -50;
spilledFuel.speed = effectiveSpeed;
spilledFuel.lastY = spilledFuel.y;
spilledFuel.lastIntersecting = spilledFuel.intersects(playerCar);
spilledFuels.push(spilledFuel);
game.addChild(spilledFuel);
}
}
// Spawn spilled boxes
spilledBoxSpawnTimer++;
if (spilledBoxSpawnTimer >= 180) {
spilledBoxSpawnTimer = 0;
if (Math.random() < 0.5) {
var spilledBox = new SpilledBox();
var randomLane = Math.floor(Math.random() * 3);
spilledBox.x = lanes[randomLane];
spilledBox.y = -50;
spilledBox.speed = effectiveSpeed;
spilledBox.lastY = spilledBox.y;
spilledBox.lastIntersecting = spilledBox.intersects(playerCar);
spilledBoxes.push(spilledBox);
game.addChild(spilledBox);
}
}
// Spawn power-ups
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= 300) {
powerUpSpawnTimer = 0;
if (Math.random() < 0.6) {
var powerUp = new PowerUp();
var randomLane = Math.floor(Math.random() * 3);
powerUp.x = lanes[randomLane];
powerUp.y = -50;
powerUp.speed = effectiveSpeed;
powerUp.lastY = powerUp.y;
powerUp.lastIntersecting = powerUp.intersects(playerCar);
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
// Update and check road lines
for (var i = roadLines.length - 1; i >= 0; i--) {
var roadLine = roadLines[i];
roadLine.speed = effectiveSpeed;
if (roadLine.lastY === undefined) roadLine.lastY = roadLine.y;
// Remove road lines that go off screen
if (roadLine.lastY <= 2732 + 50 && roadLine.y > 2732 + 50) {
roadLine.destroy();
roadLines.splice(i, 1);
continue;
}
roadLine.lastY = roadLine.y;
}
// Update and check enemy cars
for (var i = enemyCars.length - 1; i >= 0; i--) {
var enemyCar = enemyCars[i];
// Increase enemy speed based on score and distance
var speedBonus = Math.floor(LK.getScore() / 50) + Math.floor(distanceScore / 500);
var enemyBaseSpeed = (gameSpeed + 2 + speedBonus) * boostMultiplier;
enemyCar.speed = Math.min(enemyBaseSpeed, maxEffectiveSpeed + 2);
// Remove cars that go off screen
if (enemyCar.lastY <= 2732 + 100 && enemyCar.y > 2732 + 100) {
enemyCar.destroy();
enemyCars.splice(i, 1);
continue;
}
// Check collision with player
var currentIntersecting = enemyCar.intersects(playerCar);
if (!enemyCar.lastIntersecting && currentIntersecting) {
if (hasShield) {
// Shield protects from collision
hasShield = false;
shieldTimer = 0;
shieldTxt.setText('');
playerCar.tint = 0xffffff; // Remove shield tint
LK.effects.flashObject(playerCar, 0xffff00, 1000); // Yellow flash for shield break
LK.effects.flashObject(enemyCar, 0xffff00, 500);
// Push enemy car away
enemyCar.y += 200;
} else {
// Collision detected - game over
saveScore(LK.getScore());
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
enemyCar.lastY = enemyCar.y;
enemyCar.lastIntersecting = currentIntersecting;
}
// Update and check trees
for (var i = trees.length - 1; i >= 0; i--) {
var tree = trees[i];
tree.speed = effectiveSpeed;
if (tree.lastY === undefined) tree.lastY = tree.y;
// Remove trees that go off screen
if (tree.lastY <= 2732 + 100 && tree.y > 2732 + 100) {
tree.destroy();
trees.splice(i, 1);
continue;
}
tree.lastY = tree.y;
}
// Update and check bushes
for (var i = bushes.length - 1; i >= 0; i--) {
var bush = bushes[i];
bush.speed = effectiveSpeed;
if (bush.lastY === undefined) bush.lastY = bush.y;
// Remove bushes that go off screen
if (bush.lastY <= 2732 + 50 && bush.y > 2732 + 50) {
bush.destroy();
bushes.splice(i, 1);
continue;
}
bush.lastY = bush.y;
}
// Update and check coins
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
coin.speed = effectiveSpeed;
// Remove coins that go off screen
if (coin.lastY <= 2732 + 50 && coin.y > 2732 + 50) {
coin.destroy();
coins.splice(i, 1);
continue;
}
// Check collection by player
var currentIntersecting = coin.intersects(playerCar);
if (!coin.lastIntersecting && currentIntersecting) {
// Coin collected
lastCollectTime = Date.now();
comboTimer = 300; // 5 seconds at 60fps
var pointsEarned = 10 * comboMultiplier;
LK.setScore(LK.getScore() + pointsEarned);
comboMultiplier = Math.min(comboMultiplier + 1, 5); // Max combo x5
scoreTxt.setText(LK.getScore().toString());
LK.getSound('collectCoin').play();
coin.destroy();
coins.splice(i, 1);
continue;
}
coin.lastY = coin.y;
coin.lastIntersecting = currentIntersecting;
}
// Update fuel system
currentFuel -= fuelConsumptionRate * boostMultiplier;
if (currentFuel <= 0) {
currentFuel = 0;
// Game over due to no fuel
saveScore(LK.getScore());
LK.effects.flashScreen(0xff8800, 1000);
LK.showGameOver();
return;
}
// Update fuel display with color coding
var fuelPercentage = Math.floor(currentFuel / maxFuel * 100);
fuelTxt.setText('Fuel: ' + fuelPercentage + '%');
if (fuelPercentage > 50) {
fuelTxt.fill = 0x00FF00; // Green
} else if (fuelPercentage > 25) {
fuelTxt.fill = 0xFFFF00; // Yellow
} else {
fuelTxt.fill = 0xFF0000; // Red
}
// Update and check fuel tanks
for (var i = fuelTanks.length - 1; i >= 0; i--) {
var fuelTank = fuelTanks[i];
fuelTank.speed = effectiveSpeed;
// Remove fuel tanks that go off screen
if (fuelTank.lastY <= 2732 + 50 && fuelTank.y > 2732 + 50) {
fuelTank.destroy();
fuelTanks.splice(i, 1);
continue;
}
// Check collection by player
var currentIntersecting = fuelTank.intersects(playerCar);
if (!fuelTank.lastIntersecting && currentIntersecting) {
// Fuel tank collected
lastCollectTime = Date.now();
comboTimer = 300; // 5 seconds at 60fps
currentFuel = Math.min(currentFuel + 30, maxFuel);
var pointsEarned = 5 * comboMultiplier;
LK.setScore(LK.getScore() + pointsEarned);
comboMultiplier = Math.min(comboMultiplier + 1, 5); // Max combo x5
scoreTxt.setText(LK.getScore().toString());
LK.getSound('collectCoin').play();
fuelTank.destroy();
fuelTanks.splice(i, 1);
continue;
}
fuelTank.lastY = fuelTank.y;
fuelTank.lastIntersecting = currentIntersecting;
}
// Update and check spilled fuel
for (var i = spilledFuels.length - 1; i >= 0; i--) {
var spilledFuel = spilledFuels[i];
spilledFuel.speed = effectiveSpeed;
// Remove spilled fuel that goes off screen
if (spilledFuel.lastY <= 2732 + 50 && spilledFuel.y > 2732 + 50) {
spilledFuel.destroy();
spilledFuels.splice(i, 1);
continue;
}
// Check collision with player
var currentIntersecting = spilledFuel.intersects(playerCar);
if (!spilledFuel.lastIntersecting && currentIntersecting && !isSliding) {
// Spilled fuel collision - make car slide
isSliding = true;
slideDirection = (Math.random() - 0.5) * 2; // Random slide direction
slideTimer = 90; // Slide for 1.5 seconds at 60fps
// Visual effect for hitting spilled fuel
LK.effects.flashObject(playerCar, 0x8B4513, 500);
// Add spinning rotation effect
tween(playerCar, {
rotation: playerCar.rotation + Math.PI * 4 // Spin 2 full rotations
}, {
duration: 1500,
easing: tween.easeOut
});
}
spilledFuel.lastY = spilledFuel.y;
spilledFuel.lastIntersecting = currentIntersecting;
}
// Update and check spilled boxes
for (var i = spilledBoxes.length - 1; i >= 0; i--) {
var spilledBox = spilledBoxes[i];
spilledBox.speed = effectiveSpeed;
// Remove spilled boxes that go off screen
if (spilledBox.lastY <= 2732 + 50 && spilledBox.y > 2732 + 50) {
spilledBox.destroy();
spilledBoxes.splice(i, 1);
continue;
}
// Check collision with player
var currentIntersecting = spilledBox.intersects(playerCar);
if (!spilledBox.lastIntersecting && currentIntersecting) {
if (hasShield) {
// Shield protects from collision
hasShield = false;
shieldTimer = 0;
shieldTxt.setText('');
playerCar.tint = 0xffffff; // Remove shield tint
LK.effects.flashObject(playerCar, 0xffff00, 1000); // Yellow flash for shield break
// Destroy the box
spilledBox.destroy();
spilledBoxes.splice(i, 1);
continue;
} else {
// Spilled box collision - game over
saveScore(LK.getScore());
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
spilledBox.lastY = spilledBox.y;
spilledBox.lastIntersecting = currentIntersecting;
}
// Update and check power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
powerUp.speed = effectiveSpeed;
// Remove power-ups that go off screen
if (powerUp.lastY <= 2732 + 50 && powerUp.y > 2732 + 50) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check collection by player
var currentIntersecting = powerUp.intersects(playerCar);
if (!powerUp.lastIntersecting && currentIntersecting) {
// Power-up collected
lastCollectTime = Date.now();
comboTimer = 300; // 5 seconds at 60fps
if (powerUp.powerType === 0) {
// Speed boost power-up
hasSpeedBoost = true;
speedBoostTimer = 600; // 10 seconds at 60fps
LK.effects.flashObject(playerCar, 0x0099ff, 500);
} else {
// Shield power-up
hasShield = true;
shieldTimer = 900; // 15 seconds at 60fps
playerCar.tint = 0x9900ff; // Purple tint for shield
LK.effects.flashObject(playerCar, 0x9900ff, 500);
}
var pointsEarned = 20 * comboMultiplier;
LK.setScore(LK.getScore() + pointsEarned);
comboMultiplier = Math.min(comboMultiplier + 1, 5); // Max combo x5
scoreTxt.setText(LK.getScore().toString());
LK.getSound('collectCoin').play();
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
powerUp.lastY = powerUp.y;
powerUp.lastIntersecting = currentIntersecting;
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bush = Container.expand(function () {
var self = Container.call(this);
var bushGraphics = self.attachAsset('bush', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 6;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Car = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.targetX = 0;
self.lane = 1; // 0=left, 1=center, 2=right
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
coinGraphics.rotation += 0.1;
};
return self;
});
var EnemyCar = Container.expand(function () {
var self = Container.call(this);
var carTypes = ['enemyCar1', 'enemyCar2', 'enemyCar3'];
var randomType = carTypes[Math.floor(Math.random() * carTypes.length)];
var carGraphics = self.attachAsset(randomType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var FuelTank = Container.expand(function () {
var self = Container.call(this);
var fuelTankGraphics = self.attachAsset('fuelTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
fuelTankGraphics.rotation += 0.05;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Random power-up type: 0=speed boost, 1=shield
self.powerType = Math.floor(Math.random() * 2);
var powerUpGraphics;
if (self.powerType === 0) {
// Speed boost power-up (blue)
powerUpGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
powerUpGraphics.tint = 0x0099ff; // Blue tint
} else {
// Shield power-up (purple)
powerUpGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
powerUpGraphics.tint = 0x9900ff; // Purple tint
}
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
powerUpGraphics.rotation += 0.15;
// Pulsing effect
powerUpGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.2) * 0.3;
powerUpGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.2) * 0.3;
};
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 = 6;
self.update = function () {
self.y += self.speed;
};
return self;
});
var SpilledBox = Container.expand(function () {
var self = Container.call(this);
var boxGraphics = self.attachAsset('spilledBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var SpilledFuel = Container.expand(function () {
var self = Container.call(this);
var spillGraphics = self.attachAsset('spilledFuel', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Tree = Container.expand(function () {
var self = Container.call(this);
var treeGraphics = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 6;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
// Game variables
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var playerCar;
var enemyCars = [];
var coins = [];
var roadLines = [];
var trees = [];
var bushes = [];
var gameSpeed = 6;
var lanes = [2048 / 4, 2048 / 2, 3 * 2048 / 4]; // Three lanes
var spawnTimer = 0;
var coinSpawnTimer = 0;
var roadLineSpawnTimer = 0;
var treeSpawnTimer = 0;
var bushSpawnTimer = 0;
var distanceScore = 0;
var fuelTanks = [];
var fuelTankSpawnTimer = 0;
var currentFuel = 100;
var maxFuel = 100;
var fuelConsumptionRate = 0.1;
var dragActive = false;
var showingLeaderboard = false;
var leaderboardContainer;
var leaderboardScores = storage.leaderboard || [];
var gameStartTime = Date.now();
var gameTime = 0;
var spilledFuels = [];
var spilledFuelSpawnTimer = 0;
var spilledBoxes = [];
var spilledBoxSpawnTimer = 0;
var isSliding = false;
var slideDirection = 0;
var slideTimer = 0;
var powerUps = [];
var powerUpSpawnTimer = 0;
var hasShield = false;
var shieldTimer = 0;
var speedBoostTimer = 0;
var hasSpeedBoost = false;
var comboMultiplier = 1;
var comboTimer = 0;
var lastCollectTime = 0;
// Create score display using asset
var scoreDisplay = LK.getAsset('Score', {
anchorX: 0.5,
anchorY: 0
});
LK.gui.top.addChild(scoreDisplay);
// Create score text display
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = scoreDisplay.x + 60; // Position next to score image
scoreTxt.y = scoreDisplay.y;
LK.gui.top.addChild(scoreTxt);
// Create score button to show/hide score
var scoreButton = new Text2('📊', {
size: 80,
fill: 0x00FF00
});
scoreButton.anchor.set(0.5, 0);
scoreButton.x = 2048 - 200;
scoreButton.y = 20;
LK.gui.top.addChild(scoreButton);
// Create leaderboard button
var leaderboardButton = new Text2('🏆', {
size: 80,
fill: 0xFFD700
});
leaderboardButton.anchor.set(0.5, 0);
leaderboardButton.x = 2048 - 100;
leaderboardButton.y = 20;
LK.gui.top.addChild(leaderboardButton);
// Score visibility state
var showScore = true;
// Create distance display
var distanceTxt = new Text2('Distance: 0m', {
size: 60,
fill: 0xFFFFFF
});
distanceTxt.anchor.set(0.5, 0);
distanceTxt.y = 100;
LK.gui.top.addChild(distanceTxt);
// Create speedometer display
var speedometerTxt = new Text2('Speed: 0 km/h', {
size: 60,
fill: 0xFFFFFF
});
speedometerTxt.anchor.set(0.5, 0);
speedometerTxt.y = 170;
LK.gui.top.addChild(speedometerTxt);
// Create fuel display
var fuelTxt = new Text2('Fuel: 100%', {
size: 60,
fill: 0x00FF00
});
fuelTxt.anchor.set(0.5, 0);
fuelTxt.y = 240;
LK.gui.top.addChild(fuelTxt);
// Create time display
var timeTxt = new Text2('Time: 0:00', {
size: 60,
fill: 0xFFFFFF
});
timeTxt.anchor.set(0.5, 0);
timeTxt.y = 310;
LK.gui.top.addChild(timeTxt);
// Create shield indicator
var shieldTxt = new Text2('', {
size: 60,
fill: 0x9900ff
});
shieldTxt.anchor.set(0.5, 0);
shieldTxt.y = 380;
LK.gui.top.addChild(shieldTxt);
// Create speed boost indicator
var speedBoostTxt = new Text2('', {
size: 60,
fill: 0x0099ff
});
speedBoostTxt.anchor.set(0.5, 0);
speedBoostTxt.y = 450;
LK.gui.top.addChild(speedBoostTxt);
// Create combo multiplier display
var comboTxt = new Text2('', {
size: 70,
fill: 0xFFD700
});
comboTxt.anchor.set(0.5, 0);
comboTxt.y = 520;
LK.gui.top.addChild(comboTxt);
// Create left arrow button
var leftArrow = LK.getAsset('Oktusu', {
width: 300,
height: 300,
anchorX: 0.5,
anchorY: 0.5
});
leftArrow.x = 200;
leftArrow.y = 2732 - 200;
game.addChild(leftArrow);
// Create left arrow text
var leftArrowTxt = new Text2('←', {
size: 80,
fill: 0xFFFFFF
});
leftArrowTxt.anchor.set(0.5, 0.5);
leftArrowTxt.x = leftArrow.x;
leftArrowTxt.y = leftArrow.y;
game.addChild(leftArrowTxt);
// Create right arrow button
var rightArrow = LK.getAsset('Oktusu', {
width: 300,
height: 300,
anchorX: 0.5,
anchorY: 0.5
});
rightArrow.x = 2048 - 200;
rightArrow.y = 2732 - 200;
game.addChild(rightArrow);
// Create right arrow text
var rightArrowTxt = new Text2('→', {
size: 80,
fill: 0xFFFFFF
});
rightArrowTxt.anchor.set(0.5, 0.5);
rightArrowTxt.x = rightArrow.x;
rightArrowTxt.y = rightArrow.y;
game.addChild(rightArrowTxt);
// Gas pedal variables (keeping for boost system)
var isGasPedalPressed = false;
var boostMultiplier = 1.0;
// Function to show leaderboard
function showLeaderboard() {
if (showingLeaderboard) return;
showingLeaderboard = true;
leaderboardContainer = new Container();
game.addChild(leaderboardContainer);
// Semi-transparent background
var background = LK.getAsset('highway', {
width: 1800,
height: 2200,
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
background.alpha = 0.8;
background.tint = 0x000000;
leaderboardContainer.addChild(background);
// Title
var titleText = new Text2('🏆 TOP SCORES 🏆', {
size: 100,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 400;
leaderboardContainer.addChild(titleText);
// Display top 10 scores
var sortedScores = leaderboardScores.slice().sort(function (a, b) {
return b - a;
});
for (var i = 0; i < Math.min(10, sortedScores.length); i++) {
var rankText = new Text2(i + 1 + '. ' + sortedScores[i] + ' points', {
size: 80,
fill: i < 3 ? 0xFFD700 : 0xFFFFFF
});
rankText.anchor.set(0.5, 0);
rankText.x = 2048 / 2;
rankText.y = 600 + i * 120;
leaderboardContainer.addChild(rankText);
}
// Close button
var closeButton = new Text2('❌ CLOSE', {
size: 80,
fill: 0xFF4444
});
closeButton.anchor.set(0.5, 0);
closeButton.x = 2048 / 2;
closeButton.y = 2200;
leaderboardContainer.addChild(closeButton);
}
// Function to hide leaderboard
function hideLeaderboard() {
if (!showingLeaderboard) return;
showingLeaderboard = false;
if (leaderboardContainer) {
leaderboardContainer.destroy();
leaderboardContainer = null;
}
}
// Function to save score to leaderboard
function saveScore(score) {
leaderboardScores.push(score);
leaderboardScores.sort(function (a, b) {
return b - a;
});
// Keep only top 20 scores
if (leaderboardScores.length > 20) {
leaderboardScores = leaderboardScores.slice(0, 20);
}
storage.leaderboard = leaderboardScores;
}
// Create player car
playerCar = game.addChild(new Car());
playerCar.x = lanes[1]; // Start in middle lane
playerCar.y = 2732 - 300;
playerCar.targetX = playerCar.x;
// Touch controls
game.down = function (x, y, obj) {
// Check if leaderboard is showing and handle close button
if (showingLeaderboard) {
var closeButtonBounds = {
left: 2048 / 2 - 150,
right: 2048 / 2 + 150,
top: 2200 - 50,
bottom: 2200 + 50
};
if (x >= closeButtonBounds.left && x <= closeButtonBounds.right && y >= closeButtonBounds.top && y <= closeButtonBounds.bottom) {
hideLeaderboard();
return;
}
// Ignore other touches when leaderboard is showing
return;
}
// Check if score button is pressed
var scoreBounds = {
left: scoreButton.x - 50,
right: scoreButton.x + 50,
top: scoreButton.y,
bottom: scoreButton.y + 80
};
if (x >= scoreBounds.left && x <= scoreBounds.right && y >= scoreBounds.top && y <= scoreBounds.bottom) {
showScore = !showScore;
if (showScore) {
scoreDisplay.alpha = 1;
scoreTxt.alpha = 1;
} else {
scoreDisplay.alpha = 0;
scoreTxt.alpha = 0;
}
return;
}
// Check if leaderboard button is pressed
var leaderboardBounds = {
left: leaderboardButton.x - 50,
right: leaderboardButton.x + 50,
top: leaderboardButton.y,
bottom: leaderboardButton.y + 80
};
if (x >= leaderboardBounds.left && x <= leaderboardBounds.right && y >= leaderboardBounds.top && y <= leaderboardBounds.bottom) {
showLeaderboard();
return;
}
// Check if left arrow is pressed
var leftArrowBounds = {
left: leftArrow.x - 150,
right: leftArrow.x + 150,
top: leftArrow.y - 150,
bottom: leftArrow.y + 150
};
if (x >= leftArrowBounds.left && x <= leftArrowBounds.right && y >= leftArrowBounds.top && y <= leftArrowBounds.bottom) {
// Move car to left lane
if (playerCar.lane > 0) {
playerCar.lane--;
playerCar.targetX = lanes[playerCar.lane];
}
leftArrow.tint = 0xffff00; // Yellow when pressed
}
// Check if right arrow is pressed
var rightArrowBounds = {
left: rightArrow.x - 150,
right: rightArrow.x + 150,
top: rightArrow.y - 150,
bottom: rightArrow.y + 150
};
if (x >= rightArrowBounds.left && x <= rightArrowBounds.right && y >= rightArrowBounds.top && y <= rightArrowBounds.bottom) {
// Move car to right lane
if (playerCar.lane < 2) {
playerCar.lane++;
playerCar.targetX = lanes[playerCar.lane];
}
rightArrow.tint = 0xffff00; // Yellow when pressed
}
};
game.move = function (x, y, obj) {
// Don't allow movement when leaderboard is showing
if (showingLeaderboard) return;
var leftArrowBounds = {
left: leftArrow.x - 150,
right: leftArrow.x + 150,
top: leftArrow.y - 150,
bottom: leftArrow.y + 150
};
var rightArrowBounds = {
left: rightArrow.x - 150,
right: rightArrow.x + 150,
top: rightArrow.y - 150,
bottom: rightArrow.y + 150
};
};
game.up = function (x, y, obj) {
// Don't process touches when leaderboard is showing
if (showingLeaderboard) return;
// Reset arrow button colors
leftArrow.tint = 0xffffff;
rightArrow.tint = 0xffffff;
};
// Main game loop
game.update = function () {
// Don't update game when leaderboard is showing
if (showingLeaderboard) return;
// Update game time
gameTime = Math.floor((Date.now() - gameStartTime) / 1000);
var minutes = Math.floor(gameTime / 60);
var seconds = gameTime % 60;
var timeString = minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
timeTxt.setText('Time: ' + timeString);
// Update power-up timers
if (hasShield) {
shieldTimer--;
shieldTxt.setText('🛡️ Shield: ' + Math.ceil(shieldTimer / 60) + 's');
if (shieldTimer <= 0) {
hasShield = false;
shieldTxt.setText('');
// Remove shield visual effect
playerCar.tint = 0xffffff;
}
} else {
shieldTxt.setText('');
}
if (hasSpeedBoost) {
speedBoostTimer--;
speedBoostTxt.setText('⚡ Boost: ' + Math.ceil(speedBoostTimer / 60) + 's');
if (speedBoostTimer <= 0) {
hasSpeedBoost = false;
speedBoostTxt.setText('');
}
} else {
speedBoostTxt.setText('');
}
// Update combo system
if (comboTimer > 0) {
comboTimer--;
comboTxt.setText('Combo x' + comboMultiplier);
if (comboTimer <= 0) {
comboMultiplier = 1;
comboTxt.setText('');
}
} else {
comboTxt.setText('');
}
// Reset combo if too much time passed since last collect
if (Date.now() - lastCollectTime > 3000) {
comboMultiplier = 1;
comboTimer = 0;
}
// Handle sliding mechanics
if (isSliding) {
slideTimer--;
// Apply sliding movement with tween for smooth effect
var slideAmount = slideDirection * 8;
playerCar.x += slideAmount;
// Constrain car to stay within road bounds
playerCar.x = Math.max(lanes[0] - 100, Math.min(lanes[2] + 100, playerCar.x));
// Add visual sliding effect
tween(playerCar, {
rotation: slideDirection * 0.3
}, {
duration: 100,
easing: tween.easeOut
});
if (slideTimer <= 0) {
isSliding = false;
slideDirection = 0;
// Return car to normal rotation
tween(playerCar, {
rotation: 0
}, {
duration: 500,
easing: tween.easeOut
});
// Snap back to nearest lane
var closestLane = 1;
var minDistance = Math.abs(playerCar.x - lanes[1]);
for (var i = 0; i < lanes.length; i++) {
var distance = Math.abs(playerCar.x - lanes[i]);
if (distance < minDistance) {
minDistance = distance;
closestLane = i;
}
}
playerCar.lane = closestLane;
playerCar.targetX = lanes[closestLane];
}
} else {
// Normal smooth car movement to target lane
var moveSpeed = 15;
if (Math.abs(playerCar.x - playerCar.targetX) > moveSpeed) {
if (playerCar.x < playerCar.targetX) {
playerCar.x += moveSpeed;
} else {
playerCar.x -= moveSpeed;
}
} else {
playerCar.x = playerCar.targetX;
}
}
// Increase game speed over time
gameSpeed += 0.002;
// Player car accelerates 3 units per second (3/60 = 0.05 per frame at 60fps)
playerCar.speed += 0.05;
// Calculate base boost from speed boost power-up only
var targetBoost = 1.0;
if (hasSpeedBoost) {
targetBoost *= 1.5; // Additional 50% speed from power-up
}
// Apply boost with smooth transition
if (boostMultiplier < targetBoost) {
// Smoothly increase speed
tween(this, {
boostMultiplier: targetBoost
}, {
duration: 1000,
easing: tween.easeOut
});
} else if (boostMultiplier > targetBoost) {
// Smoothly decrease speed
tween(this, {
boostMultiplier: targetBoost
}, {
duration: 500,
easing: tween.easeOut
});
}
// Limit effective speed to prevent exceeding 150 km/h
var maxEffectiveSpeed = 15; // 15 * 10 = 150 km/h display limit
var effectiveSpeed = Math.min(gameSpeed * boostMultiplier, maxEffectiveSpeed);
var speedLimitRatio = effectiveSpeed / (gameSpeed * boostMultiplier);
// Update distance score
distanceScore += effectiveSpeed * 0.1;
distanceTxt.setText('Distance: ' + Math.floor(distanceScore) + 'm');
// Update speedometer display
var currentSpeed = Math.floor(gameSpeed * boostMultiplier * 10); // Convert to km/h scale
// Limit maximum displayed speed to 150 km/h
currentSpeed = Math.min(currentSpeed, 150);
speedometerTxt.setText('Speed: ' + currentSpeed + ' km/h');
// Spawn road lines
roadLineSpawnTimer++;
if (roadLineSpawnTimer >= 20) {
roadLineSpawnTimer = 0;
for (var i = 0; i < 2; i++) {
var roadLine = new RoadLine();
roadLine.x = lanes[0] + i * (lanes[2] - lanes[0]);
roadLine.y = -50;
roadLine.speed = effectiveSpeed;
roadLines.push(roadLine);
game.addChild(roadLine);
}
}
// Spawn enemy cars
spawnTimer++;
// Increase spawn rate based on score and distance
var spawnRateBonus = Math.floor(LK.getScore() / 100) + Math.floor(distanceScore / 1000);
var baseSpawnRate = Math.max(20, 90 - Math.floor(gameSpeed) - spawnRateBonus);
if (spawnTimer >= baseSpawnRate) {
spawnTimer = 0;
var enemyCar = new EnemyCar();
var randomLane = Math.floor(Math.random() * 3);
enemyCar.x = lanes[randomLane];
enemyCar.y = -100;
enemyCar.speed = (gameSpeed + Math.random() * 3) * boostMultiplier;
enemyCar.lastY = enemyCar.y;
enemyCar.lastIntersecting = enemyCar.intersects(playerCar);
enemyCars.push(enemyCar);
game.addChild(enemyCar);
}
// Spawn trees
treeSpawnTimer++;
if (treeSpawnTimer >= 60) {
treeSpawnTimer = 0;
// Spawn trees on left side
if (Math.random() < 0.8) {
var leftTree = new Tree();
leftTree.x = Math.random() * (lanes[0] - 100); // Random position on left side
leftTree.y = -100;
leftTree.speed = effectiveSpeed;
trees.push(leftTree);
game.addChild(leftTree);
}
// Spawn trees on right side
if (Math.random() < 0.8) {
var rightTree = new Tree();
rightTree.x = lanes[2] + 100 + Math.random() * (2048 - lanes[2] - 200); // Random position on right side
rightTree.y = -100;
rightTree.speed = effectiveSpeed;
trees.push(rightTree);
game.addChild(rightTree);
}
}
// Spawn bushes
bushSpawnTimer++;
if (bushSpawnTimer >= 40) {
bushSpawnTimer = 0;
// Spawn bushes on left side between trees
if (Math.random() < 0.6) {
var leftBush = new Bush();
leftBush.x = Math.random() * (lanes[0] - 50); // Random position on left side
leftBush.y = -50;
leftBush.speed = effectiveSpeed;
bushes.push(leftBush);
game.addChild(leftBush);
}
// Spawn bushes on right side between trees
if (Math.random() < 0.6) {
var rightBush = new Bush();
rightBush.x = lanes[2] + 50 + Math.random() * (2048 - lanes[2] - 150); // Random position on right side
rightBush.y = -50;
rightBush.speed = effectiveSpeed;
bushes.push(rightBush);
game.addChild(rightBush);
}
}
// Spawn coins
coinSpawnTimer++;
if (coinSpawnTimer >= 120) {
coinSpawnTimer = 0;
if (Math.random() < 0.7) {
var coin = new Coin();
var randomLane = Math.floor(Math.random() * 3);
coin.x = lanes[randomLane];
coin.y = -50;
coin.speed = effectiveSpeed;
coin.lastY = coin.y;
coin.lastIntersecting = coin.intersects(playerCar);
coins.push(coin);
game.addChild(coin);
}
}
// Spawn fuel tanks
fuelTankSpawnTimer++;
if (fuelTankSpawnTimer >= 150) {
fuelTankSpawnTimer = 0;
if (Math.random() < 0.7) {
var fuelTank = new FuelTank();
var randomLane = Math.floor(Math.random() * 3);
fuelTank.x = lanes[randomLane];
fuelTank.y = -50;
fuelTank.speed = effectiveSpeed;
fuelTank.lastY = fuelTank.y;
fuelTank.lastIntersecting = fuelTank.intersects(playerCar);
fuelTanks.push(fuelTank);
game.addChild(fuelTank);
}
}
// Spawn spilled fuel
spilledFuelSpawnTimer++;
if (spilledFuelSpawnTimer >= 200) {
spilledFuelSpawnTimer = 0;
if (Math.random() < 0.4) {
var spilledFuel = new SpilledFuel();
var randomLane = Math.floor(Math.random() * 3);
spilledFuel.x = lanes[randomLane];
spilledFuel.y = -50;
spilledFuel.speed = effectiveSpeed;
spilledFuel.lastY = spilledFuel.y;
spilledFuel.lastIntersecting = spilledFuel.intersects(playerCar);
spilledFuels.push(spilledFuel);
game.addChild(spilledFuel);
}
}
// Spawn spilled boxes
spilledBoxSpawnTimer++;
if (spilledBoxSpawnTimer >= 180) {
spilledBoxSpawnTimer = 0;
if (Math.random() < 0.5) {
var spilledBox = new SpilledBox();
var randomLane = Math.floor(Math.random() * 3);
spilledBox.x = lanes[randomLane];
spilledBox.y = -50;
spilledBox.speed = effectiveSpeed;
spilledBox.lastY = spilledBox.y;
spilledBox.lastIntersecting = spilledBox.intersects(playerCar);
spilledBoxes.push(spilledBox);
game.addChild(spilledBox);
}
}
// Spawn power-ups
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= 300) {
powerUpSpawnTimer = 0;
if (Math.random() < 0.6) {
var powerUp = new PowerUp();
var randomLane = Math.floor(Math.random() * 3);
powerUp.x = lanes[randomLane];
powerUp.y = -50;
powerUp.speed = effectiveSpeed;
powerUp.lastY = powerUp.y;
powerUp.lastIntersecting = powerUp.intersects(playerCar);
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
// Update and check road lines
for (var i = roadLines.length - 1; i >= 0; i--) {
var roadLine = roadLines[i];
roadLine.speed = effectiveSpeed;
if (roadLine.lastY === undefined) roadLine.lastY = roadLine.y;
// Remove road lines that go off screen
if (roadLine.lastY <= 2732 + 50 && roadLine.y > 2732 + 50) {
roadLine.destroy();
roadLines.splice(i, 1);
continue;
}
roadLine.lastY = roadLine.y;
}
// Update and check enemy cars
for (var i = enemyCars.length - 1; i >= 0; i--) {
var enemyCar = enemyCars[i];
// Increase enemy speed based on score and distance
var speedBonus = Math.floor(LK.getScore() / 50) + Math.floor(distanceScore / 500);
var enemyBaseSpeed = (gameSpeed + 2 + speedBonus) * boostMultiplier;
enemyCar.speed = Math.min(enemyBaseSpeed, maxEffectiveSpeed + 2);
// Remove cars that go off screen
if (enemyCar.lastY <= 2732 + 100 && enemyCar.y > 2732 + 100) {
enemyCar.destroy();
enemyCars.splice(i, 1);
continue;
}
// Check collision with player
var currentIntersecting = enemyCar.intersects(playerCar);
if (!enemyCar.lastIntersecting && currentIntersecting) {
if (hasShield) {
// Shield protects from collision
hasShield = false;
shieldTimer = 0;
shieldTxt.setText('');
playerCar.tint = 0xffffff; // Remove shield tint
LK.effects.flashObject(playerCar, 0xffff00, 1000); // Yellow flash for shield break
LK.effects.flashObject(enemyCar, 0xffff00, 500);
// Push enemy car away
enemyCar.y += 200;
} else {
// Collision detected - game over
saveScore(LK.getScore());
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
enemyCar.lastY = enemyCar.y;
enemyCar.lastIntersecting = currentIntersecting;
}
// Update and check trees
for (var i = trees.length - 1; i >= 0; i--) {
var tree = trees[i];
tree.speed = effectiveSpeed;
if (tree.lastY === undefined) tree.lastY = tree.y;
// Remove trees that go off screen
if (tree.lastY <= 2732 + 100 && tree.y > 2732 + 100) {
tree.destroy();
trees.splice(i, 1);
continue;
}
tree.lastY = tree.y;
}
// Update and check bushes
for (var i = bushes.length - 1; i >= 0; i--) {
var bush = bushes[i];
bush.speed = effectiveSpeed;
if (bush.lastY === undefined) bush.lastY = bush.y;
// Remove bushes that go off screen
if (bush.lastY <= 2732 + 50 && bush.y > 2732 + 50) {
bush.destroy();
bushes.splice(i, 1);
continue;
}
bush.lastY = bush.y;
}
// Update and check coins
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
coin.speed = effectiveSpeed;
// Remove coins that go off screen
if (coin.lastY <= 2732 + 50 && coin.y > 2732 + 50) {
coin.destroy();
coins.splice(i, 1);
continue;
}
// Check collection by player
var currentIntersecting = coin.intersects(playerCar);
if (!coin.lastIntersecting && currentIntersecting) {
// Coin collected
lastCollectTime = Date.now();
comboTimer = 300; // 5 seconds at 60fps
var pointsEarned = 10 * comboMultiplier;
LK.setScore(LK.getScore() + pointsEarned);
comboMultiplier = Math.min(comboMultiplier + 1, 5); // Max combo x5
scoreTxt.setText(LK.getScore().toString());
LK.getSound('collectCoin').play();
coin.destroy();
coins.splice(i, 1);
continue;
}
coin.lastY = coin.y;
coin.lastIntersecting = currentIntersecting;
}
// Update fuel system
currentFuel -= fuelConsumptionRate * boostMultiplier;
if (currentFuel <= 0) {
currentFuel = 0;
// Game over due to no fuel
saveScore(LK.getScore());
LK.effects.flashScreen(0xff8800, 1000);
LK.showGameOver();
return;
}
// Update fuel display with color coding
var fuelPercentage = Math.floor(currentFuel / maxFuel * 100);
fuelTxt.setText('Fuel: ' + fuelPercentage + '%');
if (fuelPercentage > 50) {
fuelTxt.fill = 0x00FF00; // Green
} else if (fuelPercentage > 25) {
fuelTxt.fill = 0xFFFF00; // Yellow
} else {
fuelTxt.fill = 0xFF0000; // Red
}
// Update and check fuel tanks
for (var i = fuelTanks.length - 1; i >= 0; i--) {
var fuelTank = fuelTanks[i];
fuelTank.speed = effectiveSpeed;
// Remove fuel tanks that go off screen
if (fuelTank.lastY <= 2732 + 50 && fuelTank.y > 2732 + 50) {
fuelTank.destroy();
fuelTanks.splice(i, 1);
continue;
}
// Check collection by player
var currentIntersecting = fuelTank.intersects(playerCar);
if (!fuelTank.lastIntersecting && currentIntersecting) {
// Fuel tank collected
lastCollectTime = Date.now();
comboTimer = 300; // 5 seconds at 60fps
currentFuel = Math.min(currentFuel + 30, maxFuel);
var pointsEarned = 5 * comboMultiplier;
LK.setScore(LK.getScore() + pointsEarned);
comboMultiplier = Math.min(comboMultiplier + 1, 5); // Max combo x5
scoreTxt.setText(LK.getScore().toString());
LK.getSound('collectCoin').play();
fuelTank.destroy();
fuelTanks.splice(i, 1);
continue;
}
fuelTank.lastY = fuelTank.y;
fuelTank.lastIntersecting = currentIntersecting;
}
// Update and check spilled fuel
for (var i = spilledFuels.length - 1; i >= 0; i--) {
var spilledFuel = spilledFuels[i];
spilledFuel.speed = effectiveSpeed;
// Remove spilled fuel that goes off screen
if (spilledFuel.lastY <= 2732 + 50 && spilledFuel.y > 2732 + 50) {
spilledFuel.destroy();
spilledFuels.splice(i, 1);
continue;
}
// Check collision with player
var currentIntersecting = spilledFuel.intersects(playerCar);
if (!spilledFuel.lastIntersecting && currentIntersecting && !isSliding) {
// Spilled fuel collision - make car slide
isSliding = true;
slideDirection = (Math.random() - 0.5) * 2; // Random slide direction
slideTimer = 90; // Slide for 1.5 seconds at 60fps
// Visual effect for hitting spilled fuel
LK.effects.flashObject(playerCar, 0x8B4513, 500);
// Add spinning rotation effect
tween(playerCar, {
rotation: playerCar.rotation + Math.PI * 4 // Spin 2 full rotations
}, {
duration: 1500,
easing: tween.easeOut
});
}
spilledFuel.lastY = spilledFuel.y;
spilledFuel.lastIntersecting = currentIntersecting;
}
// Update and check spilled boxes
for (var i = spilledBoxes.length - 1; i >= 0; i--) {
var spilledBox = spilledBoxes[i];
spilledBox.speed = effectiveSpeed;
// Remove spilled boxes that go off screen
if (spilledBox.lastY <= 2732 + 50 && spilledBox.y > 2732 + 50) {
spilledBox.destroy();
spilledBoxes.splice(i, 1);
continue;
}
// Check collision with player
var currentIntersecting = spilledBox.intersects(playerCar);
if (!spilledBox.lastIntersecting && currentIntersecting) {
if (hasShield) {
// Shield protects from collision
hasShield = false;
shieldTimer = 0;
shieldTxt.setText('');
playerCar.tint = 0xffffff; // Remove shield tint
LK.effects.flashObject(playerCar, 0xffff00, 1000); // Yellow flash for shield break
// Destroy the box
spilledBox.destroy();
spilledBoxes.splice(i, 1);
continue;
} else {
// Spilled box collision - game over
saveScore(LK.getScore());
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
spilledBox.lastY = spilledBox.y;
spilledBox.lastIntersecting = currentIntersecting;
}
// Update and check power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
powerUp.speed = effectiveSpeed;
// Remove power-ups that go off screen
if (powerUp.lastY <= 2732 + 50 && powerUp.y > 2732 + 50) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check collection by player
var currentIntersecting = powerUp.intersects(playerCar);
if (!powerUp.lastIntersecting && currentIntersecting) {
// Power-up collected
lastCollectTime = Date.now();
comboTimer = 300; // 5 seconds at 60fps
if (powerUp.powerType === 0) {
// Speed boost power-up
hasSpeedBoost = true;
speedBoostTimer = 600; // 10 seconds at 60fps
LK.effects.flashObject(playerCar, 0x0099ff, 500);
} else {
// Shield power-up
hasShield = true;
shieldTimer = 900; // 15 seconds at 60fps
playerCar.tint = 0x9900ff; // Purple tint for shield
LK.effects.flashObject(playerCar, 0x9900ff, 500);
}
var pointsEarned = 20 * comboMultiplier;
LK.setScore(LK.getScore() + pointsEarned);
comboMultiplier = Math.min(comboMultiplier + 1, 5); // Max combo x5
scoreTxt.setText(LK.getScore().toString());
LK.getSound('collectCoin').play();
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
powerUp.lastY = powerUp.y;
powerUp.lastIntersecting = currentIntersecting;
}
};
Coin. In-Game asset. 2d. High contrast. No shadows
Yol hattı. In-Game asset. 2d. High contrast. No shadows
Score. In-Game asset. 2d. High contrast. No shadows
Şehir. In-Game asset. 2d. High contrast. No shadows
Gaz pedalı. In-Game asset. 2d. High contrast. No shadows
Sağ sola hareket oktuşuşlar. In-Game asset. 2d. High contrast. No shadows
Kuş bakışı ağaç. In-Game asset. 2d. High contrast. No shadows
Çalı. In-Game asset. 2d. High contrast. No shadows
Benzin kutusu. In-Game asset. 2d. High contrast. No shadows
Dökülmüş benzin. In-Game asset. 2d. High contrast. No shadows
Yola koyulmuş kutular. In-Game asset. 2d. High contrast. No shadows
Kuş bakışı Ferrari araba. In-Game asset. 2d. High contrast. No shadows
Kuş bakışı Lamborghini. In-Game asset. 2d. High contrast. No shadows
Kuş bakışı kosiegg. In-Game asset. 2d. High contrast. No shadows
Bugatti kuş bakışı. In-Game asset. 2d. High contrast. No shadows