User prompt
show lives on lower right
User prompt
use heart to show lives
User prompt
show lives as hearts in lower left
User prompt
show score over lives
User prompt
show score on middle top
User prompt
toggle mouse
User prompt
start game with a click
User prompt
start with 0 life
User prompt
start with one life
User prompt
give additional life after each 50 points
User prompt
spawn random obstacles
User prompt
speedup lanes as game speeds up
User prompt
match lane speed to obstacles
User prompt
spawn obstacles randomly
User prompt
score counter in top middle
User prompt
rename best to high score
User prompt
keep highscore ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
obsticles move smoothly ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
speed up lanes as game speeds up
User prompt
speed up game 10% every 10 points
User prompt
put bars on roadsides
User prompt
there are buidings on road sides
User prompt
obsticles can change position
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highscore: 0
});
/****
* Classes
****/
// Player Car
var Car = 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;
// For collision box
// Removed custom getBounds to avoid recursion bug
return self;
});
// Coin
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinAsset = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = coinAsset.width;
self.height = coinAsset.height;
self.speed = 10; // Will be increased by game
self.update = function () {
self.y += self.speed;
};
// Removed custom getBounds to avoid recursion bug
return self;
});
// Obstacle
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obsAsset = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
// Assign a random color tint to the obstacle asset
var obstacleColors = [0xff4444,
// red
0x44aaff,
// blue
0x44ff44,
// green
0xffcc44,
// yellow
0xff44cc,
// pink
0xffffff,
// white
0xff8800,
// orange
0x888888 // gray
];
var colorIdx = Math.floor(Math.random() * obstacleColors.length);
obsAsset.tint = obstacleColors[colorIdx];
self.width = obsAsset.width;
self.height = obsAsset.height;
self.speed = 10; // Will be increased by game
self.update = function () {
// Store lastX for event triggers if needed
if (self.lastX === undefined) self.lastX = self.x;
// Move down
self.y += self.speed;
// Smoothly tween X position for swerving
if (!self._swerveTween || self._swerveTween.finished) {
// Pick a new target X within lane bounds
var laneIdx = Math.floor(self.x / (2048 / 3));
var laneLeft = laneIdx * (2048 / 3);
var laneRight = (laneIdx + 1) * (2048 / 3);
var minX = laneLeft + self.width / 2;
var maxX = laneRight - self.width / 2;
var swerveAmount = 120 + Math.random() * 120; // up to 240px swerve
var direction = Math.random() < 0.5 ? -1 : 1;
var targetX = self.x + direction * swerveAmount;
targetX = Math.max(minX, Math.min(maxX, targetX));
// Tween to new X over 0.3-0.6s
var duration = 300 + Math.random() * 300;
self._swerveTween = {
finished: false
};
tween(self, {
x: targetX
}, {
duration: duration,
easing: tween.easeInOut,
onFinish: function onFinish() {
self._swerveTween.finished = true;
}
});
}
self.lastX = self.x;
};
// Removed custom getBounds to avoid recursion bug
return self;
});
// RoadLine: vertical dashed line for road center/lanes
var RoadLine = Container.expand(function () {
var self = Container.call(this);
// Parameters for dashed line
var dashHeight = 120;
var gap = 80;
var lineWidth = 24;
var color = 0xffffff;
var y = 0;
// Fill vertical line with dashes
while (y < 2732 + dashHeight) {
var dash = LK.getAsset('roadline_dash', {
width: lineWidth,
height: dashHeight,
color: color,
shape: 'box',
anchorX: 0.5,
anchorY: 0
});
dash.x = 0;
dash.y = y;
self.addChild(dash);
y += dashHeight + gap;
}
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game area
// Car (player)
// Obstacle
// Coin
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
// Lane system (3 lanes)
var LANE_COUNT = 3;
var LANE_WIDTH = GAME_WIDTH / LANE_COUNT;
var LANE_X = [Math.floor(LANE_WIDTH / 2), Math.floor(GAME_WIDTH / 2), Math.floor(GAME_WIDTH - LANE_WIDTH / 2)];
// Draw road lines (between lanes)
var roadLines = [];
for (var i = 1; i < LANE_COUNT; i++) {
var line = new RoadLine();
line.x = i * LANE_WIDTH;
line.y = 0;
game.addChild(line);
roadLines.push(line);
}
// Add roadside bars (left and right)
var barWidth = 60;
var barColor = 0x888888;
var barHeight = GAME_HEIGHT + 200; // a bit longer for scrolling
var leftBar = LK.getAsset('roadline_dash', {
width: barWidth,
height: barHeight,
color: barColor,
shape: 'box',
anchorX: 0.5,
anchorY: 0
});
leftBar.x = barWidth / 2;
leftBar.y = -100;
game.addChild(leftBar);
var rightBar = LK.getAsset('roadline_dash', {
width: barWidth,
height: barHeight,
color: barColor,
shape: 'box',
anchorX: 0.5,
anchorY: 0
});
rightBar.x = GAME_WIDTH - barWidth / 2;
rightBar.y = -100;
game.addChild(rightBar);
// For rolling stripes
var roadLineSpeed = baseSpeed; // Match initial obstacle speed
// Player car
var car = new Car();
game.addChild(car);
car.x = GAME_WIDTH / 2;
car.y = GAME_HEIGHT - 400;
// Dragging
var dragCar = false;
var dragOffsetX = 0;
// Obstacles and coins
var obstacles = [];
var coins = [];
// Difficulty
var baseSpeed = 10; // Slower starting speed
var speed = baseSpeed;
var speedIncreaseInterval = 600; // every 10 seconds (60*10)
var minObstacleInterval = 36; // minimum ticks between obstacles
var obstacleInterval = 60; // ticks between obstacles, will decrease
var minCoinInterval = 30;
var coinInterval = 60;
// Score
var score = 0;
var highscore = storage.highscore || 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var highscoreTxt = new Text2('High Score: ' + highscore, {
size: 60,
fill: 0xFFFF88
});
highscoreTxt.anchor.set(0.5, 0);
highscoreTxt.x = LK.gui.top.width / 2;
highscoreTxt.y = 150;
LK.gui.top.addChild(highscoreTxt);
// Helper: collision
function rectsIntersect(a, b) {
return !(a.x + a.width < b.x || a.x > b.x + b.width || a.y + a.height < b.y || a.y > b.y + b.height);
}
// Touch controls
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
game.down = function (x, y, obj) {
// Only start drag if touch is on car
var local = car.toLocal(game.toGlobal({
x: x,
y: y
}));
if (local.x >= -car.width / 2 && local.x <= car.width / 2 && local.y >= -car.height / 2 && local.y <= car.height / 2) {
dragCar = true;
dragOffsetX = car.x - x;
}
};
game.move = function (x, y, obj) {
if (dragCar) {
// Only move horizontally, clamp to game area
var newX = clamp(x + dragOffsetX, car.width / 2, GAME_WIDTH - car.width / 2);
car.x = newX;
}
};
game.up = function (x, y, obj) {
dragCar = false;
};
// Spawning
var lastObstacleTick = 0;
var lastCoinTick = 0;
// Main update loop
game.update = function () {
// Increase speed and difficulty over time
if (LK.ticks % speedIncreaseInterval === 0 && LK.ticks > 0) {
speed += 1; // Slower speed increase
obstacleInterval = Math.max(minObstacleInterval, obstacleInterval - 4);
coinInterval = Math.max(minCoinInterval, coinInterval - 2);
// Match road line speed to obstacle speed as game speeds up
roadLineSpeed = speed;
}
// Spawn obstacles at random intervals
if (LK.ticks - lastObstacleTick >= obstacleInterval) {
var obs = new Obstacle();
obs.speed = speed;
// Random lane
var lane = Math.floor(Math.random() * LANE_COUNT);
// Allow obstacle to be anywhere inside the lane, not just center
var laneLeft = lane * LANE_WIDTH;
var laneRight = (lane + 1) * LANE_WIDTH;
var minX = laneLeft + obs.width / 2;
var maxX = laneRight - obs.width / 2;
obs.x = minX + Math.random() * (maxX - minX);
obs.y = -obs.height / 2;
obstacles.push(obs);
game.addChild(obs);
lastObstacleTick = LK.ticks;
// Set next obstacleInterval randomly between minObstacleInterval and 1.5x obstacleInterval
obstacleInterval = Math.floor(minObstacleInterval + Math.random() * (Math.max(minObstacleInterval, Math.floor(obstacleInterval * 1.5)) - minObstacleInterval));
}
// Spawn coins
if (LK.ticks - lastCoinTick >= coinInterval) {
var coin = new Coin();
coin.speed = speed;
// Random lane, but not same as last obstacle
var lane = Math.floor(Math.random() * LANE_COUNT);
coin.x = LANE_X[lane];
coin.y = -coin.height / 2 - 200;
coins.push(coin);
game.addChild(coin);
lastCoinTick = LK.ticks;
}
// Move road lines down and wrap
for (var rl = 0; rl < roadLines.length; rl++) {
var line = roadLines[rl];
line.y += roadLineSpeed;
// The height of the dashed line pattern is dash+gap repeated, so wrap when y > dash+gap
// We know from RoadLine: dashHeight=120, gap=80, so pattern=200
var patternHeight = 120 + 80;
if (line.y >= patternHeight) {
line.y -= patternHeight;
}
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if off screen
if (obs.y - obs.height / 2 > GAME_HEIGHT + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with car
if (rectsIntersect(obs.getBounds(), car.getBounds())) {
// Flash and game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
// Update coins
for (var j = coins.length - 1; j >= 0; j--) {
var coin = coins[j];
coin.update();
// Remove if off screen
if (coin.y - coin.height / 2 > GAME_HEIGHT + 100) {
coin.destroy();
coins.splice(j, 1);
continue;
}
// Collect coin
if (rectsIntersect(coin.getBounds(), car.getBounds())) {
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Update highscore if beaten
if (score > highscore) {
highscore = score;
storage.highscore = highscore;
highscoreTxt.setText('High Score: ' + highscore);
}
// Speed up game by 10% every 10 points
if (score % 10 === 0 && score > 0) {
speed = Math.round(speed * 1.1);
// Also update all current obstacles and coins to new speed
for (var oi = 0; oi < obstacles.length; oi++) {
obstacles[oi].speed = speed;
}
for (var ci = 0; ci < coins.length; ci++) {
coins[ci].speed = speed;
}
// Match road line speed to obstacle speed
roadLineSpeed = speed;
}
// Animate coin
tween(coin, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
coin.destroy();
}
});
coins.splice(j, 1);
}
}
};
// Center score text at top, avoid top left 100x100
scoreTxt.x = LK.gui.top.width / 2;
scoreTxt.y = 20; ===================================================================
--- original.js
+++ change.js
@@ -262,8 +262,10 @@
if (LK.ticks % speedIncreaseInterval === 0 && LK.ticks > 0) {
speed += 1; // Slower speed increase
obstacleInterval = Math.max(minObstacleInterval, obstacleInterval - 4);
coinInterval = Math.max(minCoinInterval, coinInterval - 2);
+ // Match road line speed to obstacle speed as game speeds up
+ roadLineSpeed = speed;
}
// Spawn obstacles at random intervals
if (LK.ticks - lastObstacleTick >= obstacleInterval) {
var obs = new Obstacle();