/****
* 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;
}