/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AICar = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('aiCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = Math.floor(Math.random() * 3);
self.speed = (8 + Math.random() * 4) * 0.8;
self.update = function () {
self.y += self.speed;
// Random lane changes
if (Math.random() < 0.005) {
var newLane = Math.floor(Math.random() * 3);
if (newLane !== self.lane) {
self.lane = newLane;
tween(self, {
x: 600 + self.lane * 400
}, {
duration: 400,
easing: tween.easeInOut
});
}
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -20;
self.update = function () {
self.y += self.speed;
};
return self;
});
var BulletPowerup = Container.expand(function () {
var self = Container.call(this);
var bulletPowerupGraphics = self.attachAsset('bulletPowerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = Math.floor(Math.random() * 3);
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
var NitroPowerup = Container.expand(function () {
var self = Container.call(this);
var nitroGraphics = self.attachAsset('nitro', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = Math.floor(Math.random() * 3);
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
self.carType = storage.selectedCar || 'car1';
var carGraphics = self.attachAsset(self.carType, {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1; // 0, 1, 2 for three lanes
self.nitroActive = false;
self.nitroTime = 0;
self.speed = 10;
self.baseSpeed = 10;
self.maxSpeed = 20;
self.minSpeed = 5;
self.nitroCount = 0;
self.bulletCount = 0;
self.update = function () {
if (self.nitroActive) {
self.nitroTime--;
if (self.nitroTime <= 0) {
self.nitroActive = false;
self.speed = 10;
}
}
};
self.changeLane = function (direction) {
if (direction === 'left' && self.lane > 0) {
self.lane--;
tween(self, {
x: 600 + self.lane * 400
}, {
duration: 200,
easing: tween.easeOut
});
} else if (direction === 'right' && self.lane < 2) {
self.lane++;
tween(self, {
x: 600 + self.lane * 400
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.activateNitro = function () {
if (!self.nitroActive) {
self.nitroActive = true;
self.nitroTime = 180; // 3 seconds at 60fps
self.speed = 20;
LK.effects.flashObject(self, 0xffff00, 500);
}
};
self.accelerate = function () {
if (!self.nitroActive && self.speed < self.maxSpeed) {
self.speed = Math.min(self.speed + 0.5, self.maxSpeed);
}
};
self.brake = function () {
if (!self.nitroActive && self.speed > self.minSpeed) {
self.speed = Math.max(self.speed - 0.5, self.minSpeed);
}
};
return self;
});
var TrackLine = Container.expand(function () {
var self = Container.call(this);
var lineGraphics = self.attachAsset('trackLine', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d5016
});
/****
* Game Code
****/
// Game states
var gameState = 'menu'; // menu, playing, rearview
var selectedMenuOption = 0;
var selectedCarOption = storage.selectedCar || 'car1';
var audioEnabled = storage.audioEnabled !== false;
var raceTime = 0;
var trackType = 0;
// Game containers
var menuContainer = null;
var gameContainer = null;
var uiContainer = null;
// Game objects
var player = null;
var aiCars = [];
var nitroPowerups = [];
var bulletPowerups = [];
var trackLines = [];
var bullets = [];
// UI elements
var timerText = null;
var nitroCounterText = null;
var bulletCounterText = null;
var minimap = null;
var dpadLeft = null;
var dpadRight = null;
var buttonA = null;
var buttonB = null;
function createMainMenu() {
menuContainer = game.addChild(new Container());
menuContainer.interactive = true;
if (audioEnabled) {
LK.playMusic('menuMusic');
}
var bg = menuContainer.attachAsset('menuBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
var titleText = new Text2('RETRO RACER', {
size: 200,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
menuContainer.addChild(titleText);
// Menu options
var menuOptions = ['GAME PLAY', 'OPTIONS', 'EXIT'];
var menuButtons = [];
for (var i = 0; i < menuOptions.length; i++) {
var button = menuContainer.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 900 + i * 200
});
button.interactive = true;
button.buttonDown = true;
button.menuIndex = i;
var buttonText = new Text2(menuOptions[i], {
size: 60,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 1024;
buttonText.y = 900 + i * 200;
menuContainer.addChild(buttonText);
menuButtons.push({
button: button,
text: buttonText,
index: i
});
}
// Highlight selected option
function updateMenuSelection() {
for (var i = 0; i < menuButtons.length; i++) {
if (i === selectedMenuOption) {
menuButtons[i].button.tint = 0x8bac0f;
menuButtons[i].text.tint = 0x000000;
} else {
menuButtons[i].button.tint = 0xffffff;
menuButtons[i].text.tint = 0xffffff;
}
}
}
updateMenuSelection();
// Add event handlers to individual buttons
for (var i = 0; i < menuButtons.length; i++) {
(function (index) {
menuButtons[index].button.down = function (x, y, obj) {
if (audioEnabled) {
LK.getSound('menuClick').play();
}
selectedMenuOption = index;
updateMenuSelection();
selectMenuOption();
};
})(i);
}
}
function createOptionsMenu() {
menuContainer = game.addChild(new Container());
menuContainer.interactive = true;
var bg = menuContainer.attachAsset('menuBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
var titleText = new Text2('OPTIONS', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
menuContainer.addChild(titleText);
// Car selection
var carText = new Text2('SELECT CAR:', {
size: 60,
fill: 0x8BAC0F
});
carText.anchor.set(0.5, 0.5);
carText.x = 1024;
carText.y = 700;
menuContainer.addChild(carText);
var carOptions = ['car1', 'car2', 'car3'];
var carButtons = [];
for (var i = 0; i < carOptions.length; i++) {
var carButton = menuContainer.attachAsset(carOptions[i], {
anchorX: 0.5,
anchorY: 0.5,
x: 700 + i * 300,
y: 900
});
carButton.interactive = true;
carButton.buttonDown = true;
carButton.carType = carOptions[i];
if (carOptions[i] === selectedCarOption) {
carButton.scale.set(1.5);
}
carButtons.push({
button: carButton,
type: carOptions[i]
});
}
// Audio toggle
var audioText = new Text2('AUDIO: ' + (audioEnabled ? 'ON' : 'OFF'), {
size: 60,
fill: 0xFFFFFF
});
audioText.anchor.set(0.5, 0.5);
audioText.x = 1024;
audioText.y = 1200;
menuContainer.addChild(audioText);
// Audio toggle button
var audioButton = menuContainer.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1200
});
audioButton.interactive = true;
audioButton.buttonDown = true;
// Back button
var backButton = menuContainer.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1600
});
backButton.interactive = true;
backButton.buttonDown = true;
var backText = new Text2('BACK', {
size: 60,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 1600;
menuContainer.addChild(backText);
// Add event handlers to car buttons
for (var i = 0; i < carButtons.length; i++) {
(function (index) {
carButtons[index].button.down = function (x, y, obj) {
if (audioEnabled) {
LK.getSound('menuClick').play();
}
selectedCarOption = carButtons[index].type;
storage.selectedCar = selectedCarOption;
menuContainer.destroy();
createOptionsMenu();
};
})(i);
}
// Add event handler to audio button
audioButton.down = function (x, y, obj) {
if (audioEnabled) {
LK.getSound('menuClick').play();
}
audioEnabled = !audioEnabled;
storage.audioEnabled = audioEnabled;
audioText.text = 'AUDIO: ' + (audioEnabled ? 'ON' : 'OFF');
};
// Add event handler to back button
backButton.down = function (x, y, obj) {
if (audioEnabled) {
LK.getSound('menuClick').play();
}
menuContainer.destroy();
createMainMenu();
};
}
function selectMenuOption() {
if (selectedMenuOption === 0) {
// Game Play
menuContainer.destroy();
startGame();
} else if (selectedMenuOption === 1) {
// Options
menuContainer.destroy();
createOptionsMenu();
} else if (selectedMenuOption === 2) {
// Exit
LK.showGameOver();
}
}
function startGame() {
gameState = 'playing';
raceTime = 0;
if (audioEnabled) {
LK.playMusic('raceMusic');
}
// Create game container
gameContainer = game.addChild(new Container());
// Create track
var track = gameContainer.attachAsset('track', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
gameContainer.setChildIndex(track, 0); // Send track to bottom layer
// Create player
player = gameContainer.addChild(new PlayerCar());
player.x = 600 + player.lane * 400;
player.y = 1700;
// Create UI
createUI();
// Start spawning game objects
spawnTrackLines();
spawnAICars();
spawnNitroPowerups();
spawnBulletPowerups();
}
function createUI() {
uiContainer = game.addChild(new Container());
uiContainer.interactive = true;
// Timer
timerText = new Text2('TIME: 0:00', {
size: 60,
fill: 0x000000
});
timerText.anchor.set(1, 0);
timerText.x = 1948;
timerText.y = 150;
uiContainer.addChild(timerText);
// Nitro counter
nitroCounterText = new Text2('NITRO: 0', {
size: 50,
fill: 0x000000
});
nitroCounterText.anchor.set(1, 0);
nitroCounterText.x = 1948;
nitroCounterText.y = 220;
uiContainer.addChild(nitroCounterText);
// Bullet counter
bulletCounterText = new Text2('BULLETS: 0', {
size: 50,
fill: 0x000000
});
bulletCounterText.anchor.set(1, 0);
bulletCounterText.x = 1948;
bulletCounterText.y = 290;
uiContainer.addChild(bulletCounterText);
// Minimap
minimap = uiContainer.attachAsset('minimap', {
anchorX: 0,
anchorY: 0,
x: 150,
y: 150
});
var playerDot = uiContainer.attachAsset('minimapDot', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: 500
});
// D-pad buttons only (no base) - further increased spacing for larger D-pad area
dpadLeft = uiContainer.attachAsset('leftButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 180,
y: 2300,
alpha: 0.5
});
dpadLeft.interactive = true;
dpadLeft.buttonDown = true;
dpadRight = uiContainer.attachAsset('rightButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 620,
y: 2300,
alpha: 0.5
});
dpadRight.interactive = true;
dpadRight.buttonDown = true;
var dpadUp = uiContainer.attachAsset('upButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 400,
y: 2080,
alpha: 0.5
});
dpadUp.interactive = true;
dpadUp.buttonDown = true;
var dpadDown = uiContainer.attachAsset('downButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 400,
y: 2520,
alpha: 0.5
});
dpadDown.interactive = true;
dpadDown.buttonDown = true;
// A/B buttons
buttonA = uiContainer.attachAsset('aButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1850,
y: 2350,
alpha: 0.5
});
buttonA.interactive = true;
buttonA.buttonDown = true;
var aText = new Text2('A', {
size: 40,
fill: 0xFFFFFF
});
aText.anchor.set(0.5, 0.5);
aText.x = 1850;
aText.y = 2350;
uiContainer.addChild(aText);
buttonB = uiContainer.attachAsset('bButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1450,
y: 2480,
alpha: 0.5
});
buttonB.interactive = true;
buttonB.buttonDown = true;
var bText = new Text2('B', {
size: 40,
fill: 0xFFFFFF
});
bText.anchor.set(0.5, 0.5);
bText.x = 1450;
bText.y = 2480;
uiContainer.addChild(bText);
// Add event handlers to UI buttons
dpadLeft.down = function (x, y, obj) {
player.changeLane('left');
dpadLeft.alpha = 0.8;
};
dpadLeft.up = function (x, y, obj) {
dpadLeft.alpha = 0.5;
};
dpadRight.down = function (x, y, obj) {
player.changeLane('right');
dpadRight.alpha = 0.8;
};
dpadRight.up = function (x, y, obj) {
dpadRight.alpha = 0.5;
};
buttonA.down = function (x, y, obj) {
if (player.nitroCount > 0) {
player.activateNitro();
player.nitroCount--;
nitroCounterText.setText('NITRO: ' + player.nitroCount);
}
buttonA.alpha = 0.8;
};
buttonA.up = function (x, y, obj) {
buttonA.alpha = 0.5;
};
buttonB.down = function (x, y, obj) {
fireBullet();
buttonB.alpha = 0.8;
};
buttonB.up = function (x, y, obj) {
buttonB.alpha = 0.5;
};
dpadUp.down = function (x, y, obj) {
player.accelerate();
dpadUp.alpha = 0.8;
};
dpadUp.up = function (x, y, obj) {
dpadUp.alpha = 0.5;
};
dpadDown.down = function (x, y, obj) {
player.brake();
dpadDown.alpha = 0.8;
};
dpadDown.up = function (x, y, obj) {
dpadDown.alpha = 0.5;
};
}
function fireBullet() {
if (gameState === 'playing' && player.bulletCount > 0) {
var bullet = gameContainer.addChild(new Bullet());
bullet.x = player.x;
bullet.y = player.y - 100;
bullets.push(bullet);
player.bulletCount--;
bulletCounterText.setText('BULLETS: ' + player.bulletCount);
}
}
function toggleRearView() {
if (gameState === 'playing') {
gameState = 'rearview';
// Flip view
gameContainer.scale.y = -1;
gameContainer.y = 2732;
} else if (gameState === 'rearview') {
gameState = 'playing';
// Restore view
gameContainer.scale.y = 1;
gameContainer.y = 0;
}
}
function spawnTrackLines() {
var lineTimer = LK.setInterval(function () {
if (gameState !== 'menu') {
// Calculate spawn interval based on player speed to maintain consistent spacing
var shouldSpawn = trackLines.length === 0 || trackLines[trackLines.length - 1] && trackLines[trackLines.length - 1].y > 200;
if (shouldSpawn) {
for (var i = 0; i < 3; i++) {
var line = gameContainer.addChild(new TrackLine());
line.x = 600 + i * 400;
line.y = -100;
line.speed = player.speed;
gameContainer.setChildIndex(line, 1); // Send tracklines above track but below other elements
trackLines.push(line);
}
}
}
}, 100); // Check more frequently for spawning
}
function spawnAICars() {
var carTimer = LK.setInterval(function () {
if (gameState !== 'menu' && aiCars.length < 5) {
var aiCar = gameContainer.addChild(new AICar());
aiCar.x = 600 + aiCar.lane * 400;
aiCar.y = -200;
aiCars.push(aiCar);
}
}, 2000);
}
function spawnNitroPowerups() {
var nitroTimer = LK.setInterval(function () {
if (gameState !== 'menu') {
var nitro = gameContainer.addChild(new NitroPowerup());
nitro.x = 600 + nitro.lane * 400;
nitro.y = -100;
nitro.speed = player.speed;
nitroPowerups.push(nitro);
}
}, 5000);
}
function spawnBulletPowerups() {
var bulletTimer = LK.setInterval(function () {
if (gameState !== 'menu') {
var bulletPowerup = gameContainer.addChild(new BulletPowerup());
bulletPowerup.x = 600 + bulletPowerup.lane * 400;
bulletPowerup.y = -100;
bulletPowerup.speed = player.speed;
bulletPowerups.push(bulletPowerup);
}
}, 3000);
}
function completeRace() {
trackType = (trackType + 1) % 3;
// Change track color based on type
var trackColors = [0x4a4a4a, 0x8b4513, 0x2f4f4f];
game.setBackgroundColor(trackColors[trackType]);
// Reset race
raceTime = 0;
// Clear existing objects
for (var i = aiCars.length - 1; i >= 0; i--) {
aiCars[i].destroy();
}
aiCars = [];
for (var j = nitroPowerups.length - 1; j >= 0; j--) {
nitroPowerups[j].destroy();
}
nitroPowerups = [];
for (var k = bulletPowerups.length - 1; k >= 0; k--) {
bulletPowerups[k].destroy();
}
bulletPowerups = [];
}
// Main game update
game.update = function () {
if (gameState === 'menu') return;
// Update timer
raceTime++;
var minutes = Math.floor(raceTime / 3600);
var seconds = Math.floor(raceTime % 3600 / 60);
timerText.setText('TIME: ' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
// Update track lines
for (var i = trackLines.length - 1; i >= 0; i--) {
var line = trackLines[i];
line.speed = player.speed;
if (line.y > 2832) {
line.destroy();
trackLines.splice(i, 1);
}
}
// Update bullets
for (var b = bullets.length - 1; b >= 0; b--) {
var bullet = bullets[b];
if (bullet.y < -100) {
bullet.destroy();
bullets.splice(b, 1);
continue;
}
// Check bullet collision with AI cars
for (var c = aiCars.length - 1; c >= 0; c--) {
var aiCar = aiCars[c];
if (bullet.intersects(aiCar)) {
if (audioEnabled) {
LK.getSound('explosion').play();
}
// Explosion effect
LK.effects.flashObject(aiCar, 0xff4500, 300);
tween(aiCar, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
aiCar.destroy();
}
});
aiCars.splice(c, 1);
bullet.destroy();
bullets.splice(b, 1);
break;
}
}
}
// Update AI cars
for (var j = aiCars.length - 1; j >= 0; j--) {
var aiCar = aiCars[j];
if (aiCar.y > 2832) {
aiCar.destroy();
aiCars.splice(j, 1);
continue;
}
// Check collision with player
if (player.intersects(aiCar)) {
if (audioEnabled) {
LK.getSound('crash').play();
}
LK.effects.flashScreen(0xff0000, 500);
LK.showGameOver();
}
}
// Update nitro powerups
for (var k = nitroPowerups.length - 1; k >= 0; k--) {
var nitro = nitroPowerups[k];
nitro.speed = player.speed;
if (nitro.y > 2832) {
nitro.destroy();
nitroPowerups.splice(k, 1);
continue;
}
// Check collection
if (player.intersects(nitro)) {
if (audioEnabled) {
LK.getSound('coinPickup').play();
}
// Increase nitro and bullet counts
player.nitroCount++;
player.bulletCount += 3;
nitroCounterText.setText('NITRO: ' + player.nitroCount);
bulletCounterText.setText('BULLETS: ' + player.bulletCount);
nitro.destroy();
nitroPowerups.splice(k, 1);
}
}
// Update bullet powerups
for (var l = bulletPowerups.length - 1; l >= 0; l--) {
var bulletPowerup = bulletPowerups[l];
bulletPowerup.speed = player.speed;
if (bulletPowerup.y > 2832) {
bulletPowerup.destroy();
bulletPowerups.splice(l, 1);
continue;
}
// Check collection
if (player.intersects(bulletPowerup)) {
if (audioEnabled) {
LK.getSound('coinPickup').play();
}
// Increase bullet count only
player.bulletCount += 5;
bulletCounterText.setText('BULLETS: ' + player.bulletCount);
bulletPowerup.destroy();
bulletPowerups.splice(l, 1);
}
}
// Complete race after 2 minutes
if (raceTime >= 7200) {
completeRace();
}
};
// Start with main menu
createMainMenu(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AICar = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('aiCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = Math.floor(Math.random() * 3);
self.speed = (8 + Math.random() * 4) * 0.8;
self.update = function () {
self.y += self.speed;
// Random lane changes
if (Math.random() < 0.005) {
var newLane = Math.floor(Math.random() * 3);
if (newLane !== self.lane) {
self.lane = newLane;
tween(self, {
x: 600 + self.lane * 400
}, {
duration: 400,
easing: tween.easeInOut
});
}
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -20;
self.update = function () {
self.y += self.speed;
};
return self;
});
var BulletPowerup = Container.expand(function () {
var self = Container.call(this);
var bulletPowerupGraphics = self.attachAsset('bulletPowerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = Math.floor(Math.random() * 3);
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
var NitroPowerup = Container.expand(function () {
var self = Container.call(this);
var nitroGraphics = self.attachAsset('nitro', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = Math.floor(Math.random() * 3);
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
self.carType = storage.selectedCar || 'car1';
var carGraphics = self.attachAsset(self.carType, {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1; // 0, 1, 2 for three lanes
self.nitroActive = false;
self.nitroTime = 0;
self.speed = 10;
self.baseSpeed = 10;
self.maxSpeed = 20;
self.minSpeed = 5;
self.nitroCount = 0;
self.bulletCount = 0;
self.update = function () {
if (self.nitroActive) {
self.nitroTime--;
if (self.nitroTime <= 0) {
self.nitroActive = false;
self.speed = 10;
}
}
};
self.changeLane = function (direction) {
if (direction === 'left' && self.lane > 0) {
self.lane--;
tween(self, {
x: 600 + self.lane * 400
}, {
duration: 200,
easing: tween.easeOut
});
} else if (direction === 'right' && self.lane < 2) {
self.lane++;
tween(self, {
x: 600 + self.lane * 400
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.activateNitro = function () {
if (!self.nitroActive) {
self.nitroActive = true;
self.nitroTime = 180; // 3 seconds at 60fps
self.speed = 20;
LK.effects.flashObject(self, 0xffff00, 500);
}
};
self.accelerate = function () {
if (!self.nitroActive && self.speed < self.maxSpeed) {
self.speed = Math.min(self.speed + 0.5, self.maxSpeed);
}
};
self.brake = function () {
if (!self.nitroActive && self.speed > self.minSpeed) {
self.speed = Math.max(self.speed - 0.5, self.minSpeed);
}
};
return self;
});
var TrackLine = Container.expand(function () {
var self = Container.call(this);
var lineGraphics = self.attachAsset('trackLine', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d5016
});
/****
* Game Code
****/
// Game states
var gameState = 'menu'; // menu, playing, rearview
var selectedMenuOption = 0;
var selectedCarOption = storage.selectedCar || 'car1';
var audioEnabled = storage.audioEnabled !== false;
var raceTime = 0;
var trackType = 0;
// Game containers
var menuContainer = null;
var gameContainer = null;
var uiContainer = null;
// Game objects
var player = null;
var aiCars = [];
var nitroPowerups = [];
var bulletPowerups = [];
var trackLines = [];
var bullets = [];
// UI elements
var timerText = null;
var nitroCounterText = null;
var bulletCounterText = null;
var minimap = null;
var dpadLeft = null;
var dpadRight = null;
var buttonA = null;
var buttonB = null;
function createMainMenu() {
menuContainer = game.addChild(new Container());
menuContainer.interactive = true;
if (audioEnabled) {
LK.playMusic('menuMusic');
}
var bg = menuContainer.attachAsset('menuBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
var titleText = new Text2('RETRO RACER', {
size: 200,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
menuContainer.addChild(titleText);
// Menu options
var menuOptions = ['GAME PLAY', 'OPTIONS', 'EXIT'];
var menuButtons = [];
for (var i = 0; i < menuOptions.length; i++) {
var button = menuContainer.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 900 + i * 200
});
button.interactive = true;
button.buttonDown = true;
button.menuIndex = i;
var buttonText = new Text2(menuOptions[i], {
size: 60,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 1024;
buttonText.y = 900 + i * 200;
menuContainer.addChild(buttonText);
menuButtons.push({
button: button,
text: buttonText,
index: i
});
}
// Highlight selected option
function updateMenuSelection() {
for (var i = 0; i < menuButtons.length; i++) {
if (i === selectedMenuOption) {
menuButtons[i].button.tint = 0x8bac0f;
menuButtons[i].text.tint = 0x000000;
} else {
menuButtons[i].button.tint = 0xffffff;
menuButtons[i].text.tint = 0xffffff;
}
}
}
updateMenuSelection();
// Add event handlers to individual buttons
for (var i = 0; i < menuButtons.length; i++) {
(function (index) {
menuButtons[index].button.down = function (x, y, obj) {
if (audioEnabled) {
LK.getSound('menuClick').play();
}
selectedMenuOption = index;
updateMenuSelection();
selectMenuOption();
};
})(i);
}
}
function createOptionsMenu() {
menuContainer = game.addChild(new Container());
menuContainer.interactive = true;
var bg = menuContainer.attachAsset('menuBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
var titleText = new Text2('OPTIONS', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
menuContainer.addChild(titleText);
// Car selection
var carText = new Text2('SELECT CAR:', {
size: 60,
fill: 0x8BAC0F
});
carText.anchor.set(0.5, 0.5);
carText.x = 1024;
carText.y = 700;
menuContainer.addChild(carText);
var carOptions = ['car1', 'car2', 'car3'];
var carButtons = [];
for (var i = 0; i < carOptions.length; i++) {
var carButton = menuContainer.attachAsset(carOptions[i], {
anchorX: 0.5,
anchorY: 0.5,
x: 700 + i * 300,
y: 900
});
carButton.interactive = true;
carButton.buttonDown = true;
carButton.carType = carOptions[i];
if (carOptions[i] === selectedCarOption) {
carButton.scale.set(1.5);
}
carButtons.push({
button: carButton,
type: carOptions[i]
});
}
// Audio toggle
var audioText = new Text2('AUDIO: ' + (audioEnabled ? 'ON' : 'OFF'), {
size: 60,
fill: 0xFFFFFF
});
audioText.anchor.set(0.5, 0.5);
audioText.x = 1024;
audioText.y = 1200;
menuContainer.addChild(audioText);
// Audio toggle button
var audioButton = menuContainer.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1200
});
audioButton.interactive = true;
audioButton.buttonDown = true;
// Back button
var backButton = menuContainer.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1600
});
backButton.interactive = true;
backButton.buttonDown = true;
var backText = new Text2('BACK', {
size: 60,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = 1024;
backText.y = 1600;
menuContainer.addChild(backText);
// Add event handlers to car buttons
for (var i = 0; i < carButtons.length; i++) {
(function (index) {
carButtons[index].button.down = function (x, y, obj) {
if (audioEnabled) {
LK.getSound('menuClick').play();
}
selectedCarOption = carButtons[index].type;
storage.selectedCar = selectedCarOption;
menuContainer.destroy();
createOptionsMenu();
};
})(i);
}
// Add event handler to audio button
audioButton.down = function (x, y, obj) {
if (audioEnabled) {
LK.getSound('menuClick').play();
}
audioEnabled = !audioEnabled;
storage.audioEnabled = audioEnabled;
audioText.text = 'AUDIO: ' + (audioEnabled ? 'ON' : 'OFF');
};
// Add event handler to back button
backButton.down = function (x, y, obj) {
if (audioEnabled) {
LK.getSound('menuClick').play();
}
menuContainer.destroy();
createMainMenu();
};
}
function selectMenuOption() {
if (selectedMenuOption === 0) {
// Game Play
menuContainer.destroy();
startGame();
} else if (selectedMenuOption === 1) {
// Options
menuContainer.destroy();
createOptionsMenu();
} else if (selectedMenuOption === 2) {
// Exit
LK.showGameOver();
}
}
function startGame() {
gameState = 'playing';
raceTime = 0;
if (audioEnabled) {
LK.playMusic('raceMusic');
}
// Create game container
gameContainer = game.addChild(new Container());
// Create track
var track = gameContainer.attachAsset('track', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
gameContainer.setChildIndex(track, 0); // Send track to bottom layer
// Create player
player = gameContainer.addChild(new PlayerCar());
player.x = 600 + player.lane * 400;
player.y = 1700;
// Create UI
createUI();
// Start spawning game objects
spawnTrackLines();
spawnAICars();
spawnNitroPowerups();
spawnBulletPowerups();
}
function createUI() {
uiContainer = game.addChild(new Container());
uiContainer.interactive = true;
// Timer
timerText = new Text2('TIME: 0:00', {
size: 60,
fill: 0x000000
});
timerText.anchor.set(1, 0);
timerText.x = 1948;
timerText.y = 150;
uiContainer.addChild(timerText);
// Nitro counter
nitroCounterText = new Text2('NITRO: 0', {
size: 50,
fill: 0x000000
});
nitroCounterText.anchor.set(1, 0);
nitroCounterText.x = 1948;
nitroCounterText.y = 220;
uiContainer.addChild(nitroCounterText);
// Bullet counter
bulletCounterText = new Text2('BULLETS: 0', {
size: 50,
fill: 0x000000
});
bulletCounterText.anchor.set(1, 0);
bulletCounterText.x = 1948;
bulletCounterText.y = 290;
uiContainer.addChild(bulletCounterText);
// Minimap
minimap = uiContainer.attachAsset('minimap', {
anchorX: 0,
anchorY: 0,
x: 150,
y: 150
});
var playerDot = uiContainer.attachAsset('minimapDot', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: 500
});
// D-pad buttons only (no base) - further increased spacing for larger D-pad area
dpadLeft = uiContainer.attachAsset('leftButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 180,
y: 2300,
alpha: 0.5
});
dpadLeft.interactive = true;
dpadLeft.buttonDown = true;
dpadRight = uiContainer.attachAsset('rightButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 620,
y: 2300,
alpha: 0.5
});
dpadRight.interactive = true;
dpadRight.buttonDown = true;
var dpadUp = uiContainer.attachAsset('upButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 400,
y: 2080,
alpha: 0.5
});
dpadUp.interactive = true;
dpadUp.buttonDown = true;
var dpadDown = uiContainer.attachAsset('downButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 400,
y: 2520,
alpha: 0.5
});
dpadDown.interactive = true;
dpadDown.buttonDown = true;
// A/B buttons
buttonA = uiContainer.attachAsset('aButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1850,
y: 2350,
alpha: 0.5
});
buttonA.interactive = true;
buttonA.buttonDown = true;
var aText = new Text2('A', {
size: 40,
fill: 0xFFFFFF
});
aText.anchor.set(0.5, 0.5);
aText.x = 1850;
aText.y = 2350;
uiContainer.addChild(aText);
buttonB = uiContainer.attachAsset('bButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1450,
y: 2480,
alpha: 0.5
});
buttonB.interactive = true;
buttonB.buttonDown = true;
var bText = new Text2('B', {
size: 40,
fill: 0xFFFFFF
});
bText.anchor.set(0.5, 0.5);
bText.x = 1450;
bText.y = 2480;
uiContainer.addChild(bText);
// Add event handlers to UI buttons
dpadLeft.down = function (x, y, obj) {
player.changeLane('left');
dpadLeft.alpha = 0.8;
};
dpadLeft.up = function (x, y, obj) {
dpadLeft.alpha = 0.5;
};
dpadRight.down = function (x, y, obj) {
player.changeLane('right');
dpadRight.alpha = 0.8;
};
dpadRight.up = function (x, y, obj) {
dpadRight.alpha = 0.5;
};
buttonA.down = function (x, y, obj) {
if (player.nitroCount > 0) {
player.activateNitro();
player.nitroCount--;
nitroCounterText.setText('NITRO: ' + player.nitroCount);
}
buttonA.alpha = 0.8;
};
buttonA.up = function (x, y, obj) {
buttonA.alpha = 0.5;
};
buttonB.down = function (x, y, obj) {
fireBullet();
buttonB.alpha = 0.8;
};
buttonB.up = function (x, y, obj) {
buttonB.alpha = 0.5;
};
dpadUp.down = function (x, y, obj) {
player.accelerate();
dpadUp.alpha = 0.8;
};
dpadUp.up = function (x, y, obj) {
dpadUp.alpha = 0.5;
};
dpadDown.down = function (x, y, obj) {
player.brake();
dpadDown.alpha = 0.8;
};
dpadDown.up = function (x, y, obj) {
dpadDown.alpha = 0.5;
};
}
function fireBullet() {
if (gameState === 'playing' && player.bulletCount > 0) {
var bullet = gameContainer.addChild(new Bullet());
bullet.x = player.x;
bullet.y = player.y - 100;
bullets.push(bullet);
player.bulletCount--;
bulletCounterText.setText('BULLETS: ' + player.bulletCount);
}
}
function toggleRearView() {
if (gameState === 'playing') {
gameState = 'rearview';
// Flip view
gameContainer.scale.y = -1;
gameContainer.y = 2732;
} else if (gameState === 'rearview') {
gameState = 'playing';
// Restore view
gameContainer.scale.y = 1;
gameContainer.y = 0;
}
}
function spawnTrackLines() {
var lineTimer = LK.setInterval(function () {
if (gameState !== 'menu') {
// Calculate spawn interval based on player speed to maintain consistent spacing
var shouldSpawn = trackLines.length === 0 || trackLines[trackLines.length - 1] && trackLines[trackLines.length - 1].y > 200;
if (shouldSpawn) {
for (var i = 0; i < 3; i++) {
var line = gameContainer.addChild(new TrackLine());
line.x = 600 + i * 400;
line.y = -100;
line.speed = player.speed;
gameContainer.setChildIndex(line, 1); // Send tracklines above track but below other elements
trackLines.push(line);
}
}
}
}, 100); // Check more frequently for spawning
}
function spawnAICars() {
var carTimer = LK.setInterval(function () {
if (gameState !== 'menu' && aiCars.length < 5) {
var aiCar = gameContainer.addChild(new AICar());
aiCar.x = 600 + aiCar.lane * 400;
aiCar.y = -200;
aiCars.push(aiCar);
}
}, 2000);
}
function spawnNitroPowerups() {
var nitroTimer = LK.setInterval(function () {
if (gameState !== 'menu') {
var nitro = gameContainer.addChild(new NitroPowerup());
nitro.x = 600 + nitro.lane * 400;
nitro.y = -100;
nitro.speed = player.speed;
nitroPowerups.push(nitro);
}
}, 5000);
}
function spawnBulletPowerups() {
var bulletTimer = LK.setInterval(function () {
if (gameState !== 'menu') {
var bulletPowerup = gameContainer.addChild(new BulletPowerup());
bulletPowerup.x = 600 + bulletPowerup.lane * 400;
bulletPowerup.y = -100;
bulletPowerup.speed = player.speed;
bulletPowerups.push(bulletPowerup);
}
}, 3000);
}
function completeRace() {
trackType = (trackType + 1) % 3;
// Change track color based on type
var trackColors = [0x4a4a4a, 0x8b4513, 0x2f4f4f];
game.setBackgroundColor(trackColors[trackType]);
// Reset race
raceTime = 0;
// Clear existing objects
for (var i = aiCars.length - 1; i >= 0; i--) {
aiCars[i].destroy();
}
aiCars = [];
for (var j = nitroPowerups.length - 1; j >= 0; j--) {
nitroPowerups[j].destroy();
}
nitroPowerups = [];
for (var k = bulletPowerups.length - 1; k >= 0; k--) {
bulletPowerups[k].destroy();
}
bulletPowerups = [];
}
// Main game update
game.update = function () {
if (gameState === 'menu') return;
// Update timer
raceTime++;
var minutes = Math.floor(raceTime / 3600);
var seconds = Math.floor(raceTime % 3600 / 60);
timerText.setText('TIME: ' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
// Update track lines
for (var i = trackLines.length - 1; i >= 0; i--) {
var line = trackLines[i];
line.speed = player.speed;
if (line.y > 2832) {
line.destroy();
trackLines.splice(i, 1);
}
}
// Update bullets
for (var b = bullets.length - 1; b >= 0; b--) {
var bullet = bullets[b];
if (bullet.y < -100) {
bullet.destroy();
bullets.splice(b, 1);
continue;
}
// Check bullet collision with AI cars
for (var c = aiCars.length - 1; c >= 0; c--) {
var aiCar = aiCars[c];
if (bullet.intersects(aiCar)) {
if (audioEnabled) {
LK.getSound('explosion').play();
}
// Explosion effect
LK.effects.flashObject(aiCar, 0xff4500, 300);
tween(aiCar, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
aiCar.destroy();
}
});
aiCars.splice(c, 1);
bullet.destroy();
bullets.splice(b, 1);
break;
}
}
}
// Update AI cars
for (var j = aiCars.length - 1; j >= 0; j--) {
var aiCar = aiCars[j];
if (aiCar.y > 2832) {
aiCar.destroy();
aiCars.splice(j, 1);
continue;
}
// Check collision with player
if (player.intersects(aiCar)) {
if (audioEnabled) {
LK.getSound('crash').play();
}
LK.effects.flashScreen(0xff0000, 500);
LK.showGameOver();
}
}
// Update nitro powerups
for (var k = nitroPowerups.length - 1; k >= 0; k--) {
var nitro = nitroPowerups[k];
nitro.speed = player.speed;
if (nitro.y > 2832) {
nitro.destroy();
nitroPowerups.splice(k, 1);
continue;
}
// Check collection
if (player.intersects(nitro)) {
if (audioEnabled) {
LK.getSound('coinPickup').play();
}
// Increase nitro and bullet counts
player.nitroCount++;
player.bulletCount += 3;
nitroCounterText.setText('NITRO: ' + player.nitroCount);
bulletCounterText.setText('BULLETS: ' + player.bulletCount);
nitro.destroy();
nitroPowerups.splice(k, 1);
}
}
// Update bullet powerups
for (var l = bulletPowerups.length - 1; l >= 0; l--) {
var bulletPowerup = bulletPowerups[l];
bulletPowerup.speed = player.speed;
if (bulletPowerup.y > 2832) {
bulletPowerup.destroy();
bulletPowerups.splice(l, 1);
continue;
}
// Check collection
if (player.intersects(bulletPowerup)) {
if (audioEnabled) {
LK.getSound('coinPickup').play();
}
// Increase bullet count only
player.bulletCount += 5;
bulletCounterText.setText('BULLETS: ' + player.bulletCount);
bulletPowerup.destroy();
bulletPowerups.splice(l, 1);
}
}
// Complete race after 2 minutes
if (raceTime >= 7200) {
completeRace();
}
};
// Start with main menu
createMainMenu();
plastic, realistic,shiny, black, only one arrow-shaped buttons. In-Game asset. 2d. High contrast. No shadows
white sports car arcade top view. In-Game asset. 2d. High contrast. No shadows
Blue sports car arcade top view. In-Game asset. 2d. High contrast. No shadows
Grey sports car arcade top view. In-Game asset. 2d. High contrast. No shadows
Yellow sports car arcade top view. In-Game asset. 2d. High contrast. No shadows
asphalt road. In-Game asset. 2d. High contrast. No shadows
Nitro image blue In-Game asset. 2d. High contrast. No shadows
Racing background wallpaper blue 2500x3125 1080p. In-Game asset. 2d. High contrast. No shadows
realistic, plastic, gray, rectangular. In-Game asset. 2d. High contrast. No shadows
Racing floor background wallpaper light grey 2500x3125 1080p. In-Game asset. 2d. High contrast. No shadows
Circle realistic plastic green. In-Game asset. 2d. High contrast. No shadows
Circle realistic plastic blue. In-Game asset. 2d. High contrast. No shadows
yellow bullet icon. In-Game asset. 2d. High contrast. No shadows
Bullet realistic icon light red color In-Game asset. 2d. High contrast. No shadows