/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Banknote = Container.expand(function () { var self = Container.call(this); var banknoteAsset = self.attachAsset('banknote', { anchorX: 0.5, anchorY: 0.5 }); banknoteAsset.width = banknoteWidth; banknoteAsset.height = banknoteHeight; self.width = banknoteAsset.width; self.height = banknoteAsset.height; self.speedY = 0; self.update = function () { self.y += self.speedY; }; return self; }); // Coin for road var Coin = Container.expand(function () { var self = Container.call(this); // Use a simple yellow ellipse as the coin var coinAsset = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); coinAsset.width = coinWidth; coinAsset.height = coinHeight; self.width = coinAsset.width; self.height = coinAsset.height; self.speedY = 0; self.update = function () { self.y += self.speedY; }; return self; }); // Banknote (paper money) for road // Road Lane Marking var LaneMarking = Container.expand(function () { var self = Container.call(this); var marking = self.attachAsset('laneMarking', { anchorX: 0.5, anchorY: 0.5 }); marking.width = laneMarkingWidth; marking.height = laneMarkingHeight; self.width = marking.width; self.height = marking.height; self.speedY = 0; self.update = function () { self.y += self.speedY; }; return self; }); // Obstacle Car var ObstacleCar = Container.expand(function () { var self = Container.call(this); var carAsset = self.attachAsset('obstacleCar', { anchorX: 0.5, anchorY: 0.5 }); carAsset.width = obstacleCarWidth; carAsset.height = obstacleCarHeight; self.width = carAsset.width; self.height = carAsset.height; self.speedY = 0; // Vertical speed self.update = function () { self.y += self.speedY; }; return self; }); // Player's Car var PlayerCar = Container.expand(function () { var self = Container.call(this); var carAsset = self.attachAsset('playerCar', { anchorX: 0.5, anchorY: 0.5 }); carAsset.width = playerCarWidth; carAsset.height = playerCarHeight; self.width = carAsset.width; self.height = carAsset.height; self.speedX = 0; // Horizontal speed // Update method called every tick self.update = function () { // --- DRIFT/SKID EFFECT --- // Initialize drift/skid state variables if not present if (self.slideAngle === undefined) self.slideAngle = 0; if (self.targetAngle === undefined) self.targetAngle = 0; if (self.driftOffset === undefined) self.driftOffset = 0; if (self.driftTargetOffset === undefined) self.driftTargetOffset = 0; // Calculate target angle and lateral offset based on speedX (simulate drift) // The more the player turns, the more the car visually rotates and slides sideways var maxDriftAngle = Math.PI / 7; // maximum visual drift angle (radians) var maxDriftOffset = 60; // maximum sideways offset (pixels) var driftSpeed = 0.18; // how quickly the car rotates to the drift angle var offsetSpeed = 0.12; // how quickly the car slides to the drift offset // Set drift targets based on speedX if (self.speedX < -1) { self.targetAngle = -maxDriftAngle; self.driftTargetOffset = -maxDriftOffset; } else if (self.speedX > 1) { self.targetAngle = maxDriftAngle; self.driftTargetOffset = maxDriftOffset; } else { self.targetAngle = 0; self.driftTargetOffset = 0; } // Smoothly interpolate slideAngle and driftOffset towards their targets self.slideAngle += (self.targetAngle - self.slideAngle) * driftSpeed; self.driftOffset += (self.driftTargetOffset - self.driftOffset) * offsetSpeed; // Apply rotation and lateral offset to car asset (visual only, not affecting movement) if (self.children && self.children.length > 0) { self.children[0].rotation = self.slideAngle; self.children[0].x = self.driftOffset; } // Move car horizontally self.x += self.speedX; // Clamp to road bounds if (self.x < roadLeft + self.width / 2) self.x = roadLeft + self.width / 2; if (self.x > roadRight - self.width / 2) self.x = roadRight - self.width / 2; }; return self; }); // Tree for road edge var Tree = Container.expand(function () { var self = Container.call(this); var treeAsset = self.attachAsset('tree', { anchorX: 0.5, anchorY: 0.5 }); self.width = treeAsset.width; self.height = treeAsset.height; self.speedY = 0; self.update = function () { self.y += self.speedY; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Road dimensions // Banknote (paper money) for road var banknoteWidth = 120; var banknoteHeight = 60; var roadWidth = 900; var roadLeft = (2048 - roadWidth) / 2; var roadRight = roadLeft + roadWidth; // Lane count and positions var laneCount = 3; var laneWidth = roadWidth / laneCount; var laneCenters = [roadLeft + laneWidth / 2, roadLeft + laneWidth * 1.5, roadLeft + laneWidth * 2.5]; // Player and obstacle car size (equalized, made slightly larger) var playerCarWidth = 200; var playerCarHeight = 320; var obstacleCarWidth = 200; var obstacleCarHeight = 320; // Lane marking size var laneMarkingWidth = 54; var laneMarkingHeight = 330; // Tree size and spacing var treeWidth = 180; var treeHeight = 270; var treeSpacing = 220; // Asset initialization (shapes) // Game variables var playerCar; var obstacles = []; var laneMarkings = []; var trees = []; var coins = []; var banknotes = []; var coinSpawnTimer = 0; var coinSpawnInterval = 45; // frames, coins spawn more frequently var banknoteSpawnTimer = 0; var banknoteSpawnInterval = 120; // frames, less frequent than coins var coinWidth = 80; var coinHeight = 80; var obstacleSpawnTimer = 0; var obstacleSpawnInterval = 60; // frames var laneMarkingSpacing = 320; var speed = 18; // vertical speed (pixels per frame) var score = 0; var distance = 0; var isGameOver = false; // Add coin score indicator to the GUI var coinScoreTxt = new Text2('0', { size: 120, fill: 0xFFE066 }); coinScoreTxt.anchor.set(0.5, 0); // Centered at top // Place at top center, but not in the top left 100x100 px LK.gui.top.addChild(coinScoreTxt); // Initialize player car playerCar = new PlayerCar(); playerCar.x = laneCenters[1]; playerCar.y = 2732 - 400; game.addChild(playerCar); // Initialize lane markings as dashed (split into short segments) var dashLength = 80; var dashGap = 80; var dashesPerMarking = Math.floor(laneMarkingHeight / (dashLength + dashGap)); for (var i = 0; i < laneCount - 1; i++) { for (var j = 0; j < Math.ceil(2732 / laneMarkingSpacing) + 2; j++) { var baseY = j * laneMarkingSpacing - laneMarkingHeight / 2; for (var d = 0; d < dashesPerMarking; d++) { var marking = new LaneMarking(); marking.x = roadLeft + laneWidth * (i + 1); marking.y = baseY + d * (dashLength + dashGap); marking.speedY = speed; marking.height = dashLength; marking.width = laneMarkingWidth; laneMarkings.push(marking); game.addChild(marking); } } } // Initialize trees along both sides of the road (slightly more trees) for (var side = 0; side < 2; side++) { var xPos = side === 0 ? roadLeft - treeWidth / 2 - 30 : roadRight + treeWidth / 2 + 30; for (var j = 0; j < 6; j++) { // 6 trees per side! var tree = new Tree(); tree.x = xPos; tree.y = j * (2732 / 6) + 100; tree.speedY = speed; trees.push(tree); game.addChild(tree); } } // Touch controls var moveLeft = false; var moveRight = false; // Helper: get which side of the screen is pressed function getSide(x) { if (x < 2048 / 2) return 'left'; return 'right'; } // Touch down game.down = function (x, y, obj) { if (isGameOver) return; var side = getSide(x); if (side === 'left') { moveLeft = true; moveRight = false; } else { moveRight = true; moveLeft = false; } updatePlayerSpeed(); }; // Touch up game.up = function (x, y, obj) { moveLeft = false; moveRight = false; updatePlayerSpeed(); }; // Touch move (optional, for smoother control) game.move = function (x, y, obj) { if (isGameOver) return; var side = getSide(x); if (side === 'left') { moveLeft = true; moveRight = false; } else { moveRight = true; moveLeft = false; } updatePlayerSpeed(); }; // Update player car speedX based on input function updatePlayerSpeed() { if (moveLeft && !moveRight) { playerCar.speedX = -22; } else if (moveRight && !moveLeft) { playerCar.speedX = 22; } else { playerCar.speedX = 0; } } // Main game update loop game.update = function () { if (isGameOver) return; // Update lane markings for (var i = 0; i < laneMarkings.length; i++) { var marking = laneMarkings[i]; marking.speedY = speed; marking.update(); if (marking.y > 2732 + laneMarkingHeight / 2) { marking.y -= (Math.ceil(2732 / laneMarkingSpacing) + 2) * laneMarkingSpacing; } } // Update trees for (var i = 0; i < trees.length; i++) { var tree = trees[i]; tree.speedY = speed; tree.update(); if (tree.y > 2732 + treeHeight / 2) { tree.y -= (Math.ceil(2732 / treeSpacing) + 3) * treeSpacing; } } // Update player car playerCar.update(); // Spawn coins coinSpawnTimer++; if (coinSpawnTimer >= coinSpawnInterval) { coinSpawnTimer = 0; // Spawn coin in a random lane var coin = new Coin(); var laneIdx = Math.floor(Math.random() * laneCount); coin.x = laneCenters[laneIdx]; coin.y = -coinHeight / 2; coin.speedY = speed; coins.push(coin); game.addChild(coin); } // Spawn banknotes banknoteSpawnTimer++; if (banknoteSpawnTimer >= banknoteSpawnInterval) { banknoteSpawnTimer = 0; var banknote = new Banknote(); var laneIdx = Math.floor(Math.random() * laneCount); banknote.x = laneCenters[laneIdx]; banknote.y = -banknoteHeight / 2; banknote.speedY = speed; banknotes.push(banknote); game.addChild(banknote); } // Update coins for (var i = coins.length - 1; i >= 0; i--) { var coin = coins[i]; coin.speedY = speed; coin.update(); // Remove if off screen if (coin.y > 2732 + coinHeight) { coin.destroy(); coins.splice(i, 1); continue; } // Collect coin if (playerCar.intersects(coin)) { coin.destroy(); coins.splice(i, 1); score += 1; // Add 1 point for each coin coinScoreTxt.setText(score); // Update coin score indicator continue; } } // Update banknotes for (var i = banknotes.length - 1; i >= 0; i--) { var banknote = banknotes[i]; banknote.speedY = speed; banknote.update(); if (banknote.y > 2732 + banknoteHeight) { banknote.destroy(); banknotes.splice(i, 1); continue; } // Collect banknote if (playerCar.intersects(banknote)) { banknote.destroy(); banknotes.splice(i, 1); score += 200; // Add 200 points for each banknote coinScoreTxt.setText(score); continue; } } // Spawn obstacles obstacleSpawnTimer++; if (obstacleSpawnTimer >= obstacleSpawnInterval) { obstacleSpawnTimer = 0; spawnObstacle(); } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); // Remove if off screen if (obs.y > 2732 + obstacleCarHeight) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision detection if (playerCar.intersects(obs)) { gameOver(); return; } } // Update distance (for possible future use) distance += speed; // Do not update score or coinScoreTxt here; only update when collecting coins // scoreTxt.setText(score);//{2B} (removed) // Gradually increase speed for difficulty if (LK.ticks % 180 === 0 && speed < 36) { speed += 1; } }; // Spawn an obstacle car in a random lane function spawnObstacle() { // Synchronize the red car (obstacle) to the blue car (player) on spawn var obs = new ObstacleCar(); obs.x = playerCar.x; obs.y = -obstacleCarHeight / 2; obs.speedY = speed; obstacles.push(obs); game.addChild(obs); } // Game over logic function gameOver() { isGameOver = true; LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); } // Reset on game restart game.on('reset', function () { // Remove all obstacles for (var i = 0; i < obstacles.length; i++) { obstacles[i].destroy(); } obstacles = []; // Remove all coins for (var i = 0; i < coins.length; i++) { coins[i].destroy(); } coins = []; // Remove all banknotes for (var i = 0; i < banknotes.length; i++) { banknotes[i].destroy(); } banknotes = []; // Remove all lane markings for (var i = 0; i < laneMarkings.length; i++) { laneMarkings[i].destroy(); } laneMarkings = []; // Remove all trees for (var i = 0; i < trees.length; i++) { trees[i].destroy(); } trees = []; // Recreate lane markings as dashed var dashLength = 80; var dashGap = 80; var dashesPerMarking = Math.floor(laneMarkingHeight / (dashLength + dashGap)); for (var i = 0; i < laneCount - 1; i++) { for (var j = 0; j < Math.ceil(2732 / laneMarkingSpacing) + 2; j++) { var baseY = j * laneMarkingSpacing - laneMarkingHeight / 2; for (var d = 0; d < dashesPerMarking; d++) { var marking = new LaneMarking(); marking.x = roadLeft + laneWidth * (i + 1); marking.y = baseY + d * (dashLength + dashGap); marking.speedY = speed; marking.height = dashLength; marking.width = laneMarkingWidth; laneMarkings.push(marking); game.addChild(marking); } } } // Recreate trees (slightly more trees) for (var side = 0; side < 2; side++) { var xPos = side === 0 ? roadLeft - treeWidth / 2 - 30 : roadRight + treeWidth / 2 + 30; for (var j = 0; j < 6; j++) { // 6 trees per side! var tree = new Tree(); tree.x = xPos; tree.y = j * (2732 / 6) + 100; tree.speedY = speed; trees.push(tree); game.addChild(tree); } } // Reset player position playerCar.x = laneCenters[1]; playerCar.y = 2732 - 400; playerCar.speedX = 0; moveLeft = false; moveRight = false; updatePlayerSpeed(); // Reset score and distance score = 0; distance = 0; coinScoreTxt.setText('0'); // Reset coin score indicator isGameOver = false; speed = 18; obstacleSpawnTimer = 0; }); // Prevent placing anything in top left 100x100 px (no code needed, just a reminder)
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Banknote = Container.expand(function () {
var self = Container.call(this);
var banknoteAsset = self.attachAsset('banknote', {
anchorX: 0.5,
anchorY: 0.5
});
banknoteAsset.width = banknoteWidth;
banknoteAsset.height = banknoteHeight;
self.width = banknoteAsset.width;
self.height = banknoteAsset.height;
self.speedY = 0;
self.update = function () {
self.y += self.speedY;
};
return self;
});
// Coin for road
var Coin = Container.expand(function () {
var self = Container.call(this);
// Use a simple yellow ellipse as the coin
var coinAsset = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinAsset.width = coinWidth;
coinAsset.height = coinHeight;
self.width = coinAsset.width;
self.height = coinAsset.height;
self.speedY = 0;
self.update = function () {
self.y += self.speedY;
};
return self;
});
// Banknote (paper money) for road
// Road Lane Marking
var LaneMarking = Container.expand(function () {
var self = Container.call(this);
var marking = self.attachAsset('laneMarking', {
anchorX: 0.5,
anchorY: 0.5
});
marking.width = laneMarkingWidth;
marking.height = laneMarkingHeight;
self.width = marking.width;
self.height = marking.height;
self.speedY = 0;
self.update = function () {
self.y += self.speedY;
};
return self;
});
// Obstacle Car
var ObstacleCar = Container.expand(function () {
var self = Container.call(this);
var carAsset = self.attachAsset('obstacleCar', {
anchorX: 0.5,
anchorY: 0.5
});
carAsset.width = obstacleCarWidth;
carAsset.height = obstacleCarHeight;
self.width = carAsset.width;
self.height = carAsset.height;
self.speedY = 0; // Vertical speed
self.update = function () {
self.y += self.speedY;
};
return self;
});
// Player's Car
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
var carAsset = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
carAsset.width = playerCarWidth;
carAsset.height = playerCarHeight;
self.width = carAsset.width;
self.height = carAsset.height;
self.speedX = 0; // Horizontal speed
// Update method called every tick
self.update = function () {
// --- DRIFT/SKID EFFECT ---
// Initialize drift/skid state variables if not present
if (self.slideAngle === undefined) self.slideAngle = 0;
if (self.targetAngle === undefined) self.targetAngle = 0;
if (self.driftOffset === undefined) self.driftOffset = 0;
if (self.driftTargetOffset === undefined) self.driftTargetOffset = 0;
// Calculate target angle and lateral offset based on speedX (simulate drift)
// The more the player turns, the more the car visually rotates and slides sideways
var maxDriftAngle = Math.PI / 7; // maximum visual drift angle (radians)
var maxDriftOffset = 60; // maximum sideways offset (pixels)
var driftSpeed = 0.18; // how quickly the car rotates to the drift angle
var offsetSpeed = 0.12; // how quickly the car slides to the drift offset
// Set drift targets based on speedX
if (self.speedX < -1) {
self.targetAngle = -maxDriftAngle;
self.driftTargetOffset = -maxDriftOffset;
} else if (self.speedX > 1) {
self.targetAngle = maxDriftAngle;
self.driftTargetOffset = maxDriftOffset;
} else {
self.targetAngle = 0;
self.driftTargetOffset = 0;
}
// Smoothly interpolate slideAngle and driftOffset towards their targets
self.slideAngle += (self.targetAngle - self.slideAngle) * driftSpeed;
self.driftOffset += (self.driftTargetOffset - self.driftOffset) * offsetSpeed;
// Apply rotation and lateral offset to car asset (visual only, not affecting movement)
if (self.children && self.children.length > 0) {
self.children[0].rotation = self.slideAngle;
self.children[0].x = self.driftOffset;
}
// Move car horizontally
self.x += self.speedX;
// Clamp to road bounds
if (self.x < roadLeft + self.width / 2) self.x = roadLeft + self.width / 2;
if (self.x > roadRight - self.width / 2) self.x = roadRight - self.width / 2;
};
return self;
});
// Tree for road edge
var Tree = Container.expand(function () {
var self = Container.call(this);
var treeAsset = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = treeAsset.width;
self.height = treeAsset.height;
self.speedY = 0;
self.update = function () {
self.y += self.speedY;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Road dimensions
// Banknote (paper money) for road
var banknoteWidth = 120;
var banknoteHeight = 60;
var roadWidth = 900;
var roadLeft = (2048 - roadWidth) / 2;
var roadRight = roadLeft + roadWidth;
// Lane count and positions
var laneCount = 3;
var laneWidth = roadWidth / laneCount;
var laneCenters = [roadLeft + laneWidth / 2, roadLeft + laneWidth * 1.5, roadLeft + laneWidth * 2.5];
// Player and obstacle car size (equalized, made slightly larger)
var playerCarWidth = 200;
var playerCarHeight = 320;
var obstacleCarWidth = 200;
var obstacleCarHeight = 320;
// Lane marking size
var laneMarkingWidth = 54;
var laneMarkingHeight = 330;
// Tree size and spacing
var treeWidth = 180;
var treeHeight = 270;
var treeSpacing = 220;
// Asset initialization (shapes)
// Game variables
var playerCar;
var obstacles = [];
var laneMarkings = [];
var trees = [];
var coins = [];
var banknotes = [];
var coinSpawnTimer = 0;
var coinSpawnInterval = 45; // frames, coins spawn more frequently
var banknoteSpawnTimer = 0;
var banknoteSpawnInterval = 120; // frames, less frequent than coins
var coinWidth = 80;
var coinHeight = 80;
var obstacleSpawnTimer = 0;
var obstacleSpawnInterval = 60; // frames
var laneMarkingSpacing = 320;
var speed = 18; // vertical speed (pixels per frame)
var score = 0;
var distance = 0;
var isGameOver = false;
// Add coin score indicator to the GUI
var coinScoreTxt = new Text2('0', {
size: 120,
fill: 0xFFE066
});
coinScoreTxt.anchor.set(0.5, 0); // Centered at top
// Place at top center, but not in the top left 100x100 px
LK.gui.top.addChild(coinScoreTxt);
// Initialize player car
playerCar = new PlayerCar();
playerCar.x = laneCenters[1];
playerCar.y = 2732 - 400;
game.addChild(playerCar);
// Initialize lane markings as dashed (split into short segments)
var dashLength = 80;
var dashGap = 80;
var dashesPerMarking = Math.floor(laneMarkingHeight / (dashLength + dashGap));
for (var i = 0; i < laneCount - 1; i++) {
for (var j = 0; j < Math.ceil(2732 / laneMarkingSpacing) + 2; j++) {
var baseY = j * laneMarkingSpacing - laneMarkingHeight / 2;
for (var d = 0; d < dashesPerMarking; d++) {
var marking = new LaneMarking();
marking.x = roadLeft + laneWidth * (i + 1);
marking.y = baseY + d * (dashLength + dashGap);
marking.speedY = speed;
marking.height = dashLength;
marking.width = laneMarkingWidth;
laneMarkings.push(marking);
game.addChild(marking);
}
}
}
// Initialize trees along both sides of the road (slightly more trees)
for (var side = 0; side < 2; side++) {
var xPos = side === 0 ? roadLeft - treeWidth / 2 - 30 : roadRight + treeWidth / 2 + 30;
for (var j = 0; j < 6; j++) {
// 6 trees per side!
var tree = new Tree();
tree.x = xPos;
tree.y = j * (2732 / 6) + 100;
tree.speedY = speed;
trees.push(tree);
game.addChild(tree);
}
}
// Touch controls
var moveLeft = false;
var moveRight = false;
// Helper: get which side of the screen is pressed
function getSide(x) {
if (x < 2048 / 2) return 'left';
return 'right';
}
// Touch down
game.down = function (x, y, obj) {
if (isGameOver) return;
var side = getSide(x);
if (side === 'left') {
moveLeft = true;
moveRight = false;
} else {
moveRight = true;
moveLeft = false;
}
updatePlayerSpeed();
};
// Touch up
game.up = function (x, y, obj) {
moveLeft = false;
moveRight = false;
updatePlayerSpeed();
};
// Touch move (optional, for smoother control)
game.move = function (x, y, obj) {
if (isGameOver) return;
var side = getSide(x);
if (side === 'left') {
moveLeft = true;
moveRight = false;
} else {
moveRight = true;
moveLeft = false;
}
updatePlayerSpeed();
};
// Update player car speedX based on input
function updatePlayerSpeed() {
if (moveLeft && !moveRight) {
playerCar.speedX = -22;
} else if (moveRight && !moveLeft) {
playerCar.speedX = 22;
} else {
playerCar.speedX = 0;
}
}
// Main game update loop
game.update = function () {
if (isGameOver) return;
// Update lane markings
for (var i = 0; i < laneMarkings.length; i++) {
var marking = laneMarkings[i];
marking.speedY = speed;
marking.update();
if (marking.y > 2732 + laneMarkingHeight / 2) {
marking.y -= (Math.ceil(2732 / laneMarkingSpacing) + 2) * laneMarkingSpacing;
}
}
// Update trees
for (var i = 0; i < trees.length; i++) {
var tree = trees[i];
tree.speedY = speed;
tree.update();
if (tree.y > 2732 + treeHeight / 2) {
tree.y -= (Math.ceil(2732 / treeSpacing) + 3) * treeSpacing;
}
}
// Update player car
playerCar.update();
// Spawn coins
coinSpawnTimer++;
if (coinSpawnTimer >= coinSpawnInterval) {
coinSpawnTimer = 0;
// Spawn coin in a random lane
var coin = new Coin();
var laneIdx = Math.floor(Math.random() * laneCount);
coin.x = laneCenters[laneIdx];
coin.y = -coinHeight / 2;
coin.speedY = speed;
coins.push(coin);
game.addChild(coin);
}
// Spawn banknotes
banknoteSpawnTimer++;
if (banknoteSpawnTimer >= banknoteSpawnInterval) {
banknoteSpawnTimer = 0;
var banknote = new Banknote();
var laneIdx = Math.floor(Math.random() * laneCount);
banknote.x = laneCenters[laneIdx];
banknote.y = -banknoteHeight / 2;
banknote.speedY = speed;
banknotes.push(banknote);
game.addChild(banknote);
}
// Update coins
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
coin.speedY = speed;
coin.update();
// Remove if off screen
if (coin.y > 2732 + coinHeight) {
coin.destroy();
coins.splice(i, 1);
continue;
}
// Collect coin
if (playerCar.intersects(coin)) {
coin.destroy();
coins.splice(i, 1);
score += 1; // Add 1 point for each coin
coinScoreTxt.setText(score); // Update coin score indicator
continue;
}
}
// Update banknotes
for (var i = banknotes.length - 1; i >= 0; i--) {
var banknote = banknotes[i];
banknote.speedY = speed;
banknote.update();
if (banknote.y > 2732 + banknoteHeight) {
banknote.destroy();
banknotes.splice(i, 1);
continue;
}
// Collect banknote
if (playerCar.intersects(banknote)) {
banknote.destroy();
banknotes.splice(i, 1);
score += 200; // Add 200 points for each banknote
coinScoreTxt.setText(score);
continue;
}
}
// Spawn obstacles
obstacleSpawnTimer++;
if (obstacleSpawnTimer >= obstacleSpawnInterval) {
obstacleSpawnTimer = 0;
spawnObstacle();
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if off screen
if (obs.y > 2732 + obstacleCarHeight) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
if (playerCar.intersects(obs)) {
gameOver();
return;
}
}
// Update distance (for possible future use)
distance += speed;
// Do not update score or coinScoreTxt here; only update when collecting coins
// scoreTxt.setText(score);//{2B} (removed)
// Gradually increase speed for difficulty
if (LK.ticks % 180 === 0 && speed < 36) {
speed += 1;
}
};
// Spawn an obstacle car in a random lane
function spawnObstacle() {
// Synchronize the red car (obstacle) to the blue car (player) on spawn
var obs = new ObstacleCar();
obs.x = playerCar.x;
obs.y = -obstacleCarHeight / 2;
obs.speedY = speed;
obstacles.push(obs);
game.addChild(obs);
}
// Game over logic
function gameOver() {
isGameOver = true;
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
// Reset on game restart
game.on('reset', function () {
// Remove all obstacles
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
obstacles = [];
// Remove all coins
for (var i = 0; i < coins.length; i++) {
coins[i].destroy();
}
coins = [];
// Remove all banknotes
for (var i = 0; i < banknotes.length; i++) {
banknotes[i].destroy();
}
banknotes = [];
// Remove all lane markings
for (var i = 0; i < laneMarkings.length; i++) {
laneMarkings[i].destroy();
}
laneMarkings = [];
// Remove all trees
for (var i = 0; i < trees.length; i++) {
trees[i].destroy();
}
trees = [];
// Recreate lane markings as dashed
var dashLength = 80;
var dashGap = 80;
var dashesPerMarking = Math.floor(laneMarkingHeight / (dashLength + dashGap));
for (var i = 0; i < laneCount - 1; i++) {
for (var j = 0; j < Math.ceil(2732 / laneMarkingSpacing) + 2; j++) {
var baseY = j * laneMarkingSpacing - laneMarkingHeight / 2;
for (var d = 0; d < dashesPerMarking; d++) {
var marking = new LaneMarking();
marking.x = roadLeft + laneWidth * (i + 1);
marking.y = baseY + d * (dashLength + dashGap);
marking.speedY = speed;
marking.height = dashLength;
marking.width = laneMarkingWidth;
laneMarkings.push(marking);
game.addChild(marking);
}
}
}
// Recreate trees (slightly more trees)
for (var side = 0; side < 2; side++) {
var xPos = side === 0 ? roadLeft - treeWidth / 2 - 30 : roadRight + treeWidth / 2 + 30;
for (var j = 0; j < 6; j++) {
// 6 trees per side!
var tree = new Tree();
tree.x = xPos;
tree.y = j * (2732 / 6) + 100;
tree.speedY = speed;
trees.push(tree);
game.addChild(tree);
}
}
// Reset player position
playerCar.x = laneCenters[1];
playerCar.y = 2732 - 400;
playerCar.speedX = 0;
moveLeft = false;
moveRight = false;
updatePlayerSpeed();
// Reset score and distance
score = 0;
distance = 0;
coinScoreTxt.setText('0'); // Reset coin score indicator
isGameOver = false;
speed = 18;
obstacleSpawnTimer = 0;
});
// Prevent placing anything in top left 100x100 px (no code needed, just a reminder)