User prompt
Add the health bar to acets
User prompt
Let the health bar be more obvious
User prompt
When we say that our car has a life, let some of its life go to the enemies, let the life bar appear on the car
User prompt
Don't let the fireball come out too much
User prompt
Add the fireball ace you added to the path
User prompt
Add fireball assets in game
User prompt
Let the fire growFire magic assets add as
User prompt
Something like a magic bottle will form on the ground, and when you pick it up, the car will burst into flames
User prompt
Please fix the bug: 'LaneDivider is not defined' in or related to this line: 'var divider = new LaneDivider();' Line Number: 222
User prompt
Remove game-breaking things
User prompt
Please fix the bug: 'PlayerCar is not defined' in or related to this line: 'playerCar = new PlayerCar();' Line Number: 128
User prompt
Fix
User prompt
Please fix the bug: 'LaneDivider is not defined' in or related to this line: 'var divider = new LaneDivider();' Line Number: 207
User prompt
Delete game-breaking things
User prompt
Please fix the bug: 'LaneDivider is not defined' in or related to this line: 'var divider = new LaneDivider();' Line Number: 207
User prompt
Fix
User prompt
Please fix the bug: 'PlayerCar is not defined' in or related to this line: 'playerCar = new PlayerCar();' Line Number: 128
User prompt
Add an enemy thief who appears after 50 points and move in all lanes assets add as.
User prompt
Place the maximum number of points on the left side of the normal number of points
User prompt
Swipe left on the highest score text
User prompt
Please fix the bug: 'TypeError: LK.effects.explosion is not a function' in or related to this line: 'LK.effects.explosion(playerCar.x, playerCar.y, {' Line Number: 410
User prompt
Add an explosion effect when you hit an enemy car or barrier
User prompt
Move the text a little more to the left
User prompt
When the shield is active, there is something white around the car, like a shield effect
User prompt
Let there be some space between the lanes
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Enemy Car Class var EnemyCar = Container.expand(function () { var self = Container.call(this); var car = self.attachAsset('enemyCar', { anchorX: 0.5, anchorY: 0.5 }); self.lane = 1; self.speed = 18; self.update = function () { self.y += self.speed * gameSpeed; }; return self; }); // Lane Divider Class var LaneDivider = Container.expand(function () { var self = Container.call(this); var div = self.attachAsset('laneDivider', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 18; self.update = function () { self.y += self.speed * gameSpeed; }; return self; }); // Obstacle Class var Obstacle = Container.expand(function () { var self = Container.call(this); var obs = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.lane = 1; self.speed = 18; self.update = function () { self.y += self.speed * gameSpeed; }; return self; }); // Player Car Class var PlayerCar = Container.expand(function () { var self = Container.call(this); var car = self.attachAsset('playerCar', { anchorX: 0.5, anchorY: 0.5 }); self.lane = 1; // 0: left, 1: center, 2: right self.setLane = function (laneIdx) { self.lane = laneIdx; // Animate to new lane position var targetX = lanes[self.lane]; tween(self, { x: targetX }, { duration: 120, easing: tween.cubicOut }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Spell bottle asset (example: blue bottle, 120x180) // Lane positions (3 lanes) // Car (player) // Enemy car // Obstacle (barrier) // Road lane divider // Sound for crash // Sound for lane change // Music (background) var laneCount = 3; var laneWidth = 520; // Increased lane width for more space between lanes var lanes = [2048 / 2 - laneWidth, // left 2048 / 2, // center 2048 / 2 + laneWidth // right ]; // Game variables var playerCar; var enemyCars = []; var obstacles = []; var laneDividers = []; var score = 0; var highScore = storage.highScore || 0; var scoreTxt; var highScoreTxt; var gameSpeed = 1; var ticksSinceStart = 0; var swipeStartX = null; var swipeStartY = null; var swipeActive = false; var lastLane = 1; var spawnTick = 0; var dividerSpacing = 320; var dragNode = null; // Score display scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0.5); LK.gui.top.addChild(scoreTxt); // Shield timer display var shieldTxt = new Text2('', { size: 80, fill: 0x2BD5E6 }); shieldTxt.anchor.set(0.5, 0.5); LK.gui.top.addChild(shieldTxt); // High Score display highScoreTxt = new Text2('HI: ' + highScore, { size: 60, fill: 0xFFFF00 }); highScoreTxt.anchor.set(0.5, 0.5); LK.gui.top.addChild(highScoreTxt); // Start music LK.playMusic('bgmusic'); // Create player car playerCar = new PlayerCar(); playerCar.x = lanes[1]; playerCar.y = 2732 - 500; playerCar.setLane(1); // Shield properties playerCar.shieldActive = false; playerCar.shieldTicks = 0; game.addChild(playerCar); // Add two vertical side stripes (left and right) to the play area var sideStripeWidth = 60; var sideStripeHeight = 2732; var leftStripe = LK.getAsset('laneDivider', { anchorX: 0.5, anchorY: 0, width: sideStripeWidth, height: sideStripeHeight, x: sideStripeWidth / 2, y: 0 }); var rightStripe = LK.getAsset('laneDivider', { anchorX: 0.5, anchorY: 0, width: sideStripeWidth, height: sideStripeHeight, x: 2048 - sideStripeWidth / 2, y: 0 }); game.addChild(leftStripe); game.addChild(rightStripe); // Create lane dividers (vertical lines for each lane) // For 3 lanes, we want to copy the center lane divider and place it to the right and left of the center stripe, without adding extra lines // The center divider is between lane 0 and lane 1, and between lane 1 and lane 2 // So, for 3 lanes, we want to draw the two dividers: one between lane 0 and 1, and one between lane 1 and 2 var dividerOffsets = []; // Find the X positions for the two dividers (between lanes) for (var l = 1; l < laneCount; l++) { dividerOffsets.push((lanes[l - 1] + lanes[l]) / 2); } // Now, for each divider, draw a set of stripes down the screen for (var d = 0; d < dividerOffsets.length; d++) { for (var i = 0; i < 10; i++) { // Center LaneDivider var divider = new LaneDivider(); divider.x = dividerOffsets[d]; divider.y = i * dividerSpacing; laneDividers.push(divider); game.addChild(divider); // Left copy var dividerLeft = new LaneDivider(); dividerLeft.x = dividerOffsets[d] - laneWidth; dividerLeft.y = i * dividerSpacing; laneDividers.push(dividerLeft); game.addChild(dividerLeft); // Right copy var dividerRight = new LaneDivider(); dividerRight.x = dividerOffsets[d] + laneWidth; dividerRight.y = i * dividerSpacing; laneDividers.push(dividerRight); game.addChild(dividerRight); } } // Prepare for dynamic spell bottle spawning var spellBottle = null; var spellBottleActive = false; var spellBottleLane = 1; // Add: track last spell bottle spawn tick to limit spawn rate var lastSpellBottleSpawnTick = -1000; // Helper: spawn enemy car or obstacle function spawnObstacleOrEnemy() { // Randomly decide: 70% enemy car, 30% obstacle var isEnemy = Math.random() < 0.7; var laneIdx = Math.floor(Math.random() * laneCount); var y = -300; if (isEnemy) { var enemy = new EnemyCar(); enemy.lane = laneIdx; enemy.x = lanes[laneIdx]; enemy.y = y; enemyCars.push(enemy); game.addChild(enemy); } else { var obs = new Obstacle(); obs.lane = laneIdx; obs.x = lanes[laneIdx]; obs.y = y; obstacles.push(obs); game.addChild(obs); } } // Helper: update score function updateScore(val) { score = val; scoreTxt.setText(score); if (score > highScore) { highScore = score; highScoreTxt.setText('HI: ' + highScore); storage.highScore = highScore; } } // Touch/drag/swipe handling game.down = function (x, y, obj) { swipeStartX = x; swipeStartY = y; swipeActive = true; dragNode = playerCar; }; game.move = function (x, y, obj) { // Only handle swipe if active if (!swipeActive) return; if (!dragNode) return; var dx = x - swipeStartX; var dy = y - swipeStartY; // Only consider horizontal swipes, ignore vertical if (Math.abs(dx) > 80 && Math.abs(dx) > Math.abs(dy)) { var newLane = playerCar.lane; if (dx < 0 && playerCar.lane > 0) { newLane = playerCar.lane - 1; } else if (dx > 0 && playerCar.lane < laneCount - 1) { newLane = playerCar.lane + 1; } if (newLane !== playerCar.lane) { playerCar.setLane(newLane); LK.getSound('swipe').play(); swipeActive = false; dragNode = null; } } }; game.up = function (x, y, obj) { swipeActive = false; dragNode = null; }; // Main game update loop game.update = function () { ticksSinceStart++; // Only increase game speed after score reaches 50 if (score >= 50) { if (ticksSinceStart % 60 === 0 && gameSpeed < 4) { // Increase speed every second, and allow it to go higher if (gameSpeed < 2) { gameSpeed += 0.08; } else if (gameSpeed < 3) { gameSpeed += 0.12; } else { gameSpeed += 0.18; } if (gameSpeed > 4) gameSpeed = 4; } } else { gameSpeed = 1; } // Move lane dividers, loop to top for (var i = 0; i < laneDividers.length; i++) { var div = laneDividers[i]; div.update(); if (div.y > 2732 + 60) { div.y -= dividerSpacing * 10; } } // Spawn or move spell bottle if (!spellBottleActive) { // Determine spawn cooldown and chance based on score var bottleCooldown = score >= 50 ? 300 : 600; // 5s if score>=50, else 10s var bottleChance = score >= 50 ? 1 / 60 : 1 / 120; // 1/60 per frame if score>=50, else 1/120 // Only allow spawn if enough time has passed since last spawn if (ticksSinceStart - lastSpellBottleSpawnTick > bottleCooldown) { // Try to spawn with the appropriate chance if (Math.random() < bottleChance) { spellBottleLane = Math.floor(Math.random() * laneCount); var bottleX = lanes[spellBottleLane]; // Place the bottle at a fixed Y position (e.g., 900px from the top) var bottleY = 900; spellBottle = LK.getAsset('spellBottle', { anchorX: 0.5, anchorY: 1.0, x: bottleX, y: bottleY }); game.addChild(spellBottle); spellBottleActive = true; lastSpellBottleSpawnTick = ticksSinceStart; } } } else if (spellBottle) { // Move the spell bottle down the screen spellBottle.y += 18 * gameSpeed; // Off screen? Remove (if it has scrolled above the visible area) if (spellBottle.y < -200 || spellBottle.y > 2732 + 200) { spellBottle.destroy(); spellBottle = null; spellBottleActive = false; } // Check collision with playerCar for shield pickup if (spellBottle && !playerCar.shieldActive && spellBottle.intersects(playerCar)) { // Grant shield for 3 seconds playerCar.shieldActive = true; playerCar.shieldTicks = 180; // 3 seconds at 60fps // Optionally, you could add a visual effect here (not required) spellBottle.destroy(); spellBottle = null; spellBottleActive = false; } } // Spawn enemies/obstacles every 40-60 ticks, randomize spawnTick++; var spawnInterval = 40 + Math.floor(Math.random() * 20); if (spawnTick > spawnInterval) { spawnObstacleOrEnemy(); spawnTick = 0; } // Update enemy cars for (var i = enemyCars.length - 1; i >= 0; i--) { var enemy = enemyCars[i]; enemy.update(); // Off screen if (enemy.y > 2732 + 300) { enemy.destroy(); enemyCars.splice(i, 1); updateScore(score + 1); continue; } // Collision with spell bottle if (spellBottle && enemy.intersects(spellBottle)) { spellBottle.destroy(); spellBottle = null; spellBottleActive = false; } // Collision with player if (enemy.intersects(playerCar)) { if (playerCar.shieldActive) { // Ignore collision, let player pass through enemy car while shield is active continue; } else { LK.getSound('crash').play(); LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } } } // Update obstacles for (var j = obstacles.length - 1; j >= 0; j--) { var obs = obstacles[j]; obs.update(); // Off screen if (obs.y > 2732 + 200) { obs.destroy(); obstacles.splice(j, 1); updateScore(score + 1); continue; } // Collision with player if (obs.intersects(playerCar)) { if (playerCar.shieldActive) { // Ignore collision, let player pass through obstacle while shield is active continue; } else { LK.getSound('crash').play(); LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } } } ; // Shield timer logic if (playerCar.shieldActive) { playerCar.shieldTicks--; // Show shield seconds left (rounded up) var shieldSeconds = Math.ceil(playerCar.shieldTicks / 60); shieldTxt.setText("Shield: " + shieldSeconds + "s"); if (playerCar.shieldTicks <= 0) { playerCar.shieldActive = false; playerCar.shieldTicks = 0; shieldTxt.setText(''); } } else { shieldTxt.setText(''); } }; // Center score text at very top, avoid top left 100x100 scoreTxt.x = LK.gui.top.width / 2; scoreTxt.y = scoreTxt.height / 2 + 10; // Position shield timer text directly below score shieldTxt.x = LK.gui.top.width / 2; shieldTxt.y = scoreTxt.y + scoreTxt.height / 2 + shieldTxt.height / 2 + 10; // Position high score text directly below shield timer highScoreTxt.x = LK.gui.top.width / 2; highScoreTxt.y = shieldTxt.y + shieldTxt.height / 2 + highScoreTxt.height / 2 + 10;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Enemy Car Class
var EnemyCar = Container.expand(function () {
var self = Container.call(this);
var car = self.attachAsset('enemyCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1;
self.speed = 18;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
// Lane Divider Class
var LaneDivider = Container.expand(function () {
var self = Container.call(this);
var div = self.attachAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 18;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
// Obstacle Class
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obs = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1;
self.speed = 18;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
// Player Car Class
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
var car = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1; // 0: left, 1: center, 2: right
self.setLane = function (laneIdx) {
self.lane = laneIdx;
// Animate to new lane position
var targetX = lanes[self.lane];
tween(self, {
x: targetX
}, {
duration: 120,
easing: tween.cubicOut
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Spell bottle asset (example: blue bottle, 120x180)
// Lane positions (3 lanes)
// Car (player)
// Enemy car
// Obstacle (barrier)
// Road lane divider
// Sound for crash
// Sound for lane change
// Music (background)
var laneCount = 3;
var laneWidth = 520; // Increased lane width for more space between lanes
var lanes = [2048 / 2 - laneWidth,
// left
2048 / 2,
// center
2048 / 2 + laneWidth // right
];
// Game variables
var playerCar;
var enemyCars = [];
var obstacles = [];
var laneDividers = [];
var score = 0;
var highScore = storage.highScore || 0;
var scoreTxt;
var highScoreTxt;
var gameSpeed = 1;
var ticksSinceStart = 0;
var swipeStartX = null;
var swipeStartY = null;
var swipeActive = false;
var lastLane = 1;
var spawnTick = 0;
var dividerSpacing = 320;
var dragNode = null;
// Score display
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(scoreTxt);
// Shield timer display
var shieldTxt = new Text2('', {
size: 80,
fill: 0x2BD5E6
});
shieldTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(shieldTxt);
// High Score display
highScoreTxt = new Text2('HI: ' + highScore, {
size: 60,
fill: 0xFFFF00
});
highScoreTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(highScoreTxt);
// Start music
LK.playMusic('bgmusic');
// Create player car
playerCar = new PlayerCar();
playerCar.x = lanes[1];
playerCar.y = 2732 - 500;
playerCar.setLane(1);
// Shield properties
playerCar.shieldActive = false;
playerCar.shieldTicks = 0;
game.addChild(playerCar);
// Add two vertical side stripes (left and right) to the play area
var sideStripeWidth = 60;
var sideStripeHeight = 2732;
var leftStripe = LK.getAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0,
width: sideStripeWidth,
height: sideStripeHeight,
x: sideStripeWidth / 2,
y: 0
});
var rightStripe = LK.getAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0,
width: sideStripeWidth,
height: sideStripeHeight,
x: 2048 - sideStripeWidth / 2,
y: 0
});
game.addChild(leftStripe);
game.addChild(rightStripe);
// Create lane dividers (vertical lines for each lane)
// For 3 lanes, we want to copy the center lane divider and place it to the right and left of the center stripe, without adding extra lines
// The center divider is between lane 0 and lane 1, and between lane 1 and lane 2
// So, for 3 lanes, we want to draw the two dividers: one between lane 0 and 1, and one between lane 1 and 2
var dividerOffsets = [];
// Find the X positions for the two dividers (between lanes)
for (var l = 1; l < laneCount; l++) {
dividerOffsets.push((lanes[l - 1] + lanes[l]) / 2);
}
// Now, for each divider, draw a set of stripes down the screen
for (var d = 0; d < dividerOffsets.length; d++) {
for (var i = 0; i < 10; i++) {
// Center LaneDivider
var divider = new LaneDivider();
divider.x = dividerOffsets[d];
divider.y = i * dividerSpacing;
laneDividers.push(divider);
game.addChild(divider);
// Left copy
var dividerLeft = new LaneDivider();
dividerLeft.x = dividerOffsets[d] - laneWidth;
dividerLeft.y = i * dividerSpacing;
laneDividers.push(dividerLeft);
game.addChild(dividerLeft);
// Right copy
var dividerRight = new LaneDivider();
dividerRight.x = dividerOffsets[d] + laneWidth;
dividerRight.y = i * dividerSpacing;
laneDividers.push(dividerRight);
game.addChild(dividerRight);
}
}
// Prepare for dynamic spell bottle spawning
var spellBottle = null;
var spellBottleActive = false;
var spellBottleLane = 1;
// Add: track last spell bottle spawn tick to limit spawn rate
var lastSpellBottleSpawnTick = -1000;
// Helper: spawn enemy car or obstacle
function spawnObstacleOrEnemy() {
// Randomly decide: 70% enemy car, 30% obstacle
var isEnemy = Math.random() < 0.7;
var laneIdx = Math.floor(Math.random() * laneCount);
var y = -300;
if (isEnemy) {
var enemy = new EnemyCar();
enemy.lane = laneIdx;
enemy.x = lanes[laneIdx];
enemy.y = y;
enemyCars.push(enemy);
game.addChild(enemy);
} else {
var obs = new Obstacle();
obs.lane = laneIdx;
obs.x = lanes[laneIdx];
obs.y = y;
obstacles.push(obs);
game.addChild(obs);
}
}
// Helper: update score
function updateScore(val) {
score = val;
scoreTxt.setText(score);
if (score > highScore) {
highScore = score;
highScoreTxt.setText('HI: ' + highScore);
storage.highScore = highScore;
}
}
// Touch/drag/swipe handling
game.down = function (x, y, obj) {
swipeStartX = x;
swipeStartY = y;
swipeActive = true;
dragNode = playerCar;
};
game.move = function (x, y, obj) {
// Only handle swipe if active
if (!swipeActive) return;
if (!dragNode) return;
var dx = x - swipeStartX;
var dy = y - swipeStartY;
// Only consider horizontal swipes, ignore vertical
if (Math.abs(dx) > 80 && Math.abs(dx) > Math.abs(dy)) {
var newLane = playerCar.lane;
if (dx < 0 && playerCar.lane > 0) {
newLane = playerCar.lane - 1;
} else if (dx > 0 && playerCar.lane < laneCount - 1) {
newLane = playerCar.lane + 1;
}
if (newLane !== playerCar.lane) {
playerCar.setLane(newLane);
LK.getSound('swipe').play();
swipeActive = false;
dragNode = null;
}
}
};
game.up = function (x, y, obj) {
swipeActive = false;
dragNode = null;
};
// Main game update loop
game.update = function () {
ticksSinceStart++;
// Only increase game speed after score reaches 50
if (score >= 50) {
if (ticksSinceStart % 60 === 0 && gameSpeed < 4) {
// Increase speed every second, and allow it to go higher
if (gameSpeed < 2) {
gameSpeed += 0.08;
} else if (gameSpeed < 3) {
gameSpeed += 0.12;
} else {
gameSpeed += 0.18;
}
if (gameSpeed > 4) gameSpeed = 4;
}
} else {
gameSpeed = 1;
}
// Move lane dividers, loop to top
for (var i = 0; i < laneDividers.length; i++) {
var div = laneDividers[i];
div.update();
if (div.y > 2732 + 60) {
div.y -= dividerSpacing * 10;
}
}
// Spawn or move spell bottle
if (!spellBottleActive) {
// Determine spawn cooldown and chance based on score
var bottleCooldown = score >= 50 ? 300 : 600; // 5s if score>=50, else 10s
var bottleChance = score >= 50 ? 1 / 60 : 1 / 120; // 1/60 per frame if score>=50, else 1/120
// Only allow spawn if enough time has passed since last spawn
if (ticksSinceStart - lastSpellBottleSpawnTick > bottleCooldown) {
// Try to spawn with the appropriate chance
if (Math.random() < bottleChance) {
spellBottleLane = Math.floor(Math.random() * laneCount);
var bottleX = lanes[spellBottleLane];
// Place the bottle at a fixed Y position (e.g., 900px from the top)
var bottleY = 900;
spellBottle = LK.getAsset('spellBottle', {
anchorX: 0.5,
anchorY: 1.0,
x: bottleX,
y: bottleY
});
game.addChild(spellBottle);
spellBottleActive = true;
lastSpellBottleSpawnTick = ticksSinceStart;
}
}
} else if (spellBottle) {
// Move the spell bottle down the screen
spellBottle.y += 18 * gameSpeed;
// Off screen? Remove (if it has scrolled above the visible area)
if (spellBottle.y < -200 || spellBottle.y > 2732 + 200) {
spellBottle.destroy();
spellBottle = null;
spellBottleActive = false;
}
// Check collision with playerCar for shield pickup
if (spellBottle && !playerCar.shieldActive && spellBottle.intersects(playerCar)) {
// Grant shield for 3 seconds
playerCar.shieldActive = true;
playerCar.shieldTicks = 180; // 3 seconds at 60fps
// Optionally, you could add a visual effect here (not required)
spellBottle.destroy();
spellBottle = null;
spellBottleActive = false;
}
}
// Spawn enemies/obstacles every 40-60 ticks, randomize
spawnTick++;
var spawnInterval = 40 + Math.floor(Math.random() * 20);
if (spawnTick > spawnInterval) {
spawnObstacleOrEnemy();
spawnTick = 0;
}
// Update enemy cars
for (var i = enemyCars.length - 1; i >= 0; i--) {
var enemy = enemyCars[i];
enemy.update();
// Off screen
if (enemy.y > 2732 + 300) {
enemy.destroy();
enemyCars.splice(i, 1);
updateScore(score + 1);
continue;
}
// Collision with spell bottle
if (spellBottle && enemy.intersects(spellBottle)) {
spellBottle.destroy();
spellBottle = null;
spellBottleActive = false;
}
// Collision with player
if (enemy.intersects(playerCar)) {
if (playerCar.shieldActive) {
// Ignore collision, let player pass through enemy car while shield is active
continue;
} else {
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
}
// Update obstacles
for (var j = obstacles.length - 1; j >= 0; j--) {
var obs = obstacles[j];
obs.update();
// Off screen
if (obs.y > 2732 + 200) {
obs.destroy();
obstacles.splice(j, 1);
updateScore(score + 1);
continue;
}
// Collision with player
if (obs.intersects(playerCar)) {
if (playerCar.shieldActive) {
// Ignore collision, let player pass through obstacle while shield is active
continue;
} else {
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
}
;
// Shield timer logic
if (playerCar.shieldActive) {
playerCar.shieldTicks--;
// Show shield seconds left (rounded up)
var shieldSeconds = Math.ceil(playerCar.shieldTicks / 60);
shieldTxt.setText("Shield: " + shieldSeconds + "s");
if (playerCar.shieldTicks <= 0) {
playerCar.shieldActive = false;
playerCar.shieldTicks = 0;
shieldTxt.setText('');
}
} else {
shieldTxt.setText('');
}
};
// Center score text at very top, avoid top left 100x100
scoreTxt.x = LK.gui.top.width / 2;
scoreTxt.y = scoreTxt.height / 2 + 10;
// Position shield timer text directly below score
shieldTxt.x = LK.gui.top.width / 2;
shieldTxt.y = scoreTxt.y + scoreTxt.height / 2 + shieldTxt.height / 2 + 10;
// Position high score text directly below shield timer
highScoreTxt.x = LK.gui.top.width / 2;
highScoreTxt.y = shieldTxt.y + shieldTxt.height / 2 + highScoreTxt.height / 2 + 10;