/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
garage: [],
crystals: 10,
cash: 5000,
garageSlots: 2
});
/****
* Classes
****/
// Car class
var Car = Container.expand(function () {
var self = Container.call(this);
// Car stats
self.stats = {
horsepower: 100,
weight: 1200,
grip: 1,
turbo: 0,
intake: 0,
tires: 1,
paint: 0x3333cc
};
// Car parts (for upgrades)
self.parts = {
engine: 1,
turbo: 0,
intake: 0,
tires: 1
};
// Cosmetic
self.paint = 0x3333cc;
// Attach car body
var body = self.attachAsset('carBody', {
anchorX: 0.5,
anchorY: 0.5,
tint: self.paint
});
// Attach wheels
var wheel1 = self.attachAsset('carWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: -120,
y: 50
});
var wheel2 = self.attachAsset('carWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: 50
});
// For race animation
self.raceProgress = 0; // 0 to 1
self.isRacing = false;
self.raceSpeed = 0;
// Set car data
self.setData = function (data) {
if (!data) return;
self.stats = data.stats;
self.parts = data.parts;
self.paint = data.paint || 0x3333cc;
body.tint = self.paint;
};
// Get car data for storage
self.getData = function () {
return {
stats: self.stats,
parts: self.parts,
paint: self.paint
};
};
// Start race
self.startRace = function (speed) {
self.isRacing = true;
self.raceProgress = 0;
self.raceSpeed = speed;
};
// Update per tick
self.update = function () {
if (self.isRacing) {
self.raceProgress += self.raceSpeed;
if (self.raceProgress > 1) self.raceProgress = 1;
}
};
return self;
});
// Shop part class
var ShopPart = Container.expand(function () {
var self = Container.call(this);
var icon = self.attachAsset('partIcon', {
anchorX: 0.5,
anchorY: 0.5
});
self.textObj = new Text2('', {
size: 32,
fill: "#222"
});
self.textObj.anchor.set(0.5, 0.5);
self.textObj.y = 60;
self.addChild(self.textObj);
self.setText = function (txt) {
self.textObj.setText(txt);
};
self.down = function (x, y, obj) {
if (self.onBuy) self.onBuy();
};
return self;
});
// Button class
var UIButton = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
self.textObj = new Text2('', {
size: 60,
fill: "#fff"
});
self.textObj.anchor.set(0.5, 0.5);
self.addChild(self.textObj);
self.setText = function (txt) {
self.textObj.setText(txt);
};
self.setColor = function (color) {
bg.tint = color;
};
self.down = function (x, y, obj) {
if (self.onClick) self.onClick();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Shop part icon
// Button
// Garage slot background
// Finish line
// Start line
// Race track
// Car wheel
// Car body (default)
// --- Global State ---
var GAME_STATE = {
MAIN_MENU: 0,
GARAGE: 1,
RACE: 2,
SHOP: 3
};
var state = GAME_STATE.MAIN_MENU;
// Player data
var garage = storage.garage && storage.garage.length ? storage.garage : [];
var crystals = typeof storage.crystals === 'number' ? storage.crystals : 10;
var cash = typeof storage.cash === 'number' ? storage.cash : 5000;
var garageSlots = typeof storage.garageSlots === 'number' ? storage.garageSlots : 2;
// UI elements
var mainMenuUI = [];
var garageUI = [];
var raceUI = [];
var shopUI = [];
var infoText = null;
var currencyText = null;
// Race state
var raceCar = null;
var raceOpponent = null;
var raceTrack = null;
var raceStartLine = null;
var raceFinishLine = null;
var raceDistance = 500; // meters
var raceStarted = false;
var raceEnded = false;
var raceTimer = 0;
var raceResultText = null;
// --- Utility Functions ---
function savePlayerData() {
storage.garage = garage;
storage.crystals = crystals;
storage.cash = cash;
storage.garageSlots = garageSlots;
}
function clearUI(uiArr) {
for (var i = 0; i < uiArr.length; i++) {
if (uiArr[i].parent) uiArr[i].parent.removeChild(uiArr[i]);
}
uiArr.length = 0;
}
function showInfo(msg, duration) {
if (!infoText) {
infoText = new Text2('', {
size: 60,
fill: "#fff"
});
infoText.anchor.set(0.5, 0);
LK.gui.top.addChild(infoText);
}
infoText.setText(msg);
infoText.visible = true;
if (duration) {
LK.setTimeout(function () {
if (infoText) infoText.visible = false;
}, duration);
}
}
function updateCurrencyText() {
if (!currencyText) {
currencyText = new Text2('', {
size: 48,
fill: "#fff"
});
currencyText.anchor.set(1, 0);
currencyText.x = LK.gui.width - 40;
currencyText.y = 10;
LK.gui.top.addChild(currencyText);
}
currencyText.setText("💎" + crystals + " $" + cash);
}
// --- Main Menu ---
function showMainMenu() {
state = GAME_STATE.MAIN_MENU;
clearUI(garageUI);
clearUI(raceUI);
clearUI(shopUI);
// Title
var title = new Text2('Drag Race Legends', {
size: 120,
fill: 0xFFD700
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 180;
LK.gui.top.addChild(title);
mainMenuUI.push(title);
// Play button
var playBtn = new UIButton();
playBtn.x = 2048 / 2;
playBtn.y = 600;
playBtn.setText("Race");
playBtn.onClick = function () {
showGarage();
};
LK.gui.center.addChild(playBtn);
mainMenuUI.push(playBtn);
// Garage button
var garageBtn = new UIButton();
garageBtn.x = 2048 / 2;
garageBtn.y = 800;
garageBtn.setText("Garage");
garageBtn.onClick = function () {
showGarage();
};
LK.gui.center.addChild(garageBtn);
mainMenuUI.push(garageBtn);
// Shop button
var shopBtn = new UIButton();
shopBtn.x = 2048 / 2;
shopBtn.y = 1000;
shopBtn.setText("Shop");
shopBtn.onClick = function () {
showShop();
};
LK.gui.center.addChild(shopBtn);
mainMenuUI.push(shopBtn);
updateCurrencyText();
}
function clearMainMenu() {
clearUI(mainMenuUI);
}
// --- Garage ---
function showGarage() {
state = GAME_STATE.GARAGE;
clearMainMenu();
clearUI(raceUI);
clearUI(shopUI);
// Title
var title = new Text2('Garage', {
size: 100,
fill: 0xFFD700
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 120;
LK.gui.top.addChild(title);
garageUI.push(title);
// Show car slots
var slotY = 350;
var slotGap = 200;
for (var i = 0; i < garageSlots; i++) {
var slotBg = LK.getAsset('garageSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: slotY + i * slotGap
});
LK.gui.center.addChild(slotBg);
garageUI.push(slotBg);
if (garage[i]) {
// Show car
var car = new Car();
car.setData(garage[i]);
car.x = 2048 / 2;
car.y = slotY + i * slotGap;
car.scaleX = 0.7;
car.scaleY = 0.7;
LK.gui.center.addChild(car);
garageUI.push(car);
// Show stats
var statTxt = new Text2("HP: " + car.stats.horsepower + " Turbo: " + car.parts.turbo + " Tires: " + car.parts.tires, {
size: 36,
fill: "#fff"
});
statTxt.anchor.set(0.5, 0);
statTxt.x = 2048 / 2;
statTxt.y = slotY + i * slotGap + 80;
LK.gui.center.addChild(statTxt);
garageUI.push(statTxt);
// Select for race button
(function (carIdx) {
var selectBtn = new UIButton();
selectBtn.x = 2048 / 2 + 300;
selectBtn.y = slotY + i * slotGap;
selectBtn.setText("Race");
selectBtn.setColor(0x00cc44);
selectBtn.onClick = function () {
startRaceWithCar(carIdx);
};
LK.gui.center.addChild(selectBtn);
garageUI.push(selectBtn);
})(i);
// Upgrade button
(function (carIdx) {
var upgradeBtn = new UIButton();
upgradeBtn.x = 2048 / 2 - 300;
upgradeBtn.y = slotY + i * slotGap;
upgradeBtn.setText("Upgrade");
upgradeBtn.setColor(0x0080cc);
upgradeBtn.onClick = function () {
showShop(carIdx);
};
LK.gui.center.addChild(upgradeBtn);
garageUI.push(upgradeBtn);
})(i);
} else {
// Empty slot
var addBtn = new UIButton();
addBtn.x = 2048 / 2;
addBtn.y = slotY + i * slotGap;
addBtn.setText("Buy Car ($2000)");
addBtn.setColor(0xcccc00);
addBtn.onClick = function () {
if (cash >= 2000) {
cash -= 2000;
var newCar = {
stats: {
horsepower: 100,
weight: 1200,
grip: 1,
turbo: 0,
intake: 0,
tires: 1,
paint: 0x3333cc
},
parts: {
engine: 1,
turbo: 0,
intake: 0,
tires: 1
},
paint: 0x3333cc
};
garage.push(newCar);
savePlayerData();
showGarage();
} else {
showInfo("Not enough cash!", 1200);
}
};
LK.gui.center.addChild(addBtn);
garageUI.push(addBtn);
}
}
// Add slot button (if < 10)
if (garageSlots < 10) {
var addSlotBtn = new UIButton();
addSlotBtn.x = 2048 / 2;
addSlotBtn.y = slotY + garageSlots * slotGap + 40;
addSlotBtn.setText("Add Slot (5💎)");
addSlotBtn.setColor(0x00cccc);
addSlotBtn.onClick = function () {
if (crystals >= 5) {
crystals -= 5;
garageSlots += 1;
savePlayerData();
showGarage();
} else {
showInfo("Not enough crystals!", 1200);
}
};
LK.gui.center.addChild(addSlotBtn);
garageUI.push(addSlotBtn);
}
// Back button
var backBtn = new UIButton();
backBtn.x = 2048 / 2;
backBtn.y = 2600;
backBtn.setText("Back");
backBtn.onClick = function () {
showMainMenu();
};
LK.gui.bottom.addChild(backBtn);
garageUI.push(backBtn);
updateCurrencyText();
}
// --- Shop ---
function showShop(carIdx) {
state = GAME_STATE.SHOP;
clearMainMenu();
clearUI(garageUI);
clearUI(raceUI);
clearUI(shopUI);
// Title
var title = new Text2('Shop', {
size: 100,
fill: 0xFFD700
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 120;
LK.gui.top.addChild(title);
shopUI.push(title);
// If carIdx is set, show upgrades for that car
var shopY = 400;
var shopGap = 220;
var shopParts = [{
name: "Engine +20HP",
stat: "horsepower",
cost: 1000,
part: "engine",
value: 20
}, {
name: "Turbo +30HP",
stat: "turbo",
cost: 1500,
part: "turbo",
value: 1
}, {
name: "Intake +10HP",
stat: "intake",
cost: 800,
part: "intake",
value: 1
}, {
name: "Tires +Grip",
stat: "tires",
cost: 600,
part: "tires",
value: 1
}, {
name: "Spray Paint",
stat: "paint",
cost: 2,
part: "paint",
value: 0,
isCrystal: true
}];
for (var i = 0; i < shopParts.length; i++) {
(function (part, idx) {
var partBtn = new ShopPart();
partBtn.x = 2048 / 2;
partBtn.y = shopY + idx * shopGap;
partBtn.setText(part.name + " - " + (part.isCrystal ? part.cost + "💎" : "$" + part.cost));
partBtn.onBuy = function () {
if (carIdx === undefined) {
showInfo("Select a car in Garage to upgrade!", 1200);
return;
}
var car = garage[carIdx];
if (!car) return;
if (part.isCrystal) {
if (crystals >= part.cost) {
crystals -= part.cost;
// Random paint
var newColor = 0x100000 + Math.floor(Math.random() * 0xEFFFFF);
car.paint = newColor;
car.stats.paint = newColor;
savePlayerData();
showInfo("Paint applied!", 1000);
showShop(carIdx);
} else {
showInfo("Not enough crystals!", 1200);
}
} else {
if (cash >= part.cost) {
cash -= part.cost;
if (part.stat === "horsepower") {
car.stats.horsepower += part.value;
car.parts.engine += 1;
} else if (part.stat === "turbo") {
car.stats.horsepower += 30;
car.parts.turbo += 1;
} else if (part.stat === "intake") {
car.stats.horsepower += 10;
car.parts.intake += 1;
} else if (part.stat === "tires") {
car.stats.grip += 0.2;
car.parts.tires += 1;
}
savePlayerData();
showInfo("Upgrade applied!", 1000);
showShop(carIdx);
} else {
showInfo("Not enough cash!", 1200);
}
}
};
LK.gui.center.addChild(partBtn);
shopUI.push(partBtn);
})(shopParts[i], i);
}
// Back button
var backBtn = new UIButton();
backBtn.x = 2048 / 2;
backBtn.y = 2600;
backBtn.setText("Back");
backBtn.onClick = function () {
showGarage();
};
LK.gui.bottom.addChild(backBtn);
shopUI.push(backBtn);
updateCurrencyText();
}
// --- Race ---
function startRaceWithCar(carIdx) {
state = GAME_STATE.RACE;
clearMainMenu();
clearUI(garageUI);
clearUI(shopUI);
clearUI(raceUI);
// Set up race track
var trackY = 1800;
raceTrack = LK.getAsset('track', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: trackY
});
game.addChild(raceTrack);
raceUI.push(raceTrack);
// Start line
raceStartLine = LK.getAsset('startLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 400,
y: trackY
});
game.addChild(raceStartLine);
raceUI.push(raceStartLine);
// Finish line
raceFinishLine = LK.getAsset('finishLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1800,
y: trackY
});
game.addChild(raceFinishLine);
raceUI.push(raceFinishLine);
// Player car
raceCar = new Car();
raceCar.setData(garage[carIdx]);
raceCar.x = 400;
raceCar.y = trackY - 80;
raceCar.scaleX = 0.8;
raceCar.scaleY = 0.8;
game.addChild(raceCar);
raceUI.push(raceCar);
// Opponent car (random stats)
raceOpponent = new Car();
var oppStats = {
stats: {
horsepower: 90 + Math.floor(Math.random() * 60),
weight: 1200,
grip: 1 + Math.random() * 0.5,
turbo: Math.floor(Math.random() * 2),
intake: Math.floor(Math.random() * 2),
tires: 1 + Math.floor(Math.random() * 2),
paint: 0x880000 + Math.floor(Math.random() * 0x77ffff)
},
parts: {
engine: 1 + Math.floor(Math.random() * 2),
turbo: Math.floor(Math.random() * 2),
intake: Math.floor(Math.random() * 2),
tires: 1 + Math.floor(Math.random() * 2)
},
paint: 0x880000 + Math.floor(Math.random() * 0x77ffff)
};
raceOpponent.setData(oppStats);
raceOpponent.x = 400;
raceOpponent.y = trackY + 80;
raceOpponent.scaleX = 0.8;
raceOpponent.scaleY = 0.8;
game.addChild(raceOpponent);
raceUI.push(raceOpponent);
// Race state
raceStarted = false;
raceEnded = false;
raceTimer = 0;
// Countdown text
var countdownText = new Text2('3', {
size: 200,
fill: "#fff"
});
countdownText.anchor.set(0.5, 0.5);
countdownText.x = 2048 / 2;
countdownText.y = 600;
LK.gui.center.addChild(countdownText);
raceUI.push(countdownText);
// Start countdown
var countdown = 3;
var countdownInterval = LK.setInterval(function () {
countdown -= 1;
if (countdown > 0) {
countdownText.setText(countdown + '');
} else if (countdown === 0) {
countdownText.setText("GO!");
// Start race
raceStarted = true;
// Calculate speed per tick (distance: 1400px, 500m)
var pxPerMeter = 1400 / raceDistance;
var carSpeed = raceCar.stats.horsepower / 100 * pxPerMeter / 60; // px per tick
var oppSpeed = raceOpponent.stats.horsepower / 100 * pxPerMeter / 60;
raceCar.startRace(carSpeed / 1400); // progress per tick
raceOpponent.startRace(oppSpeed / 1400);
} else {
LK.clearInterval(countdownInterval);
countdownText.visible = false;
}
}, 800);
// Race timer text
var timerText = new Text2('0.00s', {
size: 80,
fill: "#fff"
});
timerText.anchor.set(0.5, 0);
timerText.x = 2048 / 2;
timerText.y = 100;
LK.gui.top.addChild(timerText);
raceUI.push(timerText);
// Back button (disabled during race)
var backBtn = new UIButton();
backBtn.x = 2048 / 2;
backBtn.y = 2600;
backBtn.setText("Back");
backBtn.onClick = function () {
endRace();
showGarage();
};
LK.gui.bottom.addChild(backBtn);
raceUI.push(backBtn);
// Result text
raceResultText = new Text2('', {
size: 120,
fill: 0xFFD700
});
raceResultText.anchor.set(0.5, 0.5);
raceResultText.x = 2048 / 2;
raceResultText.y = 900;
LK.gui.center.addChild(raceResultText);
raceResultText.visible = false;
raceUI.push(raceResultText);
updateCurrencyText();
// Race update
game.update = function () {
if (state !== GAME_STATE.RACE) return;
if (raceStarted && !raceEnded) {
raceTimer += 1 / 60;
timerText.setText(raceTimer.toFixed(2) + "s");
// Move cars
if (raceCar.isRacing) {
raceCar.x = 400 + raceCar.raceProgress * 1400;
if (raceCar.raceProgress >= 1) {
raceCar.isRacing = false;
}
}
if (raceOpponent.isRacing) {
raceOpponent.x = 400 + raceOpponent.raceProgress * 1400;
if (raceOpponent.raceProgress >= 1) {
raceOpponent.isRacing = false;
}
}
// Check finish
if (!raceEnded && (raceCar.raceProgress >= 1 || raceOpponent.raceProgress >= 1)) {
raceEnded = true;
var playerWin = raceCar.raceProgress >= 1 && raceCar.raceProgress >= raceOpponent.raceProgress;
var reward = playerWin ? 1000 : 200;
var rewardCrystals = playerWin ? 1 : 0;
if (playerWin) {
raceResultText.setText("You Win!\n+$" + reward + (rewardCrystals ? " +1💎" : ""));
} else {
raceResultText.setText("You Lose!\n+$" + reward);
}
raceResultText.visible = true;
cash += reward;
crystals += rewardCrystals;
savePlayerData();
updateCurrencyText();
LK.setTimeout(function () {
endRace();
showGarage();
}, 2200);
}
}
};
}
function endRace() {
clearUI(raceUI);
raceCar = null;
raceOpponent = null;
raceTrack = null;
raceStartLine = null;
raceFinishLine = null;
raceResultText = null;
game.update = function () {};
}
// --- Start Game ---
showMainMenu(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
garage: [],
crystals: 10,
cash: 5000,
garageSlots: 2
});
/****
* Classes
****/
// Car class
var Car = Container.expand(function () {
var self = Container.call(this);
// Car stats
self.stats = {
horsepower: 100,
weight: 1200,
grip: 1,
turbo: 0,
intake: 0,
tires: 1,
paint: 0x3333cc
};
// Car parts (for upgrades)
self.parts = {
engine: 1,
turbo: 0,
intake: 0,
tires: 1
};
// Cosmetic
self.paint = 0x3333cc;
// Attach car body
var body = self.attachAsset('carBody', {
anchorX: 0.5,
anchorY: 0.5,
tint: self.paint
});
// Attach wheels
var wheel1 = self.attachAsset('carWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: -120,
y: 50
});
var wheel2 = self.attachAsset('carWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: 50
});
// For race animation
self.raceProgress = 0; // 0 to 1
self.isRacing = false;
self.raceSpeed = 0;
// Set car data
self.setData = function (data) {
if (!data) return;
self.stats = data.stats;
self.parts = data.parts;
self.paint = data.paint || 0x3333cc;
body.tint = self.paint;
};
// Get car data for storage
self.getData = function () {
return {
stats: self.stats,
parts: self.parts,
paint: self.paint
};
};
// Start race
self.startRace = function (speed) {
self.isRacing = true;
self.raceProgress = 0;
self.raceSpeed = speed;
};
// Update per tick
self.update = function () {
if (self.isRacing) {
self.raceProgress += self.raceSpeed;
if (self.raceProgress > 1) self.raceProgress = 1;
}
};
return self;
});
// Shop part class
var ShopPart = Container.expand(function () {
var self = Container.call(this);
var icon = self.attachAsset('partIcon', {
anchorX: 0.5,
anchorY: 0.5
});
self.textObj = new Text2('', {
size: 32,
fill: "#222"
});
self.textObj.anchor.set(0.5, 0.5);
self.textObj.y = 60;
self.addChild(self.textObj);
self.setText = function (txt) {
self.textObj.setText(txt);
};
self.down = function (x, y, obj) {
if (self.onBuy) self.onBuy();
};
return self;
});
// Button class
var UIButton = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
self.textObj = new Text2('', {
size: 60,
fill: "#fff"
});
self.textObj.anchor.set(0.5, 0.5);
self.addChild(self.textObj);
self.setText = function (txt) {
self.textObj.setText(txt);
};
self.setColor = function (color) {
bg.tint = color;
};
self.down = function (x, y, obj) {
if (self.onClick) self.onClick();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Shop part icon
// Button
// Garage slot background
// Finish line
// Start line
// Race track
// Car wheel
// Car body (default)
// --- Global State ---
var GAME_STATE = {
MAIN_MENU: 0,
GARAGE: 1,
RACE: 2,
SHOP: 3
};
var state = GAME_STATE.MAIN_MENU;
// Player data
var garage = storage.garage && storage.garage.length ? storage.garage : [];
var crystals = typeof storage.crystals === 'number' ? storage.crystals : 10;
var cash = typeof storage.cash === 'number' ? storage.cash : 5000;
var garageSlots = typeof storage.garageSlots === 'number' ? storage.garageSlots : 2;
// UI elements
var mainMenuUI = [];
var garageUI = [];
var raceUI = [];
var shopUI = [];
var infoText = null;
var currencyText = null;
// Race state
var raceCar = null;
var raceOpponent = null;
var raceTrack = null;
var raceStartLine = null;
var raceFinishLine = null;
var raceDistance = 500; // meters
var raceStarted = false;
var raceEnded = false;
var raceTimer = 0;
var raceResultText = null;
// --- Utility Functions ---
function savePlayerData() {
storage.garage = garage;
storage.crystals = crystals;
storage.cash = cash;
storage.garageSlots = garageSlots;
}
function clearUI(uiArr) {
for (var i = 0; i < uiArr.length; i++) {
if (uiArr[i].parent) uiArr[i].parent.removeChild(uiArr[i]);
}
uiArr.length = 0;
}
function showInfo(msg, duration) {
if (!infoText) {
infoText = new Text2('', {
size: 60,
fill: "#fff"
});
infoText.anchor.set(0.5, 0);
LK.gui.top.addChild(infoText);
}
infoText.setText(msg);
infoText.visible = true;
if (duration) {
LK.setTimeout(function () {
if (infoText) infoText.visible = false;
}, duration);
}
}
function updateCurrencyText() {
if (!currencyText) {
currencyText = new Text2('', {
size: 48,
fill: "#fff"
});
currencyText.anchor.set(1, 0);
currencyText.x = LK.gui.width - 40;
currencyText.y = 10;
LK.gui.top.addChild(currencyText);
}
currencyText.setText("💎" + crystals + " $" + cash);
}
// --- Main Menu ---
function showMainMenu() {
state = GAME_STATE.MAIN_MENU;
clearUI(garageUI);
clearUI(raceUI);
clearUI(shopUI);
// Title
var title = new Text2('Drag Race Legends', {
size: 120,
fill: 0xFFD700
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 180;
LK.gui.top.addChild(title);
mainMenuUI.push(title);
// Play button
var playBtn = new UIButton();
playBtn.x = 2048 / 2;
playBtn.y = 600;
playBtn.setText("Race");
playBtn.onClick = function () {
showGarage();
};
LK.gui.center.addChild(playBtn);
mainMenuUI.push(playBtn);
// Garage button
var garageBtn = new UIButton();
garageBtn.x = 2048 / 2;
garageBtn.y = 800;
garageBtn.setText("Garage");
garageBtn.onClick = function () {
showGarage();
};
LK.gui.center.addChild(garageBtn);
mainMenuUI.push(garageBtn);
// Shop button
var shopBtn = new UIButton();
shopBtn.x = 2048 / 2;
shopBtn.y = 1000;
shopBtn.setText("Shop");
shopBtn.onClick = function () {
showShop();
};
LK.gui.center.addChild(shopBtn);
mainMenuUI.push(shopBtn);
updateCurrencyText();
}
function clearMainMenu() {
clearUI(mainMenuUI);
}
// --- Garage ---
function showGarage() {
state = GAME_STATE.GARAGE;
clearMainMenu();
clearUI(raceUI);
clearUI(shopUI);
// Title
var title = new Text2('Garage', {
size: 100,
fill: 0xFFD700
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 120;
LK.gui.top.addChild(title);
garageUI.push(title);
// Show car slots
var slotY = 350;
var slotGap = 200;
for (var i = 0; i < garageSlots; i++) {
var slotBg = LK.getAsset('garageSlot', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: slotY + i * slotGap
});
LK.gui.center.addChild(slotBg);
garageUI.push(slotBg);
if (garage[i]) {
// Show car
var car = new Car();
car.setData(garage[i]);
car.x = 2048 / 2;
car.y = slotY + i * slotGap;
car.scaleX = 0.7;
car.scaleY = 0.7;
LK.gui.center.addChild(car);
garageUI.push(car);
// Show stats
var statTxt = new Text2("HP: " + car.stats.horsepower + " Turbo: " + car.parts.turbo + " Tires: " + car.parts.tires, {
size: 36,
fill: "#fff"
});
statTxt.anchor.set(0.5, 0);
statTxt.x = 2048 / 2;
statTxt.y = slotY + i * slotGap + 80;
LK.gui.center.addChild(statTxt);
garageUI.push(statTxt);
// Select for race button
(function (carIdx) {
var selectBtn = new UIButton();
selectBtn.x = 2048 / 2 + 300;
selectBtn.y = slotY + i * slotGap;
selectBtn.setText("Race");
selectBtn.setColor(0x00cc44);
selectBtn.onClick = function () {
startRaceWithCar(carIdx);
};
LK.gui.center.addChild(selectBtn);
garageUI.push(selectBtn);
})(i);
// Upgrade button
(function (carIdx) {
var upgradeBtn = new UIButton();
upgradeBtn.x = 2048 / 2 - 300;
upgradeBtn.y = slotY + i * slotGap;
upgradeBtn.setText("Upgrade");
upgradeBtn.setColor(0x0080cc);
upgradeBtn.onClick = function () {
showShop(carIdx);
};
LK.gui.center.addChild(upgradeBtn);
garageUI.push(upgradeBtn);
})(i);
} else {
// Empty slot
var addBtn = new UIButton();
addBtn.x = 2048 / 2;
addBtn.y = slotY + i * slotGap;
addBtn.setText("Buy Car ($2000)");
addBtn.setColor(0xcccc00);
addBtn.onClick = function () {
if (cash >= 2000) {
cash -= 2000;
var newCar = {
stats: {
horsepower: 100,
weight: 1200,
grip: 1,
turbo: 0,
intake: 0,
tires: 1,
paint: 0x3333cc
},
parts: {
engine: 1,
turbo: 0,
intake: 0,
tires: 1
},
paint: 0x3333cc
};
garage.push(newCar);
savePlayerData();
showGarage();
} else {
showInfo("Not enough cash!", 1200);
}
};
LK.gui.center.addChild(addBtn);
garageUI.push(addBtn);
}
}
// Add slot button (if < 10)
if (garageSlots < 10) {
var addSlotBtn = new UIButton();
addSlotBtn.x = 2048 / 2;
addSlotBtn.y = slotY + garageSlots * slotGap + 40;
addSlotBtn.setText("Add Slot (5💎)");
addSlotBtn.setColor(0x00cccc);
addSlotBtn.onClick = function () {
if (crystals >= 5) {
crystals -= 5;
garageSlots += 1;
savePlayerData();
showGarage();
} else {
showInfo("Not enough crystals!", 1200);
}
};
LK.gui.center.addChild(addSlotBtn);
garageUI.push(addSlotBtn);
}
// Back button
var backBtn = new UIButton();
backBtn.x = 2048 / 2;
backBtn.y = 2600;
backBtn.setText("Back");
backBtn.onClick = function () {
showMainMenu();
};
LK.gui.bottom.addChild(backBtn);
garageUI.push(backBtn);
updateCurrencyText();
}
// --- Shop ---
function showShop(carIdx) {
state = GAME_STATE.SHOP;
clearMainMenu();
clearUI(garageUI);
clearUI(raceUI);
clearUI(shopUI);
// Title
var title = new Text2('Shop', {
size: 100,
fill: 0xFFD700
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 120;
LK.gui.top.addChild(title);
shopUI.push(title);
// If carIdx is set, show upgrades for that car
var shopY = 400;
var shopGap = 220;
var shopParts = [{
name: "Engine +20HP",
stat: "horsepower",
cost: 1000,
part: "engine",
value: 20
}, {
name: "Turbo +30HP",
stat: "turbo",
cost: 1500,
part: "turbo",
value: 1
}, {
name: "Intake +10HP",
stat: "intake",
cost: 800,
part: "intake",
value: 1
}, {
name: "Tires +Grip",
stat: "tires",
cost: 600,
part: "tires",
value: 1
}, {
name: "Spray Paint",
stat: "paint",
cost: 2,
part: "paint",
value: 0,
isCrystal: true
}];
for (var i = 0; i < shopParts.length; i++) {
(function (part, idx) {
var partBtn = new ShopPart();
partBtn.x = 2048 / 2;
partBtn.y = shopY + idx * shopGap;
partBtn.setText(part.name + " - " + (part.isCrystal ? part.cost + "💎" : "$" + part.cost));
partBtn.onBuy = function () {
if (carIdx === undefined) {
showInfo("Select a car in Garage to upgrade!", 1200);
return;
}
var car = garage[carIdx];
if (!car) return;
if (part.isCrystal) {
if (crystals >= part.cost) {
crystals -= part.cost;
// Random paint
var newColor = 0x100000 + Math.floor(Math.random() * 0xEFFFFF);
car.paint = newColor;
car.stats.paint = newColor;
savePlayerData();
showInfo("Paint applied!", 1000);
showShop(carIdx);
} else {
showInfo("Not enough crystals!", 1200);
}
} else {
if (cash >= part.cost) {
cash -= part.cost;
if (part.stat === "horsepower") {
car.stats.horsepower += part.value;
car.parts.engine += 1;
} else if (part.stat === "turbo") {
car.stats.horsepower += 30;
car.parts.turbo += 1;
} else if (part.stat === "intake") {
car.stats.horsepower += 10;
car.parts.intake += 1;
} else if (part.stat === "tires") {
car.stats.grip += 0.2;
car.parts.tires += 1;
}
savePlayerData();
showInfo("Upgrade applied!", 1000);
showShop(carIdx);
} else {
showInfo("Not enough cash!", 1200);
}
}
};
LK.gui.center.addChild(partBtn);
shopUI.push(partBtn);
})(shopParts[i], i);
}
// Back button
var backBtn = new UIButton();
backBtn.x = 2048 / 2;
backBtn.y = 2600;
backBtn.setText("Back");
backBtn.onClick = function () {
showGarage();
};
LK.gui.bottom.addChild(backBtn);
shopUI.push(backBtn);
updateCurrencyText();
}
// --- Race ---
function startRaceWithCar(carIdx) {
state = GAME_STATE.RACE;
clearMainMenu();
clearUI(garageUI);
clearUI(shopUI);
clearUI(raceUI);
// Set up race track
var trackY = 1800;
raceTrack = LK.getAsset('track', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: trackY
});
game.addChild(raceTrack);
raceUI.push(raceTrack);
// Start line
raceStartLine = LK.getAsset('startLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 400,
y: trackY
});
game.addChild(raceStartLine);
raceUI.push(raceStartLine);
// Finish line
raceFinishLine = LK.getAsset('finishLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 1800,
y: trackY
});
game.addChild(raceFinishLine);
raceUI.push(raceFinishLine);
// Player car
raceCar = new Car();
raceCar.setData(garage[carIdx]);
raceCar.x = 400;
raceCar.y = trackY - 80;
raceCar.scaleX = 0.8;
raceCar.scaleY = 0.8;
game.addChild(raceCar);
raceUI.push(raceCar);
// Opponent car (random stats)
raceOpponent = new Car();
var oppStats = {
stats: {
horsepower: 90 + Math.floor(Math.random() * 60),
weight: 1200,
grip: 1 + Math.random() * 0.5,
turbo: Math.floor(Math.random() * 2),
intake: Math.floor(Math.random() * 2),
tires: 1 + Math.floor(Math.random() * 2),
paint: 0x880000 + Math.floor(Math.random() * 0x77ffff)
},
parts: {
engine: 1 + Math.floor(Math.random() * 2),
turbo: Math.floor(Math.random() * 2),
intake: Math.floor(Math.random() * 2),
tires: 1 + Math.floor(Math.random() * 2)
},
paint: 0x880000 + Math.floor(Math.random() * 0x77ffff)
};
raceOpponent.setData(oppStats);
raceOpponent.x = 400;
raceOpponent.y = trackY + 80;
raceOpponent.scaleX = 0.8;
raceOpponent.scaleY = 0.8;
game.addChild(raceOpponent);
raceUI.push(raceOpponent);
// Race state
raceStarted = false;
raceEnded = false;
raceTimer = 0;
// Countdown text
var countdownText = new Text2('3', {
size: 200,
fill: "#fff"
});
countdownText.anchor.set(0.5, 0.5);
countdownText.x = 2048 / 2;
countdownText.y = 600;
LK.gui.center.addChild(countdownText);
raceUI.push(countdownText);
// Start countdown
var countdown = 3;
var countdownInterval = LK.setInterval(function () {
countdown -= 1;
if (countdown > 0) {
countdownText.setText(countdown + '');
} else if (countdown === 0) {
countdownText.setText("GO!");
// Start race
raceStarted = true;
// Calculate speed per tick (distance: 1400px, 500m)
var pxPerMeter = 1400 / raceDistance;
var carSpeed = raceCar.stats.horsepower / 100 * pxPerMeter / 60; // px per tick
var oppSpeed = raceOpponent.stats.horsepower / 100 * pxPerMeter / 60;
raceCar.startRace(carSpeed / 1400); // progress per tick
raceOpponent.startRace(oppSpeed / 1400);
} else {
LK.clearInterval(countdownInterval);
countdownText.visible = false;
}
}, 800);
// Race timer text
var timerText = new Text2('0.00s', {
size: 80,
fill: "#fff"
});
timerText.anchor.set(0.5, 0);
timerText.x = 2048 / 2;
timerText.y = 100;
LK.gui.top.addChild(timerText);
raceUI.push(timerText);
// Back button (disabled during race)
var backBtn = new UIButton();
backBtn.x = 2048 / 2;
backBtn.y = 2600;
backBtn.setText("Back");
backBtn.onClick = function () {
endRace();
showGarage();
};
LK.gui.bottom.addChild(backBtn);
raceUI.push(backBtn);
// Result text
raceResultText = new Text2('', {
size: 120,
fill: 0xFFD700
});
raceResultText.anchor.set(0.5, 0.5);
raceResultText.x = 2048 / 2;
raceResultText.y = 900;
LK.gui.center.addChild(raceResultText);
raceResultText.visible = false;
raceUI.push(raceResultText);
updateCurrencyText();
// Race update
game.update = function () {
if (state !== GAME_STATE.RACE) return;
if (raceStarted && !raceEnded) {
raceTimer += 1 / 60;
timerText.setText(raceTimer.toFixed(2) + "s");
// Move cars
if (raceCar.isRacing) {
raceCar.x = 400 + raceCar.raceProgress * 1400;
if (raceCar.raceProgress >= 1) {
raceCar.isRacing = false;
}
}
if (raceOpponent.isRacing) {
raceOpponent.x = 400 + raceOpponent.raceProgress * 1400;
if (raceOpponent.raceProgress >= 1) {
raceOpponent.isRacing = false;
}
}
// Check finish
if (!raceEnded && (raceCar.raceProgress >= 1 || raceOpponent.raceProgress >= 1)) {
raceEnded = true;
var playerWin = raceCar.raceProgress >= 1 && raceCar.raceProgress >= raceOpponent.raceProgress;
var reward = playerWin ? 1000 : 200;
var rewardCrystals = playerWin ? 1 : 0;
if (playerWin) {
raceResultText.setText("You Win!\n+$" + reward + (rewardCrystals ? " +1💎" : ""));
} else {
raceResultText.setText("You Lose!\n+$" + reward);
}
raceResultText.visible = true;
cash += reward;
crystals += rewardCrystals;
savePlayerData();
updateCurrencyText();
LK.setTimeout(function () {
endRace();
showGarage();
}, 2200);
}
}
};
}
function endRace() {
clearUI(raceUI);
raceCar = null;
raceOpponent = null;
raceTrack = null;
raceStartLine = null;
raceFinishLine = null;
raceResultText = null;
game.update = function () {};
}
// --- Start Game ---
showMainMenu();