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 ****/ // Coin // Obstacle // Car (player) // Game area 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 = 14; // Stripes move faster than obstacles // 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; // Mouse control toggle var mouseEnabled = true; function toggleMouse() { mouseEnabled = !mouseEnabled; } // 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; // Game state: wait for click to start var gameStarted = false; // Lives for extra life mechanic var lives = 0; // Start with zero life var livesTxt = new Text2('Lives: ' + lives, { size: 60, fill: "#fff" }); livesTxt.anchor.set(0.5, 0); livesTxt.x = LK.gui.top.width / 2; livesTxt.y = 90; LK.gui.top.addChild(livesTxt); var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); scoreTxt.x = LK.gui.top.width / 2; scoreTxt.y = 20; 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); // Start text overlay var startTxt = new Text2('Tap to Start', { size: 120, fill: "#fff" }); startTxt.anchor.set(0.5, 0.5); startTxt.x = LK.gui.top.width / 2; startTxt.y = 400; LK.gui.top.addChild(startTxt); // 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) { if (!gameStarted) { // Start game on first tap gameStarted = true; if (startTxt && startTxt.parent) { startTxt.parent.removeChild(startTxt); } return; } // Only start drag if touch is on car and mouse is enabled if (!mouseEnabled) return; 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 (!gameStarted) return; if (!mouseEnabled) return; 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) { if (!gameStarted) return; if (!mouseEnabled) return; dragCar = false; }; // Spawning var lastObstacleTick = 0; var lastCoinTick = 0; // Main update loop game.update = function () { if (!gameStarted) return; // 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); } // Spawn obstacles if (LK.ticks - lastObstacleTick >= obstacleInterval) { // Randomly choose which obstacle type to spawn var obsType = Math.random() < 0.5 ? 'obstacle' : 'obstacle2'; var obs; if (obsType === 'obstacle') { obs = new Obstacle(); } else { // Use obstacle2 asset for variety obs = new Obstacle(); var obsAsset = obs.children[0]; obsAsset.texture = LK.getAsset('obstacle2', { anchorX: 0.5, anchorY: 0.5 }).texture; obs.width = obsAsset.width; obs.height = obsAsset.height; } 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; } // 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 LK.effects.flashScreen(0xff0000, 800); if (lives > 0) { lives -= 1; livesTxt.setText('Lives: ' + lives); // Remove the obstacle and continue obs.destroy(); obstacles.splice(i, 1); continue; } else { 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); // Grant extra life every 50 points if (score > 0 && score % 50 === 0) { lives += 1; livesTxt.setText('Lives: ' + lives); } // 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; } // Also speed up road lines by 10% roadLineSpeed = Math.round(roadLineSpeed * 1.1); } // 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
@@ -231,8 +231,10 @@
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
+scoreTxt.x = LK.gui.top.width / 2;
+scoreTxt.y = 20;
LK.gui.top.addChild(scoreTxt);
var highscoreTxt = new Text2('High Score: ' + highscore, {
size: 60,
fill: 0xFFFF88