/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Coin Class
var Coin = Container.expand(function () {
var self = Container.call(this);
// Gold ellipse for coin
var coin = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
color: 0xffd700,
width: 100,
height: 100,
shape: 'ellipse'
});
self.width = coin.width;
self.height = coin.height;
// Speed will be set on spawn
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Obstacle Car Class
var ObstacleCar = Container.expand(function () {
var self = Container.call(this);
// Random color for variety
var colors = [0x1e90ff, 0x32cd32, 0xffa500, 0x8a2be2, 0xff1493, 0x00ced1];
var color = colors[Math.floor(Math.random() * colors.length)];
var car = self.attachAsset('obstacleCar', {
anchorX: 0.5,
anchorY: 0.5,
color: color,
width: 200,
height: 300
});
self.width = car.width;
self.height = car.height;
// Speed will be set on spawn
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Car Class
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
// Attach car asset (red box)
var car = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
// Set initial size (about 200x300 px)
car.width = 200;
car.height = 300;
// For collision, use self as the hitbox
self.width = car.width;
self.height = car.height;
// No update needed; position is set by drag
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game area: 2048x2732
// Road boundaries (leave 200px margin on each side)
var roadLeft = 200;
var roadRight = 2048 - 200;
var roadWidth = roadRight - roadLeft;
// Lane count and positions
var laneCount = 4;
var laneWidth = roadWidth / laneCount;
var laneCenters = [];
for (var i = 0; i < laneCount; i++) {
laneCenters.push(roadLeft + laneWidth * (i + 0.5));
}
// Game state variables
var playerCar;
var obstacles = [];
var coins = [];
var dragNode = null;
var lastCrash = false;
var speed = 18; // Initial speed (pixels per frame)
var minSpeed = 12;
var maxSpeed = 38;
var speedIncreaseEvery = 600; // Increase speed every 600 ticks (~10s)
var ticksSinceStart = 0;
var distance = 0; // Distance in meters (1 meter = 10px)
var coinScore = 0;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Coin text
var coinTxt = new Text2('0', {
size: 80,
fill: 0xFFD700
});
coinTxt.anchor.set(0.5, 0);
LK.gui.topRight.addChild(coinTxt);
// Draw road (gray box)
var road = LK.getAsset('road', {
anchorX: 0,
anchorY: 0,
color: 0x444444,
width: roadWidth,
height: 2732
});
road.x = roadLeft;
road.y = 0;
game.addChild(road);
// Draw lane lines (white boxes)
for (var i = 1; i < laneCount; i++) {
var line = LK.getAsset('laneLine' + i, {
anchorX: 0.5,
anchorY: 0,
color: 0xffffff,
width: 16,
height: 2732,
shape: 'box'
});
line.x = roadLeft + laneWidth * i;
line.y = 0;
line.alpha = 0.2;
game.addChild(line);
}
// Create player car
playerCar = new PlayerCar();
playerCar.x = laneCenters[1]; // Start in lane 2
playerCar.y = 2732 - 400;
game.addChild(playerCar);
// Touch/drag controls
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp x to road
var newX = Math.max(roadLeft + playerCar.width / 2, Math.min(roadRight - playerCar.width / 2, x));
dragNode.x = newX;
}
// Crash detection
var crashed = false;
for (var i = 0; i < obstacles.length; i++) {
if (playerCar.intersects(obstacles[i])) {
crashed = true;
break;
}
}
if (!lastCrash && crashed) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
lastCrash = crashed;
// Coin collection
for (var i = coins.length - 1; i >= 0; i--) {
if (playerCar.intersects(coins[i])) {
coinScore += 1;
coinTxt.setText(coinScore);
LK.effects.flashObject(coins[i], 0xffd700, 300);
coins[i].destroy();
coins.splice(i, 1);
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only allow drag if touch is on player car or below it
if (x >= playerCar.x - playerCar.width / 2 && x <= playerCar.x + playerCar.width / 2 && y >= playerCar.y - playerCar.height / 2 && y <= playerCar.y + playerCar.height / 2) {
dragNode = playerCar;
} else if (y > playerCar.y) {
dragNode = playerCar;
}
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game loop
game.update = function () {
ticksSinceStart += 1;
// Increase speed over time
if (ticksSinceStart % speedIncreaseEvery === 0 && speed < maxSpeed) {
speed += 2;
if (speed > maxSpeed) speed = maxSpeed;
}
// Move obstacles and coins
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.speed = speed;
obs.update();
if (obs.y > 2732 + 200) {
obs.destroy();
obstacles.splice(i, 1);
}
}
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
coin.speed = speed;
coin.update();
if (coin.y > 2732 + 100) {
coin.destroy();
coins.splice(i, 1);
}
}
// Spawn obstacles
// Every 45 ticks (~0.75s at 60fps)
if (LK.ticks % 45 === 0) {
// Randomly pick 1-2 lanes to spawn cars
var lanesToUse = [];
var laneIndexes = [0, 1, 2, 3];
// Shuffle
for (var i = laneIndexes.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var t = laneIndexes[i];
laneIndexes[i] = laneIndexes[j];
laneIndexes[j] = t;
}
var carCount = Math.random() < 0.7 ? 1 : 2;
for (var i = 0; i < carCount; i++) {
lanesToUse.push(laneIndexes[i]);
}
for (var i = 0; i < lanesToUse.length; i++) {
var obs = new ObstacleCar();
obs.x = laneCenters[lanesToUse[i]];
obs.y = -200;
obs.speed = speed;
obstacles.push(obs);
game.addChild(obs);
}
}
// Spawn coins
// Every 60 ticks (~1s)
if (LK.ticks % 60 === 0) {
// 50% chance to spawn a coin in a random lane not blocked by a car
if (Math.random() < 0.5) {
// Find lanes without a car near the top
var freeLanes = [];
for (var i = 0; i < laneCount; i++) {
var blocked = false;
for (var j = 0; j < obstacles.length; j++) {
if (Math.abs(obstacles[j].x - laneCenters[i]) < 10 && obstacles[j].y < 200) {
blocked = true;
break;
}
}
if (!blocked) freeLanes.push(i);
}
if (freeLanes.length > 0) {
var laneIdx = freeLanes[Math.floor(Math.random() * freeLanes.length)];
var coin = new Coin();
coin.x = laneCenters[laneIdx];
coin.y = -100;
coin.speed = speed;
coins.push(coin);
game.addChild(coin);
}
}
}
// Update distance and score
distance += speed / 10; // 1 meter = 10px
var score = Math.floor(distance) + coinScore * 10;
scoreTxt.setText(score);
// Coin text (already updated on collect)
};
// Set initial score and coin text
scoreTxt.setText('0');
coinTxt.setText('0'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Coin Class
var Coin = Container.expand(function () {
var self = Container.call(this);
// Gold ellipse for coin
var coin = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
color: 0xffd700,
width: 100,
height: 100,
shape: 'ellipse'
});
self.width = coin.width;
self.height = coin.height;
// Speed will be set on spawn
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Obstacle Car Class
var ObstacleCar = Container.expand(function () {
var self = Container.call(this);
// Random color for variety
var colors = [0x1e90ff, 0x32cd32, 0xffa500, 0x8a2be2, 0xff1493, 0x00ced1];
var color = colors[Math.floor(Math.random() * colors.length)];
var car = self.attachAsset('obstacleCar', {
anchorX: 0.5,
anchorY: 0.5,
color: color,
width: 200,
height: 300
});
self.width = car.width;
self.height = car.height;
// Speed will be set on spawn
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Car Class
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
// Attach car asset (red box)
var car = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
// Set initial size (about 200x300 px)
car.width = 200;
car.height = 300;
// For collision, use self as the hitbox
self.width = car.width;
self.height = car.height;
// No update needed; position is set by drag
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Game area: 2048x2732
// Road boundaries (leave 200px margin on each side)
var roadLeft = 200;
var roadRight = 2048 - 200;
var roadWidth = roadRight - roadLeft;
// Lane count and positions
var laneCount = 4;
var laneWidth = roadWidth / laneCount;
var laneCenters = [];
for (var i = 0; i < laneCount; i++) {
laneCenters.push(roadLeft + laneWidth * (i + 0.5));
}
// Game state variables
var playerCar;
var obstacles = [];
var coins = [];
var dragNode = null;
var lastCrash = false;
var speed = 18; // Initial speed (pixels per frame)
var minSpeed = 12;
var maxSpeed = 38;
var speedIncreaseEvery = 600; // Increase speed every 600 ticks (~10s)
var ticksSinceStart = 0;
var distance = 0; // Distance in meters (1 meter = 10px)
var coinScore = 0;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Coin text
var coinTxt = new Text2('0', {
size: 80,
fill: 0xFFD700
});
coinTxt.anchor.set(0.5, 0);
LK.gui.topRight.addChild(coinTxt);
// Draw road (gray box)
var road = LK.getAsset('road', {
anchorX: 0,
anchorY: 0,
color: 0x444444,
width: roadWidth,
height: 2732
});
road.x = roadLeft;
road.y = 0;
game.addChild(road);
// Draw lane lines (white boxes)
for (var i = 1; i < laneCount; i++) {
var line = LK.getAsset('laneLine' + i, {
anchorX: 0.5,
anchorY: 0,
color: 0xffffff,
width: 16,
height: 2732,
shape: 'box'
});
line.x = roadLeft + laneWidth * i;
line.y = 0;
line.alpha = 0.2;
game.addChild(line);
}
// Create player car
playerCar = new PlayerCar();
playerCar.x = laneCenters[1]; // Start in lane 2
playerCar.y = 2732 - 400;
game.addChild(playerCar);
// Touch/drag controls
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp x to road
var newX = Math.max(roadLeft + playerCar.width / 2, Math.min(roadRight - playerCar.width / 2, x));
dragNode.x = newX;
}
// Crash detection
var crashed = false;
for (var i = 0; i < obstacles.length; i++) {
if (playerCar.intersects(obstacles[i])) {
crashed = true;
break;
}
}
if (!lastCrash && crashed) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
lastCrash = crashed;
// Coin collection
for (var i = coins.length - 1; i >= 0; i--) {
if (playerCar.intersects(coins[i])) {
coinScore += 1;
coinTxt.setText(coinScore);
LK.effects.flashObject(coins[i], 0xffd700, 300);
coins[i].destroy();
coins.splice(i, 1);
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only allow drag if touch is on player car or below it
if (x >= playerCar.x - playerCar.width / 2 && x <= playerCar.x + playerCar.width / 2 && y >= playerCar.y - playerCar.height / 2 && y <= playerCar.y + playerCar.height / 2) {
dragNode = playerCar;
} else if (y > playerCar.y) {
dragNode = playerCar;
}
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game loop
game.update = function () {
ticksSinceStart += 1;
// Increase speed over time
if (ticksSinceStart % speedIncreaseEvery === 0 && speed < maxSpeed) {
speed += 2;
if (speed > maxSpeed) speed = maxSpeed;
}
// Move obstacles and coins
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.speed = speed;
obs.update();
if (obs.y > 2732 + 200) {
obs.destroy();
obstacles.splice(i, 1);
}
}
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
coin.speed = speed;
coin.update();
if (coin.y > 2732 + 100) {
coin.destroy();
coins.splice(i, 1);
}
}
// Spawn obstacles
// Every 45 ticks (~0.75s at 60fps)
if (LK.ticks % 45 === 0) {
// Randomly pick 1-2 lanes to spawn cars
var lanesToUse = [];
var laneIndexes = [0, 1, 2, 3];
// Shuffle
for (var i = laneIndexes.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var t = laneIndexes[i];
laneIndexes[i] = laneIndexes[j];
laneIndexes[j] = t;
}
var carCount = Math.random() < 0.7 ? 1 : 2;
for (var i = 0; i < carCount; i++) {
lanesToUse.push(laneIndexes[i]);
}
for (var i = 0; i < lanesToUse.length; i++) {
var obs = new ObstacleCar();
obs.x = laneCenters[lanesToUse[i]];
obs.y = -200;
obs.speed = speed;
obstacles.push(obs);
game.addChild(obs);
}
}
// Spawn coins
// Every 60 ticks (~1s)
if (LK.ticks % 60 === 0) {
// 50% chance to spawn a coin in a random lane not blocked by a car
if (Math.random() < 0.5) {
// Find lanes without a car near the top
var freeLanes = [];
for (var i = 0; i < laneCount; i++) {
var blocked = false;
for (var j = 0; j < obstacles.length; j++) {
if (Math.abs(obstacles[j].x - laneCenters[i]) < 10 && obstacles[j].y < 200) {
blocked = true;
break;
}
}
if (!blocked) freeLanes.push(i);
}
if (freeLanes.length > 0) {
var laneIdx = freeLanes[Math.floor(Math.random() * freeLanes.length)];
var coin = new Coin();
coin.x = laneCenters[laneIdx];
coin.y = -100;
coin.speed = speed;
coins.push(coin);
game.addChild(coin);
}
}
}
// Update distance and score
distance += speed / 10; // 1 meter = 10px
var score = Math.floor(distance) + coinScore * 10;
scoreTxt.setText(score);
// Coin text (already updated on collect)
};
// Set initial score and coin text
scoreTxt.setText('0');
coinTxt.setText('0');