/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Collectible = Container.expand(function () {
var self = Container.call(this);
self.init = function (type) {
self.type = type;
var assetType;
switch (type) {
case 'coin':
assetType = 'coin';
break;
case 'shield':
assetType = 'shield';
break;
case 'speedBoost':
assetType = 'speedBoost';
break;
case 'superSpeedBoost':
assetType = 'speedBoost';
break;
default:
assetType = 'coin';
}
self.collectibleGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.collectibleGraphics.width;
self.height = self.collectibleGraphics.height;
self.lane = Math.floor(Math.random() * 4); // Randomly assign one of the 4 lanes
self.x = LANE_POSITIONS[self.lane];
// Animation
self.collectibleGraphics.rotation = 0;
return self;
};
self.update = function () {
self.y += gameSpeed.value;
// Rotate collectible
self.collectibleGraphics.rotation += 0.05;
// Check if the collectible is off-screen
if (self.y > 2732 + self.height) {
self.active = false;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = playerGraphics.width;
self.height = playerGraphics.height;
self.speed = 0;
self.lane = 1; // Center lane
self.shielded = false;
self.speedBoostActive = false;
self.speedBoostTimer = 0;
self.shieldTimer = 0;
self.shieldVisual = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.shieldVisual.scale.set(1.5, 1.5);
self.moveHorizontally = function (deltaX) {
self.x += deltaX;
// Ensure the player doesn't move out of the road boundaries
if (self.x < LANE_POSITIONS[0] - LANE_WIDTH / 2) {
self.x = LANE_POSITIONS[0] - LANE_WIDTH / 2;
} else if (self.x > LANE_POSITIONS[3] + LANE_WIDTH / 2) {
self.x = LANE_POSITIONS[3] + LANE_WIDTH / 2;
}
};
self.activateShield = function () {
self.shielded = true;
self.shieldTimer = 5 * 60; // 5 seconds at 60fps
tween(self.shieldVisual, {
alpha: 0.7
}, {
duration: 300
});
};
self.activateSpeedBoost = function () {
self.speedBoostActive = true;
self.speedBoostTimer = 3 * 60; // 3 seconds at 60fps
var boostMultiplier = self.type === 'superSpeedBoost' ? 6 : 1.5;
tween(gameSpeed, {
value: BASE_GAME_SPEED * boostMultiplier
}, {
duration: 300
});
};
self.update = function () {
if (self.shielded) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.shielded = false;
tween(self.shieldVisual, {
alpha: 0
}, {
duration: 300
});
}
}
if (self.speedBoostActive) {
self.speedBoostTimer--;
if (self.speedBoostTimer <= 0) {
self.speedBoostActive = false;
tween(gameSpeed, {
value: BASE_GAME_SPEED
}, {
duration: 500
});
}
}
};
return self;
});
var RoadSegment = Container.expand(function () {
var self = Container.call(this);
self.init = function () {
self.roadGraphics = self.attachAsset('road', {
anchorX: 0.5,
anchorY: 0.5
});
self.dividers = [];
for (var j = 0; j < 4; j++) {
// Create dividers between the 4 lanes
for (var i = 0; i < 20; i++) {
var divider = self.attachAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0.5
});
divider.x = LANE_POSITIONS[j] + LANE_WIDTH / 2;
divider.y = i * 150;
self.dividers.push(divider);
}
}
return self;
};
self.update = function () {
for (var i = 0; i < self.dividers.length; i++) {
var divider = self.dividers[i];
divider.y += gameSpeed.value;
// Reset divider position if it's off-screen
if (divider.y > 2732) {
divider.y = -100;
}
}
};
return self;
});
var Vehicle = Container.expand(function () {
var self = Container.call(this);
self.init = function (type) {
self.type = type;
var assetType;
switch (type) {
case 'car1':
case 'car2':
case 'car3':
assetType = type;
break;
case 'truck':
assetType = 'truck';
break;
default:
assetType = 'car1';
}
self.vehicleGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.vehicleGraphics.width;
self.height = self.vehicleGraphics.height;
self.lane = Math.floor(Math.random() * 4); // Randomly assign one of the 4 lanes
self.x = LANE_POSITIONS[self.lane];
self.speed = BASE_VEHICLE_SPEED - Math.random() * 2;
return self;
};
self.update = function () {
self.y += gameSpeed.value - self.speed;
// Check if the vehicle is off-screen
if (self.y > 2732 + self.height) {
self.active = false;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
// Constants
var BASE_GAME_SPEED = 10;
var BASE_VEHICLE_SPEED = 5;
var LANE_WIDTH = 600;
var LANE_POSITIONS = [512, 1024, 1536, 2048]; // Four lanes evenly spaced across the game width
// Game variables
var player;
var roadSegment;
var vehicles = [];
var collectibles = [];
var gameSpeed = {
value: BASE_GAME_SPEED
};
var score = 0;
var distance = 0;
var lastVehicleSpawn = 0;
var lastCollectibleSpawn = 0;
var spawnRate = 60; // Frames between vehicle spawns
var collectibleSpawnRate = 180; // Frames between collectible spawns
var difficultyTimer = 0;
var difficultyInterval = 1000; // Increase difficulty every 1000 frames
// Initialize game elements
function initGame() {
// Set up road
roadSegment = new RoadSegment();
roadSegment.init();
roadSegment.x = 2048 / 2;
roadSegment.y = 2732 / 2;
game.addChild(roadSegment);
// Set up player
player = new Player();
player.x = LANE_POSITIONS[1]; // Start in the second lane from the left
player.y = 2732 - 300; // Position near the bottom
game.addChild(player);
// Reset game state
vehicles = [];
collectibles = [];
gameSpeed.value = BASE_GAME_SPEED;
score = 0;
distance = 0;
lastVehicleSpawn = 0;
lastCollectibleSpawn = 0;
difficultyTimer = 0;
spawnRate = 60;
collectibleSpawnRate = 180;
// Start playing background music
LK.playMusic('highway_bgm');
// Update score display
LK.setScore(score);
updateScoreDisplay();
}
function spawnVehicle() {
var vehicleTypes = ['car1', 'car2', 'car3', 'truck'];
var type = vehicleTypes[Math.floor(Math.random() * vehicleTypes.length)];
var vehicle = new Vehicle();
vehicle.init(type);
vehicle.y = -vehicle.height;
vehicle.active = true;
vehicles.push(vehicle);
game.addChild(vehicle);
}
function spawnCollectible() {
var types = ['coin', 'shield', 'speedBoost', 'superSpeedBoost'];
var weights = [0.7, 0.1, 0.1, 0.1]; // 70% coins, 10% shields, 10% speed boosts, 10% super speed boosts
var rand = Math.random();
var type;
if (rand < weights[0]) {
type = types[0]; // coin
} else if (rand < weights[0] + weights[1]) {
type = types[1]; // shield
} else if (rand < weights[0] + weights[1] + weights[2]) {
type = types[2]; // speedBoost
} else {
type = types[3]; // superSpeedBoost
}
var collectible = new Collectible();
collectible.init(type);
collectible.y = -collectible.height;
collectible.active = true;
collectibles.push(collectible);
game.addChild(collectible);
}
function checkCollisions() {
// Check vehicle collisions
for (var i = 0; i < vehicles.length; i++) {
if (vehicles[i].active && player.intersects(vehicles[i])) {
if (player.shielded) {
// Shield protects from collision
player.shielded = false;
player.shieldTimer = 0;
tween(player.shieldVisual, {
alpha: 0
}, {
duration: 300
});
// Move the vehicle out of the way
tween(vehicles[i], {
x: vehicles[i].x + (Math.random() > 0.5 ? 200 : -200)
}, {
duration: 300,
easing: tween.easeOut
});
} else {
// Collision
LK.getSound('crash').play();
// Game over
if (score > storage.highScore) {
storage.highScore = score;
}
LK.showGameOver();
return true;
}
}
}
// Check collectible collisions
for (var j = 0; j < collectibles.length; j++) {
if (collectibles[j].active && player.intersects(collectibles[j])) {
switch (collectibles[j].type) {
case 'coin':
score += 10;
LK.getSound('coin_collect').play();
break;
case 'shield':
player.activateShield();
LK.getSound('powerup_collect').play();
break;
case 'speedBoost':
player.activateSpeedBoost();
LK.getSound('powerup_collect').play();
break;
case 'superSpeedBoost':
player.activateSpeedBoost();
LK.getSound('powerup_collect').play();
break;
}
collectibles[j].active = false;
collectibles[j].destroy();
collectibles.splice(j, 1);
j--;
// Update score
LK.setScore(score);
updateScoreDisplay();
}
}
return false;
}
function updateScoreDisplay() {
scoreText.setText("SCORE: " + score + "\nHIGH: " + storage.highScore);
}
function increaseDifficulty() {
spawnRate = Math.max(30, spawnRate - 1);
gameSpeed.value = Math.min(BASE_GAME_SPEED * 1.5, gameSpeed.value + 0.1);
}
// Set up UI
var scoreText = new Text2("SCORE: 0\nHIGH: " + storage.highScore, {
size: 70,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreText);
// Display speed on the top left corner
var speedText = new Text2("SPEED: " + gameSpeed.value.toFixed(1), {
size: 70,
fill: 0xFFFFFF
});
speedText.anchor.set(0, 0);
LK.gui.topLeft.addChild(speedText);
// Game controls
var touchStartX = 0;
var touchStartY = 0;
var swipeThreshold = 50;
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
};
game.move = function (x, y, obj) {
// Implemented in the up handler for better control
};
game.up = function (x, y, obj) {
// Move player to the x-coordinate of the click
player.x = x;
};
// Initialize the game
initGame();
// Game update loop
game.update = function () {
// Update distance/score
distance += gameSpeed.value / 60;
score = Math.floor(distance) + Math.floor(score);
LK.setScore(score);
// Update objects
roadSegment.update();
player.update();
// Spawn vehicles
lastVehicleSpawn++;
if (lastVehicleSpawn >= spawnRate) {
spawnVehicle();
lastVehicleSpawn = 0;
}
// Spawn collectibles
lastCollectibleSpawn++;
if (lastCollectibleSpawn >= collectibleSpawnRate) {
spawnCollectible();
lastCollectibleSpawn = 0;
}
// Update vehicles
for (var i = vehicles.length - 1; i >= 0; i--) {
if (vehicles[i].active) {
vehicles[i].update();
// Remove if inactive
if (!vehicles[i].active) {
vehicles[i].destroy();
vehicles.splice(i, 1);
}
}
}
// Update collectibles
for (var j = collectibles.length - 1; j >= 0; j--) {
if (collectibles[j].active) {
collectibles[j].update();
// Remove if inactive
if (!collectibles[j].active) {
collectibles[j].destroy();
collectibles.splice(j, 1);
}
}
}
// Check collisions
if (checkCollisions()) {
return; // Game over, stop updating
}
// Increase difficulty over time
difficultyTimer++;
if (difficultyTimer >= difficultyInterval) {
increaseDifficulty();
difficultyTimer = 0;
}
// Update the score display periodically
if (LK.ticks % 10 === 0) {
updateScoreDisplay();
speedText.setText("SPEED: " + gameSpeed.value.toFixed(1));
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Collectible = Container.expand(function () {
var self = Container.call(this);
self.init = function (type) {
self.type = type;
var assetType;
switch (type) {
case 'coin':
assetType = 'coin';
break;
case 'shield':
assetType = 'shield';
break;
case 'speedBoost':
assetType = 'speedBoost';
break;
case 'superSpeedBoost':
assetType = 'speedBoost';
break;
default:
assetType = 'coin';
}
self.collectibleGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.collectibleGraphics.width;
self.height = self.collectibleGraphics.height;
self.lane = Math.floor(Math.random() * 4); // Randomly assign one of the 4 lanes
self.x = LANE_POSITIONS[self.lane];
// Animation
self.collectibleGraphics.rotation = 0;
return self;
};
self.update = function () {
self.y += gameSpeed.value;
// Rotate collectible
self.collectibleGraphics.rotation += 0.05;
// Check if the collectible is off-screen
if (self.y > 2732 + self.height) {
self.active = false;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = playerGraphics.width;
self.height = playerGraphics.height;
self.speed = 0;
self.lane = 1; // Center lane
self.shielded = false;
self.speedBoostActive = false;
self.speedBoostTimer = 0;
self.shieldTimer = 0;
self.shieldVisual = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.shieldVisual.scale.set(1.5, 1.5);
self.moveHorizontally = function (deltaX) {
self.x += deltaX;
// Ensure the player doesn't move out of the road boundaries
if (self.x < LANE_POSITIONS[0] - LANE_WIDTH / 2) {
self.x = LANE_POSITIONS[0] - LANE_WIDTH / 2;
} else if (self.x > LANE_POSITIONS[3] + LANE_WIDTH / 2) {
self.x = LANE_POSITIONS[3] + LANE_WIDTH / 2;
}
};
self.activateShield = function () {
self.shielded = true;
self.shieldTimer = 5 * 60; // 5 seconds at 60fps
tween(self.shieldVisual, {
alpha: 0.7
}, {
duration: 300
});
};
self.activateSpeedBoost = function () {
self.speedBoostActive = true;
self.speedBoostTimer = 3 * 60; // 3 seconds at 60fps
var boostMultiplier = self.type === 'superSpeedBoost' ? 6 : 1.5;
tween(gameSpeed, {
value: BASE_GAME_SPEED * boostMultiplier
}, {
duration: 300
});
};
self.update = function () {
if (self.shielded) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.shielded = false;
tween(self.shieldVisual, {
alpha: 0
}, {
duration: 300
});
}
}
if (self.speedBoostActive) {
self.speedBoostTimer--;
if (self.speedBoostTimer <= 0) {
self.speedBoostActive = false;
tween(gameSpeed, {
value: BASE_GAME_SPEED
}, {
duration: 500
});
}
}
};
return self;
});
var RoadSegment = Container.expand(function () {
var self = Container.call(this);
self.init = function () {
self.roadGraphics = self.attachAsset('road', {
anchorX: 0.5,
anchorY: 0.5
});
self.dividers = [];
for (var j = 0; j < 4; j++) {
// Create dividers between the 4 lanes
for (var i = 0; i < 20; i++) {
var divider = self.attachAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0.5
});
divider.x = LANE_POSITIONS[j] + LANE_WIDTH / 2;
divider.y = i * 150;
self.dividers.push(divider);
}
}
return self;
};
self.update = function () {
for (var i = 0; i < self.dividers.length; i++) {
var divider = self.dividers[i];
divider.y += gameSpeed.value;
// Reset divider position if it's off-screen
if (divider.y > 2732) {
divider.y = -100;
}
}
};
return self;
});
var Vehicle = Container.expand(function () {
var self = Container.call(this);
self.init = function (type) {
self.type = type;
var assetType;
switch (type) {
case 'car1':
case 'car2':
case 'car3':
assetType = type;
break;
case 'truck':
assetType = 'truck';
break;
default:
assetType = 'car1';
}
self.vehicleGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.width = self.vehicleGraphics.width;
self.height = self.vehicleGraphics.height;
self.lane = Math.floor(Math.random() * 4); // Randomly assign one of the 4 lanes
self.x = LANE_POSITIONS[self.lane];
self.speed = BASE_VEHICLE_SPEED - Math.random() * 2;
return self;
};
self.update = function () {
self.y += gameSpeed.value - self.speed;
// Check if the vehicle is off-screen
if (self.y > 2732 + self.height) {
self.active = false;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
// Constants
var BASE_GAME_SPEED = 10;
var BASE_VEHICLE_SPEED = 5;
var LANE_WIDTH = 600;
var LANE_POSITIONS = [512, 1024, 1536, 2048]; // Four lanes evenly spaced across the game width
// Game variables
var player;
var roadSegment;
var vehicles = [];
var collectibles = [];
var gameSpeed = {
value: BASE_GAME_SPEED
};
var score = 0;
var distance = 0;
var lastVehicleSpawn = 0;
var lastCollectibleSpawn = 0;
var spawnRate = 60; // Frames between vehicle spawns
var collectibleSpawnRate = 180; // Frames between collectible spawns
var difficultyTimer = 0;
var difficultyInterval = 1000; // Increase difficulty every 1000 frames
// Initialize game elements
function initGame() {
// Set up road
roadSegment = new RoadSegment();
roadSegment.init();
roadSegment.x = 2048 / 2;
roadSegment.y = 2732 / 2;
game.addChild(roadSegment);
// Set up player
player = new Player();
player.x = LANE_POSITIONS[1]; // Start in the second lane from the left
player.y = 2732 - 300; // Position near the bottom
game.addChild(player);
// Reset game state
vehicles = [];
collectibles = [];
gameSpeed.value = BASE_GAME_SPEED;
score = 0;
distance = 0;
lastVehicleSpawn = 0;
lastCollectibleSpawn = 0;
difficultyTimer = 0;
spawnRate = 60;
collectibleSpawnRate = 180;
// Start playing background music
LK.playMusic('highway_bgm');
// Update score display
LK.setScore(score);
updateScoreDisplay();
}
function spawnVehicle() {
var vehicleTypes = ['car1', 'car2', 'car3', 'truck'];
var type = vehicleTypes[Math.floor(Math.random() * vehicleTypes.length)];
var vehicle = new Vehicle();
vehicle.init(type);
vehicle.y = -vehicle.height;
vehicle.active = true;
vehicles.push(vehicle);
game.addChild(vehicle);
}
function spawnCollectible() {
var types = ['coin', 'shield', 'speedBoost', 'superSpeedBoost'];
var weights = [0.7, 0.1, 0.1, 0.1]; // 70% coins, 10% shields, 10% speed boosts, 10% super speed boosts
var rand = Math.random();
var type;
if (rand < weights[0]) {
type = types[0]; // coin
} else if (rand < weights[0] + weights[1]) {
type = types[1]; // shield
} else if (rand < weights[0] + weights[1] + weights[2]) {
type = types[2]; // speedBoost
} else {
type = types[3]; // superSpeedBoost
}
var collectible = new Collectible();
collectible.init(type);
collectible.y = -collectible.height;
collectible.active = true;
collectibles.push(collectible);
game.addChild(collectible);
}
function checkCollisions() {
// Check vehicle collisions
for (var i = 0; i < vehicles.length; i++) {
if (vehicles[i].active && player.intersects(vehicles[i])) {
if (player.shielded) {
// Shield protects from collision
player.shielded = false;
player.shieldTimer = 0;
tween(player.shieldVisual, {
alpha: 0
}, {
duration: 300
});
// Move the vehicle out of the way
tween(vehicles[i], {
x: vehicles[i].x + (Math.random() > 0.5 ? 200 : -200)
}, {
duration: 300,
easing: tween.easeOut
});
} else {
// Collision
LK.getSound('crash').play();
// Game over
if (score > storage.highScore) {
storage.highScore = score;
}
LK.showGameOver();
return true;
}
}
}
// Check collectible collisions
for (var j = 0; j < collectibles.length; j++) {
if (collectibles[j].active && player.intersects(collectibles[j])) {
switch (collectibles[j].type) {
case 'coin':
score += 10;
LK.getSound('coin_collect').play();
break;
case 'shield':
player.activateShield();
LK.getSound('powerup_collect').play();
break;
case 'speedBoost':
player.activateSpeedBoost();
LK.getSound('powerup_collect').play();
break;
case 'superSpeedBoost':
player.activateSpeedBoost();
LK.getSound('powerup_collect').play();
break;
}
collectibles[j].active = false;
collectibles[j].destroy();
collectibles.splice(j, 1);
j--;
// Update score
LK.setScore(score);
updateScoreDisplay();
}
}
return false;
}
function updateScoreDisplay() {
scoreText.setText("SCORE: " + score + "\nHIGH: " + storage.highScore);
}
function increaseDifficulty() {
spawnRate = Math.max(30, spawnRate - 1);
gameSpeed.value = Math.min(BASE_GAME_SPEED * 1.5, gameSpeed.value + 0.1);
}
// Set up UI
var scoreText = new Text2("SCORE: 0\nHIGH: " + storage.highScore, {
size: 70,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreText);
// Display speed on the top left corner
var speedText = new Text2("SPEED: " + gameSpeed.value.toFixed(1), {
size: 70,
fill: 0xFFFFFF
});
speedText.anchor.set(0, 0);
LK.gui.topLeft.addChild(speedText);
// Game controls
var touchStartX = 0;
var touchStartY = 0;
var swipeThreshold = 50;
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
};
game.move = function (x, y, obj) {
// Implemented in the up handler for better control
};
game.up = function (x, y, obj) {
// Move player to the x-coordinate of the click
player.x = x;
};
// Initialize the game
initGame();
// Game update loop
game.update = function () {
// Update distance/score
distance += gameSpeed.value / 60;
score = Math.floor(distance) + Math.floor(score);
LK.setScore(score);
// Update objects
roadSegment.update();
player.update();
// Spawn vehicles
lastVehicleSpawn++;
if (lastVehicleSpawn >= spawnRate) {
spawnVehicle();
lastVehicleSpawn = 0;
}
// Spawn collectibles
lastCollectibleSpawn++;
if (lastCollectibleSpawn >= collectibleSpawnRate) {
spawnCollectible();
lastCollectibleSpawn = 0;
}
// Update vehicles
for (var i = vehicles.length - 1; i >= 0; i--) {
if (vehicles[i].active) {
vehicles[i].update();
// Remove if inactive
if (!vehicles[i].active) {
vehicles[i].destroy();
vehicles.splice(i, 1);
}
}
}
// Update collectibles
for (var j = collectibles.length - 1; j >= 0; j--) {
if (collectibles[j].active) {
collectibles[j].update();
// Remove if inactive
if (!collectibles[j].active) {
collectibles[j].destroy();
collectibles.splice(j, 1);
}
}
}
// Check collisions
if (checkCollisions()) {
return; // Game over, stop updating
}
// Increase difficulty over time
difficultyTimer++;
if (difficultyTimer >= difficultyInterval) {
increaseDifficulty();
difficultyTimer = 0;
}
// Update the score display periodically
if (LK.ticks % 10 === 0) {
updateScoreDisplay();
speedText.setText("SPEED: " + gameSpeed.value.toFixed(1));
}
};