/**** * 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