/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var CarPreview = Container.expand(function (carType) {
var self = Container.call(this);
if (carType === 'sports') {
// Sports car preview
var body = self.attachAsset('sportsCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('sportsCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -40;
var rearWindow = self.attachAsset('sportsCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 40;
var leftWindow = self.attachAsset('sportsCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -30;
leftWindow.y = -10;
var rightWindow = self.attachAsset('sportsCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 30;
rightWindow.y = -10;
var spoiler = self.attachAsset('sportsCarSpoiler', {
anchorX: 0.5,
anchorY: 0.5
});
spoiler.y = 80;
var stripe = self.attachAsset('sportsCarStripe', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (carType === 'luxury') {
// Luxury car preview
var body = self.attachAsset('luxuryCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('luxuryCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -45;
var rearWindow = self.attachAsset('luxuryCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 45;
var leftWindow = self.attachAsset('luxuryCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -35;
leftWindow.y = -15;
var rightWindow = self.attachAsset('luxuryCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 35;
rightWindow.y = -15;
var grill = self.attachAsset('luxuryCarGrill', {
anchorX: 0.5,
anchorY: 0.5
});
grill.y = -90;
var trim = self.attachAsset('luxuryCarTrim', {
anchorX: 0.5,
anchorY: 0.5
});
trim.y = 90;
} else if (carType === 'race') {
// Race car preview
var body = self.attachAsset('raceCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('raceCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -35;
var rearWindow = self.attachAsset('raceCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 35;
var leftWindow = self.attachAsset('raceCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -25;
leftWindow.y = -5;
var rightWindow = self.attachAsset('raceCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 25;
rightWindow.y = -5;
var wing = self.attachAsset('raceCarWing', {
anchorX: 0.5,
anchorY: 0.5
});
wing.y = 75;
var number = self.attachAsset('raceCarNumber', {
anchorX: 0.5,
anchorY: 0.5
});
number.y = -60;
} else if (carType === 'classic') {
// Classic car preview
var body = self.attachAsset('classicCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('classicCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -42;
var rearWindow = self.attachAsset('classicCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 42;
var leftWindow = self.attachAsset('classicCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -32;
leftWindow.y = -12;
var rightWindow = self.attachAsset('classicCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 32;
rightWindow.y = -12;
var bumper = self.attachAsset('classicCarBumper', {
anchorX: 0.5,
anchorY: 0.5
});
bumper.y = 87;
var trim = self.attachAsset('classicCarTrim', {
anchorX: 0.5,
anchorY: 0.5
});
trim.y = -87;
}
return self;
});
var CarSelectionScreen = Container.expand(function () {
var self = Container.call(this);
// Background panel
var panel = self.attachAsset('carSelectPanel', {
anchorX: 0.5,
anchorY: 0.5
});
panel.alpha = 0.95;
// Title
var titleBg = self.attachAsset('carSelectTitle', {
anchorX: 0.5,
anchorY: 0.5
});
titleBg.y = -450;
titleBg.alpha = 0.9;
titleBg.scaleX = 1.4;
titleBg.scaleY = 1.3;
var titleText = new Text2('🚗 SELECT YOUR CAR', {
size: 95,
fill: '#ffffff'
});
titleText.anchor.set(0.5, 0.5);
titleBg.addChild(titleText);
// Back button
var backButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
backButton.y = -370;
backButton.alpha = 0.95;
backButton.scaleX = 1.1;
backButton.scaleY = 1.1;
var backText = new Text2('⬅️ BACK', {
size: 40,
fill: '#ffffff'
});
backText.anchor.set(0.5, 0.5);
backButton.addChild(backText);
// Road selection section
var roadTitleBg = self.attachAsset('carSelectTitle', {
anchorX: 0.5,
anchorY: 0.5
});
roadTitleBg.y = 350;
roadTitleBg.alpha = 0.8;
var roadTitleText = new Text2('SELECT ROAD TYPE', {
size: 60,
fill: '#ffffff'
});
roadTitleText.anchor.set(0.5, 0.5);
roadTitleBg.addChild(roadTitleText);
// Road type buttons
var roadTypes = [{
type: 'highway',
name: 'HIGHWAY',
description: 'Fast traffic'
}, {
type: 'city',
name: 'CITY ROAD',
description: 'Heavy traffic'
}];
var roadButtons = [];
for (var r = 0; r < roadTypes.length; r++) {
var roadButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
roadButton.x = (r - 0.5) * 400;
roadButton.y = 450;
roadButton.alpha = 0.9;
roadButton.roadType = roadTypes[r].type;
var roadButtonText = new Text2(roadTypes[r].name, {
size: 35,
fill: '#ffffff'
});
roadButtonText.anchor.set(0.5, 0.5);
roadButton.addChild(roadButtonText);
roadButtons.push(roadButton);
}
// Get owned cars from storage
var ownedCars = storage.ownedCars || ['default'];
var allCarTypes = [{
type: 'default',
name: 'DEFAULT CAR',
speed: 'MEDIUM',
handling: 'GOOD'
}, {
type: 'sports',
name: 'SPORTS CAR',
speed: 'HIGH',
handling: 'EXCELLENT'
}, {
type: 'luxury',
name: 'LUXURY CAR',
speed: 'MEDIUM',
handling: 'GOOD'
}, {
type: 'race',
name: 'RACE CAR',
speed: 'EXTREME',
handling: 'PERFECT'
}, {
type: 'classic',
name: 'CLASSIC CAR',
speed: 'LOW',
handling: 'STABLE'
}];
// Filter to only show owned cars
var availableCarTypes = [];
for (var a = 0; a < allCarTypes.length; a++) {
if (ownedCars.indexOf(allCarTypes[a].type) !== -1) {
availableCarTypes.push(allCarTypes[a]);
}
}
var cards = [];
for (var i = 0; i < availableCarTypes.length; i++) {
var carType = availableCarTypes[i];
var card = self.addChild(new Container());
var cardBg = card.attachAsset('carSelectCard', {
anchorX: 0.5,
anchorY: 0.5
});
cardBg.alpha = 0.8;
// Position cards in rows, up to 3 per row
var col = i % 3;
var row = Math.floor(i / 3);
card.x = (col - 1) * 400;
card.y = (row - 0.5) * 350 - 100;
// Car preview
var carPreview = card.addChild(new CarPreview(carType.type));
carPreview.y = -80;
carPreview.scaleX = 0.7;
carPreview.scaleY = 0.7;
// Car name
var nameText = new Text2(carType.name, {
size: 35,
fill: '#ffffff'
});
nameText.anchor.set(0.5, 0.5);
card.addChild(nameText);
nameText.y = 50;
// Stats
var speedText = new Text2('SPEED: ' + carType.speed, {
size: 22,
fill: '#f39c12'
});
speedText.anchor.set(0.5, 0.5);
card.addChild(speedText);
speedText.y = 80;
var handlingText = new Text2('HANDLING: ' + carType.handling, {
size: 22,
fill: '#3498db'
});
handlingText.anchor.set(0.5, 0.5);
card.addChild(handlingText);
handlingText.y = 110;
// Select button
var selectButton = card.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
selectButton.y = 160;
selectButton.alpha = 0.9;
var buttonText = new Text2('SELECT', {
size: 30,
fill: '#ffffff'
});
buttonText.anchor.set(0.5, 0.5);
selectButton.addChild(buttonText);
// Store car type for selection
selectButton.carType = carType.type;
cards.push({
card: card,
button: selectButton,
type: carType.type
});
}
self.cards = cards;
self.roadButtons = roadButtons;
self.selectedCar = null;
self.selectedRoad = null;
self.down = function (x, y, obj) {
// Check back button
var backBounds = {
left: backButton.x - 165,
right: backButton.x + 165,
top: backButton.y - 50,
bottom: backButton.y + 50
};
if (x >= backBounds.left && x <= backBounds.right && y >= backBounds.top && y <= backBounds.bottom) {
LK.effects.flashObject(backButton, 0x00ff00, 200);
self.goBackToMenu();
return;
}
// Check if any car card was clicked
for (var i = 0; i < self.cards.length; i++) {
var card = self.cards[i].card;
// Check entire card bounds for easier selection
var cardBounds = {
left: card.x - 220,
right: card.x + 220,
top: card.y - 200,
bottom: card.y + 200
};
// Check if touch is within card bounds
if (x >= cardBounds.left && x <= cardBounds.right && y >= cardBounds.top && y <= cardBounds.bottom) {
// Flash the selected card for visual feedback
LK.effects.flashObject(card, 0x00ff00, 200);
self.selectedCar = self.cards[i].type;
selectedCarType = self.cards[i].type;
// Check if both car and road are selected
if (self.selectedCar && self.selectedRoad) {
self.startGameWithSelections();
}
break;
}
}
// Check if any road button was clicked
for (var r = 0; r < self.roadButtons.length; r++) {
var roadBtn = self.roadButtons[r];
var roadBounds = {
left: roadBtn.x - 180,
right: roadBtn.x + 180,
top: roadBtn.y - 50,
bottom: roadBtn.y + 50
};
if (x >= roadBounds.left && x <= roadBounds.right && y >= roadBounds.top && y <= roadBounds.bottom) {
// Flash the selected road button
LK.effects.flashObject(roadBtn, 0x00ff00, 200);
self.selectedRoad = roadBtn.roadType;
selectedRoadType = roadBtn.roadType;
// Check if both car and road are selected
if (self.selectedCar && self.selectedRoad) {
self.startGameWithSelections();
}
break;
}
}
};
self.goBackToMenu = function () {
LK.setTimeout(function () {
if (carSelectionScreen) {
carSelectionScreen.destroy();
carSelectionScreen = null;
}
initMainMenu();
}, 300);
};
self.startGameWithSelections = function () {
// Small delay before starting game
LK.setTimeout(function () {
if (carSelectionScreen) {
carSelectionScreen.destroy();
carSelectionScreen = null;
}
startGame();
}, 300);
};
return self;
});
var LaneDivider = Container.expand(function () {
var self = Container.call(this);
var dividerGraphics = self.attachAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.update = function () {
self.y += self.speed + gameSpeed;
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Background panel
var panel = self.attachAsset('carSelectPanel', {
anchorX: 0.5,
anchorY: 0.5
});
panel.alpha = 0.95;
panel.scaleX = 1.1;
panel.scaleY = 1.1;
// Title
var titleBg = self.attachAsset('carSelectTitle', {
anchorX: 0.5,
anchorY: 0.5
});
titleBg.y = -450;
titleBg.alpha = 0.9;
titleBg.scaleX = 1.5;
titleBg.scaleY = 1.3;
var titleText = new Text2('🏎️ RACING LEGENDS', {
size: 100,
fill: '#ffffff'
});
titleText.anchor.set(0.5, 0.5);
titleBg.addChild(titleText);
// Animate title
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
// Coins display
var coinsBg = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
coinsBg.y = -300;
coinsBg.alpha = 0.95;
coinsBg.scaleX = 1.3;
coinsBg.scaleY = 1.2;
var coinsText = new Text2('💰 COINS: ' + (storage.totalCoins || 0), {
size: 50,
fill: '#ffd700'
});
coinsText.anchor.set(0.5, 0.5);
coinsBg.addChild(coinsText);
// Menu buttons with larger size and better styling
var playButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
playButton.y = -180;
playButton.alpha = 0.95;
playButton.scaleX = 1.4;
playButton.scaleY = 1.3;
var playText = new Text2('🎮 PLAY GAME', {
size: 60,
fill: '#ffffff'
});
playText.anchor.set(0.5, 0.5);
playButton.addChild(playText);
var shopButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
shopButton.y = -60;
shopButton.alpha = 0.95;
shopButton.scaleX = 1.4;
shopButton.scaleY = 1.3;
var shopText = new Text2('🛒 SHOP', {
size: 60,
fill: '#ffffff'
});
shopText.anchor.set(0.5, 0.5);
shopButton.addChild(shopText);
var statsButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
statsButton.y = 60;
statsButton.alpha = 0.95;
statsButton.scaleX = 1.4;
statsButton.scaleY = 1.3;
var statsText = new Text2('📊 STATS', {
size: 60,
fill: '#ffffff'
});
statsText.anchor.set(0.5, 0.5);
statsButton.addChild(statsText);
// Add glowing effect to buttons
var buttons = [playButton, shopButton, statsButton];
for (var b = 0; b < buttons.length; b++) {
var btn = buttons[b];
btn.originalAlpha = btn.alpha;
tween(btn, {
alpha: btn.originalAlpha + 0.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function () {
tween(this, {
alpha: this.originalAlpha
}, {
duration: 800,
easing: tween.easeInOut
});
}.bind(btn)
});
}
// Stats display with enhanced styling
var stats = storage.playerStats || {
totalDistance: 0,
totalCoins: 0,
bestScore: 0,
gamesPlayed: 0
};
var statsBg = self.attachAsset('carSelectCard', {
anchorX: 0.5,
anchorY: 0.5
});
statsBg.y = 280;
statsBg.alpha = 0.9;
statsBg.scaleX = 1.2;
statsBg.scaleY = 0.8;
var statsTitle = new Text2('🏆 YOUR STATS', {
size: 45,
fill: '#ffffff'
});
statsTitle.anchor.set(0.5, 0.5);
statsBg.addChild(statsTitle);
statsTitle.y = -90;
var bestScoreText = new Text2('🥇 BEST: ' + stats.bestScore + 'M', {
size: 32,
fill: '#00ff00'
});
bestScoreText.anchor.set(0.5, 0.5);
statsBg.addChild(bestScoreText);
bestScoreText.y = -45;
var totalDistanceText = new Text2('🛣️ TOTAL: ' + stats.totalDistance + 'M', {
size: 32,
fill: '#ffff00'
});
totalDistanceText.anchor.set(0.5, 0.5);
statsBg.addChild(totalDistanceText);
totalDistanceText.y = -5;
var gamesPlayedText = new Text2('🎯 GAMES: ' + stats.gamesPlayed, {
size: 32,
fill: '#ff9900'
});
gamesPlayedText.anchor.set(0.5, 0.5);
statsBg.addChild(gamesPlayedText);
gamesPlayedText.y = 35;
self.playButton = playButton;
self.shopButton = shopButton;
self.statsButton = statsButton;
self.down = function (x, y, obj) {
// Check play button with enlarged bounds
var playBounds = {
left: self.playButton.x - 280,
right: self.playButton.x + 280,
top: self.playButton.y - 65,
bottom: self.playButton.y + 65
};
if (x >= playBounds.left && x <= playBounds.right && y >= playBounds.top && y <= playBounds.bottom) {
// Enhanced button feedback
tween(self.playButton, {
scaleX: 1.5,
scaleY: 1.4
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.playButton, {
scaleX: 1.4,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(self.playButton, 0x00ff00, 300);
self.startCarSelection();
return;
}
// Check shop button with enlarged bounds
var shopBounds = {
left: self.shopButton.x - 280,
right: self.shopButton.x + 280,
top: self.shopButton.y - 65,
bottom: self.shopButton.y + 65
};
if (x >= shopBounds.left && x <= shopBounds.right && y >= shopBounds.top && y <= shopBounds.bottom) {
// Enhanced button feedback
tween(self.shopButton, {
scaleX: 1.5,
scaleY: 1.4
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.shopButton, {
scaleX: 1.4,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(self.shopButton, 0x00ff00, 300);
self.openShop();
return;
}
// Check stats button with enlarged bounds
var statsBounds = {
left: self.statsButton.x - 280,
right: self.statsButton.x + 280,
top: self.statsButton.y - 65,
bottom: self.statsButton.y + 65
};
if (x >= statsBounds.left && x <= statsBounds.right && y >= statsBounds.top && y <= statsBounds.bottom) {
// Enhanced button feedback
tween(self.statsButton, {
scaleX: 1.5,
scaleY: 1.4
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.statsButton, {
scaleX: 1.4,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(self.statsButton, 0x3498db, 300);
return;
}
};
self.startCarSelection = function () {
LK.setTimeout(function () {
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
initCarSelection();
}, 300);
};
self.openShop = function () {
LK.setTimeout(function () {
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
shop = game.addChild(new Shop());
shop.x = 1024;
shop.y = 1366;
}, 300);
};
return self;
});
var Obstacle = Container.expand(function (type) {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
// Add details based on vehicle type
if (type === 'enemyCar') {
// Add windows to enemy car
var frontWindow = self.attachAsset('enemyCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -40;
var rearWindow = self.attachAsset('enemyCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 40;
var leftWindow = self.attachAsset('enemyCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -25;
leftWindow.y = -5;
var rightWindow = self.attachAsset('enemyCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 25;
rightWindow.y = -5;
} else if (type === 'truck') {
// Add truck cab windows
var truckWindow = self.attachAsset('truckWindow', {
anchorX: 0.5,
anchorY: 0.5
});
truckWindow.y = -60;
// Add truck cargo area details
var cargoDetail = self.attachAsset('truckCargo', {
anchorX: 0.5,
anchorY: 0.5
});
cargoDetail.y = 30;
} else if (type === 'barrier') {
// Add warning stripes to barrier
var stripe1 = self.attachAsset('barrierStripe', {
anchorX: 0.5,
anchorY: 0.5
});
stripe1.y = -15;
var stripe2 = self.attachAsset('barrierStripe', {
anchorX: 0.5,
anchorY: 0.5
});
stripe2.y = 15;
}
self.speed = 8;
self.obstacleType = type;
self.passed = false;
self.update = function () {
self.y += self.speed + gameSpeed;
};
return self;
});
var ParticleSystem = Container.expand(function (particleType, count) {
var self = Container.call(this);
self.particles = [];
self.particleType = particleType;
for (var i = 0; i < count; i++) {
var particle = self.attachAsset(particleType, {
anchorX: 0.5,
anchorY: 0.5
});
particle.vx = (Math.random() - 0.5) * 4;
particle.vy = (Math.random() - 0.5) * 4;
particle.life = 1.0;
particle.maxLife = 1.0;
particle.alpha = 0;
self.particles.push(particle);
}
self.emit = function (x, y, force) {
force = force || 1;
for (var i = 0; i < self.particles.length; i++) {
var particle = self.particles[i];
if (particle.life <= 0) {
particle.x = x + (Math.random() - 0.5) * 20;
particle.y = y + (Math.random() - 0.5) * 20;
particle.vx = (Math.random() - 0.5) * 6 * force;
particle.vy = (Math.random() - 0.5) * 6 * force;
particle.life = 1.0;
particle.alpha = 1.0;
break;
}
}
};
self.update = function () {
for (var i = 0; i < self.particles.length; i++) {
var particle = self.particles[i];
if (particle.life > 0) {
particle.x += particle.vx;
particle.y += particle.vy;
particle.life -= 0.02;
particle.alpha = particle.life;
particle.scaleX = particle.life;
particle.scaleY = particle.life;
}
}
};
return self;
});
var PlayerCar = Container.expand(function (carType) {
var self = Container.call(this);
carType = carType || 'default';
if (carType === 'sports') {
// Sports car with ultra-realistic details
var carGraphics = self.attachAsset('sportsCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('sportsCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -40;
var rearWindow = self.attachAsset('sportsCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 40;
var leftWindow = self.attachAsset('sportsCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -30;
leftWindow.y = -10;
var rightWindow = self.attachAsset('sportsCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 30;
rightWindow.y = -10;
var spoiler = self.attachAsset('sportsCarSpoiler', {
anchorX: 0.5,
anchorY: 0.5
});
spoiler.y = 80;
var stripe = self.attachAsset('sportsCarStripe', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (carType === 'luxury') {
// Luxury car with ultra-realistic details
var carGraphics = self.attachAsset('luxuryCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('luxuryCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -45;
var rearWindow = self.attachAsset('luxuryCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 45;
var leftWindow = self.attachAsset('luxuryCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -35;
leftWindow.y = -15;
var rightWindow = self.attachAsset('luxuryCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 35;
rightWindow.y = -15;
var grill = self.attachAsset('luxuryCarGrill', {
anchorX: 0.5,
anchorY: 0.5
});
grill.y = -90;
var trim = self.attachAsset('luxuryCarTrim', {
anchorX: 0.5,
anchorY: 0.5
});
trim.y = 90;
} else if (carType === 'race') {
// Race car with ultra-realistic details
var carGraphics = self.attachAsset('raceCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('raceCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -35;
var rearWindow = self.attachAsset('raceCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 35;
var leftWindow = self.attachAsset('raceCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -25;
leftWindow.y = -5;
var rightWindow = self.attachAsset('raceCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 25;
rightWindow.y = -5;
var wing = self.attachAsset('raceCarWing', {
anchorX: 0.5,
anchorY: 0.5
});
wing.y = 75;
var number = self.attachAsset('raceCarNumber', {
anchorX: 0.5,
anchorY: 0.5
});
number.y = -60;
} else if (carType === 'classic') {
// Classic car with ultra-realistic details
var carGraphics = self.attachAsset('classicCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('classicCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -42;
var rearWindow = self.attachAsset('classicCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 42;
var leftWindow = self.attachAsset('classicCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -32;
leftWindow.y = -12;
var rightWindow = self.attachAsset('classicCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 32;
rightWindow.y = -12;
var bumper = self.attachAsset('classicCarBumper', {
anchorX: 0.5,
anchorY: 0.5
});
bumper.y = 87;
var trim = self.attachAsset('classicCarTrim', {
anchorX: 0.5,
anchorY: 0.5
});
trim.y = -87;
} else {
// Default car
var carGraphics = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('playerCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -40;
var rearWindow = self.attachAsset('playerCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 40;
var leftWindow = self.attachAsset('playerCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -30;
leftWindow.y = -10;
var rightWindow = self.attachAsset('playerCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 30;
rightWindow.y = -10;
}
self.currentLane = 0; // 0 = left lane, 1 = right lane
self.targetX = 0;
self.speed = 0;
self.carType = carType;
self.shieldActive = false;
self.shieldTime = 0;
self.boostActive = false;
self.boostTime = 0;
self.nitroActive = false; // Track nitro boost separately
self.nitroBoostAmount = 0; // Track nitro boost amount
self.regularBoostActive = false; // Track regular boost separately
self.regularBoostAmount = 0; // Track regular boost amount
// Add enhanced headlight system with multiple layers
// Left headlight system
var leftHeadlightGlow = self.attachAsset('lightGlow', {
anchorX: 0.5,
anchorY: 1
});
leftHeadlightGlow.x = -25;
leftHeadlightGlow.y = -80;
leftHeadlightGlow.alpha = 0.15;
leftHeadlightGlow.scaleY = 1.5;
var leftHeadlightOuter = self.attachAsset('lightBeamOuter', {
anchorX: 0.5,
anchorY: 1
});
leftHeadlightOuter.x = -25;
leftHeadlightOuter.y = -80;
leftHeadlightOuter.alpha = 0.4;
var leftHeadlight = self.attachAsset('lightBeam', {
anchorX: 0.5,
anchorY: 1
});
leftHeadlight.x = -25;
leftHeadlight.y = -80;
leftHeadlight.alpha = 0.7;
var leftHeadlightInner = self.attachAsset('lightBeamInner', {
anchorX: 0.5,
anchorY: 1
});
leftHeadlightInner.x = -25;
leftHeadlightInner.y = -80;
leftHeadlightInner.alpha = 0.9;
// Right headlight system
var rightHeadlightGlow = self.attachAsset('lightGlow', {
anchorX: 0.5,
anchorY: 1
});
rightHeadlightGlow.x = 25;
rightHeadlightGlow.y = -80;
rightHeadlightGlow.alpha = 0.15;
rightHeadlightGlow.scaleY = 1.5;
var rightHeadlightOuter = self.attachAsset('lightBeamOuter', {
anchorX: 0.5,
anchorY: 1
});
rightHeadlightOuter.x = 25;
rightHeadlightOuter.y = -80;
rightHeadlightOuter.alpha = 0.4;
var rightHeadlight = self.attachAsset('lightBeam', {
anchorX: 0.5,
anchorY: 1
});
rightHeadlight.x = 25;
rightHeadlight.y = -80;
rightHeadlight.alpha = 0.7;
var rightHeadlightInner = self.attachAsset('lightBeamInner', {
anchorX: 0.5,
anchorY: 1
});
rightHeadlightInner.x = 25;
rightHeadlightInner.y = -80;
rightHeadlightInner.alpha = 0.9;
// Store headlight references for dynamic effects
self.leftHeadlights = [leftHeadlightGlow, leftHeadlightOuter, leftHeadlight, leftHeadlightInner];
self.rightHeadlights = [rightHeadlightGlow, rightHeadlightOuter, rightHeadlight, rightHeadlightInner];
// Add exhaust particles
self.exhaustSystem = self.addChild(new ParticleSystem('exhaustParticle', 15));
self.exhaustSystem.y = 90;
// Add headlight sparkle system for enhanced visual effects
self.headlightSparkleSystem = self.addChild(new ParticleSystem('sparkleParticle', 10));
self.headlightSparkleSystem.y = -80;
// Add explosion system for collisions
self.explosionSystem = self.addChild(new ParticleSystem('explosionParticle', 30));
// Add shield effect (initially hidden)
self.shieldEffect = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
self.shieldEffect.alpha = 0;
self.shieldEffect.scaleX = 1.5;
self.shieldEffect.scaleY = 1.5;
self.switchLane = function (lane) {
if (self.currentLane !== lane) {
self.currentLane = lane;
self.targetX = lane === 0 ? leftLaneX : rightLaneX;
LK.getSound('switch').play();
}
};
self.activateShield = function () {
self.shieldActive = true;
self.shieldTime = 300; // 5 seconds at 60fps
tween(self.shieldEffect, {
alpha: 0.6
}, {
duration: 200
});
LK.getSound('powerup').play();
};
self.activateBoost = function () {
self.boostActive = true;
self.boostTime = 180; // 3 seconds at 60fps
self.regularBoostActive = true; // Track regular boost separately
self.regularBoostAmount = 3; // Track how much boost regular adds
gameSpeed += self.regularBoostAmount;
LK.getSound('boost').play();
// Screen effect
tween(game, {
tint: 0x00ffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(game, {
tint: 0xffffff
}, {
duration: 100
});
}
});
};
self.triggerExplosion = function (x, y) {
// Create dramatic explosion effect
for (var i = 0; i < 20; i++) {
self.explosionSystem.emit(x, y, 5);
}
// Screen shake effect
tween(self, {
x: self.x + 10
}, {
duration: 50,
onFinish: function onFinish() {
tween(self, {
x: self.x - 10
}, {
duration: 50,
onFinish: function onFinish() {
tween(self, {
x: self.targetX
}, {
duration: 50
});
}
});
}
});
};
self.update = function () {
// Smooth lane switching with tween animation
var diff = self.targetX - self.x;
if (Math.abs(diff) > 2) {
self.x += diff * 0.15;
} else {
self.x = self.targetX;
}
// Update exhaust particles
if (self.exhaustSystem) {
self.exhaustSystem.emit(0, 90, 0.5);
self.exhaustSystem.update();
}
// Update explosion system
if (self.explosionSystem) {
self.explosionSystem.update();
}
// Update headlight sparkle system for enhanced visual effects
if (self.headlightSparkleSystem) {
// Emit sparkles from headlight positions occasionally
if (Math.random() < 0.1) {
self.headlightSparkleSystem.emit(-25, -80, 0.5);
self.headlightSparkleSystem.emit(25, -80, 0.5);
}
// Extra sparkles during boost
if (self.boostActive && Math.random() < 0.3) {
self.headlightSparkleSystem.emit(-25, -80, 1.5);
self.headlightSparkleSystem.emit(25, -80, 1.5);
}
self.headlightSparkleSystem.update();
}
// Update shield effect
if (self.shieldActive) {
self.shieldTime--;
if (self.shieldTime <= 0) {
self.shieldActive = false;
tween(self.shieldEffect, {
alpha: 0
}, {
duration: 300
});
} else {
self.shieldEffect.rotation += 0.1;
self.shieldEffect.alpha = 0.6 + Math.sin(LK.ticks * 0.2) * 0.2;
}
}
// Update boost effect
if (self.boostActive) {
self.boostTime--;
if (self.boostTime <= 0) {
self.boostActive = false;
// Properly remove boost amounts based on what was active
if (self.nitroActive) {
gameSpeed = Math.max(gameSpeed - self.nitroBoostAmount, 2);
self.nitroActive = false;
self.nitroBoostAmount = 0;
}
if (self.regularBoostActive) {
gameSpeed = Math.max(gameSpeed - self.regularBoostAmount, 2);
self.regularBoostActive = false;
self.regularBoostAmount = 0;
}
}
// Emit nitro flames with enhanced effects
if (self.exhaustSystem) {
self.exhaustSystem.emit(-10, 90, 3);
self.exhaustSystem.emit(10, 90, 3);
// Extra flame particles for nitro effect
self.exhaustSystem.emit(-15, 85, 2);
self.exhaustSystem.emit(15, 85, 2);
}
}
// Enhanced headlight effects with dynamic behavior
if (self.leftHeadlights && self.rightHeadlights) {
// Base pulsing effect synchronized with engine
var pulseIntensity = 0.1 + Math.sin(LK.ticks * 0.1) * 0.05;
// Speed-based brightness - faster = brighter beams
var speedMultiplier = 1 + (gameSpeed - 2) * 0.1;
// Boost effects on headlights
var boostMultiplier = 1;
if (self.boostActive) {
boostMultiplier = 1.5;
// Flickering effect during boost
pulseIntensity += Math.sin(LK.ticks * 0.3) * 0.2;
}
if (self.nitroActive) {
boostMultiplier = 2;
// Intense flickering for nitro
pulseIntensity += Math.sin(LK.ticks * 0.5) * 0.3;
}
// Apply effects to both headlight systems
for (var h = 0; h < self.leftHeadlights.length; h++) {
var leftBeam = self.leftHeadlights[h];
var rightBeam = self.rightHeadlights[h];
// Dynamic brightness based on speed and boost
var baseBrightness = h === 0 ? 0.15 : h === 1 ? 0.4 : h === 2 ? 0.7 : 0.9;
var finalBrightness = baseBrightness * speedMultiplier * boostMultiplier;
leftBeam.alpha = Math.min(finalBrightness + pulseIntensity, 1.0);
rightBeam.alpha = Math.min(finalBrightness + pulseIntensity, 1.0);
// Dynamic beam scaling based on speed
var scaleMultiplier = 1 + (gameSpeed - 2) * 0.05;
leftBeam.scaleY = (h === 0 ? 1.5 : 1.0) * scaleMultiplier;
rightBeam.scaleY = (h === 0 ? 1.5 : 1.0) * scaleMultiplier;
}
// Lane switching beam angle effect
var laneOffset = (self.targetX - self.x) * 0.01;
for (var h = 0; h < self.leftHeadlights.length; h++) {
self.leftHeadlights[h].rotation = laneOffset;
self.rightHeadlights[h].rotation = laneOffset;
}
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.powerType = type;
var powerGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
// Add glow effect with different colors based on type
var glowColor = 0x00ffff; // Default cyan
if (type === 'nitroFlame') {
glowColor = 0xff4500; // Orange for nitro
} else if (type === 'coin') {
glowColor = 0xffd700; // Gold for coins
}
var glow = self.attachAsset('glowEffect', {
anchorX: 0.5,
anchorY: 0.5
});
glow.alpha = 0.3;
glow.scaleX = 0.5;
glow.scaleY = 0.5;
glow.tint = glowColor;
self.speed = 8;
self.collected = false;
self.rotationSpeed = 0.1;
self.multiplier = 1; // Default multiplier for coins
// Set coin multiplier based on type
if (type === 'coin2x') {
self.multiplier = 2;
self.rotationSpeed = 0.2;
} else if (type === 'coin3x') {
self.multiplier = 3;
self.rotationSpeed = 0.3;
}
self.update = function () {
self.y += self.speed + gameSpeed;
self.rotation += self.rotationSpeed;
// Enhanced pulsing glow effect with different intensities
var pulseIntensity = self.multiplier > 1 ? 0.4 : 0.2;
glow.alpha = 0.3 + Math.sin(LK.ticks * 0.1) * pulseIntensity;
glow.scaleX = 0.5 + Math.sin(LK.ticks * 0.1) * pulseIntensity;
glow.scaleY = 0.5 + Math.sin(LK.ticks * 0.1) * pulseIntensity;
// Extra rotation for multiplier coins
if (self.multiplier > 1) {
powerGraphics.rotation += self.rotationSpeed * 0.5;
}
};
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 + gameSpeed;
};
return self;
});
var Shop = Container.expand(function () {
var self = Container.call(this);
// Background panel
var panel = self.attachAsset('carSelectPanel', {
anchorX: 0.5,
anchorY: 0.5
});
panel.alpha = 0.95;
// Title
var titleBg = self.attachAsset('carSelectTitle', {
anchorX: 0.5,
anchorY: 0.5
});
titleBg.y = -500;
titleBg.alpha = 0.9;
titleBg.scaleX = 1.4;
titleBg.scaleY = 1.3;
var titleText = new Text2('🏪 SHOP', {
size: 95,
fill: '#ffffff'
});
titleText.anchor.set(0.5, 0.5);
titleBg.addChild(titleText);
// Coins display
var coinsBg = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
coinsBg.y = -400;
coinsBg.alpha = 0.95;
coinsBg.scaleX = 1.3;
coinsBg.scaleY = 1.2;
var coinsText = new Text2('💰 COINS: ' + (storage.totalCoins || 0), {
size: 55,
fill: '#ffd700'
});
coinsText.anchor.set(0.5, 0.5);
coinsBg.addChild(coinsText);
// Shop items
var shopItems = [{
name: 'SPORTS CAR',
type: 'sports',
price: 500,
description: 'High speed racing car'
}, {
name: 'LUXURY CAR',
type: 'luxury',
price: 1000,
description: 'Premium comfort vehicle'
}, {
name: 'RACE CAR',
type: 'race',
price: 2000,
description: 'Professional racing machine'
}, {
name: 'CLASSIC CAR',
type: 'classic',
price: 750,
description: 'Vintage style automobile'
}];
var itemCards = [];
for (var i = 0; i < shopItems.length; i++) {
var item = shopItems[i];
var card = self.addChild(new Container());
var cardBg = card.attachAsset('carSelectCard', {
anchorX: 0.5,
anchorY: 0.5
});
cardBg.alpha = 0.8;
// Position cards in 2x2 grid
var col = i % 2;
var row = Math.floor(i / 2);
card.x = (col - 0.5) * 500;
card.y = (row - 0.5) * 300 - 50;
// Car preview
var carPreview = card.addChild(new CarPreview(item.type));
carPreview.y = -100;
carPreview.scaleX = 0.6;
carPreview.scaleY = 0.6;
// Item name
var nameText = new Text2(item.name, {
size: 30,
fill: '#ffffff'
});
nameText.anchor.set(0.5, 0.5);
card.addChild(nameText);
nameText.y = 20;
// Price
var priceText = new Text2(item.price + ' COINS', {
size: 25,
fill: '#ffd700'
});
priceText.anchor.set(0.5, 0.5);
card.addChild(priceText);
priceText.y = 50;
// Description
var descText = new Text2(item.description, {
size: 18,
fill: '#cccccc'
});
descText.anchor.set(0.5, 0.5);
card.addChild(descText);
descText.y = 80;
// Buy/Owned button
var buyButton = card.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
buyButton.y = 120;
buyButton.alpha = 0.9;
var ownedCars = storage.ownedCars || ['default'];
var isOwned = ownedCars.indexOf(item.type) !== -1;
var canAfford = (storage.totalCoins || 0) >= item.price;
var buttonText = new Text2(isOwned ? 'OWNED' : canAfford ? 'BUY' : 'NOT ENOUGH COINS', {
size: 20,
fill: isOwned ? '#00ff00' : canAfford ? '#ffffff' : '#ff0000'
});
buttonText.anchor.set(0.5, 0.5);
buyButton.addChild(buttonText);
buyButton.itemType = item.type;
buyButton.itemPrice = item.price;
buyButton.isOwned = isOwned;
buyButton.canAfford = canAfford;
itemCards.push({
card: card,
button: buyButton,
item: item
});
}
// Back button
var backButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
backButton.y = 400;
backButton.alpha = 0.9;
var backText = new Text2('BACK TO MENU', {
size: 30,
fill: '#ffffff'
});
backText.anchor.set(0.5, 0.5);
backButton.addChild(backText);
self.itemCards = itemCards;
self.backButton = backButton;
self.coinsText = coinsText;
self.down = function (x, y, obj) {
// Check back button
var backBounds = {
left: self.backButton.x - 180,
right: self.backButton.x + 180,
top: self.backButton.y - 50,
bottom: self.backButton.y + 50
};
if (x >= backBounds.left && x <= backBounds.right && y >= backBounds.top && y <= backBounds.bottom) {
LK.effects.flashObject(self.backButton, 0x00ff00, 200);
self.goBackToMenu();
return;
}
// Check item cards
for (var i = 0; i < self.itemCards.length; i++) {
var cardData = self.itemCards[i];
var button = cardData.button;
var buttonBounds = {
left: cardData.card.x + button.x - 180,
right: cardData.card.x + button.x + 180,
top: cardData.card.y + button.y - 50,
bottom: cardData.card.y + button.y + 50
};
if (x >= buttonBounds.left && x <= buttonBounds.right && y >= buttonBounds.top && y <= buttonBounds.bottom) {
if (!button.isOwned && button.canAfford) {
self.purchaseItem(cardData.item);
LK.effects.flashObject(button, 0x00ff00, 200);
} else {
LK.effects.flashObject(button, 0xff0000, 200);
}
break;
}
}
};
self.purchaseItem = function (item) {
var currentCoins = storage.totalCoins || 0;
if (currentCoins >= item.price) {
// Deduct coins
storage.totalCoins = currentCoins - item.price;
// Add car to owned cars
var ownedCars = storage.ownedCars || ['default'];
ownedCars.push(item.type);
storage.ownedCars = ownedCars;
// Update display
self.coinsText.setText('COINS: ' + storage.totalCoins);
// Refresh shop display
self.destroy();
shop = game.addChild(new Shop());
shop.x = 1024;
shop.y = 1366;
}
};
self.goBackToMenu = function () {
LK.setTimeout(function () {
if (shop) {
shop.destroy();
shop = null;
}
initMainMenu();
}, 300);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game state variables
// Player car detail assets
// Enemy car detail assets
// Truck detail assets
// Barrier detail assets
// Car selection assets
// Car selection UI assets
var gameState = 'mainMenu'; // 'mainMenu', 'carSelection', 'playing', 'shop'
var selectedCarType = 'default';
var selectedRoadType = 'highway';
var mainMenu = null;
var carSelectionScreen = null;
var shop = null;
// Enhanced game features
var rainSystem = null;
var sparkleSystem = null;
var powerUps = [];
var coins = [];
var playerStats = storage.playerStats || {
totalDistance: 0,
totalCoins: 0,
bestScore: 0,
gamesPlayed: 0
};
var currentCoins = 0;
var coinMultiplier = 1;
var coinMultiplierTime = 0;
// Initialize storage defaults
if (!storage.totalCoins) storage.totalCoins = 0;
if (!storage.ownedCars) storage.ownedCars = ['default'];
var weatherEnabled = true;
var lightingEnabled = true;
// Game variables
var gameSpeed = 2;
var difficultyTimer = 0;
var obstacleTimer = 0;
var roadLineTimer = 0;
var leftLaneX = 1024 - 200;
var rightLaneX = 1024 + 200;
// Game objects arrays
var obstacles = [];
var roadLines = [];
var obstacleTypes = ['enemyCar', 'truck', 'barrier'];
// Create road surface
var roadSurface = game.addChild(LK.getAsset('roadSurface', {
anchorX: 0.5,
anchorY: 0.5
}));
roadSurface.x = 1024;
roadSurface.y = 1366;
// Add road illumination spots that will be lit by headlights
var roadIlluminationSpots = [];
for (var i = 0; i < 20; i++) {
var spot = game.addChild(LK.getAsset('lightGlow', {
anchorX: 0.5,
anchorY: 0.5
}));
spot.x = 1024;
spot.y = 1500 + i * 200;
spot.alpha = 0;
spot.scaleX = 2;
spot.scaleY = 1.5;
spot.tint = 0xffff99;
roadIlluminationSpots.push(spot);
}
// Add road texture patterns for realism
for (var i = 0; i < 60; i++) {
var textureStripe = game.addChild(LK.getAsset('roadTexture', {
anchorX: 0.5,
anchorY: 0.5
}));
textureStripe.x = 1024;
textureStripe.y = i * 50;
textureStripe.alpha = 0.3;
}
// Add asphalt pattern details
for (var i = 0; i < 200; i++) {
var pattern = game.addChild(LK.getAsset('asphaltPattern', {
anchorX: 0.5,
anchorY: 0.5
}));
pattern.x = 424 + Math.random() * 1200;
pattern.y = Math.random() * 2732;
pattern.alpha = 0.2;
pattern.rotation = Math.random() * Math.PI;
}
// Create road sides
var leftSide = game.addChild(LK.getAsset('roadSide', {
anchorX: 0.5,
anchorY: 0.5
}));
leftSide.x = 374;
leftSide.y = 1366;
var rightSide = game.addChild(LK.getAsset('roadSide', {
anchorX: 0.5,
anchorY: 0.5
}));
rightSide.x = 1674;
rightSide.y = 1366;
// Add road edge lines for realism
var leftEdge = game.addChild(LK.getAsset('roadEdge', {
anchorX: 0.5,
anchorY: 0.5
}));
leftEdge.x = 424;
leftEdge.y = 1366;
var rightEdge = game.addChild(LK.getAsset('roadEdge', {
anchorX: 0.5,
anchorY: 0.5
}));
rightEdge.x = 1624;
rightEdge.y = 1366;
// Initialize main menu with enhanced animations
function initMainMenu() {
mainMenu = game.addChild(new MainMenu());
mainMenu.x = 1024;
mainMenu.y = 1366;
// Add animated background elements
for (var i = 0; i < 8; i++) {
var bgCar = game.addChild(LK.getAsset('sportsCar', {
anchorX: 0.5,
anchorY: 0.5
}));
bgCar.x = Math.random() * 2048;
bgCar.y = Math.random() * 2732;
bgCar.alpha = 0.1;
bgCar.scaleX = 0.3;
bgCar.scaleY = 0.3;
bgCar.rotation = Math.random() * Math.PI * 2;
// Animate background cars
tween(bgCar, {
rotation: bgCar.rotation + Math.PI * 2
}, {
duration: 8000 + Math.random() * 4000,
easing: tween.linear
});
}
// Add sparkle effects
if (!sparkleSystem) {
sparkleSystem = game.addChild(new ParticleSystem('sparkleParticle', 20));
}
}
// Initialize car selection screen
function initCarSelection() {
carSelectionScreen = game.addChild(new CarSelectionScreen());
carSelectionScreen.x = 1024;
carSelectionScreen.y = 1366;
}
initMainMenu();
// Game start function
function startGame() {
gameState = 'playing';
// Create player car with selected type
playerCar = game.addChild(new PlayerCar(selectedCarType));
playerCar.x = leftLaneX;
playerCar.y = 2400;
playerCar.targetX = leftLaneX;
// Make playerCar globally accessible
game.playerCar = playerCar;
// Initialize particle systems
rainSystem = game.addChild(new ParticleSystem('rainDrop', 50));
sparkleSystem = game.addChild(new ParticleSystem('sparkleParticle', 30));
// Lighting effects removed from game environment
// Car headlights remain intact in PlayerCar class
// Adjust game difficulty based on road type
if (selectedRoadType === 'city') {
gameSpeed = 3;
obstacleTypes = ['enemyCar', 'truck', 'barrier']; // Start with balanced obstacles
} else {
gameSpeed = 2;
obstacleTypes = ['enemyCar', 'truck', 'barrier']; // Default highway
}
}
// Placeholder for player car (will be created after car selection)
var playerCar = null;
// Create dashboard panel
var dashboardPanel = LK.getAsset('dashboardPanel', {
anchorX: 0.5,
anchorY: 0
});
LK.gui.top.addChild(dashboardPanel);
dashboardPanel.y = 20;
dashboardPanel.alpha = 0.8;
// Create speedometer
var speedometer = LK.getAsset('speedometer', {
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.topRight.addChild(speedometer);
speedometer.x = -150;
speedometer.y = 100;
speedometer.alpha = 0.9;
// Create speedometer needle
var speedometerNeedle = LK.getAsset('speedometerNeedle', {
anchorX: 0.5,
anchorY: 1
});
speedometer.addChild(speedometerNeedle);
speedometerNeedle.y = 20;
// Create mini map
var miniMap = LK.getAsset('miniMap', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(miniMap);
miniMap.x = 120;
miniMap.y = 50;
miniMap.alpha = 0.7;
// Create score display with dashboard styling
var scoreText = new Text2('DISTANCE: 0', {
size: 50,
fill: '#00ff00'
});
scoreText.anchor.set(0.5, 0.5);
dashboardPanel.addChild(scoreText);
scoreText.y = -15;
// Create speed display with dashboard styling
var speedText = new Text2('SPEED: 1', {
size: 40,
fill: '#ffff00'
});
speedText.anchor.set(0.5, 0.5);
dashboardPanel.addChild(speedText);
speedText.y = 25;
// Create coin counter display
var coinText = new Text2('COINS: 0', {
size: 35,
fill: '#ffd700'
});
coinText.anchor.set(0.5, 0.5);
dashboardPanel.addChild(coinText);
coinText.y = 55;
// Touch controls
game.down = function (x, y, obj) {
if (gameState === 'carSelection' && carSelectionScreen) {
// Convert touch coordinates to car selection screen coordinates
var localPos = carSelectionScreen.toLocal({
x: x,
y: y
});
carSelectionScreen.down(localPos.x, localPos.y, obj);
return;
} else if (gameState === 'playing' && game.playerCar) {
if (x < 1024) {
// Left side of screen - switch to left lane
game.playerCar.switchLane(0);
} else {
// Right side of screen - switch to right lane
game.playerCar.switchLane(1);
}
}
};
// Spawn obstacle function
function spawnObstacle() {
// Difficulty scaling based on score
var currentScore = LK.getScore();
var difficultyLevel = Math.floor(currentScore / 100); // Every 100 points increases difficulty
var barrierChance = Math.min(0.1 + difficultyLevel * 0.05, 0.4); // Start with 10% barriers, max 40%
var enemyChance = Math.min(0.6 + difficultyLevel * 0.1, 0.8); // Start with 60% enemies, max 80%
// Select obstacle type based on difficulty
var obstacleType;
var rand = Math.random();
if (rand < barrierChance) {
obstacleType = 'barrier';
} else if (rand < barrierChance + enemyChance) {
obstacleType = 'enemyCar';
} else {
obstacleType = 'truck';
}
var obstacle = new Obstacle(obstacleType);
// Randomly place in left or right lane
var lane = Math.floor(Math.random() * 2);
obstacle.x = lane === 0 ? leftLaneX : rightLaneX;
obstacle.y = -200;
obstacle.lane = lane;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Spawn road line function
function spawnRoadLine() {
var roadLine = new RoadLine();
roadLine.x = 1024;
roadLine.y = -50;
roadLines.push(roadLine);
game.addChild(roadLine);
}
// Spawn power-up function
function spawnPowerUp() {
var powerUpTypes = ['speedBoost', 'shield'];
var powerUpType = powerUpTypes[Math.floor(Math.random() * powerUpTypes.length)];
var powerUp = new PowerUp(powerUpType);
var lane = Math.floor(Math.random() * 2);
powerUp.x = lane === 0 ? leftLaneX : rightLaneX;
powerUp.y = -200;
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Spawn coin function
function spawnCoin() {
var coinTypes = ['coin', 'coin', 'coin', 'coin', 'coin2x', 'coin3x']; // Regular coins more common
var coinType = coinTypes[Math.floor(Math.random() * coinTypes.length)];
var coin = new PowerUp(coinType);
var lane = Math.floor(Math.random() * 2);
coin.x = lane === 0 ? leftLaneX : rightLaneX;
coin.y = -200;
coins.push(coin);
game.addChild(coin);
}
// Precise collision detection function
function checkPreciseCollision(obj1, obj2) {
// Get the bounds of both objects
var obj1Bounds = {
left: obj1.x - obj1.width / 2,
right: obj1.x + obj1.width / 2,
top: obj1.y - obj1.height / 2,
bottom: obj1.y + obj1.height / 2
};
var obj2Bounds = {
left: obj2.x - obj2.width / 2,
right: obj2.x + obj2.width / 2,
top: obj2.y - obj2.height / 2,
bottom: obj2.y + obj2.height / 2
};
// Check for precise overlap (not just touching)
var overlapX = Math.max(0, Math.min(obj1Bounds.right, obj2Bounds.right) - Math.max(obj1Bounds.left, obj2Bounds.left));
var overlapY = Math.max(0, Math.min(obj1Bounds.bottom, obj2Bounds.bottom) - Math.max(obj1Bounds.top, obj2Bounds.top));
// Require significant overlap (at least 30 pixels in both directions)
return overlapX >= 30 && overlapY >= 30;
}
// Main game update loop
game.update = function () {
if (gameState === 'mainMenu' || gameState === 'carSelection' || gameState === 'shop') {
// Add sparkle effects to menu screens
if (sparkleSystem && Math.random() < 0.3) {
sparkleSystem.emit(Math.random() * 2048, Math.random() * 2732, 0.8);
}
if (sparkleSystem) {
sparkleSystem.update();
}
// Menu screens are active, don't update game logic
return;
}
if (gameState === 'playing' && game.playerCar) {
// Update difficulty
difficultyTimer++;
if (difficultyTimer % 600 === 0) {
// Every 10 seconds
gameSpeed += 0.5;
speedText.setText('SPEED: ' + Math.floor(gameSpeed) + ' KM/H');
}
// Update score
LK.setScore(Math.floor(LK.ticks / 10));
scoreText.setText('DISTANCE: ' + LK.getScore() + ' M');
// Update coin multiplier timer
if (coinMultiplierTime > 0) {
coinMultiplierTime--;
if (coinMultiplierTime <= 0) {
coinMultiplier = 1;
}
}
// Display coins with multiplier info
var coinDisplayText = 'COINS: ' + currentCoins;
if (coinMultiplier > 1) {
coinDisplayText += ' (x' + coinMultiplier + ')';
}
coinText.setText(coinDisplayText);
// Toggle night mode every 30 seconds for dynamic gameplay
var isNightTime = Math.floor(LK.ticks / 1800) % 2 === 1;
if (isNightTime) {
// Darken the game environment
roadSurface.tint = 0x444444;
for (var side = 0; side < 2; side++) {
if (side === 0) leftSide.tint = 0x222222;else rightSide.tint = 0x222222;
}
} else {
// Daytime colors
roadSurface.tint = 0xffffff;
leftSide.tint = 0xffffff;
rightSide.tint = 0xffffff;
}
// Update road illumination based on player car position and headlights
if (game.playerCar && roadIlluminationSpots) {
for (var i = 0; i < roadIlluminationSpots.length; i++) {
var spot = roadIlluminationSpots[i];
var distanceFromPlayer = Math.abs(spot.y - game.playerCar.y);
// Illuminate spots in front of the car
if (distanceFromPlayer < 300 && spot.y > game.playerCar.y - 100) {
var intensity = Math.max(0, 1 - distanceFromPlayer / 300);
spot.alpha = intensity * 0.3 * (isNightTime ? 2 : 0.5);
// Move spots to follow road movement
spot.y += gameSpeed + 2;
if (spot.y > 2800) {
spot.y = -100;
}
} else {
spot.alpha = 0;
}
}
}
// Update environmental effects
if (weatherEnabled && rainSystem) {
for (var r = 0; r < 3; r++) {
rainSystem.emit(Math.random() * 2048, -50, 1.5);
}
rainSystem.update();
}
if (sparkleSystem) {
if (Math.random() < 0.1) {
sparkleSystem.emit(Math.random() * 2048, Math.random() * 2732, 0.5);
}
sparkleSystem.update();
}
// Spawn obstacles
obstacleTimer++;
// Progressive difficulty: spawn rate increases with score
var currentScore = LK.getScore();
var difficultyLevel = Math.floor(currentScore / 50); // Every 50 points increases spawn rate
var baseSpawnRate = 120; // Start with slower spawn rate (2 seconds)
var spawnRate = Math.max(baseSpawnRate - difficultyLevel * 10, 45); // Minimum 0.75 seconds between spawns
if (obstacleTimer % spawnRate === 0) {
spawnObstacle();
}
// Spawn power-ups occasionally
if (LK.ticks % 600 === 0) {
// Every 10 seconds
spawnPowerUp();
}
// Spawn coins frequently
if (LK.ticks % 180 === 0) {
// Every 3 seconds
spawnCoin();
}
// Spawn road lines
roadLineTimer++;
if (roadLineTimer % 40 === 0) {
spawnRoadLine();
}
// Spawn lane dividers for center line
if (roadLineTimer % 30 === 0) {
var laneDivider = new LaneDivider();
laneDivider.x = 1024;
laneDivider.y = -50;
roadLines.push(laneDivider);
game.addChild(laneDivider);
}
// Update speedometer needle rotation based on speed
speedometerNeedle.rotation = gameSpeed / 10 * Math.PI * 0.5;
// Update and check obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Check if obstacle is off screen
if (obstacle.y > 2800) {
// Give points for passing obstacle
if (!obstacle.passed) {
LK.setScore(LK.getScore() + 10);
obstacle.passed = true;
}
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with player using precise detection (skip if shield is active)
if (checkPreciseCollision(obstacle, game.playerCar) && !game.playerCar.shieldActive) {
// Trigger explosion effect at collision point
var explosionX = (obstacle.x + game.playerCar.x) / 2;
var explosionY = (obstacle.y + game.playerCar.y) / 2;
game.playerCar.triggerExplosion(explosionX, explosionY);
// Multiple explosion bursts for dramatic effect
LK.setTimeout(function () {
game.playerCar.triggerExplosion(explosionX + 20, explosionY - 10);
}, 100);
LK.setTimeout(function () {
game.playerCar.triggerExplosion(explosionX - 15, explosionY + 15);
}, 200);
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 1000);
// Update player stats and storage
playerStats.totalDistance += LK.getScore();
playerStats.totalCoins += currentCoins;
playerStats.gamesPlayed++;
if (LK.getScore() > playerStats.bestScore) {
playerStats.bestScore = LK.getScore();
}
storage.playerStats = playerStats;
// Add coins to total storage
storage.totalCoins = (storage.totalCoins || 0) + currentCoins;
// Reset game state
gameState = 'mainMenu';
LK.showGameOver();
return;
}
// Check if obstacle was passed for scoring
if (!obstacle.passed && obstacle.y > game.playerCar.y + 100) {
obstacle.passed = true;
LK.setScore(LK.getScore() + 5);
}
}
// Update and check power-ups
for (var p = powerUps.length - 1; p >= 0; p--) {
var powerUp = powerUps[p];
if (powerUp.y > 2800) {
powerUp.destroy();
powerUps.splice(p, 1);
continue;
}
// Check collection
if (powerUp.intersects(game.playerCar) && !powerUp.collected) {
powerUp.collected = true;
// Activate power-up effect
if (powerUp.powerType === 'speedBoost') {
game.playerCar.activateBoost();
} else if (powerUp.powerType === 'shield') {
game.playerCar.activateShield();
}
// Visual feedback
sparkleSystem.emit(powerUp.x, powerUp.y, 2);
tween(powerUp, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
powerUp.destroy();
}
});
powerUps.splice(p, 1);
}
}
// Update and check coins
for (var c = coins.length - 1; c >= 0; c--) {
var coin = coins[c];
if (coin.y > 2800) {
coin.destroy();
coins.splice(c, 1);
continue;
}
// Check collection
if (coin.intersects(game.playerCar) && !coin.collected) {
coin.collected = true;
var coinsEarned = coin.multiplier || 1;
// Apply global coin multiplier if active
if (coinMultiplierTime > 0) {
coinsEarned *= coinMultiplier;
}
currentCoins += coinsEarned;
LK.getSound('coin').play();
// Enhanced visual feedback for multiplier coins
var sparkleForce = coin.multiplier > 1 ? 3 : 1.5;
sparkleSystem.emit(coin.x, coin.y, sparkleForce);
// Special effect for multiplier coins
if (coin.multiplier > 1) {
coinMultiplier = coin.multiplier;
coinMultiplierTime = 600; // 10 seconds at 60fps
// Flash effect for multiplier activation
tween(coinText, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xffd700
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(coinText, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
tween(coin, {
alpha: 0,
y: coin.y - 50
}, {
duration: 500,
onFinish: function onFinish() {
coin.destroy();
}
});
coins.splice(c, 1);
}
}
// Update and clean up road lines
for (var j = roadLines.length - 1; j >= 0; j--) {
var roadLine = roadLines[j];
if (roadLine.y > 2800) {
roadLine.destroy();
roadLines.splice(j, 1);
}
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var CarPreview = Container.expand(function (carType) {
var self = Container.call(this);
if (carType === 'sports') {
// Sports car preview
var body = self.attachAsset('sportsCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('sportsCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -40;
var rearWindow = self.attachAsset('sportsCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 40;
var leftWindow = self.attachAsset('sportsCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -30;
leftWindow.y = -10;
var rightWindow = self.attachAsset('sportsCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 30;
rightWindow.y = -10;
var spoiler = self.attachAsset('sportsCarSpoiler', {
anchorX: 0.5,
anchorY: 0.5
});
spoiler.y = 80;
var stripe = self.attachAsset('sportsCarStripe', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (carType === 'luxury') {
// Luxury car preview
var body = self.attachAsset('luxuryCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('luxuryCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -45;
var rearWindow = self.attachAsset('luxuryCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 45;
var leftWindow = self.attachAsset('luxuryCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -35;
leftWindow.y = -15;
var rightWindow = self.attachAsset('luxuryCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 35;
rightWindow.y = -15;
var grill = self.attachAsset('luxuryCarGrill', {
anchorX: 0.5,
anchorY: 0.5
});
grill.y = -90;
var trim = self.attachAsset('luxuryCarTrim', {
anchorX: 0.5,
anchorY: 0.5
});
trim.y = 90;
} else if (carType === 'race') {
// Race car preview
var body = self.attachAsset('raceCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('raceCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -35;
var rearWindow = self.attachAsset('raceCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 35;
var leftWindow = self.attachAsset('raceCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -25;
leftWindow.y = -5;
var rightWindow = self.attachAsset('raceCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 25;
rightWindow.y = -5;
var wing = self.attachAsset('raceCarWing', {
anchorX: 0.5,
anchorY: 0.5
});
wing.y = 75;
var number = self.attachAsset('raceCarNumber', {
anchorX: 0.5,
anchorY: 0.5
});
number.y = -60;
} else if (carType === 'classic') {
// Classic car preview
var body = self.attachAsset('classicCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('classicCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -42;
var rearWindow = self.attachAsset('classicCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 42;
var leftWindow = self.attachAsset('classicCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -32;
leftWindow.y = -12;
var rightWindow = self.attachAsset('classicCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 32;
rightWindow.y = -12;
var bumper = self.attachAsset('classicCarBumper', {
anchorX: 0.5,
anchorY: 0.5
});
bumper.y = 87;
var trim = self.attachAsset('classicCarTrim', {
anchorX: 0.5,
anchorY: 0.5
});
trim.y = -87;
}
return self;
});
var CarSelectionScreen = Container.expand(function () {
var self = Container.call(this);
// Background panel
var panel = self.attachAsset('carSelectPanel', {
anchorX: 0.5,
anchorY: 0.5
});
panel.alpha = 0.95;
// Title
var titleBg = self.attachAsset('carSelectTitle', {
anchorX: 0.5,
anchorY: 0.5
});
titleBg.y = -450;
titleBg.alpha = 0.9;
titleBg.scaleX = 1.4;
titleBg.scaleY = 1.3;
var titleText = new Text2('🚗 SELECT YOUR CAR', {
size: 95,
fill: '#ffffff'
});
titleText.anchor.set(0.5, 0.5);
titleBg.addChild(titleText);
// Back button
var backButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
backButton.y = -370;
backButton.alpha = 0.95;
backButton.scaleX = 1.1;
backButton.scaleY = 1.1;
var backText = new Text2('⬅️ BACK', {
size: 40,
fill: '#ffffff'
});
backText.anchor.set(0.5, 0.5);
backButton.addChild(backText);
// Road selection section
var roadTitleBg = self.attachAsset('carSelectTitle', {
anchorX: 0.5,
anchorY: 0.5
});
roadTitleBg.y = 350;
roadTitleBg.alpha = 0.8;
var roadTitleText = new Text2('SELECT ROAD TYPE', {
size: 60,
fill: '#ffffff'
});
roadTitleText.anchor.set(0.5, 0.5);
roadTitleBg.addChild(roadTitleText);
// Road type buttons
var roadTypes = [{
type: 'highway',
name: 'HIGHWAY',
description: 'Fast traffic'
}, {
type: 'city',
name: 'CITY ROAD',
description: 'Heavy traffic'
}];
var roadButtons = [];
for (var r = 0; r < roadTypes.length; r++) {
var roadButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
roadButton.x = (r - 0.5) * 400;
roadButton.y = 450;
roadButton.alpha = 0.9;
roadButton.roadType = roadTypes[r].type;
var roadButtonText = new Text2(roadTypes[r].name, {
size: 35,
fill: '#ffffff'
});
roadButtonText.anchor.set(0.5, 0.5);
roadButton.addChild(roadButtonText);
roadButtons.push(roadButton);
}
// Get owned cars from storage
var ownedCars = storage.ownedCars || ['default'];
var allCarTypes = [{
type: 'default',
name: 'DEFAULT CAR',
speed: 'MEDIUM',
handling: 'GOOD'
}, {
type: 'sports',
name: 'SPORTS CAR',
speed: 'HIGH',
handling: 'EXCELLENT'
}, {
type: 'luxury',
name: 'LUXURY CAR',
speed: 'MEDIUM',
handling: 'GOOD'
}, {
type: 'race',
name: 'RACE CAR',
speed: 'EXTREME',
handling: 'PERFECT'
}, {
type: 'classic',
name: 'CLASSIC CAR',
speed: 'LOW',
handling: 'STABLE'
}];
// Filter to only show owned cars
var availableCarTypes = [];
for (var a = 0; a < allCarTypes.length; a++) {
if (ownedCars.indexOf(allCarTypes[a].type) !== -1) {
availableCarTypes.push(allCarTypes[a]);
}
}
var cards = [];
for (var i = 0; i < availableCarTypes.length; i++) {
var carType = availableCarTypes[i];
var card = self.addChild(new Container());
var cardBg = card.attachAsset('carSelectCard', {
anchorX: 0.5,
anchorY: 0.5
});
cardBg.alpha = 0.8;
// Position cards in rows, up to 3 per row
var col = i % 3;
var row = Math.floor(i / 3);
card.x = (col - 1) * 400;
card.y = (row - 0.5) * 350 - 100;
// Car preview
var carPreview = card.addChild(new CarPreview(carType.type));
carPreview.y = -80;
carPreview.scaleX = 0.7;
carPreview.scaleY = 0.7;
// Car name
var nameText = new Text2(carType.name, {
size: 35,
fill: '#ffffff'
});
nameText.anchor.set(0.5, 0.5);
card.addChild(nameText);
nameText.y = 50;
// Stats
var speedText = new Text2('SPEED: ' + carType.speed, {
size: 22,
fill: '#f39c12'
});
speedText.anchor.set(0.5, 0.5);
card.addChild(speedText);
speedText.y = 80;
var handlingText = new Text2('HANDLING: ' + carType.handling, {
size: 22,
fill: '#3498db'
});
handlingText.anchor.set(0.5, 0.5);
card.addChild(handlingText);
handlingText.y = 110;
// Select button
var selectButton = card.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
selectButton.y = 160;
selectButton.alpha = 0.9;
var buttonText = new Text2('SELECT', {
size: 30,
fill: '#ffffff'
});
buttonText.anchor.set(0.5, 0.5);
selectButton.addChild(buttonText);
// Store car type for selection
selectButton.carType = carType.type;
cards.push({
card: card,
button: selectButton,
type: carType.type
});
}
self.cards = cards;
self.roadButtons = roadButtons;
self.selectedCar = null;
self.selectedRoad = null;
self.down = function (x, y, obj) {
// Check back button
var backBounds = {
left: backButton.x - 165,
right: backButton.x + 165,
top: backButton.y - 50,
bottom: backButton.y + 50
};
if (x >= backBounds.left && x <= backBounds.right && y >= backBounds.top && y <= backBounds.bottom) {
LK.effects.flashObject(backButton, 0x00ff00, 200);
self.goBackToMenu();
return;
}
// Check if any car card was clicked
for (var i = 0; i < self.cards.length; i++) {
var card = self.cards[i].card;
// Check entire card bounds for easier selection
var cardBounds = {
left: card.x - 220,
right: card.x + 220,
top: card.y - 200,
bottom: card.y + 200
};
// Check if touch is within card bounds
if (x >= cardBounds.left && x <= cardBounds.right && y >= cardBounds.top && y <= cardBounds.bottom) {
// Flash the selected card for visual feedback
LK.effects.flashObject(card, 0x00ff00, 200);
self.selectedCar = self.cards[i].type;
selectedCarType = self.cards[i].type;
// Check if both car and road are selected
if (self.selectedCar && self.selectedRoad) {
self.startGameWithSelections();
}
break;
}
}
// Check if any road button was clicked
for (var r = 0; r < self.roadButtons.length; r++) {
var roadBtn = self.roadButtons[r];
var roadBounds = {
left: roadBtn.x - 180,
right: roadBtn.x + 180,
top: roadBtn.y - 50,
bottom: roadBtn.y + 50
};
if (x >= roadBounds.left && x <= roadBounds.right && y >= roadBounds.top && y <= roadBounds.bottom) {
// Flash the selected road button
LK.effects.flashObject(roadBtn, 0x00ff00, 200);
self.selectedRoad = roadBtn.roadType;
selectedRoadType = roadBtn.roadType;
// Check if both car and road are selected
if (self.selectedCar && self.selectedRoad) {
self.startGameWithSelections();
}
break;
}
}
};
self.goBackToMenu = function () {
LK.setTimeout(function () {
if (carSelectionScreen) {
carSelectionScreen.destroy();
carSelectionScreen = null;
}
initMainMenu();
}, 300);
};
self.startGameWithSelections = function () {
// Small delay before starting game
LK.setTimeout(function () {
if (carSelectionScreen) {
carSelectionScreen.destroy();
carSelectionScreen = null;
}
startGame();
}, 300);
};
return self;
});
var LaneDivider = Container.expand(function () {
var self = Container.call(this);
var dividerGraphics = self.attachAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.update = function () {
self.y += self.speed + gameSpeed;
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Background panel
var panel = self.attachAsset('carSelectPanel', {
anchorX: 0.5,
anchorY: 0.5
});
panel.alpha = 0.95;
panel.scaleX = 1.1;
panel.scaleY = 1.1;
// Title
var titleBg = self.attachAsset('carSelectTitle', {
anchorX: 0.5,
anchorY: 0.5
});
titleBg.y = -450;
titleBg.alpha = 0.9;
titleBg.scaleX = 1.5;
titleBg.scaleY = 1.3;
var titleText = new Text2('🏎️ RACING LEGENDS', {
size: 100,
fill: '#ffffff'
});
titleText.anchor.set(0.5, 0.5);
titleBg.addChild(titleText);
// Animate title
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
// Coins display
var coinsBg = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
coinsBg.y = -300;
coinsBg.alpha = 0.95;
coinsBg.scaleX = 1.3;
coinsBg.scaleY = 1.2;
var coinsText = new Text2('💰 COINS: ' + (storage.totalCoins || 0), {
size: 50,
fill: '#ffd700'
});
coinsText.anchor.set(0.5, 0.5);
coinsBg.addChild(coinsText);
// Menu buttons with larger size and better styling
var playButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
playButton.y = -180;
playButton.alpha = 0.95;
playButton.scaleX = 1.4;
playButton.scaleY = 1.3;
var playText = new Text2('🎮 PLAY GAME', {
size: 60,
fill: '#ffffff'
});
playText.anchor.set(0.5, 0.5);
playButton.addChild(playText);
var shopButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
shopButton.y = -60;
shopButton.alpha = 0.95;
shopButton.scaleX = 1.4;
shopButton.scaleY = 1.3;
var shopText = new Text2('🛒 SHOP', {
size: 60,
fill: '#ffffff'
});
shopText.anchor.set(0.5, 0.5);
shopButton.addChild(shopText);
var statsButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
statsButton.y = 60;
statsButton.alpha = 0.95;
statsButton.scaleX = 1.4;
statsButton.scaleY = 1.3;
var statsText = new Text2('📊 STATS', {
size: 60,
fill: '#ffffff'
});
statsText.anchor.set(0.5, 0.5);
statsButton.addChild(statsText);
// Add glowing effect to buttons
var buttons = [playButton, shopButton, statsButton];
for (var b = 0; b < buttons.length; b++) {
var btn = buttons[b];
btn.originalAlpha = btn.alpha;
tween(btn, {
alpha: btn.originalAlpha + 0.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function () {
tween(this, {
alpha: this.originalAlpha
}, {
duration: 800,
easing: tween.easeInOut
});
}.bind(btn)
});
}
// Stats display with enhanced styling
var stats = storage.playerStats || {
totalDistance: 0,
totalCoins: 0,
bestScore: 0,
gamesPlayed: 0
};
var statsBg = self.attachAsset('carSelectCard', {
anchorX: 0.5,
anchorY: 0.5
});
statsBg.y = 280;
statsBg.alpha = 0.9;
statsBg.scaleX = 1.2;
statsBg.scaleY = 0.8;
var statsTitle = new Text2('🏆 YOUR STATS', {
size: 45,
fill: '#ffffff'
});
statsTitle.anchor.set(0.5, 0.5);
statsBg.addChild(statsTitle);
statsTitle.y = -90;
var bestScoreText = new Text2('🥇 BEST: ' + stats.bestScore + 'M', {
size: 32,
fill: '#00ff00'
});
bestScoreText.anchor.set(0.5, 0.5);
statsBg.addChild(bestScoreText);
bestScoreText.y = -45;
var totalDistanceText = new Text2('🛣️ TOTAL: ' + stats.totalDistance + 'M', {
size: 32,
fill: '#ffff00'
});
totalDistanceText.anchor.set(0.5, 0.5);
statsBg.addChild(totalDistanceText);
totalDistanceText.y = -5;
var gamesPlayedText = new Text2('🎯 GAMES: ' + stats.gamesPlayed, {
size: 32,
fill: '#ff9900'
});
gamesPlayedText.anchor.set(0.5, 0.5);
statsBg.addChild(gamesPlayedText);
gamesPlayedText.y = 35;
self.playButton = playButton;
self.shopButton = shopButton;
self.statsButton = statsButton;
self.down = function (x, y, obj) {
// Check play button with enlarged bounds
var playBounds = {
left: self.playButton.x - 280,
right: self.playButton.x + 280,
top: self.playButton.y - 65,
bottom: self.playButton.y + 65
};
if (x >= playBounds.left && x <= playBounds.right && y >= playBounds.top && y <= playBounds.bottom) {
// Enhanced button feedback
tween(self.playButton, {
scaleX: 1.5,
scaleY: 1.4
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.playButton, {
scaleX: 1.4,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(self.playButton, 0x00ff00, 300);
self.startCarSelection();
return;
}
// Check shop button with enlarged bounds
var shopBounds = {
left: self.shopButton.x - 280,
right: self.shopButton.x + 280,
top: self.shopButton.y - 65,
bottom: self.shopButton.y + 65
};
if (x >= shopBounds.left && x <= shopBounds.right && y >= shopBounds.top && y <= shopBounds.bottom) {
// Enhanced button feedback
tween(self.shopButton, {
scaleX: 1.5,
scaleY: 1.4
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.shopButton, {
scaleX: 1.4,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(self.shopButton, 0x00ff00, 300);
self.openShop();
return;
}
// Check stats button with enlarged bounds
var statsBounds = {
left: self.statsButton.x - 280,
right: self.statsButton.x + 280,
top: self.statsButton.y - 65,
bottom: self.statsButton.y + 65
};
if (x >= statsBounds.left && x <= statsBounds.right && y >= statsBounds.top && y <= statsBounds.bottom) {
// Enhanced button feedback
tween(self.statsButton, {
scaleX: 1.5,
scaleY: 1.4
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.statsButton, {
scaleX: 1.4,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
}
});
LK.effects.flashObject(self.statsButton, 0x3498db, 300);
return;
}
};
self.startCarSelection = function () {
LK.setTimeout(function () {
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
initCarSelection();
}, 300);
};
self.openShop = function () {
LK.setTimeout(function () {
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
shop = game.addChild(new Shop());
shop.x = 1024;
shop.y = 1366;
}, 300);
};
return self;
});
var Obstacle = Container.expand(function (type) {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
// Add details based on vehicle type
if (type === 'enemyCar') {
// Add windows to enemy car
var frontWindow = self.attachAsset('enemyCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -40;
var rearWindow = self.attachAsset('enemyCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 40;
var leftWindow = self.attachAsset('enemyCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -25;
leftWindow.y = -5;
var rightWindow = self.attachAsset('enemyCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 25;
rightWindow.y = -5;
} else if (type === 'truck') {
// Add truck cab windows
var truckWindow = self.attachAsset('truckWindow', {
anchorX: 0.5,
anchorY: 0.5
});
truckWindow.y = -60;
// Add truck cargo area details
var cargoDetail = self.attachAsset('truckCargo', {
anchorX: 0.5,
anchorY: 0.5
});
cargoDetail.y = 30;
} else if (type === 'barrier') {
// Add warning stripes to barrier
var stripe1 = self.attachAsset('barrierStripe', {
anchorX: 0.5,
anchorY: 0.5
});
stripe1.y = -15;
var stripe2 = self.attachAsset('barrierStripe', {
anchorX: 0.5,
anchorY: 0.5
});
stripe2.y = 15;
}
self.speed = 8;
self.obstacleType = type;
self.passed = false;
self.update = function () {
self.y += self.speed + gameSpeed;
};
return self;
});
var ParticleSystem = Container.expand(function (particleType, count) {
var self = Container.call(this);
self.particles = [];
self.particleType = particleType;
for (var i = 0; i < count; i++) {
var particle = self.attachAsset(particleType, {
anchorX: 0.5,
anchorY: 0.5
});
particle.vx = (Math.random() - 0.5) * 4;
particle.vy = (Math.random() - 0.5) * 4;
particle.life = 1.0;
particle.maxLife = 1.0;
particle.alpha = 0;
self.particles.push(particle);
}
self.emit = function (x, y, force) {
force = force || 1;
for (var i = 0; i < self.particles.length; i++) {
var particle = self.particles[i];
if (particle.life <= 0) {
particle.x = x + (Math.random() - 0.5) * 20;
particle.y = y + (Math.random() - 0.5) * 20;
particle.vx = (Math.random() - 0.5) * 6 * force;
particle.vy = (Math.random() - 0.5) * 6 * force;
particle.life = 1.0;
particle.alpha = 1.0;
break;
}
}
};
self.update = function () {
for (var i = 0; i < self.particles.length; i++) {
var particle = self.particles[i];
if (particle.life > 0) {
particle.x += particle.vx;
particle.y += particle.vy;
particle.life -= 0.02;
particle.alpha = particle.life;
particle.scaleX = particle.life;
particle.scaleY = particle.life;
}
}
};
return self;
});
var PlayerCar = Container.expand(function (carType) {
var self = Container.call(this);
carType = carType || 'default';
if (carType === 'sports') {
// Sports car with ultra-realistic details
var carGraphics = self.attachAsset('sportsCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('sportsCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -40;
var rearWindow = self.attachAsset('sportsCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 40;
var leftWindow = self.attachAsset('sportsCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -30;
leftWindow.y = -10;
var rightWindow = self.attachAsset('sportsCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 30;
rightWindow.y = -10;
var spoiler = self.attachAsset('sportsCarSpoiler', {
anchorX: 0.5,
anchorY: 0.5
});
spoiler.y = 80;
var stripe = self.attachAsset('sportsCarStripe', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (carType === 'luxury') {
// Luxury car with ultra-realistic details
var carGraphics = self.attachAsset('luxuryCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('luxuryCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -45;
var rearWindow = self.attachAsset('luxuryCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 45;
var leftWindow = self.attachAsset('luxuryCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -35;
leftWindow.y = -15;
var rightWindow = self.attachAsset('luxuryCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 35;
rightWindow.y = -15;
var grill = self.attachAsset('luxuryCarGrill', {
anchorX: 0.5,
anchorY: 0.5
});
grill.y = -90;
var trim = self.attachAsset('luxuryCarTrim', {
anchorX: 0.5,
anchorY: 0.5
});
trim.y = 90;
} else if (carType === 'race') {
// Race car with ultra-realistic details
var carGraphics = self.attachAsset('raceCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('raceCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -35;
var rearWindow = self.attachAsset('raceCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 35;
var leftWindow = self.attachAsset('raceCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -25;
leftWindow.y = -5;
var rightWindow = self.attachAsset('raceCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 25;
rightWindow.y = -5;
var wing = self.attachAsset('raceCarWing', {
anchorX: 0.5,
anchorY: 0.5
});
wing.y = 75;
var number = self.attachAsset('raceCarNumber', {
anchorX: 0.5,
anchorY: 0.5
});
number.y = -60;
} else if (carType === 'classic') {
// Classic car with ultra-realistic details
var carGraphics = self.attachAsset('classicCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('classicCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -42;
var rearWindow = self.attachAsset('classicCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 42;
var leftWindow = self.attachAsset('classicCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -32;
leftWindow.y = -12;
var rightWindow = self.attachAsset('classicCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 32;
rightWindow.y = -12;
var bumper = self.attachAsset('classicCarBumper', {
anchorX: 0.5,
anchorY: 0.5
});
bumper.y = 87;
var trim = self.attachAsset('classicCarTrim', {
anchorX: 0.5,
anchorY: 0.5
});
trim.y = -87;
} else {
// Default car
var carGraphics = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWindow = self.attachAsset('playerCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
frontWindow.y = -40;
var rearWindow = self.attachAsset('playerCarWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rearWindow.y = 40;
var leftWindow = self.attachAsset('playerCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
leftWindow.x = -30;
leftWindow.y = -10;
var rightWindow = self.attachAsset('playerCarSideWindow', {
anchorX: 0.5,
anchorY: 0.5
});
rightWindow.x = 30;
rightWindow.y = -10;
}
self.currentLane = 0; // 0 = left lane, 1 = right lane
self.targetX = 0;
self.speed = 0;
self.carType = carType;
self.shieldActive = false;
self.shieldTime = 0;
self.boostActive = false;
self.boostTime = 0;
self.nitroActive = false; // Track nitro boost separately
self.nitroBoostAmount = 0; // Track nitro boost amount
self.regularBoostActive = false; // Track regular boost separately
self.regularBoostAmount = 0; // Track regular boost amount
// Add enhanced headlight system with multiple layers
// Left headlight system
var leftHeadlightGlow = self.attachAsset('lightGlow', {
anchorX: 0.5,
anchorY: 1
});
leftHeadlightGlow.x = -25;
leftHeadlightGlow.y = -80;
leftHeadlightGlow.alpha = 0.15;
leftHeadlightGlow.scaleY = 1.5;
var leftHeadlightOuter = self.attachAsset('lightBeamOuter', {
anchorX: 0.5,
anchorY: 1
});
leftHeadlightOuter.x = -25;
leftHeadlightOuter.y = -80;
leftHeadlightOuter.alpha = 0.4;
var leftHeadlight = self.attachAsset('lightBeam', {
anchorX: 0.5,
anchorY: 1
});
leftHeadlight.x = -25;
leftHeadlight.y = -80;
leftHeadlight.alpha = 0.7;
var leftHeadlightInner = self.attachAsset('lightBeamInner', {
anchorX: 0.5,
anchorY: 1
});
leftHeadlightInner.x = -25;
leftHeadlightInner.y = -80;
leftHeadlightInner.alpha = 0.9;
// Right headlight system
var rightHeadlightGlow = self.attachAsset('lightGlow', {
anchorX: 0.5,
anchorY: 1
});
rightHeadlightGlow.x = 25;
rightHeadlightGlow.y = -80;
rightHeadlightGlow.alpha = 0.15;
rightHeadlightGlow.scaleY = 1.5;
var rightHeadlightOuter = self.attachAsset('lightBeamOuter', {
anchorX: 0.5,
anchorY: 1
});
rightHeadlightOuter.x = 25;
rightHeadlightOuter.y = -80;
rightHeadlightOuter.alpha = 0.4;
var rightHeadlight = self.attachAsset('lightBeam', {
anchorX: 0.5,
anchorY: 1
});
rightHeadlight.x = 25;
rightHeadlight.y = -80;
rightHeadlight.alpha = 0.7;
var rightHeadlightInner = self.attachAsset('lightBeamInner', {
anchorX: 0.5,
anchorY: 1
});
rightHeadlightInner.x = 25;
rightHeadlightInner.y = -80;
rightHeadlightInner.alpha = 0.9;
// Store headlight references for dynamic effects
self.leftHeadlights = [leftHeadlightGlow, leftHeadlightOuter, leftHeadlight, leftHeadlightInner];
self.rightHeadlights = [rightHeadlightGlow, rightHeadlightOuter, rightHeadlight, rightHeadlightInner];
// Add exhaust particles
self.exhaustSystem = self.addChild(new ParticleSystem('exhaustParticle', 15));
self.exhaustSystem.y = 90;
// Add headlight sparkle system for enhanced visual effects
self.headlightSparkleSystem = self.addChild(new ParticleSystem('sparkleParticle', 10));
self.headlightSparkleSystem.y = -80;
// Add explosion system for collisions
self.explosionSystem = self.addChild(new ParticleSystem('explosionParticle', 30));
// Add shield effect (initially hidden)
self.shieldEffect = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
self.shieldEffect.alpha = 0;
self.shieldEffect.scaleX = 1.5;
self.shieldEffect.scaleY = 1.5;
self.switchLane = function (lane) {
if (self.currentLane !== lane) {
self.currentLane = lane;
self.targetX = lane === 0 ? leftLaneX : rightLaneX;
LK.getSound('switch').play();
}
};
self.activateShield = function () {
self.shieldActive = true;
self.shieldTime = 300; // 5 seconds at 60fps
tween(self.shieldEffect, {
alpha: 0.6
}, {
duration: 200
});
LK.getSound('powerup').play();
};
self.activateBoost = function () {
self.boostActive = true;
self.boostTime = 180; // 3 seconds at 60fps
self.regularBoostActive = true; // Track regular boost separately
self.regularBoostAmount = 3; // Track how much boost regular adds
gameSpeed += self.regularBoostAmount;
LK.getSound('boost').play();
// Screen effect
tween(game, {
tint: 0x00ffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(game, {
tint: 0xffffff
}, {
duration: 100
});
}
});
};
self.triggerExplosion = function (x, y) {
// Create dramatic explosion effect
for (var i = 0; i < 20; i++) {
self.explosionSystem.emit(x, y, 5);
}
// Screen shake effect
tween(self, {
x: self.x + 10
}, {
duration: 50,
onFinish: function onFinish() {
tween(self, {
x: self.x - 10
}, {
duration: 50,
onFinish: function onFinish() {
tween(self, {
x: self.targetX
}, {
duration: 50
});
}
});
}
});
};
self.update = function () {
// Smooth lane switching with tween animation
var diff = self.targetX - self.x;
if (Math.abs(diff) > 2) {
self.x += diff * 0.15;
} else {
self.x = self.targetX;
}
// Update exhaust particles
if (self.exhaustSystem) {
self.exhaustSystem.emit(0, 90, 0.5);
self.exhaustSystem.update();
}
// Update explosion system
if (self.explosionSystem) {
self.explosionSystem.update();
}
// Update headlight sparkle system for enhanced visual effects
if (self.headlightSparkleSystem) {
// Emit sparkles from headlight positions occasionally
if (Math.random() < 0.1) {
self.headlightSparkleSystem.emit(-25, -80, 0.5);
self.headlightSparkleSystem.emit(25, -80, 0.5);
}
// Extra sparkles during boost
if (self.boostActive && Math.random() < 0.3) {
self.headlightSparkleSystem.emit(-25, -80, 1.5);
self.headlightSparkleSystem.emit(25, -80, 1.5);
}
self.headlightSparkleSystem.update();
}
// Update shield effect
if (self.shieldActive) {
self.shieldTime--;
if (self.shieldTime <= 0) {
self.shieldActive = false;
tween(self.shieldEffect, {
alpha: 0
}, {
duration: 300
});
} else {
self.shieldEffect.rotation += 0.1;
self.shieldEffect.alpha = 0.6 + Math.sin(LK.ticks * 0.2) * 0.2;
}
}
// Update boost effect
if (self.boostActive) {
self.boostTime--;
if (self.boostTime <= 0) {
self.boostActive = false;
// Properly remove boost amounts based on what was active
if (self.nitroActive) {
gameSpeed = Math.max(gameSpeed - self.nitroBoostAmount, 2);
self.nitroActive = false;
self.nitroBoostAmount = 0;
}
if (self.regularBoostActive) {
gameSpeed = Math.max(gameSpeed - self.regularBoostAmount, 2);
self.regularBoostActive = false;
self.regularBoostAmount = 0;
}
}
// Emit nitro flames with enhanced effects
if (self.exhaustSystem) {
self.exhaustSystem.emit(-10, 90, 3);
self.exhaustSystem.emit(10, 90, 3);
// Extra flame particles for nitro effect
self.exhaustSystem.emit(-15, 85, 2);
self.exhaustSystem.emit(15, 85, 2);
}
}
// Enhanced headlight effects with dynamic behavior
if (self.leftHeadlights && self.rightHeadlights) {
// Base pulsing effect synchronized with engine
var pulseIntensity = 0.1 + Math.sin(LK.ticks * 0.1) * 0.05;
// Speed-based brightness - faster = brighter beams
var speedMultiplier = 1 + (gameSpeed - 2) * 0.1;
// Boost effects on headlights
var boostMultiplier = 1;
if (self.boostActive) {
boostMultiplier = 1.5;
// Flickering effect during boost
pulseIntensity += Math.sin(LK.ticks * 0.3) * 0.2;
}
if (self.nitroActive) {
boostMultiplier = 2;
// Intense flickering for nitro
pulseIntensity += Math.sin(LK.ticks * 0.5) * 0.3;
}
// Apply effects to both headlight systems
for (var h = 0; h < self.leftHeadlights.length; h++) {
var leftBeam = self.leftHeadlights[h];
var rightBeam = self.rightHeadlights[h];
// Dynamic brightness based on speed and boost
var baseBrightness = h === 0 ? 0.15 : h === 1 ? 0.4 : h === 2 ? 0.7 : 0.9;
var finalBrightness = baseBrightness * speedMultiplier * boostMultiplier;
leftBeam.alpha = Math.min(finalBrightness + pulseIntensity, 1.0);
rightBeam.alpha = Math.min(finalBrightness + pulseIntensity, 1.0);
// Dynamic beam scaling based on speed
var scaleMultiplier = 1 + (gameSpeed - 2) * 0.05;
leftBeam.scaleY = (h === 0 ? 1.5 : 1.0) * scaleMultiplier;
rightBeam.scaleY = (h === 0 ? 1.5 : 1.0) * scaleMultiplier;
}
// Lane switching beam angle effect
var laneOffset = (self.targetX - self.x) * 0.01;
for (var h = 0; h < self.leftHeadlights.length; h++) {
self.leftHeadlights[h].rotation = laneOffset;
self.rightHeadlights[h].rotation = laneOffset;
}
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.powerType = type;
var powerGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
// Add glow effect with different colors based on type
var glowColor = 0x00ffff; // Default cyan
if (type === 'nitroFlame') {
glowColor = 0xff4500; // Orange for nitro
} else if (type === 'coin') {
glowColor = 0xffd700; // Gold for coins
}
var glow = self.attachAsset('glowEffect', {
anchorX: 0.5,
anchorY: 0.5
});
glow.alpha = 0.3;
glow.scaleX = 0.5;
glow.scaleY = 0.5;
glow.tint = glowColor;
self.speed = 8;
self.collected = false;
self.rotationSpeed = 0.1;
self.multiplier = 1; // Default multiplier for coins
// Set coin multiplier based on type
if (type === 'coin2x') {
self.multiplier = 2;
self.rotationSpeed = 0.2;
} else if (type === 'coin3x') {
self.multiplier = 3;
self.rotationSpeed = 0.3;
}
self.update = function () {
self.y += self.speed + gameSpeed;
self.rotation += self.rotationSpeed;
// Enhanced pulsing glow effect with different intensities
var pulseIntensity = self.multiplier > 1 ? 0.4 : 0.2;
glow.alpha = 0.3 + Math.sin(LK.ticks * 0.1) * pulseIntensity;
glow.scaleX = 0.5 + Math.sin(LK.ticks * 0.1) * pulseIntensity;
glow.scaleY = 0.5 + Math.sin(LK.ticks * 0.1) * pulseIntensity;
// Extra rotation for multiplier coins
if (self.multiplier > 1) {
powerGraphics.rotation += self.rotationSpeed * 0.5;
}
};
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 + gameSpeed;
};
return self;
});
var Shop = Container.expand(function () {
var self = Container.call(this);
// Background panel
var panel = self.attachAsset('carSelectPanel', {
anchorX: 0.5,
anchorY: 0.5
});
panel.alpha = 0.95;
// Title
var titleBg = self.attachAsset('carSelectTitle', {
anchorX: 0.5,
anchorY: 0.5
});
titleBg.y = -500;
titleBg.alpha = 0.9;
titleBg.scaleX = 1.4;
titleBg.scaleY = 1.3;
var titleText = new Text2('🏪 SHOP', {
size: 95,
fill: '#ffffff'
});
titleText.anchor.set(0.5, 0.5);
titleBg.addChild(titleText);
// Coins display
var coinsBg = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
coinsBg.y = -400;
coinsBg.alpha = 0.95;
coinsBg.scaleX = 1.3;
coinsBg.scaleY = 1.2;
var coinsText = new Text2('💰 COINS: ' + (storage.totalCoins || 0), {
size: 55,
fill: '#ffd700'
});
coinsText.anchor.set(0.5, 0.5);
coinsBg.addChild(coinsText);
// Shop items
var shopItems = [{
name: 'SPORTS CAR',
type: 'sports',
price: 500,
description: 'High speed racing car'
}, {
name: 'LUXURY CAR',
type: 'luxury',
price: 1000,
description: 'Premium comfort vehicle'
}, {
name: 'RACE CAR',
type: 'race',
price: 2000,
description: 'Professional racing machine'
}, {
name: 'CLASSIC CAR',
type: 'classic',
price: 750,
description: 'Vintage style automobile'
}];
var itemCards = [];
for (var i = 0; i < shopItems.length; i++) {
var item = shopItems[i];
var card = self.addChild(new Container());
var cardBg = card.attachAsset('carSelectCard', {
anchorX: 0.5,
anchorY: 0.5
});
cardBg.alpha = 0.8;
// Position cards in 2x2 grid
var col = i % 2;
var row = Math.floor(i / 2);
card.x = (col - 0.5) * 500;
card.y = (row - 0.5) * 300 - 50;
// Car preview
var carPreview = card.addChild(new CarPreview(item.type));
carPreview.y = -100;
carPreview.scaleX = 0.6;
carPreview.scaleY = 0.6;
// Item name
var nameText = new Text2(item.name, {
size: 30,
fill: '#ffffff'
});
nameText.anchor.set(0.5, 0.5);
card.addChild(nameText);
nameText.y = 20;
// Price
var priceText = new Text2(item.price + ' COINS', {
size: 25,
fill: '#ffd700'
});
priceText.anchor.set(0.5, 0.5);
card.addChild(priceText);
priceText.y = 50;
// Description
var descText = new Text2(item.description, {
size: 18,
fill: '#cccccc'
});
descText.anchor.set(0.5, 0.5);
card.addChild(descText);
descText.y = 80;
// Buy/Owned button
var buyButton = card.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
buyButton.y = 120;
buyButton.alpha = 0.9;
var ownedCars = storage.ownedCars || ['default'];
var isOwned = ownedCars.indexOf(item.type) !== -1;
var canAfford = (storage.totalCoins || 0) >= item.price;
var buttonText = new Text2(isOwned ? 'OWNED' : canAfford ? 'BUY' : 'NOT ENOUGH COINS', {
size: 20,
fill: isOwned ? '#00ff00' : canAfford ? '#ffffff' : '#ff0000'
});
buttonText.anchor.set(0.5, 0.5);
buyButton.addChild(buttonText);
buyButton.itemType = item.type;
buyButton.itemPrice = item.price;
buyButton.isOwned = isOwned;
buyButton.canAfford = canAfford;
itemCards.push({
card: card,
button: buyButton,
item: item
});
}
// Back button
var backButton = self.attachAsset('carSelectButton', {
anchorX: 0.5,
anchorY: 0.5
});
backButton.y = 400;
backButton.alpha = 0.9;
var backText = new Text2('BACK TO MENU', {
size: 30,
fill: '#ffffff'
});
backText.anchor.set(0.5, 0.5);
backButton.addChild(backText);
self.itemCards = itemCards;
self.backButton = backButton;
self.coinsText = coinsText;
self.down = function (x, y, obj) {
// Check back button
var backBounds = {
left: self.backButton.x - 180,
right: self.backButton.x + 180,
top: self.backButton.y - 50,
bottom: self.backButton.y + 50
};
if (x >= backBounds.left && x <= backBounds.right && y >= backBounds.top && y <= backBounds.bottom) {
LK.effects.flashObject(self.backButton, 0x00ff00, 200);
self.goBackToMenu();
return;
}
// Check item cards
for (var i = 0; i < self.itemCards.length; i++) {
var cardData = self.itemCards[i];
var button = cardData.button;
var buttonBounds = {
left: cardData.card.x + button.x - 180,
right: cardData.card.x + button.x + 180,
top: cardData.card.y + button.y - 50,
bottom: cardData.card.y + button.y + 50
};
if (x >= buttonBounds.left && x <= buttonBounds.right && y >= buttonBounds.top && y <= buttonBounds.bottom) {
if (!button.isOwned && button.canAfford) {
self.purchaseItem(cardData.item);
LK.effects.flashObject(button, 0x00ff00, 200);
} else {
LK.effects.flashObject(button, 0xff0000, 200);
}
break;
}
}
};
self.purchaseItem = function (item) {
var currentCoins = storage.totalCoins || 0;
if (currentCoins >= item.price) {
// Deduct coins
storage.totalCoins = currentCoins - item.price;
// Add car to owned cars
var ownedCars = storage.ownedCars || ['default'];
ownedCars.push(item.type);
storage.ownedCars = ownedCars;
// Update display
self.coinsText.setText('COINS: ' + storage.totalCoins);
// Refresh shop display
self.destroy();
shop = game.addChild(new Shop());
shop.x = 1024;
shop.y = 1366;
}
};
self.goBackToMenu = function () {
LK.setTimeout(function () {
if (shop) {
shop.destroy();
shop = null;
}
initMainMenu();
}, 300);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game state variables
// Player car detail assets
// Enemy car detail assets
// Truck detail assets
// Barrier detail assets
// Car selection assets
// Car selection UI assets
var gameState = 'mainMenu'; // 'mainMenu', 'carSelection', 'playing', 'shop'
var selectedCarType = 'default';
var selectedRoadType = 'highway';
var mainMenu = null;
var carSelectionScreen = null;
var shop = null;
// Enhanced game features
var rainSystem = null;
var sparkleSystem = null;
var powerUps = [];
var coins = [];
var playerStats = storage.playerStats || {
totalDistance: 0,
totalCoins: 0,
bestScore: 0,
gamesPlayed: 0
};
var currentCoins = 0;
var coinMultiplier = 1;
var coinMultiplierTime = 0;
// Initialize storage defaults
if (!storage.totalCoins) storage.totalCoins = 0;
if (!storage.ownedCars) storage.ownedCars = ['default'];
var weatherEnabled = true;
var lightingEnabled = true;
// Game variables
var gameSpeed = 2;
var difficultyTimer = 0;
var obstacleTimer = 0;
var roadLineTimer = 0;
var leftLaneX = 1024 - 200;
var rightLaneX = 1024 + 200;
// Game objects arrays
var obstacles = [];
var roadLines = [];
var obstacleTypes = ['enemyCar', 'truck', 'barrier'];
// Create road surface
var roadSurface = game.addChild(LK.getAsset('roadSurface', {
anchorX: 0.5,
anchorY: 0.5
}));
roadSurface.x = 1024;
roadSurface.y = 1366;
// Add road illumination spots that will be lit by headlights
var roadIlluminationSpots = [];
for (var i = 0; i < 20; i++) {
var spot = game.addChild(LK.getAsset('lightGlow', {
anchorX: 0.5,
anchorY: 0.5
}));
spot.x = 1024;
spot.y = 1500 + i * 200;
spot.alpha = 0;
spot.scaleX = 2;
spot.scaleY = 1.5;
spot.tint = 0xffff99;
roadIlluminationSpots.push(spot);
}
// Add road texture patterns for realism
for (var i = 0; i < 60; i++) {
var textureStripe = game.addChild(LK.getAsset('roadTexture', {
anchorX: 0.5,
anchorY: 0.5
}));
textureStripe.x = 1024;
textureStripe.y = i * 50;
textureStripe.alpha = 0.3;
}
// Add asphalt pattern details
for (var i = 0; i < 200; i++) {
var pattern = game.addChild(LK.getAsset('asphaltPattern', {
anchorX: 0.5,
anchorY: 0.5
}));
pattern.x = 424 + Math.random() * 1200;
pattern.y = Math.random() * 2732;
pattern.alpha = 0.2;
pattern.rotation = Math.random() * Math.PI;
}
// Create road sides
var leftSide = game.addChild(LK.getAsset('roadSide', {
anchorX: 0.5,
anchorY: 0.5
}));
leftSide.x = 374;
leftSide.y = 1366;
var rightSide = game.addChild(LK.getAsset('roadSide', {
anchorX: 0.5,
anchorY: 0.5
}));
rightSide.x = 1674;
rightSide.y = 1366;
// Add road edge lines for realism
var leftEdge = game.addChild(LK.getAsset('roadEdge', {
anchorX: 0.5,
anchorY: 0.5
}));
leftEdge.x = 424;
leftEdge.y = 1366;
var rightEdge = game.addChild(LK.getAsset('roadEdge', {
anchorX: 0.5,
anchorY: 0.5
}));
rightEdge.x = 1624;
rightEdge.y = 1366;
// Initialize main menu with enhanced animations
function initMainMenu() {
mainMenu = game.addChild(new MainMenu());
mainMenu.x = 1024;
mainMenu.y = 1366;
// Add animated background elements
for (var i = 0; i < 8; i++) {
var bgCar = game.addChild(LK.getAsset('sportsCar', {
anchorX: 0.5,
anchorY: 0.5
}));
bgCar.x = Math.random() * 2048;
bgCar.y = Math.random() * 2732;
bgCar.alpha = 0.1;
bgCar.scaleX = 0.3;
bgCar.scaleY = 0.3;
bgCar.rotation = Math.random() * Math.PI * 2;
// Animate background cars
tween(bgCar, {
rotation: bgCar.rotation + Math.PI * 2
}, {
duration: 8000 + Math.random() * 4000,
easing: tween.linear
});
}
// Add sparkle effects
if (!sparkleSystem) {
sparkleSystem = game.addChild(new ParticleSystem('sparkleParticle', 20));
}
}
// Initialize car selection screen
function initCarSelection() {
carSelectionScreen = game.addChild(new CarSelectionScreen());
carSelectionScreen.x = 1024;
carSelectionScreen.y = 1366;
}
initMainMenu();
// Game start function
function startGame() {
gameState = 'playing';
// Create player car with selected type
playerCar = game.addChild(new PlayerCar(selectedCarType));
playerCar.x = leftLaneX;
playerCar.y = 2400;
playerCar.targetX = leftLaneX;
// Make playerCar globally accessible
game.playerCar = playerCar;
// Initialize particle systems
rainSystem = game.addChild(new ParticleSystem('rainDrop', 50));
sparkleSystem = game.addChild(new ParticleSystem('sparkleParticle', 30));
// Lighting effects removed from game environment
// Car headlights remain intact in PlayerCar class
// Adjust game difficulty based on road type
if (selectedRoadType === 'city') {
gameSpeed = 3;
obstacleTypes = ['enemyCar', 'truck', 'barrier']; // Start with balanced obstacles
} else {
gameSpeed = 2;
obstacleTypes = ['enemyCar', 'truck', 'barrier']; // Default highway
}
}
// Placeholder for player car (will be created after car selection)
var playerCar = null;
// Create dashboard panel
var dashboardPanel = LK.getAsset('dashboardPanel', {
anchorX: 0.5,
anchorY: 0
});
LK.gui.top.addChild(dashboardPanel);
dashboardPanel.y = 20;
dashboardPanel.alpha = 0.8;
// Create speedometer
var speedometer = LK.getAsset('speedometer', {
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.topRight.addChild(speedometer);
speedometer.x = -150;
speedometer.y = 100;
speedometer.alpha = 0.9;
// Create speedometer needle
var speedometerNeedle = LK.getAsset('speedometerNeedle', {
anchorX: 0.5,
anchorY: 1
});
speedometer.addChild(speedometerNeedle);
speedometerNeedle.y = 20;
// Create mini map
var miniMap = LK.getAsset('miniMap', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(miniMap);
miniMap.x = 120;
miniMap.y = 50;
miniMap.alpha = 0.7;
// Create score display with dashboard styling
var scoreText = new Text2('DISTANCE: 0', {
size: 50,
fill: '#00ff00'
});
scoreText.anchor.set(0.5, 0.5);
dashboardPanel.addChild(scoreText);
scoreText.y = -15;
// Create speed display with dashboard styling
var speedText = new Text2('SPEED: 1', {
size: 40,
fill: '#ffff00'
});
speedText.anchor.set(0.5, 0.5);
dashboardPanel.addChild(speedText);
speedText.y = 25;
// Create coin counter display
var coinText = new Text2('COINS: 0', {
size: 35,
fill: '#ffd700'
});
coinText.anchor.set(0.5, 0.5);
dashboardPanel.addChild(coinText);
coinText.y = 55;
// Touch controls
game.down = function (x, y, obj) {
if (gameState === 'carSelection' && carSelectionScreen) {
// Convert touch coordinates to car selection screen coordinates
var localPos = carSelectionScreen.toLocal({
x: x,
y: y
});
carSelectionScreen.down(localPos.x, localPos.y, obj);
return;
} else if (gameState === 'playing' && game.playerCar) {
if (x < 1024) {
// Left side of screen - switch to left lane
game.playerCar.switchLane(0);
} else {
// Right side of screen - switch to right lane
game.playerCar.switchLane(1);
}
}
};
// Spawn obstacle function
function spawnObstacle() {
// Difficulty scaling based on score
var currentScore = LK.getScore();
var difficultyLevel = Math.floor(currentScore / 100); // Every 100 points increases difficulty
var barrierChance = Math.min(0.1 + difficultyLevel * 0.05, 0.4); // Start with 10% barriers, max 40%
var enemyChance = Math.min(0.6 + difficultyLevel * 0.1, 0.8); // Start with 60% enemies, max 80%
// Select obstacle type based on difficulty
var obstacleType;
var rand = Math.random();
if (rand < barrierChance) {
obstacleType = 'barrier';
} else if (rand < barrierChance + enemyChance) {
obstacleType = 'enemyCar';
} else {
obstacleType = 'truck';
}
var obstacle = new Obstacle(obstacleType);
// Randomly place in left or right lane
var lane = Math.floor(Math.random() * 2);
obstacle.x = lane === 0 ? leftLaneX : rightLaneX;
obstacle.y = -200;
obstacle.lane = lane;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Spawn road line function
function spawnRoadLine() {
var roadLine = new RoadLine();
roadLine.x = 1024;
roadLine.y = -50;
roadLines.push(roadLine);
game.addChild(roadLine);
}
// Spawn power-up function
function spawnPowerUp() {
var powerUpTypes = ['speedBoost', 'shield'];
var powerUpType = powerUpTypes[Math.floor(Math.random() * powerUpTypes.length)];
var powerUp = new PowerUp(powerUpType);
var lane = Math.floor(Math.random() * 2);
powerUp.x = lane === 0 ? leftLaneX : rightLaneX;
powerUp.y = -200;
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Spawn coin function
function spawnCoin() {
var coinTypes = ['coin', 'coin', 'coin', 'coin', 'coin2x', 'coin3x']; // Regular coins more common
var coinType = coinTypes[Math.floor(Math.random() * coinTypes.length)];
var coin = new PowerUp(coinType);
var lane = Math.floor(Math.random() * 2);
coin.x = lane === 0 ? leftLaneX : rightLaneX;
coin.y = -200;
coins.push(coin);
game.addChild(coin);
}
// Precise collision detection function
function checkPreciseCollision(obj1, obj2) {
// Get the bounds of both objects
var obj1Bounds = {
left: obj1.x - obj1.width / 2,
right: obj1.x + obj1.width / 2,
top: obj1.y - obj1.height / 2,
bottom: obj1.y + obj1.height / 2
};
var obj2Bounds = {
left: obj2.x - obj2.width / 2,
right: obj2.x + obj2.width / 2,
top: obj2.y - obj2.height / 2,
bottom: obj2.y + obj2.height / 2
};
// Check for precise overlap (not just touching)
var overlapX = Math.max(0, Math.min(obj1Bounds.right, obj2Bounds.right) - Math.max(obj1Bounds.left, obj2Bounds.left));
var overlapY = Math.max(0, Math.min(obj1Bounds.bottom, obj2Bounds.bottom) - Math.max(obj1Bounds.top, obj2Bounds.top));
// Require significant overlap (at least 30 pixels in both directions)
return overlapX >= 30 && overlapY >= 30;
}
// Main game update loop
game.update = function () {
if (gameState === 'mainMenu' || gameState === 'carSelection' || gameState === 'shop') {
// Add sparkle effects to menu screens
if (sparkleSystem && Math.random() < 0.3) {
sparkleSystem.emit(Math.random() * 2048, Math.random() * 2732, 0.8);
}
if (sparkleSystem) {
sparkleSystem.update();
}
// Menu screens are active, don't update game logic
return;
}
if (gameState === 'playing' && game.playerCar) {
// Update difficulty
difficultyTimer++;
if (difficultyTimer % 600 === 0) {
// Every 10 seconds
gameSpeed += 0.5;
speedText.setText('SPEED: ' + Math.floor(gameSpeed) + ' KM/H');
}
// Update score
LK.setScore(Math.floor(LK.ticks / 10));
scoreText.setText('DISTANCE: ' + LK.getScore() + ' M');
// Update coin multiplier timer
if (coinMultiplierTime > 0) {
coinMultiplierTime--;
if (coinMultiplierTime <= 0) {
coinMultiplier = 1;
}
}
// Display coins with multiplier info
var coinDisplayText = 'COINS: ' + currentCoins;
if (coinMultiplier > 1) {
coinDisplayText += ' (x' + coinMultiplier + ')';
}
coinText.setText(coinDisplayText);
// Toggle night mode every 30 seconds for dynamic gameplay
var isNightTime = Math.floor(LK.ticks / 1800) % 2 === 1;
if (isNightTime) {
// Darken the game environment
roadSurface.tint = 0x444444;
for (var side = 0; side < 2; side++) {
if (side === 0) leftSide.tint = 0x222222;else rightSide.tint = 0x222222;
}
} else {
// Daytime colors
roadSurface.tint = 0xffffff;
leftSide.tint = 0xffffff;
rightSide.tint = 0xffffff;
}
// Update road illumination based on player car position and headlights
if (game.playerCar && roadIlluminationSpots) {
for (var i = 0; i < roadIlluminationSpots.length; i++) {
var spot = roadIlluminationSpots[i];
var distanceFromPlayer = Math.abs(spot.y - game.playerCar.y);
// Illuminate spots in front of the car
if (distanceFromPlayer < 300 && spot.y > game.playerCar.y - 100) {
var intensity = Math.max(0, 1 - distanceFromPlayer / 300);
spot.alpha = intensity * 0.3 * (isNightTime ? 2 : 0.5);
// Move spots to follow road movement
spot.y += gameSpeed + 2;
if (spot.y > 2800) {
spot.y = -100;
}
} else {
spot.alpha = 0;
}
}
}
// Update environmental effects
if (weatherEnabled && rainSystem) {
for (var r = 0; r < 3; r++) {
rainSystem.emit(Math.random() * 2048, -50, 1.5);
}
rainSystem.update();
}
if (sparkleSystem) {
if (Math.random() < 0.1) {
sparkleSystem.emit(Math.random() * 2048, Math.random() * 2732, 0.5);
}
sparkleSystem.update();
}
// Spawn obstacles
obstacleTimer++;
// Progressive difficulty: spawn rate increases with score
var currentScore = LK.getScore();
var difficultyLevel = Math.floor(currentScore / 50); // Every 50 points increases spawn rate
var baseSpawnRate = 120; // Start with slower spawn rate (2 seconds)
var spawnRate = Math.max(baseSpawnRate - difficultyLevel * 10, 45); // Minimum 0.75 seconds between spawns
if (obstacleTimer % spawnRate === 0) {
spawnObstacle();
}
// Spawn power-ups occasionally
if (LK.ticks % 600 === 0) {
// Every 10 seconds
spawnPowerUp();
}
// Spawn coins frequently
if (LK.ticks % 180 === 0) {
// Every 3 seconds
spawnCoin();
}
// Spawn road lines
roadLineTimer++;
if (roadLineTimer % 40 === 0) {
spawnRoadLine();
}
// Spawn lane dividers for center line
if (roadLineTimer % 30 === 0) {
var laneDivider = new LaneDivider();
laneDivider.x = 1024;
laneDivider.y = -50;
roadLines.push(laneDivider);
game.addChild(laneDivider);
}
// Update speedometer needle rotation based on speed
speedometerNeedle.rotation = gameSpeed / 10 * Math.PI * 0.5;
// Update and check obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Check if obstacle is off screen
if (obstacle.y > 2800) {
// Give points for passing obstacle
if (!obstacle.passed) {
LK.setScore(LK.getScore() + 10);
obstacle.passed = true;
}
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with player using precise detection (skip if shield is active)
if (checkPreciseCollision(obstacle, game.playerCar) && !game.playerCar.shieldActive) {
// Trigger explosion effect at collision point
var explosionX = (obstacle.x + game.playerCar.x) / 2;
var explosionY = (obstacle.y + game.playerCar.y) / 2;
game.playerCar.triggerExplosion(explosionX, explosionY);
// Multiple explosion bursts for dramatic effect
LK.setTimeout(function () {
game.playerCar.triggerExplosion(explosionX + 20, explosionY - 10);
}, 100);
LK.setTimeout(function () {
game.playerCar.triggerExplosion(explosionX - 15, explosionY + 15);
}, 200);
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 1000);
// Update player stats and storage
playerStats.totalDistance += LK.getScore();
playerStats.totalCoins += currentCoins;
playerStats.gamesPlayed++;
if (LK.getScore() > playerStats.bestScore) {
playerStats.bestScore = LK.getScore();
}
storage.playerStats = playerStats;
// Add coins to total storage
storage.totalCoins = (storage.totalCoins || 0) + currentCoins;
// Reset game state
gameState = 'mainMenu';
LK.showGameOver();
return;
}
// Check if obstacle was passed for scoring
if (!obstacle.passed && obstacle.y > game.playerCar.y + 100) {
obstacle.passed = true;
LK.setScore(LK.getScore() + 5);
}
}
// Update and check power-ups
for (var p = powerUps.length - 1; p >= 0; p--) {
var powerUp = powerUps[p];
if (powerUp.y > 2800) {
powerUp.destroy();
powerUps.splice(p, 1);
continue;
}
// Check collection
if (powerUp.intersects(game.playerCar) && !powerUp.collected) {
powerUp.collected = true;
// Activate power-up effect
if (powerUp.powerType === 'speedBoost') {
game.playerCar.activateBoost();
} else if (powerUp.powerType === 'shield') {
game.playerCar.activateShield();
}
// Visual feedback
sparkleSystem.emit(powerUp.x, powerUp.y, 2);
tween(powerUp, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
powerUp.destroy();
}
});
powerUps.splice(p, 1);
}
}
// Update and check coins
for (var c = coins.length - 1; c >= 0; c--) {
var coin = coins[c];
if (coin.y > 2800) {
coin.destroy();
coins.splice(c, 1);
continue;
}
// Check collection
if (coin.intersects(game.playerCar) && !coin.collected) {
coin.collected = true;
var coinsEarned = coin.multiplier || 1;
// Apply global coin multiplier if active
if (coinMultiplierTime > 0) {
coinsEarned *= coinMultiplier;
}
currentCoins += coinsEarned;
LK.getSound('coin').play();
// Enhanced visual feedback for multiplier coins
var sparkleForce = coin.multiplier > 1 ? 3 : 1.5;
sparkleSystem.emit(coin.x, coin.y, sparkleForce);
// Special effect for multiplier coins
if (coin.multiplier > 1) {
coinMultiplier = coin.multiplier;
coinMultiplierTime = 600; // 10 seconds at 60fps
// Flash effect for multiplier activation
tween(coinText, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xffd700
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(coinText, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0xffffff
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
tween(coin, {
alpha: 0,
y: coin.y - 50
}, {
duration: 500,
onFinish: function onFinish() {
coin.destroy();
}
});
coins.splice(c, 1);
}
}
// Update and clean up road lines
for (var j = roadLines.length - 1; j >= 0; j--) {
var roadLine = roadLines[j];
if (roadLine.y > 2800) {
roadLine.destroy();
roadLines.splice(j, 1);
}
}
}
};
Modern App Store icon, high definition, square with rounded corners, for a game titled "Highway Dodge" and with the description "A fast-paced 2D top-down car game where players dodge obstacles on a two-lane highway by switching lanes, with increasing speed and difficulty for endless replayability.". No text on icon!
madeni para. In-Game asset. 2d. High contrast. No shadows
glow effect. In-Game asset. 2d. High contrast. No shadows