/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Obstacle var Obstacle = Container.expand(function () { var self = Container.call(this); var obsAsset = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsAsset.width; self.height = obsAsset.height; self.speed = 0; self.lane = 1; self.update = function () { self.y += self.speed; }; return self; }); // Player Car var PlayerCar = Container.expand(function () { var self = Container.call(this); var carAsset = self.attachAsset('car', { anchorX: 0.5, anchorY: 0.5 }); self.width = carAsset.width; self.height = carAsset.height; self.lane = 1; // 0: left, 1: center, 2: right self.invincible = false; self.invincibleTimer = 0; // Flash effect for invincibility self.setInvincible = function (duration) { self.invincible = true; self.invincibleTimer = LK.ticks + Math.floor(duration * 60 / 1000); tween(self, { alpha: 0.5 }, { duration: 100, easing: tween.linear, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 100, easing: tween.linear }); } }); }; self.update = function () { if (self.invincible && LK.ticks > self.invincibleTimer) { self.invincible = false; self.alpha = 1; } }; return self; }); // PowerUp var PowerUp = Container.expand(function () { var self = Container.call(this); var puAsset = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.width = puAsset.width; self.height = puAsset.height; self.speed = 0; self.lane = 1; self.update = function () { self.y += self.speed; }; return self; }); // Rival Car var RivalCar = Container.expand(function () { var self = Container.call(this); var rivalAsset = self.attachAsset('rival', { anchorX: 0.5, anchorY: 0.5 }); self.width = rivalAsset.width; self.height = rivalAsset.height; self.speed = 0; self.lane = 1; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Lane positions (3 lanes) // Car (player) // Rival car // Obstacle (barrier) // Power-up (star) // Road lane var laneCount = 3; var laneWidth = 400; var laneX = [2048 / 2 - laneWidth, // left 2048 / 2, // center 2048 / 2 + laneWidth // right ]; // Draw road lanes (visual only) for (var i = 0; i < laneCount + 1; i++) { var laneLine = LK.getAsset('lane', { anchorX: 0.5, anchorY: 0, x: 2048 / 2 - laneWidth * 1.5 + i * laneWidth, y: 0, scaleY: 7 }); laneLine.alpha = 0.2; game.addChild(laneLine); } // Player car var player = new PlayerCar(); player.x = laneX[1]; player.y = 2732 - 400; player.lane = 1; game.addChild(player); // Score var score = 0; var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Power-up timer text var powerupTxt = new Text2('', { size: 70, fill: 0xFFE082 }); powerupTxt.anchor.set(0.5, 0); LK.gui.top.addChild(powerupTxt); powerupTxt.y = 130; // Game state var rivals = []; var obstacles = []; var powerups = []; var gameSpeed = 18; // pixels per frame var spawnTimer = 0; var powerupActive = false; var powerupEndTick = 0; var dragNode = null; var lastTouchX = 0; // Helper: Clamp lane function clampLane(lane) { if (lane < 0) return 0; if (lane > laneCount - 1) return laneCount - 1; return lane; } // Helper: Move player to x function movePlayerToX(x) { // Find closest lane var minDist = 99999; var bestLane = 1; for (var i = 0; i < laneCount; i++) { var dist = Math.abs(x - laneX[i]); if (dist < minDist) { minDist = dist; bestLane = i; } } player.lane = bestLane; // Tween to lane center tween.stop(player, { x: true }); tween(player, { x: laneX[bestLane] }, { duration: 120, easing: tween.cubicOut }); } // Touch/drag controls game.down = function (x, y, obj) { // Only allow drag if touch is on player car or below it if (y >= player.y - player.height / 2 && y <= player.y + player.height / 2) { dragNode = player; lastTouchX = x; } }; game.move = function (x, y, obj) { if (dragNode === player) { // Move car horizontally, snap to nearest lane movePlayerToX(x); lastTouchX = x; } }; game.up = function (x, y, obj) { dragNode = null; }; // Spawning logic function spawnRival() { var rival = new RivalCar(); rival.lane = Math.floor(Math.random() * laneCount); rival.x = laneX[rival.lane]; rival.y = -rival.height; rival.speed = gameSpeed + Math.random() * 4; rival.lastY = rival.y; rivals.push(rival); game.addChild(rival); } function spawnObstacle() { var obs = new Obstacle(); obs.lane = Math.floor(Math.random() * laneCount); obs.x = laneX[obs.lane]; obs.y = -obs.height; obs.speed = gameSpeed; obstacles.push(obs); game.addChild(obs); } function spawnPowerUp() { var pu = new PowerUp(); pu.lane = Math.floor(Math.random() * laneCount); pu.x = laneX[pu.lane]; pu.y = -pu.height; pu.speed = gameSpeed; powerups.push(pu); game.addChild(pu); } // Main update loop game.update = function () { // Increase score over time if (LK.ticks % 6 === 0) { score += 1; scoreTxt.setText(score); // Win condition: reach 500 points if (score >= 500) { LK.showYouWin(); return; } } // Power-up timer if (powerupActive) { var ticksLeft = powerupEndTick - LK.ticks; if (ticksLeft > 0) { powerupTxt.setText('Invincible: ' + Math.ceil(ticksLeft / 60) + 's'); } else { powerupActive = false; player.invincible = false; player.alpha = 1; powerupTxt.setText(''); } } // Player update (invincibility) player.update(); // Spawn rivals, obstacles, powerups if (spawnTimer <= 0) { var r = Math.random(); if (r < 0.45) { spawnRival(); } else if (r < 0.8) { spawnObstacle(); } else { spawnPowerUp(); } spawnTimer = 36 + Math.floor(Math.random() * 30); // ~0.6s } else { spawnTimer--; } // Update rivals for (var i = rivals.length - 1; i >= 0; i--) { var rival = rivals[i]; if (rival.lastY === undefined) rival.lastY = rival.y; // Track lastY for overtaking rival.update(); // Remove if off screen if (rival.y > 2732 + rival.height) { rival.destroy(); rivals.splice(i, 1); continue; } // Collision with player if (rival.intersects(player)) { if (!player.invincible) { LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } else { // Remove rival rival.destroy(); rivals.splice(i, 1); continue; } } // Overtake detection: player passes rival (player.y < rival.y, and was not before) if (rival.lastY < player.y && rival.y >= player.y) { score += 10; scoreTxt.setText(score); } rival.lastY = rival.y; } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); if (obs.y > 2732 + obs.height) { obs.destroy(); obstacles.splice(i, 1); continue; } if (obs.intersects(player)) { if (!player.invincible) { LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } else { obs.destroy(); obstacles.splice(i, 1); continue; } } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { var pu = powerups[i]; pu.update(); if (pu.y > 2732 + pu.height) { pu.destroy(); powerups.splice(i, 1); continue; } if (pu.intersects(player)) { // Activate invincibility for 3 seconds powerupActive = true; powerupEndTick = LK.ticks + 180; player.setInvincible(3000); powerupTxt.setText('Invincible: 3s'); // Flash player car yellow for feedback LK.effects.flashObject(player, 0xffeb3b, 600); // Play power-up sound LK.getSound('shoot').play(); pu.destroy(); powerups.splice(i, 1); continue; } } };
===================================================================
--- original.js
+++ change.js
@@ -103,14 +103,14 @@
/****
* Game Code
****/
-// Road lane
-// Power-up (star)
-// Obstacle (barrier)
-// Rival car
-// Car (player)
// Lane positions (3 lanes)
+// Car (player)
+// Rival car
+// Obstacle (barrier)
+// Power-up (star)
+// Road lane
var laneCount = 3;
var laneWidth = 400;
var laneX = [2048 / 2 - laneWidth,
// left
@@ -216,8 +216,9 @@
rival.lane = Math.floor(Math.random() * laneCount);
rival.x = laneX[rival.lane];
rival.y = -rival.height;
rival.speed = gameSpeed + Math.random() * 4;
+ rival.lastY = rival.y;
rivals.push(rival);
game.addChild(rival);
}
function spawnObstacle() {
@@ -243,8 +244,13 @@
// Increase score over time
if (LK.ticks % 6 === 0) {
score += 1;
scoreTxt.setText(score);
+ // Win condition: reach 500 points
+ if (score >= 500) {
+ LK.showYouWin();
+ return;
+ }
}
// Power-up timer
if (powerupActive) {
var ticksLeft = powerupEndTick - LK.ticks;
@@ -275,8 +281,9 @@
}
// Update rivals
for (var i = rivals.length - 1; i >= 0; i--) {
var rival = rivals[i];
+ if (rival.lastY === undefined) rival.lastY = rival.y; // Track lastY for overtaking
rival.update();
// Remove if off screen
if (rival.y > 2732 + rival.height) {
rival.destroy();
@@ -295,8 +302,14 @@
rivals.splice(i, 1);
continue;
}
}
+ // Overtake detection: player passes rival (player.y < rival.y, and was not before)
+ if (rival.lastY < player.y && rival.y >= player.y) {
+ score += 10;
+ scoreTxt.setText(score);
+ }
+ rival.lastY = rival.y;
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
@@ -332,8 +345,12 @@
powerupActive = true;
powerupEndTick = LK.ticks + 180;
player.setInvincible(3000);
powerupTxt.setText('Invincible: 3s');
+ // Flash player car yellow for feedback
+ LK.effects.flashObject(player, 0xffeb3b, 600);
+ // Play power-up sound
+ LK.getSound('shoot').play();
pu.destroy();
powerups.splice(i, 1);
continue;
}