/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Barrier = Container.expand(function () { var self = Container.call(this); var barrierGraphics = self.attachAsset('barrier', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.blocking = true; self.update = function () { self.y += self.speed + gameSpeed; // Add sliding animation barrierGraphics.x = Math.sin(LK.ticks * 0.05) * 20; }; return self; }); var CharacterButton = Container.expand(function (vehicleType, vehicleAsset) { var self = Container.call(this); self.vehicleType = vehicleType; var buttonBg = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); var vehiclePreview = self.attachAsset(vehicleAsset, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.4 }); self.down = function (x, y, obj) { buttonBg.alpha = 0.7; selectedVehicle = self.vehicleType; // Update all character buttons to show selection updateCharacterButtons(); }; self.up = function (x, y, obj) { buttonBg.alpha = 1.0; }; self.setSelected = function (isSelected) { if (isSelected) { buttonBg.tint = 0x00ff00; vehiclePreview.tint = 0x00ff00; } else { buttonBg.tint = 0xffffff; vehiclePreview.tint = 0xffffff; } }; return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.update = function () { self.y += self.speed + gameSpeed; // Ensure cone doesn't rotate obstacleGraphics.rotation = 0; }; return self; }); var OilSpill = Container.expand(function () { var self = Container.call(this); var oilGraphics = self.attachAsset('oilspill', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.slippery = true; self.update = function () { self.y += self.speed + gameSpeed; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.update = function () { // Power-up stays stationary, only rotate for visual effect powerupGraphics.rotation += 0.1; }; return self; }); var Spike = Container.expand(function () { var self = Container.call(this); var spikeGraphics = self.attachAsset('spike', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.deadly = true; self.update = function () { self.y += self.speed + gameSpeed; // Add pulsing effect spikeGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.1; }; return self; }); var StartButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5 }); // Text removed from button self.down = function (x, y, obj) { buttonGraphics.alpha = 0.7; if (!gameStarted && characterSelectionVisible) { startGame(); } }; self.up = function (x, y, obj) { buttonGraphics.alpha = 1.0; }; return self; }); var TrapHole = Container.expand(function () { var self = Container.call(this); var trapGraphics = self.attachAsset('trap', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.stunEffect = true; self.update = function () { self.y += self.speed + gameSpeed; }; return self; }); var Vehicle = Container.expand(function () { var self = Container.call(this); var vehicleGraphics = self.attachAsset(selectedVehicle, { anchorX: 0.5, anchorY: 0.5 }); self.speed = 0; self.targetX = 0; self.update = function () { // Check if vehicle is stunned (cannot move) if (vehicleStunned) { // Vehicle cannot move at all when stunned return; } // Smooth movement toward target position var dx = self.targetX - self.x; var moveSpeed = originalVehicleSpeed; // Apply slowdown effect if active if (vehicleSlowed) { moveSpeed = originalVehicleSpeed * 0.3; // 70% slower } if (Math.abs(dx) > 2) { self.x += dx * moveSpeed; } else { self.x = self.targetX; } // Keep vehicle within bounds horizontally var halfWidth = vehicleGraphics.width / 2; if (self.x - halfWidth < 200) { self.x = 200 + halfWidth; self.targetX = self.x; } if (self.x + halfWidth > 1848) { self.x = 1848 - halfWidth; self.targetX = self.x; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ // Add background var background = game.addChild(LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 })); background.x = 1024; background.y = 1208; // Add white car background made with pixels var whiteCar = game.addChild(LK.getAsset('whitecar', { anchorX: 0.5, anchorY: 0.5 })); whiteCar.x = 1024; whiteCar.y = 1366; whiteCar.tint = 0xffffff; whiteCar.scaleX = 2; whiteCar.scaleY = 2; var gameSpeed = 5; var maxSpeed = 20; var speedIncrement = 0.01; var distanceTraveled = 0; var obstacles = []; var powerups = []; var vehicle = null; var dragNode = null; var gameRunning = true; var gameStarted = false; var lives = 3; var maxLives = 3; var heartIcons = []; var speedBoostActive = false; var speedBoostEndTime = 0; var originalSpeed = 5; var vehicleStunned = false; var vehicleStunnedEndTime = 0; var vehicleSlowed = false; var vehicleSlowedEndTime = 0; var originalVehicleSpeed = 0.15; var vehicleInvincible = false; var vehicleInvincibleEndTime = 0; var startButton = null; var selectedVehicle = 'vehicle'; var characterButtons = []; var characterSelectionVisible = false; // Create score display var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); scoreTxt.visible = false; LK.gui.top.addChild(scoreTxt); // Create speed display var speedTxt = new Text2('Speed: 5', { size: 60, fill: 0xFFFFFF }); speedTxt.anchor.set(0, 0); speedTxt.x = 50; speedTxt.y = 50; speedTxt.visible = false; LK.gui.topLeft.addChild(speedTxt); // Create heart icons for lives display for (var h = 0; h < maxLives; h++) { var heart = LK.getAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); heart.x = 1950 - h * 80; // Position hearts from right to left heart.y = 80; heart.visible = false; heartIcons.push(heart); LK.gui.bottomRight.addChild(heart); } // Create character selection button startButton = game.addChild(new StartButton()); startButton.x = 1024; startButton.y = 1600; // Create speedrunner logo for character selection var speedrunnerLogo = game.addChild(LK.getAsset('speedrunner', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 })); speedrunnerLogo.x = 1024; speedrunnerLogo.y = 600; speedrunnerLogo.visible = false; // Create character selection buttons (initially hidden) var vehicleTypes = ['vehicle', 'vehicle2', 'vehicle3', 'vehicle4', 'truck', 'motorbike', 'policecar']; var vehicleAssets = ['vehicle', 'vehicle2', 'vehicle3', 'vehicle4', 'truck', 'motorbike', 'policecar']; for (var c = 0; c < vehicleTypes.length; c++) { var charButton = game.addChild(new CharacterButton(vehicleTypes[c], vehicleAssets[c])); charButton.x = 200 + c * 280; charButton.y = 1200; charButton.visible = false; characterButtons.push(charButton); } // Set default selection characterButtons[0].setSelected(true); // Create vehicle (initially hidden) - positioned higher vehicle = game.addChild(new Vehicle()); vehicle.x = 1024; vehicle.y = 2000; vehicle.targetX = vehicle.x; vehicle.visible = false; // Show character selection function showCharacterSelection() { characterSelectionVisible = true; // Show speedrunner logo speedrunnerLogo.visible = true; // Show character buttons for (var c = 0; c < characterButtons.length; c++) { characterButtons[c].visible = true; } } // Show character selection immediately on game start showCharacterSelection(); // Update character button selection states function updateCharacterButtons() { for (var c = 0; c < characterButtons.length; c++) { characterButtons[c].setSelected(characterButtons[c].vehicleType === selectedVehicle); } } // Start game function function startGame() { gameStarted = true; gameRunning = true; // Hide start menu startButton.visible = false; whiteCar.visible = false; // Hide speedrunner logo speedrunnerLogo.visible = false; // Hide character selection for (var c = 0; c < characterButtons.length; c++) { characterButtons[c].visible = false; } characterSelectionVisible = false; // Recreate vehicle with selected character vehicle.destroy(); vehicle = game.addChild(new Vehicle()); vehicle.x = 1024; vehicle.y = 2000; vehicle.targetX = vehicle.x; vehicle.visible = true; // Show UI elements scoreTxt.visible = true; speedTxt.visible = true; // Show heart icons for (var h = 0; h < heartIcons.length; h++) { heartIcons[h].visible = true; } // Play startup sound when game starts LK.getSound('startup').play(); // Start playing music on loop LK.playMusic('musica'); } // Spawn obstacles function spawnObstacle() { if (!gameRunning) return; var obstacle; var obstacleType = Math.random(); if (obstacleType < 0.3) { obstacle = new Obstacle(); } else if (obstacleType < 0.5) { obstacle = new OilSpill(); } else if (obstacleType < 0.7) { obstacle = new Spike(); } else if (obstacleType < 0.9) { obstacle = new TrapHole(); } else { obstacle = new Barrier(); } // Random position within track bounds obstacle.x = 300 + Math.random() * 1448; obstacle.y = -100; obstacles.push(obstacle); game.addChild(obstacle); } // Update and clean up power-ups for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; // Check if power-up went off screen if (powerup.y > 2800) { powerup.destroy(); powerups.splice(i, 1); continue; } // Check collision with vehicle if (powerup.intersects(vehicle)) { // Activate speed boost speedBoostActive = true; speedBoostEndTime = LK.ticks + 600; // 10 seconds at 60 FPS originalSpeed = gameSpeed; gameSpeed = Math.min(gameSpeed + 10, maxSpeed); // Increase speed by 10 LK.getSound('powerup').play(); // Flash screen gold LK.effects.flashScreen(0xffd700, 500); // Animate vehicle with golden tint and pulsing effect tween(vehicle, { tint: 0xffd700 }, { duration: 200 }); // Remove the power-up powerup.destroy(); powerups.splice(i, 1); continue; } } // Update and clean up track lines function spawnPowerUp() { if (!gameRunning) return; var powerup = new PowerUp(); // Random position within track bounds powerup.x = 300 + Math.random() * 1448; powerup.y = -100; powerups.push(powerup); game.addChild(powerup); } // Handle touch input function handleMove(x, y, obj) { if (!gameRunning) return; if (dragNode) { // Convert touch position to vehicle target position vehicle.targetX = x; } } game.move = handleMove; game.down = function (x, y, obj) { if (!gameRunning) return; dragNode = vehicle; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; // Main game loop game.update = function () { if (!gameStarted || !gameRunning) return; // Increase speed over time if (gameSpeed < maxSpeed) { gameSpeed += speedIncrement; } // Update distance traveled distanceTraveled += gameSpeed; // Update score based on distance var score = Math.floor(distanceTraveled / 10); LK.setScore(score); scoreTxt.setText(score); speedTxt.setText('Speed: ' + Math.floor(gameSpeed)); // Check win condition at 7,500 points if (score >= 7500) { gameRunning = false; LK.setTimeout(function () { LK.showYouWin(); }, 500); return; } // Check if speed boost expired if (speedBoostActive && LK.ticks > speedBoostEndTime) { speedBoostActive = false; // Restore normal speed (but keep natural progression) gameSpeed = Math.max(originalSpeed, 5 + distanceTraveled / 10000 * speedIncrement); // Stop tween and restore normal vehicle color tween.stop(vehicle); vehicle.tint = 0xffffff; } // Check if vehicle stun expired if (vehicleStunned && LK.ticks > vehicleStunnedEndTime) { vehicleStunned = false; // Stop tween and restore normal vehicle color tween.stop(vehicle); vehicle.tint = 0xffffff; // Reset rotation to normal vehicle.rotation = 0; } // Check if vehicle slowdown expired if (vehicleSlowed && LK.ticks > vehicleSlowedEndTime) { vehicleSlowed = false; // Stop tween and restore normal vehicle color if not stunned if (!vehicleStunned) { tween.stop(vehicle); vehicle.tint = 0xffffff; } } // Check if vehicle invincibility expired if (vehicleInvincible && LK.ticks > vehicleInvincibleEndTime) { vehicleInvincible = false; // Stop flashing effect tween.stop(vehicle, { alpha: true }); vehicle.alpha = 1.0; } // Progressive obstacle spawning - gradually increase frequency and probability var baseSpawnRate = Math.max(70 - Math.floor(gameSpeed * 2), 30); // Faster spawn rate var progressMultiplier = Math.min(1 + distanceTraveled / 5000, 3); // Up to 3x more likely over time var spawnProbability = Math.min(0.3 + distanceTraveled / 8000, 0.8); // Start at 30%, increase to 80% if (LK.ticks % baseSpawnRate === 0) { // Multiple obstacle spawning based on progress var numObstacles = Math.floor(progressMultiplier); for (var spawns = 0; spawns < numObstacles; spawns++) { // Check if we already have maximum number of obstacles on screen if (obstacles.length >= 5) { break; // Stop spawning if we have 5 or more obstacles } if (Math.random() < spawnProbability) { spawnObstacle(); } } } // Spawn power-ups occasionally (15% chance when spawning obstacles) if (LK.ticks % Math.max(60 - Math.floor(gameSpeed), 30) === 0 && Math.random() < 0.15) { spawnPowerUp(); } // Update and clean up obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; // Check if obstacle went off screen if (obstacle.y > 2800) { obstacle.destroy(); obstacles.splice(i, 1); continue; } // Check collision with vehicle if (obstacle.intersects(vehicle) && !vehicleInvincible) { if (obstacle.slippery) { // Oil spill effect - vehicle slides randomly and slows down for 1 second vehicle.targetX += (Math.random() - 0.5) * 400; vehicleSlowed = true; vehicleSlowedEndTime = LK.ticks + 60; // 1 second at 60 FPS LK.effects.flashScreen(0x8B4513, 300); // Tint vehicle brown to show oil effect tween(vehicle, { tint: 0x8B4513 }, { duration: 200 }); // Slight damage but no life lost } else if (obstacle.deadly) { // Spike - instant death lives = 0; LK.effects.flashScreen(0xff0000, 1000); LK.getSound('crash').play(); } else if (obstacle.stunEffect) { // Trap hole - stun vehicle for 2 seconds (cannot move) vehicleStunned = true; vehicleStunnedEndTime = LK.ticks + 120; // 2 seconds at 60 FPS // Add rotation animation while stunned tween(vehicle, { rotation: vehicle.rotation + Math.PI * 4 // 2 full rotations }, { duration: 2000, // 2 seconds easing: tween.easeOut }); // No life lost, just stunning effect } else if (obstacle.blocking) { // Barrier - damages vehicle and pushes it back lives--; LK.getSound('crash').play(); // Push vehicle back slightly vehicle.targetX = vehicle.x + (Math.random() - 0.5) * 200; } else { // Regular obstacle lives--; LK.effects.flashScreen(0xff0000, 500); LK.getSound('crash').play(); } // Hide a heart icon for regular, deadly, and blocking obstacles if (!obstacle.slippery && !obstacle.stunEffect && lives >= 0 && lives < heartIcons.length) { heartIcons[heartIcons.length - 1 - lives].visible = false; } // Activate invincibility for 1 second after any collision vehicleInvincible = true; vehicleInvincibleEndTime = LK.ticks + 60; // 1 second at 60 FPS // Add flashing effect during invincibility tween(vehicle, { alpha: 0.3 }, { duration: 100, easing: tween.linear, onFinish: function onFinish() { if (vehicleInvincible) { tween(vehicle, { alpha: 1.0 }, { duration: 100, easing: tween.linear, onFinish: function onFinish() { if (vehicleInvincible) { // Continue flashing by calling this recursively tween(vehicle, { alpha: 0.3 }, { duration: 100, easing: tween.linear, onFinish: function onFinish() { if (vehicleInvincible) { tween(vehicle, { alpha: 1.0 }, { duration: 100 }); } } }); } } }); } } }); // Remove the obstacle that was hit obstacle.destroy(); obstacles.splice(i, 1); // Check if game over if (lives <= 0) { gameRunning = false; LK.setTimeout(function () { LK.showGameOver(); }, 500); return; } continue; } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Barrier = Container.expand(function () {
var self = Container.call(this);
var barrierGraphics = self.attachAsset('barrier', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.blocking = true;
self.update = function () {
self.y += self.speed + gameSpeed;
// Add sliding animation
barrierGraphics.x = Math.sin(LK.ticks * 0.05) * 20;
};
return self;
});
var CharacterButton = Container.expand(function (vehicleType, vehicleAsset) {
var self = Container.call(this);
self.vehicleType = vehicleType;
var buttonBg = self.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
var vehiclePreview = self.attachAsset(vehicleAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4
});
self.down = function (x, y, obj) {
buttonBg.alpha = 0.7;
selectedVehicle = self.vehicleType;
// Update all character buttons to show selection
updateCharacterButtons();
};
self.up = function (x, y, obj) {
buttonBg.alpha = 1.0;
};
self.setSelected = function (isSelected) {
if (isSelected) {
buttonBg.tint = 0x00ff00;
vehiclePreview.tint = 0x00ff00;
} else {
buttonBg.tint = 0xffffff;
vehiclePreview.tint = 0xffffff;
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed + gameSpeed;
// Ensure cone doesn't rotate
obstacleGraphics.rotation = 0;
};
return self;
});
var OilSpill = Container.expand(function () {
var self = Container.call(this);
var oilGraphics = self.attachAsset('oilspill', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.slippery = true;
self.update = function () {
self.y += self.speed + gameSpeed;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
// Power-up stays stationary, only rotate for visual effect
powerupGraphics.rotation += 0.1;
};
return self;
});
var Spike = Container.expand(function () {
var self = Container.call(this);
var spikeGraphics = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.deadly = true;
self.update = function () {
self.y += self.speed + gameSpeed;
// Add pulsing effect
spikeGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
};
return self;
});
var StartButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
// Text removed from button
self.down = function (x, y, obj) {
buttonGraphics.alpha = 0.7;
if (!gameStarted && characterSelectionVisible) {
startGame();
}
};
self.up = function (x, y, obj) {
buttonGraphics.alpha = 1.0;
};
return self;
});
var TrapHole = Container.expand(function () {
var self = Container.call(this);
var trapGraphics = self.attachAsset('trap', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.stunEffect = true;
self.update = function () {
self.y += self.speed + gameSpeed;
};
return self;
});
var Vehicle = Container.expand(function () {
var self = Container.call(this);
var vehicleGraphics = self.attachAsset(selectedVehicle, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.targetX = 0;
self.update = function () {
// Check if vehicle is stunned (cannot move)
if (vehicleStunned) {
// Vehicle cannot move at all when stunned
return;
}
// Smooth movement toward target position
var dx = self.targetX - self.x;
var moveSpeed = originalVehicleSpeed;
// Apply slowdown effect if active
if (vehicleSlowed) {
moveSpeed = originalVehicleSpeed * 0.3; // 70% slower
}
if (Math.abs(dx) > 2) {
self.x += dx * moveSpeed;
} else {
self.x = self.targetX;
}
// Keep vehicle within bounds horizontally
var halfWidth = vehicleGraphics.width / 2;
if (self.x - halfWidth < 200) {
self.x = 200 + halfWidth;
self.targetX = self.x;
}
if (self.x + halfWidth > 1848) {
self.x = 1848 - halfWidth;
self.targetX = self.x;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Add background
var background = game.addChild(LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
}));
background.x = 1024;
background.y = 1208;
// Add white car background made with pixels
var whiteCar = game.addChild(LK.getAsset('whitecar', {
anchorX: 0.5,
anchorY: 0.5
}));
whiteCar.x = 1024;
whiteCar.y = 1366;
whiteCar.tint = 0xffffff;
whiteCar.scaleX = 2;
whiteCar.scaleY = 2;
var gameSpeed = 5;
var maxSpeed = 20;
var speedIncrement = 0.01;
var distanceTraveled = 0;
var obstacles = [];
var powerups = [];
var vehicle = null;
var dragNode = null;
var gameRunning = true;
var gameStarted = false;
var lives = 3;
var maxLives = 3;
var heartIcons = [];
var speedBoostActive = false;
var speedBoostEndTime = 0;
var originalSpeed = 5;
var vehicleStunned = false;
var vehicleStunnedEndTime = 0;
var vehicleSlowed = false;
var vehicleSlowedEndTime = 0;
var originalVehicleSpeed = 0.15;
var vehicleInvincible = false;
var vehicleInvincibleEndTime = 0;
var startButton = null;
var selectedVehicle = 'vehicle';
var characterButtons = [];
var characterSelectionVisible = false;
// Create score display
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.visible = false;
LK.gui.top.addChild(scoreTxt);
// Create speed display
var speedTxt = new Text2('Speed: 5', {
size: 60,
fill: 0xFFFFFF
});
speedTxt.anchor.set(0, 0);
speedTxt.x = 50;
speedTxt.y = 50;
speedTxt.visible = false;
LK.gui.topLeft.addChild(speedTxt);
// Create heart icons for lives display
for (var h = 0; h < maxLives; h++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = 1950 - h * 80; // Position hearts from right to left
heart.y = 80;
heart.visible = false;
heartIcons.push(heart);
LK.gui.bottomRight.addChild(heart);
}
// Create character selection button
startButton = game.addChild(new StartButton());
startButton.x = 1024;
startButton.y = 1600;
// Create speedrunner logo for character selection
var speedrunnerLogo = game.addChild(LK.getAsset('speedrunner', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3
}));
speedrunnerLogo.x = 1024;
speedrunnerLogo.y = 600;
speedrunnerLogo.visible = false;
// Create character selection buttons (initially hidden)
var vehicleTypes = ['vehicle', 'vehicle2', 'vehicle3', 'vehicle4', 'truck', 'motorbike', 'policecar'];
var vehicleAssets = ['vehicle', 'vehicle2', 'vehicle3', 'vehicle4', 'truck', 'motorbike', 'policecar'];
for (var c = 0; c < vehicleTypes.length; c++) {
var charButton = game.addChild(new CharacterButton(vehicleTypes[c], vehicleAssets[c]));
charButton.x = 200 + c * 280;
charButton.y = 1200;
charButton.visible = false;
characterButtons.push(charButton);
}
// Set default selection
characterButtons[0].setSelected(true);
// Create vehicle (initially hidden) - positioned higher
vehicle = game.addChild(new Vehicle());
vehicle.x = 1024;
vehicle.y = 2000;
vehicle.targetX = vehicle.x;
vehicle.visible = false;
// Show character selection
function showCharacterSelection() {
characterSelectionVisible = true;
// Show speedrunner logo
speedrunnerLogo.visible = true;
// Show character buttons
for (var c = 0; c < characterButtons.length; c++) {
characterButtons[c].visible = true;
}
}
// Show character selection immediately on game start
showCharacterSelection();
// Update character button selection states
function updateCharacterButtons() {
for (var c = 0; c < characterButtons.length; c++) {
characterButtons[c].setSelected(characterButtons[c].vehicleType === selectedVehicle);
}
}
// Start game function
function startGame() {
gameStarted = true;
gameRunning = true;
// Hide start menu
startButton.visible = false;
whiteCar.visible = false;
// Hide speedrunner logo
speedrunnerLogo.visible = false;
// Hide character selection
for (var c = 0; c < characterButtons.length; c++) {
characterButtons[c].visible = false;
}
characterSelectionVisible = false;
// Recreate vehicle with selected character
vehicle.destroy();
vehicle = game.addChild(new Vehicle());
vehicle.x = 1024;
vehicle.y = 2000;
vehicle.targetX = vehicle.x;
vehicle.visible = true;
// Show UI elements
scoreTxt.visible = true;
speedTxt.visible = true;
// Show heart icons
for (var h = 0; h < heartIcons.length; h++) {
heartIcons[h].visible = true;
}
// Play startup sound when game starts
LK.getSound('startup').play();
// Start playing music on loop
LK.playMusic('musica');
}
// Spawn obstacles
function spawnObstacle() {
if (!gameRunning) return;
var obstacle;
var obstacleType = Math.random();
if (obstacleType < 0.3) {
obstacle = new Obstacle();
} else if (obstacleType < 0.5) {
obstacle = new OilSpill();
} else if (obstacleType < 0.7) {
obstacle = new Spike();
} else if (obstacleType < 0.9) {
obstacle = new TrapHole();
} else {
obstacle = new Barrier();
}
// Random position within track bounds
obstacle.x = 300 + Math.random() * 1448;
obstacle.y = -100;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Update and clean up power-ups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
// Check if power-up went off screen
if (powerup.y > 2800) {
powerup.destroy();
powerups.splice(i, 1);
continue;
}
// Check collision with vehicle
if (powerup.intersects(vehicle)) {
// Activate speed boost
speedBoostActive = true;
speedBoostEndTime = LK.ticks + 600; // 10 seconds at 60 FPS
originalSpeed = gameSpeed;
gameSpeed = Math.min(gameSpeed + 10, maxSpeed); // Increase speed by 10
LK.getSound('powerup').play();
// Flash screen gold
LK.effects.flashScreen(0xffd700, 500);
// Animate vehicle with golden tint and pulsing effect
tween(vehicle, {
tint: 0xffd700
}, {
duration: 200
});
// Remove the power-up
powerup.destroy();
powerups.splice(i, 1);
continue;
}
}
// Update and clean up track lines
function spawnPowerUp() {
if (!gameRunning) return;
var powerup = new PowerUp();
// Random position within track bounds
powerup.x = 300 + Math.random() * 1448;
powerup.y = -100;
powerups.push(powerup);
game.addChild(powerup);
}
// Handle touch input
function handleMove(x, y, obj) {
if (!gameRunning) return;
if (dragNode) {
// Convert touch position to vehicle target position
vehicle.targetX = x;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (!gameRunning) return;
dragNode = vehicle;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game loop
game.update = function () {
if (!gameStarted || !gameRunning) return;
// Increase speed over time
if (gameSpeed < maxSpeed) {
gameSpeed += speedIncrement;
}
// Update distance traveled
distanceTraveled += gameSpeed;
// Update score based on distance
var score = Math.floor(distanceTraveled / 10);
LK.setScore(score);
scoreTxt.setText(score);
speedTxt.setText('Speed: ' + Math.floor(gameSpeed));
// Check win condition at 7,500 points
if (score >= 7500) {
gameRunning = false;
LK.setTimeout(function () {
LK.showYouWin();
}, 500);
return;
}
// Check if speed boost expired
if (speedBoostActive && LK.ticks > speedBoostEndTime) {
speedBoostActive = false;
// Restore normal speed (but keep natural progression)
gameSpeed = Math.max(originalSpeed, 5 + distanceTraveled / 10000 * speedIncrement);
// Stop tween and restore normal vehicle color
tween.stop(vehicle);
vehicle.tint = 0xffffff;
}
// Check if vehicle stun expired
if (vehicleStunned && LK.ticks > vehicleStunnedEndTime) {
vehicleStunned = false;
// Stop tween and restore normal vehicle color
tween.stop(vehicle);
vehicle.tint = 0xffffff;
// Reset rotation to normal
vehicle.rotation = 0;
}
// Check if vehicle slowdown expired
if (vehicleSlowed && LK.ticks > vehicleSlowedEndTime) {
vehicleSlowed = false;
// Stop tween and restore normal vehicle color if not stunned
if (!vehicleStunned) {
tween.stop(vehicle);
vehicle.tint = 0xffffff;
}
}
// Check if vehicle invincibility expired
if (vehicleInvincible && LK.ticks > vehicleInvincibleEndTime) {
vehicleInvincible = false;
// Stop flashing effect
tween.stop(vehicle, {
alpha: true
});
vehicle.alpha = 1.0;
}
// Progressive obstacle spawning - gradually increase frequency and probability
var baseSpawnRate = Math.max(70 - Math.floor(gameSpeed * 2), 30); // Faster spawn rate
var progressMultiplier = Math.min(1 + distanceTraveled / 5000, 3); // Up to 3x more likely over time
var spawnProbability = Math.min(0.3 + distanceTraveled / 8000, 0.8); // Start at 30%, increase to 80%
if (LK.ticks % baseSpawnRate === 0) {
// Multiple obstacle spawning based on progress
var numObstacles = Math.floor(progressMultiplier);
for (var spawns = 0; spawns < numObstacles; spawns++) {
// Check if we already have maximum number of obstacles on screen
if (obstacles.length >= 5) {
break; // Stop spawning if we have 5 or more obstacles
}
if (Math.random() < spawnProbability) {
spawnObstacle();
}
}
}
// Spawn power-ups occasionally (15% chance when spawning obstacles)
if (LK.ticks % Math.max(60 - Math.floor(gameSpeed), 30) === 0 && Math.random() < 0.15) {
spawnPowerUp();
}
// Update and clean up obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Check if obstacle went off screen
if (obstacle.y > 2800) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with vehicle
if (obstacle.intersects(vehicle) && !vehicleInvincible) {
if (obstacle.slippery) {
// Oil spill effect - vehicle slides randomly and slows down for 1 second
vehicle.targetX += (Math.random() - 0.5) * 400;
vehicleSlowed = true;
vehicleSlowedEndTime = LK.ticks + 60; // 1 second at 60 FPS
LK.effects.flashScreen(0x8B4513, 300);
// Tint vehicle brown to show oil effect
tween(vehicle, {
tint: 0x8B4513
}, {
duration: 200
});
// Slight damage but no life lost
} else if (obstacle.deadly) {
// Spike - instant death
lives = 0;
LK.effects.flashScreen(0xff0000, 1000);
LK.getSound('crash').play();
} else if (obstacle.stunEffect) {
// Trap hole - stun vehicle for 2 seconds (cannot move)
vehicleStunned = true;
vehicleStunnedEndTime = LK.ticks + 120; // 2 seconds at 60 FPS
// Add rotation animation while stunned
tween(vehicle, {
rotation: vehicle.rotation + Math.PI * 4 // 2 full rotations
}, {
duration: 2000,
// 2 seconds
easing: tween.easeOut
});
// No life lost, just stunning effect
} else if (obstacle.blocking) {
// Barrier - damages vehicle and pushes it back
lives--;
LK.getSound('crash').play();
// Push vehicle back slightly
vehicle.targetX = vehicle.x + (Math.random() - 0.5) * 200;
} else {
// Regular obstacle
lives--;
LK.effects.flashScreen(0xff0000, 500);
LK.getSound('crash').play();
}
// Hide a heart icon for regular, deadly, and blocking obstacles
if (!obstacle.slippery && !obstacle.stunEffect && lives >= 0 && lives < heartIcons.length) {
heartIcons[heartIcons.length - 1 - lives].visible = false;
}
// Activate invincibility for 1 second after any collision
vehicleInvincible = true;
vehicleInvincibleEndTime = LK.ticks + 60; // 1 second at 60 FPS
// Add flashing effect during invincibility
tween(vehicle, {
alpha: 0.3
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
if (vehicleInvincible) {
tween(vehicle, {
alpha: 1.0
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
if (vehicleInvincible) {
// Continue flashing by calling this recursively
tween(vehicle, {
alpha: 0.3
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
if (vehicleInvincible) {
tween(vehicle, {
alpha: 1.0
}, {
duration: 100
});
}
}
});
}
}
});
}
}
});
// Remove the obstacle that was hit
obstacle.destroy();
obstacles.splice(i, 1);
// Check if game over
if (lives <= 0) {
gameRunning = false;
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
return;
}
continue;
}
}
};
un propulsor turbo de carreras que expulse fuego con perspectiva hacia arriba In-Game asset. 2d. High contrast. No shadows
carretera oscura con perspectiva desde arriba. In-Game asset. 2d. High contrast. No shadows
carro azul deportivo con la perspectiva hacia arriba. In-Game asset. 2d. High contrast. No shadows hecho con pixeles acelerando con perspectiva trasera sin el rastro
un carro rojo deportivo con la perspectiva hacia arriba. In-Game asset. 2d. High contrast. No shadows hecho con pixeles
tres corazones hechos con pixeles. In-Game asset. 2d. High contrast. No shadows
un coche blanco deportivo hecho con pixeles con perspectiva desde arriba de la parte trasera. In-Game asset. 2d. High contrast. No shadows
tira de puas hecho con pixeles. In-Game asset. 2d. High contrast. No shadows
boton rojo hecho con pixeles con la palabra play en medio In-Game asset. 2d. High contrast. No shadows
un auto verde deportivo con perspectiva desde arriba hecho con pixeles. In-Game asset. 2d. High contrast. No shadows con perspectiva trasera
un auto amarillo deportivo con perspectiva desde arriba hecho con pixeles. In-Game asset. 2d. High contrast. No shadows con perspectiva trasera
un auto negro deportivo hecho con pixeles con la perspectiva desde arriba y trasera. In-Game asset. 2d. High contrast. No shadows
agujero de la calle hecho con pixeles. In-Game asset. 2d. High contrast. No shadows
un barril derramando petroleo negro hecho con pixeles In-Game asset. 2d. High contrast. No shadows
coche de policia hecho con pixeles con perspectiva desde arriba In-Game asset. 2d. High contrast. No shadows
motociclista de chaqueta negra hecha con pixeles con perspectiva desde arriba y trasera. In-Game asset. 2d. High contrast. No shadows
auto celeste deportivo con perspectiva desde arriba y trasera hecho con pixeles. In-Game asset. 2d. High contrast. No shadows
letras que dicen speed runner las letras speed tienen un color blanco con contorno negro y las letras runner un color celeste con un contorno azul todo hecho con pixeles y con una cursiva. In-Game asset. 2d. High contrast. No shadows