/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ var Collectible = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'coin'; var collectibleGraphics = self.attachAsset(self.type, { anchorX: 0.5, anchorY: 0.5 }); self.lane = Math.floor(Math.random() * 3); // 0, 1, 2 for left, center, right self.speed = 4 + Math.random() * 2; self.update = function () { self.y += self.speed; // Rotate coins for visual effect if (self.type === 'coin') { collectibleGraphics.rotation += 0.05; } }; return self; }); var GrassTile = Container.expand(function () { var self = Container.call(this); // Main grass tile var grassBase = self.attachAsset('grassTile', { anchorX: 0.5, anchorY: 0.5 }); // Add random grass dots for texture var dotCount = Math.floor(1 + Math.random() * 3); for (var i = 0; i < dotCount; i++) { var dot = LK.getAsset('grassDot', { anchorX: 0.5, anchorY: 0.5, x: -30 + Math.random() * 60, y: -30 + Math.random() * 60 }); // Slightly vary the color of dots for more texture dot.tint = Math.random() > 0.5 ? 0x7CFC00 : 0x98FB98; self.addChild(dot); } // Grass tiles move with the road but slower self.speed = roadSpeed * 0.2; self.update = function () { self.y += self.speed; }; return self; }); var House = Container.expand(function () { var self = Container.call(this); // Randomize house properties var width = 100 + Math.random() * 100; var height = 150 + Math.random() * 250; var color = Math.random() > 0.5 ? 0x555555 : 0x777777; // Different gray shades // Main building var building = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 1.0, // Bottom anchor for proper ground alignment width: width, height: height, tint: color }); // Add windows (simplified 8-bit style) var windowCount = Math.floor(2 + Math.random() * 4); var floors = Math.floor(2 + Math.random() * 5); for (var f = 0; f < floors; f++) { for (var w = 0; w < windowCount; w++) { var windowObj = LK.getAsset('obstacle', { anchorX: 0.5, anchorY: 0.5, width: 15, height: 20, tint: Math.random() > 0.2 ? 0xFFFF99 : 0x333333, // Some windows lit, some dark x: (w - (windowCount - 1) / 2) * (width / windowCount), y: -height + 30 + f * (height / (floors + 1)) }); self.addChild(windowObj); } } // Add a roof (optional, for some variation) if (Math.random() > 0.3) { var roof = LK.getAsset('obstacle', { anchorX: 0.5, anchorY: 1.0, width: width + 20, height: 25, tint: 0x883333, // Reddish roof color y: -height }); self.addChild(roof); } // Lane is used for positioning (off the main road) self.lane = Math.random() > 0.5 ? -1 : 2; // Either far left or far right self.speed = roadSpeed * 0.4; // Houses move slower than the road to create parallax self.update = function () { self.y += self.speed; }; return self; }); // (Obstacle/mud class removed) var PlayerCar = Container.expand(function () { var self = Container.call(this); // Create an 8-bit style car with multiple sprites self.carContainer = new Container(); self.addChild(self.carContainer); // Car body - main part var carBody = self.carContainer.attachAsset('playerCarBody', { anchorX: 0.5, anchorY: 0.5 }); // Car window - top part of the car var carWindow = LK.getAsset('playerCarWindow', { anchorX: 0.5, anchorY: 0.5, y: -35 }); self.carContainer.addChild(carWindow); // Left front wheel var leftFrontWheel = LK.getAsset('playerCarWheel', { anchorX: 0.5, anchorY: 0.5, x: -35, y: -40 }); self.carContainer.addChild(leftFrontWheel); // Right front wheel var rightFrontWheel = LK.getAsset('playerCarWheel', { anchorX: 0.5, anchorY: 0.5, x: 35, y: -40 }); self.carContainer.addChild(rightFrontWheel); // Left rear wheel var leftRearWheel = LK.getAsset('playerCarWheel', { anchorX: 0.5, anchorY: 0.5, x: -35, y: 40 }); self.carContainer.addChild(leftRearWheel); // Right rear wheel var rightRearWheel = LK.getAsset('playerCarWheel', { anchorX: 0.5, anchorY: 0.5, x: 35, y: 40 }); self.carContainer.addChild(rightRearWheel); // Left headlight var leftHeadlight = LK.getAsset('playerCarLight', { anchorX: 0.5, anchorY: 0.5, x: -25, y: -65 }); self.carContainer.addChild(leftHeadlight); // Right headlight var rightHeadlight = LK.getAsset('playerCarLight', { anchorX: 0.5, anchorY: 0.5, x: 25, y: -65 }); self.carContainer.addChild(rightHeadlight); // Front grill var grill = LK.getAsset('playerCarGrill', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -50 }); self.carContainer.addChild(grill); self.lane = 1; // 0, 1, 2 for left, center, right self.speed = 5; self.isInvincible = false; self.invincibleTime = 0; self.setInvincible = function (duration) { self.isInvincible = true; self.invincibleTime = duration; // Flash effect for invincibility var flashInterval = LK.setInterval(function () { self.carContainer.alpha = self.carContainer.alpha === 1 ? 0.5 : 1; }, 100); LK.setTimeout(function () { self.isInvincible = false; self.carContainer.alpha = 1; LK.clearInterval(flashInterval); }, duration); }; return self; }); var RoadLine = Container.expand(function () { var self = Container.call(this); var lineGraphics = self.attachAsset('roadLine', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.update = function () { self.y += self.speed; }; return self; }); var TrafficCar = Container.expand(function () { var self = Container.call(this); // Create a container for the truck parts self.truckContainer = new Container(); self.addChild(self.truckContainer); // Randomize between police vehicle and regular truck var isPolice = Math.random() < 0.2; var mainColor = isPolice ? 'policeCar' : 'trafficCar'; // Main truck body (larger than regular cars) var truckBody = self.truckContainer.attachAsset(mainColor, { anchorX: 0.5, anchorY: 0.5, scaleY: 1.1 }); // Truck cabin (upper part) var truckCabin = LK.getAsset(mainColor === 'policeCar' ? 'policeCar' : 'trafficCar', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.5, y: -65 }); self.truckContainer.addChild(truckCabin); // Add truck wheels (16-bit style as squares) var leftFrontWheel = LK.getAsset('playerCarWheel', { anchorX: 0.5, anchorY: 0.5, x: -40, y: -35, scaleX: 1.1 }); self.truckContainer.addChild(leftFrontWheel); var rightFrontWheel = LK.getAsset('playerCarWheel', { anchorX: 0.5, anchorY: 0.5, x: 40, y: -35, scaleX: 1.1 }); self.truckContainer.addChild(rightFrontWheel); var leftRearWheel = LK.getAsset('playerCarWheel', { anchorX: 0.5, anchorY: 0.5, x: -40, y: 50, scaleX: 1.1 }); self.truckContainer.addChild(leftRearWheel); var rightRearWheel = LK.getAsset('playerCarWheel', { anchorX: 0.5, anchorY: 0.5, x: 40, y: 50, scaleX: 1.1 }); self.truckContainer.addChild(rightRearWheel); // Add truck headlights if (isPolice) { // Police light bar var policeLight = LK.getAsset('playerCarLight', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -80, scaleX: 3, scaleY: 0.8, tint: 0xff0000 }); self.truckContainer.addChild(policeLight); // Flash the police lights LK.setInterval(function () { policeLight.tint = policeLight.tint === 0xff0000 ? 0x0000ff : 0xff0000; }, 500); } else { // Regular truck headlights var leftHeadlight = LK.getAsset('playerCarLight', { anchorX: 0.5, anchorY: 0.5, x: -25, y: -80 }); self.truckContainer.addChild(leftHeadlight); var rightHeadlight = LK.getAsset('playerCarLight', { anchorX: 0.5, anchorY: 0.5, x: 25, y: -80 }); self.truckContainer.addChild(rightHeadlight); } // Add a cargo section for regular trucks if (!isPolice) { var truckCargo = LK.getAsset('trafficCar', { anchorX: 0.5, anchorY: 0.5, y: 30, scaleY: 0.4, tint: Math.random() > 0.5 ? 0x884400 : 0x777777 }); self.truckContainer.addChild(truckCargo); } self.lane = Math.floor(Math.random() * 3); // 0, 1, 2 for left, center, right // Traffic cars get faster as the game progresses self.baseSpeed = 3 + Math.random() * 2; self.speed = self.baseSpeed; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x228B22 // Forest green for grass base color }); /**** * Game Code ****/ // Create an 8-bit style race car using multiple shapes instead of a simple box // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var LANE_WIDTH = 250; var LANE_POSITIONS = [GAME_WIDTH / 2 - LANE_WIDTH, GAME_WIDTH / 2, GAME_WIDTH / 2 + LANE_WIDTH]; // Game variables var isGameStarted = false; var score = 0; var distance = 0; var difficulty = 1; var lastTrafficSpawn = 0; var lastObstacleSpawn = 0; var lastCollectibleSpawn = 0; var lastRoadLineSpawn = 0; var lastGrassTileSpawn = 0; // Track last grass tile spawn time var roadSpeed = 10; var trafficCars = []; var obstacles = []; var collectibles = []; var roadLines = []; var houses = []; // Array to store house instances var grassTiles = []; // Array to store grass tiles var lastHouseSpawn = 0; // Track last house spawn time var lastBackgroundHouseSpawn = 0; // Track last background house spawn time var touchStartX = 0; var touchStartY = 0; var playerCar; var scoreTxt; var highScoreTxt; var readyTxt; // Create road background // (spawnObstacle function removed) var roadBackground = LK.getAsset('roadBackground', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2, width: 800, height: GAME_HEIGHT }); game.addChild(roadBackground); // Initialize player car playerCar = new PlayerCar(); playerCar.x = LANE_POSITIONS[playerCar.lane]; playerCar.y = GAME_HEIGHT - 300; game.addChild(playerCar); // Create score display scoreTxt = new Text2('SCORE: 0', { size: 70, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -scoreTxt.width - 20; scoreTxt.y = 20; // Create speed display speedTxt = new Text2('SPEED: 10', { size: 50, fill: 0x00FFFF }); speedTxt.anchor.set(0, 0); LK.gui.topRight.addChild(speedTxt); speedTxt.x = -speedTxt.width - 20; speedTxt.y = 170; // Create high score display highScoreTxt = new Text2('HIGH SCORE: ' + storage.highScore, { size: 50, fill: 0xFFFF00 }); highScoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(highScoreTxt); highScoreTxt.x = -highScoreTxt.width - 20; highScoreTxt.y = 100; // Create ready text readyTxt = new Text2('TAP TO START', { size: 100, fill: 0xFFFFFF }); readyTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(readyTxt); // Start game music LK.playMusic('raceMusic', { fade: { start: 0, end: 1, duration: 1000 } }); // Handle game touch events game.down = function (x, y, obj) { if (!isGameStarted) { startGame(); return; } touchStartX = x; touchStartY = y; }; game.up = function (x, y, obj) { if (!isGameStarted) { return; } var deltaX = x - touchStartX; var deltaY = y - touchStartY; // If more horizontal than vertical movement if (Math.abs(deltaX) > Math.abs(deltaY)) { if (deltaX > 50 && playerCar.lane < 2) { // Swipe right playerCar.lane++; tween(playerCar, { x: LANE_POSITIONS[playerCar.lane] }, { duration: 200, easing: tween.easeOut }); } else if (deltaX < -50 && playerCar.lane > 0) { // Swipe left playerCar.lane--; tween(playerCar, { x: LANE_POSITIONS[playerCar.lane] }, { duration: 200, easing: tween.easeOut }); } } }; game.move = function (x, y, obj) { // Not using move for this game }; function startGame() { isGameStarted = true; score = 0; distance = 0; difficulty = 1; roadSpeed = 10; // Reset arrays clearGameObjects(); // Hide ready text LK.gui.center.removeChild(readyTxt); // Update score display updateScoreDisplay(); } function clearGameObjects() { // Clear traffic cars for (var i = trafficCars.length - 1; i >= 0; i--) { trafficCars[i].destroy(); trafficCars.splice(i, 1); } // (obstacle clearing removed) // Clear collectibles for (var i = collectibles.length - 1; i >= 0; i--) { collectibles[i].destroy(); collectibles.splice(i, 1); } // Clear road lines for (var i = roadLines.length - 1; i >= 0; i--) { roadLines[i].destroy(); roadLines.splice(i, 1); } // Clear houses for (var i = houses.length - 1; i >= 0; i--) { houses[i].destroy(); houses.splice(i, 1); } // Clear grass tiles for (var i = grassTiles.length - 1; i >= 0; i--) { grassTiles[i].destroy(); grassTiles.splice(i, 1); } } function spawnTrafficCar() { var trafficCar = new TrafficCar(); trafficCar.x = LANE_POSITIONS[trafficCar.lane]; trafficCar.y = -200; trafficCars.push(trafficCar); game.addChild(trafficCar); } function spawnCollectible() { var type = Math.random() < 0.2 ? 'speedBoost' : 'coin'; var collectible = new Collectible(type); collectible.x = LANE_POSITIONS[collectible.lane]; collectible.y = -200; collectibles.push(collectible); game.addChild(collectible); } function spawnRoadLine() { var leftLine = new RoadLine(); leftLine.x = GAME_WIDTH / 2 - LANE_WIDTH / 2 - 125; leftLine.y = -100; roadLines.push(leftLine); game.addChild(leftLine); var rightLine = new RoadLine(); rightLine.x = GAME_WIDTH / 2 + LANE_WIDTH / 2 + 125; rightLine.y = -100; roadLines.push(rightLine); game.addChild(rightLine); } function spawnHouse() { // Create multiple houses at once for a more populated city scenery var houseCount = 1 + Math.floor(Math.random() * 3); // Create 1-3 houses at once for (var i = 0; i < houseCount; i++) { var house = new House(); // Position houses far to the left or right of the road if (house.lane === -1) { // Far left with some variation in x position house.x = GAME_WIDTH / 2 - LANE_WIDTH * (2.5 + Math.random() * 1.5); } else { // Far right with some variation in x position house.x = GAME_WIDTH / 2 + LANE_WIDTH * (2.5 + Math.random() * 1.5); } // Vary the y position slightly to avoid houses appearing in straight lines house.y = -300 - i * 150 - Math.random() * 100; houses.push(house); // Add houses beneath the road to create a layered effect game.addChildAt(house, game.getChildIndex(roadBackground)); } } function spawnBackgroundHouses() { // Create distant background houses for additional depth var house = new House(); // Make the house smaller and more faded to give appearance of distance house.scale.set(0.7); house.alpha = 0.7; // Position houses very far to the left or right if (Math.random() > 0.5) { // Far left background house.x = GAME_WIDTH / 2 - LANE_WIDTH * (4 + Math.random() * 2); } else { // Far right background house.x = GAME_WIDTH / 2 + LANE_WIDTH * (4 + Math.random() * 2); } house.y = -300; houses.push(house); // Add background houses at the very bottom layer for proper depth perception game.addChildAt(house, 0); } function spawnGrassTiles() { // Create grass tiles for the whole width of the game var tilesPerRow = Math.ceil(GAME_WIDTH / 100); // 100 is the width of a tile for (var i = 0; i < tilesPerRow; i++) { var grassTile = new GrassTile(); grassTile.x = i * 100; grassTile.y = -100; // Start above the screen grassTiles.push(grassTile); // Add grass tiles below everything for proper layering game.addChildAt(grassTile, 0); } } function updateScoreDisplay() { scoreTxt.setText('SCORE: ' + Math.floor(score)); scoreTxt.x = -scoreTxt.width - 20; // Update speed display speedTxt.setText('SPEED: ' + Math.floor(roadSpeed)); speedTxt.x = -speedTxt.width - 20; // Color the speed text based on speed value - faster = more red var r = Math.min(255, Math.floor(roadSpeed * 10)); var g = 255 - Math.min(255, Math.floor(roadSpeed * 5)); var b = 255; var speedColor = r << 16 | g << 8 | b; // Update high score if needed if (score > storage.highScore) { storage.highScore = Math.floor(score); // Save high score to storage storage.highScore = storage.highScore; highScoreTxt.setText('HIGH SCORE: ' + storage.highScore); highScoreTxt.x = -highScoreTxt.width - 20; } } function checkCollisions() { // Check collision with traffic cars for (var i = trafficCars.length - 1; i >= 0; i--) { if (playerCar.intersects(trafficCars[i]) && !playerCar.isInvincible) { LK.getSound('crash').play(); LK.effects.flashScreen(0xff0000, 500); LK.showGameOver(); return; } } // (obstacle collision removed) // Check collision with collectibles for (var i = collectibles.length - 1; i >= 0; i--) { if (playerCar.intersects(collectibles[i])) { if (collectibles[i].type === 'coin') { score += 10; LK.getSound('coinCollect').play(); } else if (collectibles[i].type === 'speedBoost') { playerCar.setInvincible(3000); roadSpeed += 5; LK.setTimeout(function () { roadSpeed -= 5; }, 3000); LK.getSound('powerup').play(); } collectibles[i].destroy(); collectibles.splice(i, 1); updateScoreDisplay(); } } } game.update = function () { if (!isGameStarted) { return; } // Increase distance and score distance += roadSpeed / 10; score += 0.1 * difficulty; // Update difficulty based on distance and time passed - increase more aggressively difficulty = 1 + Math.floor(distance / 800) * 0.3 + LK.ticks / 2400; // Update road speed - increase speed more dramatically over time roadSpeed = 10 + Math.floor(distance / 400) + LK.ticks / 450; // Spawn game objects // Spawn traffic cars much more frequently as time progresses var trafficSpawnRate = Math.max(40, 120 - difficulty * 15 - LK.ticks / 800); if (LK.ticks - lastTrafficSpawn > trafficSpawnRate) { spawnTrafficCar(); lastTrafficSpawn = LK.ticks; } // (obstacle spawning removed) if (LK.ticks - lastCollectibleSpawn > 90) { spawnCollectible(); lastCollectibleSpawn = LK.ticks; } if (LK.ticks - lastRoadLineSpawn > 30) { spawnRoadLine(); lastRoadLineSpawn = LK.ticks; } // Spawn houses more frequently to create a dense city environment if (LK.ticks - lastHouseSpawn > 100) { // Reduced from 180 to 100 spawnHouse(); lastHouseSpawn = LK.ticks; } // Spawn grass tiles for 8-bit grass background if (LK.ticks - lastGrassTileSpawn > 40) { spawnGrassTiles(); lastGrassTileSpawn = LK.ticks; } // Spawn additional background houses for depth if (LK.ticks - lastBackgroundHouseSpawn > 150) { spawnBackgroundHouses(); lastBackgroundHouseSpawn = LK.ticks; } // Update road lines for (var i = roadLines.length - 1; i >= 0; i--) { roadLines[i].speed = roadSpeed; roadLines[i].update(); if (roadLines[i].y > GAME_HEIGHT + 100) { roadLines[i].destroy(); roadLines.splice(i, 1); } } // Update traffic cars - speed increases with game time for (var i = trafficCars.length - 1; i >= 0; i--) { // Speed factor increases with time more aggressively var timeFactor = 0.7 + LK.ticks / 15000; // Add variety to traffic car speeds based on game time var speedVariation = Math.random() * 0.3 * (1 + LK.ticks / 30000); trafficCars[i].speed = roadSpeed * Math.min(timeFactor, 1.8) * (1 - speedVariation); trafficCars[i].update(); if (trafficCars[i].y > GAME_HEIGHT + 200) { trafficCars[i].destroy(); trafficCars.splice(i, 1); } } // (obstacle update and cleanup removed) // Update collectibles for (var i = collectibles.length - 1; i >= 0; i--) { collectibles[i].speed = roadSpeed * 0.8; collectibles[i].update(); if (collectibles[i].y > GAME_HEIGHT + 100) { collectibles[i].destroy(); collectibles.splice(i, 1); } } // Update houses for (var i = houses.length - 1; i >= 0; i--) { houses[i].speed = roadSpeed * 0.4; // Slower movement for parallax effect houses[i].update(); if (houses[i].y > GAME_HEIGHT + 300) { houses[i].destroy(); houses.splice(i, 1); } } // Update grass tiles for (var i = grassTiles.length - 1; i >= 0; i--) { grassTiles[i].speed = roadSpeed * 0.2; // Very slow movement for distant background effect grassTiles[i].update(); if (grassTiles[i].y > GAME_HEIGHT + 100) { grassTiles[i].destroy(); grassTiles.splice(i, 1); } } // Check collisions checkCollisions(); // Decrease invincible time if (playerCar.isInvincible && playerCar.invincibleTime > 0) { playerCar.invincibleTime -= 16.67; // ~60fps } // Update score display every second if (LK.ticks % 60 === 0) { updateScoreDisplay(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Collectible = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'coin';
var collectibleGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = Math.floor(Math.random() * 3); // 0, 1, 2 for left, center, right
self.speed = 4 + Math.random() * 2;
self.update = function () {
self.y += self.speed;
// Rotate coins for visual effect
if (self.type === 'coin') {
collectibleGraphics.rotation += 0.05;
}
};
return self;
});
var GrassTile = Container.expand(function () {
var self = Container.call(this);
// Main grass tile
var grassBase = self.attachAsset('grassTile', {
anchorX: 0.5,
anchorY: 0.5
});
// Add random grass dots for texture
var dotCount = Math.floor(1 + Math.random() * 3);
for (var i = 0; i < dotCount; i++) {
var dot = LK.getAsset('grassDot', {
anchorX: 0.5,
anchorY: 0.5,
x: -30 + Math.random() * 60,
y: -30 + Math.random() * 60
});
// Slightly vary the color of dots for more texture
dot.tint = Math.random() > 0.5 ? 0x7CFC00 : 0x98FB98;
self.addChild(dot);
}
// Grass tiles move with the road but slower
self.speed = roadSpeed * 0.2;
self.update = function () {
self.y += self.speed;
};
return self;
});
var House = Container.expand(function () {
var self = Container.call(this);
// Randomize house properties
var width = 100 + Math.random() * 100;
var height = 150 + Math.random() * 250;
var color = Math.random() > 0.5 ? 0x555555 : 0x777777; // Different gray shades
// Main building
var building = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
// Bottom anchor for proper ground alignment
width: width,
height: height,
tint: color
});
// Add windows (simplified 8-bit style)
var windowCount = Math.floor(2 + Math.random() * 4);
var floors = Math.floor(2 + Math.random() * 5);
for (var f = 0; f < floors; f++) {
for (var w = 0; w < windowCount; w++) {
var windowObj = LK.getAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
width: 15,
height: 20,
tint: Math.random() > 0.2 ? 0xFFFF99 : 0x333333,
// Some windows lit, some dark
x: (w - (windowCount - 1) / 2) * (width / windowCount),
y: -height + 30 + f * (height / (floors + 1))
});
self.addChild(windowObj);
}
}
// Add a roof (optional, for some variation)
if (Math.random() > 0.3) {
var roof = LK.getAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
width: width + 20,
height: 25,
tint: 0x883333,
// Reddish roof color
y: -height
});
self.addChild(roof);
}
// Lane is used for positioning (off the main road)
self.lane = Math.random() > 0.5 ? -1 : 2; // Either far left or far right
self.speed = roadSpeed * 0.4; // Houses move slower than the road to create parallax
self.update = function () {
self.y += self.speed;
};
return self;
});
// (Obstacle/mud class removed)
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
// Create an 8-bit style car with multiple sprites
self.carContainer = new Container();
self.addChild(self.carContainer);
// Car body - main part
var carBody = self.carContainer.attachAsset('playerCarBody', {
anchorX: 0.5,
anchorY: 0.5
});
// Car window - top part of the car
var carWindow = LK.getAsset('playerCarWindow', {
anchorX: 0.5,
anchorY: 0.5,
y: -35
});
self.carContainer.addChild(carWindow);
// Left front wheel
var leftFrontWheel = LK.getAsset('playerCarWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: -35,
y: -40
});
self.carContainer.addChild(leftFrontWheel);
// Right front wheel
var rightFrontWheel = LK.getAsset('playerCarWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: 35,
y: -40
});
self.carContainer.addChild(rightFrontWheel);
// Left rear wheel
var leftRearWheel = LK.getAsset('playerCarWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: -35,
y: 40
});
self.carContainer.addChild(leftRearWheel);
// Right rear wheel
var rightRearWheel = LK.getAsset('playerCarWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: 35,
y: 40
});
self.carContainer.addChild(rightRearWheel);
// Left headlight
var leftHeadlight = LK.getAsset('playerCarLight', {
anchorX: 0.5,
anchorY: 0.5,
x: -25,
y: -65
});
self.carContainer.addChild(leftHeadlight);
// Right headlight
var rightHeadlight = LK.getAsset('playerCarLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 25,
y: -65
});
self.carContainer.addChild(rightHeadlight);
// Front grill
var grill = LK.getAsset('playerCarGrill', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50
});
self.carContainer.addChild(grill);
self.lane = 1; // 0, 1, 2 for left, center, right
self.speed = 5;
self.isInvincible = false;
self.invincibleTime = 0;
self.setInvincible = function (duration) {
self.isInvincible = true;
self.invincibleTime = duration;
// Flash effect for invincibility
var flashInterval = LK.setInterval(function () {
self.carContainer.alpha = self.carContainer.alpha === 1 ? 0.5 : 1;
}, 100);
LK.setTimeout(function () {
self.isInvincible = false;
self.carContainer.alpha = 1;
LK.clearInterval(flashInterval);
}, duration);
};
return self;
});
var RoadLine = Container.expand(function () {
var self = Container.call(this);
var lineGraphics = self.attachAsset('roadLine', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
var TrafficCar = Container.expand(function () {
var self = Container.call(this);
// Create a container for the truck parts
self.truckContainer = new Container();
self.addChild(self.truckContainer);
// Randomize between police vehicle and regular truck
var isPolice = Math.random() < 0.2;
var mainColor = isPolice ? 'policeCar' : 'trafficCar';
// Main truck body (larger than regular cars)
var truckBody = self.truckContainer.attachAsset(mainColor, {
anchorX: 0.5,
anchorY: 0.5,
scaleY: 1.1
});
// Truck cabin (upper part)
var truckCabin = LK.getAsset(mainColor === 'policeCar' ? 'policeCar' : 'trafficCar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.5,
y: -65
});
self.truckContainer.addChild(truckCabin);
// Add truck wheels (16-bit style as squares)
var leftFrontWheel = LK.getAsset('playerCarWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: -40,
y: -35,
scaleX: 1.1
});
self.truckContainer.addChild(leftFrontWheel);
var rightFrontWheel = LK.getAsset('playerCarWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: 40,
y: -35,
scaleX: 1.1
});
self.truckContainer.addChild(rightFrontWheel);
var leftRearWheel = LK.getAsset('playerCarWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: -40,
y: 50,
scaleX: 1.1
});
self.truckContainer.addChild(leftRearWheel);
var rightRearWheel = LK.getAsset('playerCarWheel', {
anchorX: 0.5,
anchorY: 0.5,
x: 40,
y: 50,
scaleX: 1.1
});
self.truckContainer.addChild(rightRearWheel);
// Add truck headlights
if (isPolice) {
// Police light bar
var policeLight = LK.getAsset('playerCarLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -80,
scaleX: 3,
scaleY: 0.8,
tint: 0xff0000
});
self.truckContainer.addChild(policeLight);
// Flash the police lights
LK.setInterval(function () {
policeLight.tint = policeLight.tint === 0xff0000 ? 0x0000ff : 0xff0000;
}, 500);
} else {
// Regular truck headlights
var leftHeadlight = LK.getAsset('playerCarLight', {
anchorX: 0.5,
anchorY: 0.5,
x: -25,
y: -80
});
self.truckContainer.addChild(leftHeadlight);
var rightHeadlight = LK.getAsset('playerCarLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 25,
y: -80
});
self.truckContainer.addChild(rightHeadlight);
}
// Add a cargo section for regular trucks
if (!isPolice) {
var truckCargo = LK.getAsset('trafficCar', {
anchorX: 0.5,
anchorY: 0.5,
y: 30,
scaleY: 0.4,
tint: Math.random() > 0.5 ? 0x884400 : 0x777777
});
self.truckContainer.addChild(truckCargo);
}
self.lane = Math.floor(Math.random() * 3); // 0, 1, 2 for left, center, right
// Traffic cars get faster as the game progresses
self.baseSpeed = 3 + Math.random() * 2;
self.speed = self.baseSpeed;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22 // Forest green for grass base color
});
/****
* Game Code
****/
// Create an 8-bit style race car using multiple shapes instead of a simple box
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var LANE_WIDTH = 250;
var LANE_POSITIONS = [GAME_WIDTH / 2 - LANE_WIDTH, GAME_WIDTH / 2, GAME_WIDTH / 2 + LANE_WIDTH];
// Game variables
var isGameStarted = false;
var score = 0;
var distance = 0;
var difficulty = 1;
var lastTrafficSpawn = 0;
var lastObstacleSpawn = 0;
var lastCollectibleSpawn = 0;
var lastRoadLineSpawn = 0;
var lastGrassTileSpawn = 0; // Track last grass tile spawn time
var roadSpeed = 10;
var trafficCars = [];
var obstacles = [];
var collectibles = [];
var roadLines = [];
var houses = []; // Array to store house instances
var grassTiles = []; // Array to store grass tiles
var lastHouseSpawn = 0; // Track last house spawn time
var lastBackgroundHouseSpawn = 0; // Track last background house spawn time
var touchStartX = 0;
var touchStartY = 0;
var playerCar;
var scoreTxt;
var highScoreTxt;
var readyTxt;
// Create road background
// (spawnObstacle function removed)
var roadBackground = LK.getAsset('roadBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2,
width: 800,
height: GAME_HEIGHT
});
game.addChild(roadBackground);
// Initialize player car
playerCar = new PlayerCar();
playerCar.x = LANE_POSITIONS[playerCar.lane];
playerCar.y = GAME_HEIGHT - 300;
game.addChild(playerCar);
// Create score display
scoreTxt = new Text2('SCORE: 0', {
size: 70,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -scoreTxt.width - 20;
scoreTxt.y = 20;
// Create speed display
speedTxt = new Text2('SPEED: 10', {
size: 50,
fill: 0x00FFFF
});
speedTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(speedTxt);
speedTxt.x = -speedTxt.width - 20;
speedTxt.y = 170;
// Create high score display
highScoreTxt = new Text2('HIGH SCORE: ' + storage.highScore, {
size: 50,
fill: 0xFFFF00
});
highScoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(highScoreTxt);
highScoreTxt.x = -highScoreTxt.width - 20;
highScoreTxt.y = 100;
// Create ready text
readyTxt = new Text2('TAP TO START', {
size: 100,
fill: 0xFFFFFF
});
readyTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(readyTxt);
// Start game music
LK.playMusic('raceMusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
// Handle game touch events
game.down = function (x, y, obj) {
if (!isGameStarted) {
startGame();
return;
}
touchStartX = x;
touchStartY = y;
};
game.up = function (x, y, obj) {
if (!isGameStarted) {
return;
}
var deltaX = x - touchStartX;
var deltaY = y - touchStartY;
// If more horizontal than vertical movement
if (Math.abs(deltaX) > Math.abs(deltaY)) {
if (deltaX > 50 && playerCar.lane < 2) {
// Swipe right
playerCar.lane++;
tween(playerCar, {
x: LANE_POSITIONS[playerCar.lane]
}, {
duration: 200,
easing: tween.easeOut
});
} else if (deltaX < -50 && playerCar.lane > 0) {
// Swipe left
playerCar.lane--;
tween(playerCar, {
x: LANE_POSITIONS[playerCar.lane]
}, {
duration: 200,
easing: tween.easeOut
});
}
}
};
game.move = function (x, y, obj) {
// Not using move for this game
};
function startGame() {
isGameStarted = true;
score = 0;
distance = 0;
difficulty = 1;
roadSpeed = 10;
// Reset arrays
clearGameObjects();
// Hide ready text
LK.gui.center.removeChild(readyTxt);
// Update score display
updateScoreDisplay();
}
function clearGameObjects() {
// Clear traffic cars
for (var i = trafficCars.length - 1; i >= 0; i--) {
trafficCars[i].destroy();
trafficCars.splice(i, 1);
}
// (obstacle clearing removed)
// Clear collectibles
for (var i = collectibles.length - 1; i >= 0; i--) {
collectibles[i].destroy();
collectibles.splice(i, 1);
}
// Clear road lines
for (var i = roadLines.length - 1; i >= 0; i--) {
roadLines[i].destroy();
roadLines.splice(i, 1);
}
// Clear houses
for (var i = houses.length - 1; i >= 0; i--) {
houses[i].destroy();
houses.splice(i, 1);
}
// Clear grass tiles
for (var i = grassTiles.length - 1; i >= 0; i--) {
grassTiles[i].destroy();
grassTiles.splice(i, 1);
}
}
function spawnTrafficCar() {
var trafficCar = new TrafficCar();
trafficCar.x = LANE_POSITIONS[trafficCar.lane];
trafficCar.y = -200;
trafficCars.push(trafficCar);
game.addChild(trafficCar);
}
function spawnCollectible() {
var type = Math.random() < 0.2 ? 'speedBoost' : 'coin';
var collectible = new Collectible(type);
collectible.x = LANE_POSITIONS[collectible.lane];
collectible.y = -200;
collectibles.push(collectible);
game.addChild(collectible);
}
function spawnRoadLine() {
var leftLine = new RoadLine();
leftLine.x = GAME_WIDTH / 2 - LANE_WIDTH / 2 - 125;
leftLine.y = -100;
roadLines.push(leftLine);
game.addChild(leftLine);
var rightLine = new RoadLine();
rightLine.x = GAME_WIDTH / 2 + LANE_WIDTH / 2 + 125;
rightLine.y = -100;
roadLines.push(rightLine);
game.addChild(rightLine);
}
function spawnHouse() {
// Create multiple houses at once for a more populated city scenery
var houseCount = 1 + Math.floor(Math.random() * 3); // Create 1-3 houses at once
for (var i = 0; i < houseCount; i++) {
var house = new House();
// Position houses far to the left or right of the road
if (house.lane === -1) {
// Far left with some variation in x position
house.x = GAME_WIDTH / 2 - LANE_WIDTH * (2.5 + Math.random() * 1.5);
} else {
// Far right with some variation in x position
house.x = GAME_WIDTH / 2 + LANE_WIDTH * (2.5 + Math.random() * 1.5);
}
// Vary the y position slightly to avoid houses appearing in straight lines
house.y = -300 - i * 150 - Math.random() * 100;
houses.push(house);
// Add houses beneath the road to create a layered effect
game.addChildAt(house, game.getChildIndex(roadBackground));
}
}
function spawnBackgroundHouses() {
// Create distant background houses for additional depth
var house = new House();
// Make the house smaller and more faded to give appearance of distance
house.scale.set(0.7);
house.alpha = 0.7;
// Position houses very far to the left or right
if (Math.random() > 0.5) {
// Far left background
house.x = GAME_WIDTH / 2 - LANE_WIDTH * (4 + Math.random() * 2);
} else {
// Far right background
house.x = GAME_WIDTH / 2 + LANE_WIDTH * (4 + Math.random() * 2);
}
house.y = -300;
houses.push(house);
// Add background houses at the very bottom layer for proper depth perception
game.addChildAt(house, 0);
}
function spawnGrassTiles() {
// Create grass tiles for the whole width of the game
var tilesPerRow = Math.ceil(GAME_WIDTH / 100); // 100 is the width of a tile
for (var i = 0; i < tilesPerRow; i++) {
var grassTile = new GrassTile();
grassTile.x = i * 100;
grassTile.y = -100; // Start above the screen
grassTiles.push(grassTile);
// Add grass tiles below everything for proper layering
game.addChildAt(grassTile, 0);
}
}
function updateScoreDisplay() {
scoreTxt.setText('SCORE: ' + Math.floor(score));
scoreTxt.x = -scoreTxt.width - 20;
// Update speed display
speedTxt.setText('SPEED: ' + Math.floor(roadSpeed));
speedTxt.x = -speedTxt.width - 20;
// Color the speed text based on speed value - faster = more red
var r = Math.min(255, Math.floor(roadSpeed * 10));
var g = 255 - Math.min(255, Math.floor(roadSpeed * 5));
var b = 255;
var speedColor = r << 16 | g << 8 | b;
// Update high score if needed
if (score > storage.highScore) {
storage.highScore = Math.floor(score);
// Save high score to storage
storage.highScore = storage.highScore;
highScoreTxt.setText('HIGH SCORE: ' + storage.highScore);
highScoreTxt.x = -highScoreTxt.width - 20;
}
}
function checkCollisions() {
// Check collision with traffic cars
for (var i = trafficCars.length - 1; i >= 0; i--) {
if (playerCar.intersects(trafficCars[i]) && !playerCar.isInvincible) {
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 500);
LK.showGameOver();
return;
}
}
// (obstacle collision removed)
// Check collision with collectibles
for (var i = collectibles.length - 1; i >= 0; i--) {
if (playerCar.intersects(collectibles[i])) {
if (collectibles[i].type === 'coin') {
score += 10;
LK.getSound('coinCollect').play();
} else if (collectibles[i].type === 'speedBoost') {
playerCar.setInvincible(3000);
roadSpeed += 5;
LK.setTimeout(function () {
roadSpeed -= 5;
}, 3000);
LK.getSound('powerup').play();
}
collectibles[i].destroy();
collectibles.splice(i, 1);
updateScoreDisplay();
}
}
}
game.update = function () {
if (!isGameStarted) {
return;
}
// Increase distance and score
distance += roadSpeed / 10;
score += 0.1 * difficulty;
// Update difficulty based on distance and time passed - increase more aggressively
difficulty = 1 + Math.floor(distance / 800) * 0.3 + LK.ticks / 2400;
// Update road speed - increase speed more dramatically over time
roadSpeed = 10 + Math.floor(distance / 400) + LK.ticks / 450;
// Spawn game objects
// Spawn traffic cars much more frequently as time progresses
var trafficSpawnRate = Math.max(40, 120 - difficulty * 15 - LK.ticks / 800);
if (LK.ticks - lastTrafficSpawn > trafficSpawnRate) {
spawnTrafficCar();
lastTrafficSpawn = LK.ticks;
}
// (obstacle spawning removed)
if (LK.ticks - lastCollectibleSpawn > 90) {
spawnCollectible();
lastCollectibleSpawn = LK.ticks;
}
if (LK.ticks - lastRoadLineSpawn > 30) {
spawnRoadLine();
lastRoadLineSpawn = LK.ticks;
}
// Spawn houses more frequently to create a dense city environment
if (LK.ticks - lastHouseSpawn > 100) {
// Reduced from 180 to 100
spawnHouse();
lastHouseSpawn = LK.ticks;
}
// Spawn grass tiles for 8-bit grass background
if (LK.ticks - lastGrassTileSpawn > 40) {
spawnGrassTiles();
lastGrassTileSpawn = LK.ticks;
}
// Spawn additional background houses for depth
if (LK.ticks - lastBackgroundHouseSpawn > 150) {
spawnBackgroundHouses();
lastBackgroundHouseSpawn = LK.ticks;
}
// Update road lines
for (var i = roadLines.length - 1; i >= 0; i--) {
roadLines[i].speed = roadSpeed;
roadLines[i].update();
if (roadLines[i].y > GAME_HEIGHT + 100) {
roadLines[i].destroy();
roadLines.splice(i, 1);
}
}
// Update traffic cars - speed increases with game time
for (var i = trafficCars.length - 1; i >= 0; i--) {
// Speed factor increases with time more aggressively
var timeFactor = 0.7 + LK.ticks / 15000;
// Add variety to traffic car speeds based on game time
var speedVariation = Math.random() * 0.3 * (1 + LK.ticks / 30000);
trafficCars[i].speed = roadSpeed * Math.min(timeFactor, 1.8) * (1 - speedVariation);
trafficCars[i].update();
if (trafficCars[i].y > GAME_HEIGHT + 200) {
trafficCars[i].destroy();
trafficCars.splice(i, 1);
}
}
// (obstacle update and cleanup removed)
// Update collectibles
for (var i = collectibles.length - 1; i >= 0; i--) {
collectibles[i].speed = roadSpeed * 0.8;
collectibles[i].update();
if (collectibles[i].y > GAME_HEIGHT + 100) {
collectibles[i].destroy();
collectibles.splice(i, 1);
}
}
// Update houses
for (var i = houses.length - 1; i >= 0; i--) {
houses[i].speed = roadSpeed * 0.4; // Slower movement for parallax effect
houses[i].update();
if (houses[i].y > GAME_HEIGHT + 300) {
houses[i].destroy();
houses.splice(i, 1);
}
}
// Update grass tiles
for (var i = grassTiles.length - 1; i >= 0; i--) {
grassTiles[i].speed = roadSpeed * 0.2; // Very slow movement for distant background effect
grassTiles[i].update();
if (grassTiles[i].y > GAME_HEIGHT + 100) {
grassTiles[i].destroy();
grassTiles.splice(i, 1);
}
}
// Check collisions
checkCollisions();
// Decrease invincible time
if (playerCar.isInvincible && playerCar.invincibleTime > 0) {
playerCar.invincibleTime -= 16.67; // ~60fps
}
// Update score display every second
if (LK.ticks % 60 === 0) {
updateScoreDisplay();
}
};