/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Car = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.maxSpeed = 5;
self.acceleration = 0.1;
self.deceleration = 0.1;
self.turnSpeed = 0.05;
self.drifting = false;
self.driftPower = 0;
self.maxDriftPower = 100;
self.driftDirection = 0;
self.driftBoost = 0;
self.isDead = false;
// Particle system for drift effect
self.particles = [];
self.particleTimer = 0;
self.startDrift = function (direction) {
if (!self.drifting) {
self.drifting = true;
self.driftDirection = direction;
LK.getSound('drift').play();
}
};
self.stopDrift = function () {
if (self.drifting) {
self.drifting = false;
// Apply drift boost based on accumulated drift power
self.driftBoost = self.driftPower / 20;
// Reset drift power
self.driftPower = 0;
}
};
self.createDriftParticle = function () {
var particle = LK.getAsset('driftParticle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
// Position behind the car
var angle = self.rotation - Math.PI;
var distance = 30;
particle.x = self.x + Math.cos(angle) * distance;
particle.y = self.y + Math.sin(angle) * distance;
// Store particle data
particle.lifetime = 30; // frames
particle.initialAlpha = 0.7;
return particle;
};
self.update = function () {
if (self.isDead) {
return;
}
// Update speed
if (self.driftBoost > 0) {
self.speed = Math.min(self.speed + self.driftBoost, self.maxSpeed * 1.5);
self.driftBoost -= 0.1;
} else {
self.speed = Math.min(self.speed + self.acceleration, self.maxSpeed);
}
// Apply deceleration when drifting
if (self.drifting) {
self.speed *= 0.98;
// Accumulate drift power
self.driftPower = Math.min(self.driftPower + 1, self.maxDriftPower);
// Create drift particles
self.particleTimer++;
if (self.particleTimer >= 3) {
// Every 3 frames
self.particleTimer = 0;
game.addChild(self.createDriftParticle());
}
}
// Update position based on speed and rotation
self.x += Math.cos(self.rotation) * self.speed;
self.y += Math.sin(self.rotation) * self.speed;
// Apply drift effect to rotation
if (self.drifting) {
self.rotation += self.turnSpeed * 1.5 * self.driftDirection;
}
// Keep car within game bounds
self.x = Math.max(100, Math.min(self.x, 2048 - 100));
self.y = Math.max(100, Math.min(self.y, 2732 - 100));
};
self.crash = function () {
if (!self.isDead) {
self.isDead = true;
LK.getSound('crash').play();
// Visual effect for crash
tween(carGraphics, {
alpha: 0.5,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.showGameOver();
}
});
}
};
return self;
});
var Monster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3; // Reduced speed to slow down monsters
self.target = null;
self.active = true;
self.setTarget = function (target) {
self.target = target;
};
self.update = function () {
if (!self.active || !self.target) {
return;
}
// Calculate direction to target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move towards target
if (distance > 10) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
// Rotate towards target
self.rotation = Math.atan2(dy, dx);
}
// Check if caught the target
if (distance < 80 && self.target && !self.target.isDead) {
self.target.crash();
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'speed'; // Default type
self.active = true;
self.setType = function (type) {
self.type = type;
// Set color based on type
if (type === 'speed') {
powerupGraphics.tint = 0x00ffff;
} else if (type === 'invincibility') {
powerupGraphics.tint = 0xff00ff;
} else if (type === 'slowMonsters') {
powerupGraphics.tint = 0xffff00;
}
};
// Animate the power-up
tween(powerupGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear
});
self.update = function () {
if (!self.active) {
return;
}
// Simple bobbing animation
powerupGraphics.y = Math.sin(LK.ticks / 10) * 5;
};
self.collect = function () {
if (self.active) {
self.active = false;
LK.getSound('powerup').play();
// Visual effect when collected
tween(powerupGraphics, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return self.type;
}
return null;
};
return self;
});
var Track = Container.expand(function () {
var self = Container.call(this);
// Track background
var trackBg = self.attachAsset('trackBorder', {
anchorX: 0.5,
anchorY: 0.5
});
// Main track
var trackMain = self.attachAsset('track', {
anchorX: 0.5,
anchorY: 0.5
});
self.checkpoints = [];
self.powerupSpots = [];
self.createCheckpoint = function (x, y, rotation) {
var checkpoint = LK.getAsset('trackCheckpoint', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5,
x: x,
y: y,
rotation: rotation
});
self.checkpoints.push(checkpoint);
self.addChild(checkpoint);
return checkpoint;
};
self.getRandomPowerupPosition = function () {
if (self.powerupSpots.length === 0) {
return {
x: 0,
y: 0
};
}
var spot = self.powerupSpots[Math.floor(Math.random() * self.powerupSpots.length)];
return {
x: spot.x,
y: spot.y
};
};
self.setupTrack = function (level) {
// Clear existing checkpoints
for (var i = 0; i < self.checkpoints.length; i++) {
self.checkpoints[i].destroy();
}
self.checkpoints = [];
self.powerupSpots = [];
// Create track layout based on level
if (level === 1) {
// Simple oval track
self.createCheckpoint(0, -500, 0);
self.createCheckpoint(500, 0, Math.PI / 2);
self.createCheckpoint(0, 500, Math.PI);
self.createCheckpoint(-500, 0, -Math.PI / 2);
// Add powerup spots
self.powerupSpots = [{
x: 0,
y: -300
}, {
x: 300,
y: 0
}, {
x: 0,
y: 300
}, {
x: -300,
y: 0
}];
} else if (level === 2) {
// Figure-8 track
self.createCheckpoint(0, -500, 0);
self.createCheckpoint(500, -250, Math.PI / 4);
self.createCheckpoint(250, 0, Math.PI / 2);
self.createCheckpoint(500, 250, 3 * Math.PI / 4);
self.createCheckpoint(0, 500, Math.PI);
self.createCheckpoint(-500, 250, -3 * Math.PI / 4);
self.createCheckpoint(-250, 0, -Math.PI / 2);
self.createCheckpoint(-500, -250, -Math.PI / 4);
// Add powerup spots
self.powerupSpots = [{
x: 0,
y: -300
}, {
x: 300,
y: -150
}, {
x: 150,
y: 0
}, {
x: 300,
y: 150
}, {
x: 0,
y: 300
}, {
x: -300,
y: 150
}, {
x: -150,
y: 0
}, {
x: -300,
y: -150
}];
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x225522
});
/****
* Game Code
****/
// Game state variables
var car;
var monsters = [];
var powerups = [];
var track;
var gameStarted = false;
var score = 0;
var level = 1;
var gameTime = 0;
var powerupTimer = 0;
var spawnMonsterTimer = 0;
var gameActive = true;
var invincibilityTimer = 0;
var slowMonstersTimer = 0;
// UI elements
var scoreTxt = new Text2("SCORE: 0", {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var levelTxt = new Text2("LEVEL: 1", {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
levelTxt.y = 70;
LK.gui.top.addChild(levelTxt);
var timeTxt = new Text2("TIME: 0", {
size: 60,
fill: 0xFFFFFF
});
timeTxt.anchor.set(0, 0);
timeTxt.x = 20;
timeTxt.y = 20;
LK.gui.topRight.addChild(timeTxt);
var statusTxt = new Text2("", {
size: 50,
fill: 0xFFFF00
});
statusTxt.anchor.set(0.5, 0);
statusTxt.y = 140;
LK.gui.top.addChild(statusTxt);
// Initialize track
track = new Track();
track.x = 2048 / 2;
track.y = 2732 / 2;
game.addChild(track);
track.setupTrack(level);
// Initialize car
car = new Car();
car.x = 2048 / 2;
car.y = 2732 / 2 + 400;
car.rotation = -Math.PI / 2;
game.addChild(car);
// Game initialization
function startGame() {
gameStarted = true;
gameActive = true;
score = 0;
gameTime = 0;
level = 1;
// Reset car
car.speed = 0;
car.drifting = false;
car.driftPower = 0;
car.driftBoost = 0;
car.isDead = false;
car.x = 2048 / 2;
car.y = 2732 / 2 + 400;
car.rotation = -Math.PI / 2;
// Clear monsters
for (var i = 0; i < monsters.length; i++) {
monsters[i].destroy();
}
monsters = [];
// Clear powerups
for (var i = 0; i < powerups.length; i++) {
powerups[i].destroy();
}
powerups = [];
// Start timers
powerupTimer = 180; // 3 seconds (60fps * 3)
spawnMonsterTimer = 300; // 5 seconds
// Reset track
track.setupTrack(level);
// Reset status effects
invincibilityTimer = 0;
slowMonstersTimer = 0;
// Update UI
updateScore(0);
updateLevel(1);
// Play music
LK.playMusic('raceMusic');
}
// Update score display
function updateScore(newScore) {
score = newScore;
scoreTxt.setText("SCORE: " + score);
// Check for level up
if (score >= level * 500) {
levelUp();
}
}
// Update level display
function updateLevel(newLevel) {
level = newLevel;
levelTxt.setText("LEVEL: " + level);
// Update track for new level
track.setupTrack(level % 2 === 0 ? 2 : 1);
}
// Level up
function levelUp() {
updateLevel(level + 1);
// Visual effect
LK.effects.flashScreen(0x00ff00, 500);
statusTxt.setText("LEVEL UP!");
// Clear status text after 2 seconds
LK.setTimeout(function () {
statusTxt.setText("");
}, 2000);
}
// Spawn a monster
function spawnMonster() {
var monster = new Monster();
// Position monster away from player
var angle = Math.random() * Math.PI * 2;
var distance = 800;
monster.x = car.x + Math.cos(angle) * distance;
monster.y = car.y + Math.sin(angle) * distance;
// Keep monster within game bounds
monster.x = Math.max(100, Math.min(monster.x, 2048 - 100));
monster.y = Math.max(100, Math.min(monster.y, 2732 - 100));
// Set target and speed based on level
monster.setTarget(car);
monster.speed = 3 + level * 0.3;
game.addChild(monster);
monsters.push(monster);
}
// Spawn a powerup
function spawnPowerup() {
var powerup = new PowerUp();
// Set random position from track's powerup spots
var pos = track.getRandomPowerupPosition();
powerup.x = track.x + pos.x;
powerup.y = track.y + pos.y;
// Set random type
var types = ['speed', 'invincibility', 'slowMonsters'];
var type = types[Math.floor(Math.random() * types.length)];
powerup.setType(type);
game.addChild(powerup);
powerups.push(powerup);
}
// Apply powerup effect
function applyPowerup(type) {
if (type === 'speed') {
car.speed += 5;
car.maxSpeed += 2;
// Reset max speed after 5 seconds
LK.setTimeout(function () {
car.maxSpeed -= 2;
}, 5000);
statusTxt.setText("SPEED BOOST!");
} else if (type === 'invincibility') {
invincibilityTimer = 300; // 5 seconds
car.alpha = 0.7;
statusTxt.setText("INVINCIBLE!");
} else if (type === 'slowMonsters') {
slowMonstersTimer = 300; // 5 seconds
statusTxt.setText("MONSTERS SLOWED!");
}
// Clear status text after 2 seconds
LK.setTimeout(function () {
statusTxt.setText("");
}, 2000);
}
// Handle drift controls
var isDrifting = false;
var driftDirection = 0;
function startDrifting(direction) {
if (!isDrifting) {
isDrifting = true;
driftDirection = direction;
car.startDrift(direction);
}
}
function stopDrifting() {
if (isDrifting) {
isDrifting = false;
car.stopDrift();
}
}
// Handle touch input
var touchStartX = 0;
var touchStartY = 0;
var touchMoved = false;
// Handle touch start
game.down = function (x, y, obj) {
if (!gameStarted) {
startGame();
return;
}
if (!isDrifting) {
startDrifting(1); // Start drifting to the right by default
} else {
stopDrifting(); // Stop drifting if already drifting
}
};
// Handle touch move
game.move = function (x, y, obj) {
if (!gameStarted || !gameActive) {
return;
}
// No longer need to detect swipe direction for drifting
};
// Handle touch end
game.up = function (x, y, obj) {
if (!gameStarted || !gameActive) {
return;
}
// No longer need to handle touch end for drifting
};
// Game update loop
game.update = function () {
if (!gameStarted) {
return;
}
// Update game time
gameTime++;
timeTxt.setText("TIME: " + Math.floor(gameTime / 60));
// Update status effect timers
if (invincibilityTimer > 0) {
invincibilityTimer--;
if (invincibilityTimer === 0) {
car.alpha = 1;
}
}
if (slowMonstersTimer > 0) {
slowMonstersTimer--;
}
// Spawn powerups
powerupTimer--;
if (powerupTimer <= 0) {
spawnPowerup();
powerupTimer = 300 + Math.random() * 300; // 5-10 seconds
}
// Spawn monsters
spawnMonsterTimer--;
if (spawnMonsterTimer <= 0) {
spawnMonster();
spawnMonsterTimer = 300 - level * 20; // Reduces delay as level increases
spawnMonsterTimer = Math.max(spawnMonsterTimer, 60); // Minimum 1 second
}
// Update car
car.update();
// Update monsters
for (var i = monsters.length - 1; i >= 0; i--) {
var monster = monsters[i];
// Apply slow effect if active
if (slowMonstersTimer > 0) {
monster.speed = (5 + level * 0.5) * 0.5;
} else {
monster.speed = 3 + level * 0.3;
}
monster.update();
// Check for collision with car if not invincible
if (monster.intersects(car) && invincibilityTimer <= 0 && !car.isDead) {
car.crash();
// Update high score
if (score > storage.highScore) {
storage.highScore = score;
}
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
powerup.update();
// Check for collection
if (powerup.intersects(car) && powerup.active) {
var type = powerup.collect();
if (type) {
applyPowerup(type);
updateScore(score + 50);
}
powerups.splice(i, 1);
}
}
// Update drift particles - they're created directly in the game container
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child.lifetime !== undefined) {
// It's a particle
child.lifetime--;
child.alpha = child.lifetime / 30 * child.initialAlpha;
if (child.lifetime <= 0) {
child.destroy();
}
}
}
// Increase score based on car speed when drifting
if (car.drifting) {
updateScore(score + Math.floor(car.speed / 5));
}
};
// Start by showing a message to the player
statusTxt.setText("TAP TO START!");
// Play background music
LK.playMusic('raceMusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Car = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.maxSpeed = 5;
self.acceleration = 0.1;
self.deceleration = 0.1;
self.turnSpeed = 0.05;
self.drifting = false;
self.driftPower = 0;
self.maxDriftPower = 100;
self.driftDirection = 0;
self.driftBoost = 0;
self.isDead = false;
// Particle system for drift effect
self.particles = [];
self.particleTimer = 0;
self.startDrift = function (direction) {
if (!self.drifting) {
self.drifting = true;
self.driftDirection = direction;
LK.getSound('drift').play();
}
};
self.stopDrift = function () {
if (self.drifting) {
self.drifting = false;
// Apply drift boost based on accumulated drift power
self.driftBoost = self.driftPower / 20;
// Reset drift power
self.driftPower = 0;
}
};
self.createDriftParticle = function () {
var particle = LK.getAsset('driftParticle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
// Position behind the car
var angle = self.rotation - Math.PI;
var distance = 30;
particle.x = self.x + Math.cos(angle) * distance;
particle.y = self.y + Math.sin(angle) * distance;
// Store particle data
particle.lifetime = 30; // frames
particle.initialAlpha = 0.7;
return particle;
};
self.update = function () {
if (self.isDead) {
return;
}
// Update speed
if (self.driftBoost > 0) {
self.speed = Math.min(self.speed + self.driftBoost, self.maxSpeed * 1.5);
self.driftBoost -= 0.1;
} else {
self.speed = Math.min(self.speed + self.acceleration, self.maxSpeed);
}
// Apply deceleration when drifting
if (self.drifting) {
self.speed *= 0.98;
// Accumulate drift power
self.driftPower = Math.min(self.driftPower + 1, self.maxDriftPower);
// Create drift particles
self.particleTimer++;
if (self.particleTimer >= 3) {
// Every 3 frames
self.particleTimer = 0;
game.addChild(self.createDriftParticle());
}
}
// Update position based on speed and rotation
self.x += Math.cos(self.rotation) * self.speed;
self.y += Math.sin(self.rotation) * self.speed;
// Apply drift effect to rotation
if (self.drifting) {
self.rotation += self.turnSpeed * 1.5 * self.driftDirection;
}
// Keep car within game bounds
self.x = Math.max(100, Math.min(self.x, 2048 - 100));
self.y = Math.max(100, Math.min(self.y, 2732 - 100));
};
self.crash = function () {
if (!self.isDead) {
self.isDead = true;
LK.getSound('crash').play();
// Visual effect for crash
tween(carGraphics, {
alpha: 0.5,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.showGameOver();
}
});
}
};
return self;
});
var Monster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3; // Reduced speed to slow down monsters
self.target = null;
self.active = true;
self.setTarget = function (target) {
self.target = target;
};
self.update = function () {
if (!self.active || !self.target) {
return;
}
// Calculate direction to target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move towards target
if (distance > 10) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
// Rotate towards target
self.rotation = Math.atan2(dy, dx);
}
// Check if caught the target
if (distance < 80 && self.target && !self.target.isDead) {
self.target.crash();
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'speed'; // Default type
self.active = true;
self.setType = function (type) {
self.type = type;
// Set color based on type
if (type === 'speed') {
powerupGraphics.tint = 0x00ffff;
} else if (type === 'invincibility') {
powerupGraphics.tint = 0xff00ff;
} else if (type === 'slowMonsters') {
powerupGraphics.tint = 0xffff00;
}
};
// Animate the power-up
tween(powerupGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear
});
self.update = function () {
if (!self.active) {
return;
}
// Simple bobbing animation
powerupGraphics.y = Math.sin(LK.ticks / 10) * 5;
};
self.collect = function () {
if (self.active) {
self.active = false;
LK.getSound('powerup').play();
// Visual effect when collected
tween(powerupGraphics, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return self.type;
}
return null;
};
return self;
});
var Track = Container.expand(function () {
var self = Container.call(this);
// Track background
var trackBg = self.attachAsset('trackBorder', {
anchorX: 0.5,
anchorY: 0.5
});
// Main track
var trackMain = self.attachAsset('track', {
anchorX: 0.5,
anchorY: 0.5
});
self.checkpoints = [];
self.powerupSpots = [];
self.createCheckpoint = function (x, y, rotation) {
var checkpoint = LK.getAsset('trackCheckpoint', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5,
x: x,
y: y,
rotation: rotation
});
self.checkpoints.push(checkpoint);
self.addChild(checkpoint);
return checkpoint;
};
self.getRandomPowerupPosition = function () {
if (self.powerupSpots.length === 0) {
return {
x: 0,
y: 0
};
}
var spot = self.powerupSpots[Math.floor(Math.random() * self.powerupSpots.length)];
return {
x: spot.x,
y: spot.y
};
};
self.setupTrack = function (level) {
// Clear existing checkpoints
for (var i = 0; i < self.checkpoints.length; i++) {
self.checkpoints[i].destroy();
}
self.checkpoints = [];
self.powerupSpots = [];
// Create track layout based on level
if (level === 1) {
// Simple oval track
self.createCheckpoint(0, -500, 0);
self.createCheckpoint(500, 0, Math.PI / 2);
self.createCheckpoint(0, 500, Math.PI);
self.createCheckpoint(-500, 0, -Math.PI / 2);
// Add powerup spots
self.powerupSpots = [{
x: 0,
y: -300
}, {
x: 300,
y: 0
}, {
x: 0,
y: 300
}, {
x: -300,
y: 0
}];
} else if (level === 2) {
// Figure-8 track
self.createCheckpoint(0, -500, 0);
self.createCheckpoint(500, -250, Math.PI / 4);
self.createCheckpoint(250, 0, Math.PI / 2);
self.createCheckpoint(500, 250, 3 * Math.PI / 4);
self.createCheckpoint(0, 500, Math.PI);
self.createCheckpoint(-500, 250, -3 * Math.PI / 4);
self.createCheckpoint(-250, 0, -Math.PI / 2);
self.createCheckpoint(-500, -250, -Math.PI / 4);
// Add powerup spots
self.powerupSpots = [{
x: 0,
y: -300
}, {
x: 300,
y: -150
}, {
x: 150,
y: 0
}, {
x: 300,
y: 150
}, {
x: 0,
y: 300
}, {
x: -300,
y: 150
}, {
x: -150,
y: 0
}, {
x: -300,
y: -150
}];
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x225522
});
/****
* Game Code
****/
// Game state variables
var car;
var monsters = [];
var powerups = [];
var track;
var gameStarted = false;
var score = 0;
var level = 1;
var gameTime = 0;
var powerupTimer = 0;
var spawnMonsterTimer = 0;
var gameActive = true;
var invincibilityTimer = 0;
var slowMonstersTimer = 0;
// UI elements
var scoreTxt = new Text2("SCORE: 0", {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var levelTxt = new Text2("LEVEL: 1", {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
levelTxt.y = 70;
LK.gui.top.addChild(levelTxt);
var timeTxt = new Text2("TIME: 0", {
size: 60,
fill: 0xFFFFFF
});
timeTxt.anchor.set(0, 0);
timeTxt.x = 20;
timeTxt.y = 20;
LK.gui.topRight.addChild(timeTxt);
var statusTxt = new Text2("", {
size: 50,
fill: 0xFFFF00
});
statusTxt.anchor.set(0.5, 0);
statusTxt.y = 140;
LK.gui.top.addChild(statusTxt);
// Initialize track
track = new Track();
track.x = 2048 / 2;
track.y = 2732 / 2;
game.addChild(track);
track.setupTrack(level);
// Initialize car
car = new Car();
car.x = 2048 / 2;
car.y = 2732 / 2 + 400;
car.rotation = -Math.PI / 2;
game.addChild(car);
// Game initialization
function startGame() {
gameStarted = true;
gameActive = true;
score = 0;
gameTime = 0;
level = 1;
// Reset car
car.speed = 0;
car.drifting = false;
car.driftPower = 0;
car.driftBoost = 0;
car.isDead = false;
car.x = 2048 / 2;
car.y = 2732 / 2 + 400;
car.rotation = -Math.PI / 2;
// Clear monsters
for (var i = 0; i < monsters.length; i++) {
monsters[i].destroy();
}
monsters = [];
// Clear powerups
for (var i = 0; i < powerups.length; i++) {
powerups[i].destroy();
}
powerups = [];
// Start timers
powerupTimer = 180; // 3 seconds (60fps * 3)
spawnMonsterTimer = 300; // 5 seconds
// Reset track
track.setupTrack(level);
// Reset status effects
invincibilityTimer = 0;
slowMonstersTimer = 0;
// Update UI
updateScore(0);
updateLevel(1);
// Play music
LK.playMusic('raceMusic');
}
// Update score display
function updateScore(newScore) {
score = newScore;
scoreTxt.setText("SCORE: " + score);
// Check for level up
if (score >= level * 500) {
levelUp();
}
}
// Update level display
function updateLevel(newLevel) {
level = newLevel;
levelTxt.setText("LEVEL: " + level);
// Update track for new level
track.setupTrack(level % 2 === 0 ? 2 : 1);
}
// Level up
function levelUp() {
updateLevel(level + 1);
// Visual effect
LK.effects.flashScreen(0x00ff00, 500);
statusTxt.setText("LEVEL UP!");
// Clear status text after 2 seconds
LK.setTimeout(function () {
statusTxt.setText("");
}, 2000);
}
// Spawn a monster
function spawnMonster() {
var monster = new Monster();
// Position monster away from player
var angle = Math.random() * Math.PI * 2;
var distance = 800;
monster.x = car.x + Math.cos(angle) * distance;
monster.y = car.y + Math.sin(angle) * distance;
// Keep monster within game bounds
monster.x = Math.max(100, Math.min(monster.x, 2048 - 100));
monster.y = Math.max(100, Math.min(monster.y, 2732 - 100));
// Set target and speed based on level
monster.setTarget(car);
monster.speed = 3 + level * 0.3;
game.addChild(monster);
monsters.push(monster);
}
// Spawn a powerup
function spawnPowerup() {
var powerup = new PowerUp();
// Set random position from track's powerup spots
var pos = track.getRandomPowerupPosition();
powerup.x = track.x + pos.x;
powerup.y = track.y + pos.y;
// Set random type
var types = ['speed', 'invincibility', 'slowMonsters'];
var type = types[Math.floor(Math.random() * types.length)];
powerup.setType(type);
game.addChild(powerup);
powerups.push(powerup);
}
// Apply powerup effect
function applyPowerup(type) {
if (type === 'speed') {
car.speed += 5;
car.maxSpeed += 2;
// Reset max speed after 5 seconds
LK.setTimeout(function () {
car.maxSpeed -= 2;
}, 5000);
statusTxt.setText("SPEED BOOST!");
} else if (type === 'invincibility') {
invincibilityTimer = 300; // 5 seconds
car.alpha = 0.7;
statusTxt.setText("INVINCIBLE!");
} else if (type === 'slowMonsters') {
slowMonstersTimer = 300; // 5 seconds
statusTxt.setText("MONSTERS SLOWED!");
}
// Clear status text after 2 seconds
LK.setTimeout(function () {
statusTxt.setText("");
}, 2000);
}
// Handle drift controls
var isDrifting = false;
var driftDirection = 0;
function startDrifting(direction) {
if (!isDrifting) {
isDrifting = true;
driftDirection = direction;
car.startDrift(direction);
}
}
function stopDrifting() {
if (isDrifting) {
isDrifting = false;
car.stopDrift();
}
}
// Handle touch input
var touchStartX = 0;
var touchStartY = 0;
var touchMoved = false;
// Handle touch start
game.down = function (x, y, obj) {
if (!gameStarted) {
startGame();
return;
}
if (!isDrifting) {
startDrifting(1); // Start drifting to the right by default
} else {
stopDrifting(); // Stop drifting if already drifting
}
};
// Handle touch move
game.move = function (x, y, obj) {
if (!gameStarted || !gameActive) {
return;
}
// No longer need to detect swipe direction for drifting
};
// Handle touch end
game.up = function (x, y, obj) {
if (!gameStarted || !gameActive) {
return;
}
// No longer need to handle touch end for drifting
};
// Game update loop
game.update = function () {
if (!gameStarted) {
return;
}
// Update game time
gameTime++;
timeTxt.setText("TIME: " + Math.floor(gameTime / 60));
// Update status effect timers
if (invincibilityTimer > 0) {
invincibilityTimer--;
if (invincibilityTimer === 0) {
car.alpha = 1;
}
}
if (slowMonstersTimer > 0) {
slowMonstersTimer--;
}
// Spawn powerups
powerupTimer--;
if (powerupTimer <= 0) {
spawnPowerup();
powerupTimer = 300 + Math.random() * 300; // 5-10 seconds
}
// Spawn monsters
spawnMonsterTimer--;
if (spawnMonsterTimer <= 0) {
spawnMonster();
spawnMonsterTimer = 300 - level * 20; // Reduces delay as level increases
spawnMonsterTimer = Math.max(spawnMonsterTimer, 60); // Minimum 1 second
}
// Update car
car.update();
// Update monsters
for (var i = monsters.length - 1; i >= 0; i--) {
var monster = monsters[i];
// Apply slow effect if active
if (slowMonstersTimer > 0) {
monster.speed = (5 + level * 0.5) * 0.5;
} else {
monster.speed = 3 + level * 0.3;
}
monster.update();
// Check for collision with car if not invincible
if (monster.intersects(car) && invincibilityTimer <= 0 && !car.isDead) {
car.crash();
// Update high score
if (score > storage.highScore) {
storage.highScore = score;
}
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
powerup.update();
// Check for collection
if (powerup.intersects(car) && powerup.active) {
var type = powerup.collect();
if (type) {
applyPowerup(type);
updateScore(score + 50);
}
powerups.splice(i, 1);
}
}
// Update drift particles - they're created directly in the game container
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child.lifetime !== undefined) {
// It's a particle
child.lifetime--;
child.alpha = child.lifetime / 30 * child.initialAlpha;
if (child.lifetime <= 0) {
child.destroy();
}
}
}
// Increase score based on car speed when drifting
if (car.drifting) {
updateScore(score + Math.floor(car.speed / 5));
}
};
// Start by showing a message to the player
statusTxt.setText("TAP TO START!");
// Play background music
LK.playMusic('raceMusic');
car. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
monster. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
particle. Single Game Texture. Blank background. High contrast. No shadows
checkpoint. Single Game Texture. In-Game asset. Blank background. High contrast. No shadows