/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bike = Container.expand(function () {
var self = Container.call(this);
var bikeBody = self.attachAsset('bike', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWheel = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
x: 25,
y: 15
});
var backWheel = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
x: -25,
y: 15
});
self.velocityY = 0;
self.gravity = 0.8;
self.jumpPower = -18;
self.isGrounded = false;
self.groundY = 0;
self.jump = function (chargeMultiplier) {
if (self.isGrounded) {
var jumpStrength = self.jumpPower * (1 + chargeMultiplier);
self.velocityY = jumpStrength;
self.isGrounded = false;
LK.getSound('jump').play();
}
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Ground collision
if (self.y >= self.groundY) {
self.y = self.groundY;
self.velocityY = 0;
self.isGrounded = true;
}
// Animate wheels
frontWheel.rotation += 0.3;
backWheel.rotation += 0.3;
// Bike tilt based on velocity
bikeBody.rotation = self.velocityY * 0.02;
};
return self;
});
var GroundSegment = Container.expand(function () {
var self = Container.call(this);
var groundGraphics = self.attachAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -18;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -18;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Ramp = Container.expand(function () {
var self = Container.call(this);
var rampGraphics = self.attachAsset('ramp', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -18;
self.update = function () {
self.x += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var bike;
var obstacles = [];
var ramps = [];
var groundSegments = [];
var gameSpeed = 18;
var distanceScore = 0;
var isGameRunning = true;
var groundLevel = 2400;
var lastObstacleSpawn = 0;
var spawnDistance = 300;
var currentLevel = 1;
var levelDistance = 500; // Distance between level changes
var levelConfigs = [
// Level 1: Easy - Single obstacles
{
obstacleChance: 0.6,
rampChance: 0.4,
minSpacing: 250,
maxSpacing: 400,
patterns: ['single']
},
// Level 2: Medium - Paired obstacles
{
obstacleChance: 0.7,
rampChance: 0.3,
minSpacing: 200,
maxSpacing: 350,
patterns: ['single', 'double']
},
// Level 3: Hard - Triple obstacles and gaps
{
obstacleChance: 0.75,
rampChance: 0.25,
minSpacing: 180,
maxSpacing: 300,
patterns: ['single', 'double', 'triple']
},
// Level 4: Expert - Mixed patterns with tight spacing
{
obstacleChance: 0.8,
rampChance: 0.2,
minSpacing: 150,
maxSpacing: 250,
patterns: ['single', 'double', 'triple', 'staggered']
},
// Level 5: Master - All patterns with minimal spacing
{
obstacleChance: 0.85,
rampChance: 0.15,
minSpacing: 120,
maxSpacing: 200,
patterns: ['single', 'double', 'triple', 'staggered', 'wall']
}];
var isCharging = false;
var chargeStartTime = 0;
var currentCharge = 0;
var maxCharge = 100;
var chargeRate = 2;
// Create score display
var scoreTxt = new Text2('Distance: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create jump meter background
var meterBg = LK.getAsset('obstacle', {
anchorX: 0,
anchorY: 0,
scaleX: 4,
scaleY: 0.5,
tint: 0x333333
});
meterBg.x = 100;
meterBg.y = 150;
LK.gui.topLeft.addChild(meterBg);
// Create jump meter fill
var meterFill = LK.getAsset('obstacle', {
anchorX: 0,
anchorY: 0,
scaleX: 0,
scaleY: 0.5,
tint: 0x00ff00
});
meterFill.x = 100;
meterFill.y = 150;
LK.gui.topLeft.addChild(meterFill);
// Create jump meter label
var meterLabel = new Text2('JUMP POWER', {
size: 40,
fill: 0xFFFFFF
});
meterLabel.anchor.set(0, 0);
meterLabel.x = 100;
meterLabel.y = 100;
LK.gui.topLeft.addChild(meterLabel);
// Create level indicator
var levelTxt = new Text2('LEVEL 1', {
size: 60,
fill: 0xFFFF00
});
levelTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(levelTxt);
// Add sky background
var skyBackground = game.addChild(LK.getAsset('sky', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1366 / 2
}));
// Create bike
bike = game.addChild(new Bike());
bike.x = 400;
bike.y = groundLevel;
bike.groundY = groundLevel;
// Initialize ground segments
function createGroundSegments() {
for (var i = 0; i < 15; i++) {
var segment = new GroundSegment();
segment.x = i * 200;
segment.y = groundLevel + 40;
groundSegments.push(segment);
game.addChild(segment);
}
}
createGroundSegments();
// Spawn obstacle patterns based on current level
function spawnObstaclePattern(pattern) {
switch (pattern) {
case 'single':
spawnSingleObstacle();
break;
case 'double':
spawnDoubleObstacles();
break;
case 'triple':
spawnTripleObstacles();
break;
case 'staggered':
spawnStaggeredObstacles();
break;
case 'wall':
spawnWallObstacles();
break;
default:
spawnSingleObstacle();
}
}
// Single obstacle
function spawnSingleObstacle() {
var obstacle = new Obstacle();
obstacle.x = 2200;
obstacle.y = groundLevel;
obstacle.speed = -gameSpeed;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Double obstacles - side by side gap
function spawnDoubleObstacles() {
var obstacle1 = new Obstacle();
obstacle1.x = 2200;
obstacle1.y = groundLevel;
obstacle1.speed = -gameSpeed;
obstacles.push(obstacle1);
game.addChild(obstacle1);
var obstacle2 = new Obstacle();
obstacle2.x = 2280;
obstacle2.y = groundLevel;
obstacle2.speed = -gameSpeed;
obstacles.push(obstacle2);
game.addChild(obstacle2);
}
// Triple obstacles - requires precise jumping
function spawnTripleObstacles() {
for (var i = 0; i < 3; i++) {
var obstacle = new Obstacle();
obstacle.x = 2200 + i * 70;
obstacle.y = groundLevel;
obstacle.speed = -gameSpeed;
obstacles.push(obstacle);
game.addChild(obstacle);
}
}
// Staggered obstacles - different heights
function spawnStaggeredObstacles() {
var obstacle1 = new Obstacle();
obstacle1.x = 2200;
obstacle1.y = groundLevel;
obstacle1.speed = -gameSpeed;
obstacles.push(obstacle1);
game.addChild(obstacle1);
var obstacle2 = new Obstacle();
obstacle2.x = 2300;
obstacle2.y = groundLevel - 60;
obstacle2.speed = -gameSpeed;
obstacles.push(obstacle2);
game.addChild(obstacle2);
}
// Wall pattern - high obstacle requiring max jump
function spawnWallObstacles() {
var obstacle1 = new Obstacle();
obstacle1.x = 2200;
obstacle1.y = groundLevel;
obstacle1.speed = -gameSpeed;
obstacles.push(obstacle1);
game.addChild(obstacle1);
var obstacle2 = new Obstacle();
obstacle2.x = 2200;
obstacle2.y = groundLevel - 60;
obstacle2.speed = -gameSpeed;
obstacles.push(obstacle2);
game.addChild(obstacle2);
}
// Legacy single obstacle function for compatibility
function spawnObstacle() {
spawnSingleObstacle();
}
// Spawn ramp
function spawnRamp() {
var ramp = new Ramp();
ramp.x = 2200;
ramp.y = groundLevel;
ramp.speed = -gameSpeed;
ramps.push(ramp);
game.addChild(ramp);
}
// Game input - start charging
game.down = function (x, y, obj) {
if (isGameRunning && bike.isGrounded) {
isCharging = true;
chargeStartTime = LK.ticks;
currentCharge = 0;
}
};
// Game input - release jump
game.up = function (x, y, obj) {
if (isGameRunning && isCharging) {
var chargeMultiplier = currentCharge / maxCharge;
bike.jump(chargeMultiplier);
isCharging = false;
currentCharge = 0;
}
};
// Main game loop
game.update = function () {
if (!isGameRunning) return;
// Update jump charge system
if (isCharging && bike.isGrounded) {
currentCharge += chargeRate;
if (currentCharge > maxCharge) {
currentCharge = maxCharge;
}
} else if (!bike.isGrounded) {
isCharging = false;
currentCharge = 0;
}
// Update jump meter UI
var fillPercent = currentCharge / maxCharge;
meterFill.scaleX = 4 * fillPercent;
// Change color based on charge level
if (fillPercent < 0.3) {
meterFill.tint = 0xff0000; // Red
} else if (fillPercent < 0.7) {
meterFill.tint = 0xffff00; // Yellow
} else {
meterFill.tint = 0x00ff00; // Green
}
// Update distance score
distanceScore += 1;
LK.setScore(Math.floor(distanceScore / 10));
scoreTxt.setText('Distance: ' + Math.floor(distanceScore / 10));
// Update level indicator
levelTxt.setText('LEVEL ' + currentLevel);
// Increase game speed gradually
if (LK.ticks % 300 === 0) {
gameSpeed += 1.2;
}
// Update ground segments
for (var i = groundSegments.length - 1; i >= 0; i--) {
var segment = groundSegments[i];
segment.speed = -gameSpeed;
if (segment.x < -200) {
segment.x = (groundSegments.length - 1) * 200;
}
}
// Update current level based on distance
var newLevel = Math.min(5, Math.floor(distanceScore / levelDistance) + 1);
if (newLevel !== currentLevel) {
currentLevel = newLevel;
}
// Get current level configuration
var config = levelConfigs[currentLevel - 1];
// Spawn obstacles and ramps based on current level
if (distanceScore - lastObstacleSpawn > spawnDistance) {
var randomValue = Math.random();
if (randomValue < config.obstacleChance) {
// Choose random pattern from current level patterns
var patterns = config.patterns;
var randomPattern = patterns[Math.floor(Math.random() * patterns.length)];
spawnObstaclePattern(randomPattern);
} else {
spawnRamp();
}
lastObstacleSpawn = distanceScore;
spawnDistance = config.minSpacing + Math.random() * (config.maxSpacing - config.minSpacing);
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
obstacle.speed = -gameSpeed;
// Remove off-screen obstacles
if (obstacle.x < -100) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
if (bike.intersects(obstacle)) {
// Game over
isGameRunning = false;
LK.getSound('crash').play();
LK.showGameOver();
return;
}
}
// Update ramps
for (var i = ramps.length - 1; i >= 0; i--) {
var ramp = ramps[i];
ramp.speed = -gameSpeed;
// Remove off-screen ramps
if (ramp.x < -100) {
ramp.destroy();
ramps.splice(i, 1);
continue;
}
// Ramp boost effect
if (bike.intersects(ramp) && bike.isGrounded) {
bike.velocityY = bike.jumpPower * 1.2;
bike.isGrounded = false;
}
}
// Check if bike fell off the track
if (bike.y > groundLevel + 200) {
isGameRunning = false;
LK.getSound('crash').play();
LK.showGameOver();
}
};
// Start background music
LK.playMusic('1crossbikecountryracetheme'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bike = Container.expand(function () {
var self = Container.call(this);
var bikeBody = self.attachAsset('bike', {
anchorX: 0.5,
anchorY: 0.5
});
var frontWheel = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
x: 25,
y: 15
});
var backWheel = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5,
x: -25,
y: 15
});
self.velocityY = 0;
self.gravity = 0.8;
self.jumpPower = -18;
self.isGrounded = false;
self.groundY = 0;
self.jump = function (chargeMultiplier) {
if (self.isGrounded) {
var jumpStrength = self.jumpPower * (1 + chargeMultiplier);
self.velocityY = jumpStrength;
self.isGrounded = false;
LK.getSound('jump').play();
}
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Ground collision
if (self.y >= self.groundY) {
self.y = self.groundY;
self.velocityY = 0;
self.isGrounded = true;
}
// Animate wheels
frontWheel.rotation += 0.3;
backWheel.rotation += 0.3;
// Bike tilt based on velocity
bikeBody.rotation = self.velocityY * 0.02;
};
return self;
});
var GroundSegment = Container.expand(function () {
var self = Container.call(this);
var groundGraphics = self.attachAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -18;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -18;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Ramp = Container.expand(function () {
var self = Container.call(this);
var rampGraphics = self.attachAsset('ramp', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -18;
self.update = function () {
self.x += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var bike;
var obstacles = [];
var ramps = [];
var groundSegments = [];
var gameSpeed = 18;
var distanceScore = 0;
var isGameRunning = true;
var groundLevel = 2400;
var lastObstacleSpawn = 0;
var spawnDistance = 300;
var currentLevel = 1;
var levelDistance = 500; // Distance between level changes
var levelConfigs = [
// Level 1: Easy - Single obstacles
{
obstacleChance: 0.6,
rampChance: 0.4,
minSpacing: 250,
maxSpacing: 400,
patterns: ['single']
},
// Level 2: Medium - Paired obstacles
{
obstacleChance: 0.7,
rampChance: 0.3,
minSpacing: 200,
maxSpacing: 350,
patterns: ['single', 'double']
},
// Level 3: Hard - Triple obstacles and gaps
{
obstacleChance: 0.75,
rampChance: 0.25,
minSpacing: 180,
maxSpacing: 300,
patterns: ['single', 'double', 'triple']
},
// Level 4: Expert - Mixed patterns with tight spacing
{
obstacleChance: 0.8,
rampChance: 0.2,
minSpacing: 150,
maxSpacing: 250,
patterns: ['single', 'double', 'triple', 'staggered']
},
// Level 5: Master - All patterns with minimal spacing
{
obstacleChance: 0.85,
rampChance: 0.15,
minSpacing: 120,
maxSpacing: 200,
patterns: ['single', 'double', 'triple', 'staggered', 'wall']
}];
var isCharging = false;
var chargeStartTime = 0;
var currentCharge = 0;
var maxCharge = 100;
var chargeRate = 2;
// Create score display
var scoreTxt = new Text2('Distance: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create jump meter background
var meterBg = LK.getAsset('obstacle', {
anchorX: 0,
anchorY: 0,
scaleX: 4,
scaleY: 0.5,
tint: 0x333333
});
meterBg.x = 100;
meterBg.y = 150;
LK.gui.topLeft.addChild(meterBg);
// Create jump meter fill
var meterFill = LK.getAsset('obstacle', {
anchorX: 0,
anchorY: 0,
scaleX: 0,
scaleY: 0.5,
tint: 0x00ff00
});
meterFill.x = 100;
meterFill.y = 150;
LK.gui.topLeft.addChild(meterFill);
// Create jump meter label
var meterLabel = new Text2('JUMP POWER', {
size: 40,
fill: 0xFFFFFF
});
meterLabel.anchor.set(0, 0);
meterLabel.x = 100;
meterLabel.y = 100;
LK.gui.topLeft.addChild(meterLabel);
// Create level indicator
var levelTxt = new Text2('LEVEL 1', {
size: 60,
fill: 0xFFFF00
});
levelTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(levelTxt);
// Add sky background
var skyBackground = game.addChild(LK.getAsset('sky', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1366 / 2
}));
// Create bike
bike = game.addChild(new Bike());
bike.x = 400;
bike.y = groundLevel;
bike.groundY = groundLevel;
// Initialize ground segments
function createGroundSegments() {
for (var i = 0; i < 15; i++) {
var segment = new GroundSegment();
segment.x = i * 200;
segment.y = groundLevel + 40;
groundSegments.push(segment);
game.addChild(segment);
}
}
createGroundSegments();
// Spawn obstacle patterns based on current level
function spawnObstaclePattern(pattern) {
switch (pattern) {
case 'single':
spawnSingleObstacle();
break;
case 'double':
spawnDoubleObstacles();
break;
case 'triple':
spawnTripleObstacles();
break;
case 'staggered':
spawnStaggeredObstacles();
break;
case 'wall':
spawnWallObstacles();
break;
default:
spawnSingleObstacle();
}
}
// Single obstacle
function spawnSingleObstacle() {
var obstacle = new Obstacle();
obstacle.x = 2200;
obstacle.y = groundLevel;
obstacle.speed = -gameSpeed;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Double obstacles - side by side gap
function spawnDoubleObstacles() {
var obstacle1 = new Obstacle();
obstacle1.x = 2200;
obstacle1.y = groundLevel;
obstacle1.speed = -gameSpeed;
obstacles.push(obstacle1);
game.addChild(obstacle1);
var obstacle2 = new Obstacle();
obstacle2.x = 2280;
obstacle2.y = groundLevel;
obstacle2.speed = -gameSpeed;
obstacles.push(obstacle2);
game.addChild(obstacle2);
}
// Triple obstacles - requires precise jumping
function spawnTripleObstacles() {
for (var i = 0; i < 3; i++) {
var obstacle = new Obstacle();
obstacle.x = 2200 + i * 70;
obstacle.y = groundLevel;
obstacle.speed = -gameSpeed;
obstacles.push(obstacle);
game.addChild(obstacle);
}
}
// Staggered obstacles - different heights
function spawnStaggeredObstacles() {
var obstacle1 = new Obstacle();
obstacle1.x = 2200;
obstacle1.y = groundLevel;
obstacle1.speed = -gameSpeed;
obstacles.push(obstacle1);
game.addChild(obstacle1);
var obstacle2 = new Obstacle();
obstacle2.x = 2300;
obstacle2.y = groundLevel - 60;
obstacle2.speed = -gameSpeed;
obstacles.push(obstacle2);
game.addChild(obstacle2);
}
// Wall pattern - high obstacle requiring max jump
function spawnWallObstacles() {
var obstacle1 = new Obstacle();
obstacle1.x = 2200;
obstacle1.y = groundLevel;
obstacle1.speed = -gameSpeed;
obstacles.push(obstacle1);
game.addChild(obstacle1);
var obstacle2 = new Obstacle();
obstacle2.x = 2200;
obstacle2.y = groundLevel - 60;
obstacle2.speed = -gameSpeed;
obstacles.push(obstacle2);
game.addChild(obstacle2);
}
// Legacy single obstacle function for compatibility
function spawnObstacle() {
spawnSingleObstacle();
}
// Spawn ramp
function spawnRamp() {
var ramp = new Ramp();
ramp.x = 2200;
ramp.y = groundLevel;
ramp.speed = -gameSpeed;
ramps.push(ramp);
game.addChild(ramp);
}
// Game input - start charging
game.down = function (x, y, obj) {
if (isGameRunning && bike.isGrounded) {
isCharging = true;
chargeStartTime = LK.ticks;
currentCharge = 0;
}
};
// Game input - release jump
game.up = function (x, y, obj) {
if (isGameRunning && isCharging) {
var chargeMultiplier = currentCharge / maxCharge;
bike.jump(chargeMultiplier);
isCharging = false;
currentCharge = 0;
}
};
// Main game loop
game.update = function () {
if (!isGameRunning) return;
// Update jump charge system
if (isCharging && bike.isGrounded) {
currentCharge += chargeRate;
if (currentCharge > maxCharge) {
currentCharge = maxCharge;
}
} else if (!bike.isGrounded) {
isCharging = false;
currentCharge = 0;
}
// Update jump meter UI
var fillPercent = currentCharge / maxCharge;
meterFill.scaleX = 4 * fillPercent;
// Change color based on charge level
if (fillPercent < 0.3) {
meterFill.tint = 0xff0000; // Red
} else if (fillPercent < 0.7) {
meterFill.tint = 0xffff00; // Yellow
} else {
meterFill.tint = 0x00ff00; // Green
}
// Update distance score
distanceScore += 1;
LK.setScore(Math.floor(distanceScore / 10));
scoreTxt.setText('Distance: ' + Math.floor(distanceScore / 10));
// Update level indicator
levelTxt.setText('LEVEL ' + currentLevel);
// Increase game speed gradually
if (LK.ticks % 300 === 0) {
gameSpeed += 1.2;
}
// Update ground segments
for (var i = groundSegments.length - 1; i >= 0; i--) {
var segment = groundSegments[i];
segment.speed = -gameSpeed;
if (segment.x < -200) {
segment.x = (groundSegments.length - 1) * 200;
}
}
// Update current level based on distance
var newLevel = Math.min(5, Math.floor(distanceScore / levelDistance) + 1);
if (newLevel !== currentLevel) {
currentLevel = newLevel;
}
// Get current level configuration
var config = levelConfigs[currentLevel - 1];
// Spawn obstacles and ramps based on current level
if (distanceScore - lastObstacleSpawn > spawnDistance) {
var randomValue = Math.random();
if (randomValue < config.obstacleChance) {
// Choose random pattern from current level patterns
var patterns = config.patterns;
var randomPattern = patterns[Math.floor(Math.random() * patterns.length)];
spawnObstaclePattern(randomPattern);
} else {
spawnRamp();
}
lastObstacleSpawn = distanceScore;
spawnDistance = config.minSpacing + Math.random() * (config.maxSpacing - config.minSpacing);
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
obstacle.speed = -gameSpeed;
// Remove off-screen obstacles
if (obstacle.x < -100) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
if (bike.intersects(obstacle)) {
// Game over
isGameRunning = false;
LK.getSound('crash').play();
LK.showGameOver();
return;
}
}
// Update ramps
for (var i = ramps.length - 1; i >= 0; i--) {
var ramp = ramps[i];
ramp.speed = -gameSpeed;
// Remove off-screen ramps
if (ramp.x < -100) {
ramp.destroy();
ramps.splice(i, 1);
continue;
}
// Ramp boost effect
if (bike.intersects(ramp) && bike.isGrounded) {
bike.velocityY = bike.jumpPower * 1.2;
bike.isGrounded = false;
}
}
// Check if bike fell off the track
if (bike.y > groundLevel + 200) {
isGameRunning = false;
LK.getSound('crash').play();
LK.showGameOver();
}
};
// Start background music
LK.playMusic('1crossbikecountryracetheme');