/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
bestDistance: 0,
coins: 0,
upgrades: {
power: 1,
bounce: 1
}
});
/****
* Classes
****/
// Bat class: the weapon to hit the geek
var Bat = Container.expand(function () {
var self = Container.call(this);
var batSprite = self.attachAsset('bat', {
anchorX: 0.1,
anchorY: 0.5
});
self.swinging = false;
self.angle = -Math.PI / 4; // resting angle
self.power = 0;
self.maxPower = 1;
self.swingTween = null;
self.setAngle = function (a) {
self.rotation = a;
self.angle = a;
};
self.swing = function (onHit) {
if (self.swinging) return;
self.swinging = true;
// Animate swing
tween(self, {
rotation: Math.PI / 2
}, {
duration: 180,
easing: tween.cubicOut,
onFinish: function onFinish() {
self.swinging = false;
self.setAngle(-Math.PI / 4);
if (onHit) onHit();
}
});
};
return self;
});
// Geek class: the character to launch
var Geek = Container.expand(function () {
var self = Container.call(this);
var geekSprite = self.attachAsset('geek', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = geekSprite.width / 2;
self.vx = 0; // velocity x
self.vy = 0; // velocity y
self.rotationSpeed = 0;
self.isFlying = false;
self.isStopped = false;
self.distance = 0;
self.bounceCount = 0;
// For collision detection
self.getBounds = function () {
return {
x: self.x - self.radius,
y: self.y - self.radius,
width: self.radius * 2,
height: self.radius * 2
};
};
// Called every tick
self.update = function () {
if (!self.isFlying || self.isStopped) return;
// Physics
self.x += self.vx;
self.y += self.vy;
self.vy += 1.2; // gravity
// Air friction
self.vx *= 0.995;
self.vy *= 0.995;
// Rotation
self.rotation += self.rotationSpeed;
// Distance tracking
self.distance += self.vx;
// Ground collision
if (self.y + self.radius >= groundY) {
self.y = groundY - self.radius;
if (Math.abs(self.vy) > 8) {
// Bounce
self.vy = -Math.abs(self.vy) * (0.45 + 0.05 * upgrades.bounce);
self.vx *= 0.92;
self.rotationSpeed *= 0.7;
self.bounceCount++;
LK.getSound('bounce').play();
// Small upward nudge to avoid sticking
self.y -= 2;
} else {
// Stop
self.vy = 0;
self.vx = 0;
self.isStopped = true;
self.isFlying = false;
onGeekStopped();
}
}
};
return self;
});
// Obstacle (rock)
var Rock = Container.expand(function () {
var self = Container.call(this);
var rockSprite = self.attachAsset('rock', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = rockSprite.width / 2;
self.getBounds = function () {
return {
x: self.x - self.radius,
y: self.y - self.radius,
width: self.radius * 2,
height: self.radius * 2
};
};
return self;
});
// Power-up (spring)
var Spring = Container.expand(function () {
var self = Container.call(this);
var springSprite = self.attachAsset('spring', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = springSprite.width / 2;
self.getBounds = function () {
return {
x: self.x - self.radius,
y: self.y - self.radius,
width: self.radius * 2,
height: self.radius * 2
};
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Music
// Sound effects
// Power-up (spring)
// Obstacle (rock)
// Ground
// Bat (the weapon)
// Geek (the character to launch)
// --- Global variables ---
var groundY = 2732 - 80; // ground top
var geek, bat;
var rocks = [];
var springs = [];
var upgrades = storage.upgrades || {
power: 1,
bounce: 1
};
var coins = storage.coins || 0;
var bestDistance = storage.bestDistance || 0;
var runDistance = 0;
var runCoins = 0;
var isAiming = false;
var aimPower = 0;
var aimAngle = -Math.PI / 4;
var aimMaxPower = 1.5 + 0.2 * upgrades.power;
var aimMinAngle = -Math.PI / 3;
var aimMaxAngle = -Math.PI / 8;
var aimDir = 1;
var aimTimer = 0;
var gameState = 'aim'; // 'aim', 'flying', 'stopped'
// --- GUI ---
var scoreTxt = new Text2('0 m', {
size: 100,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var coinTxt = new Text2('0', {
size: 70,
fill: 0xFFD700
});
coinTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(coinTxt);
var bestTxt = new Text2('Best: 0 m', {
size: 60,
fill: "#fff"
});
bestTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(bestTxt);
var upgradeTxt = new Text2('', {
size: 60,
fill: "#fff"
});
upgradeTxt.anchor.set(0.5, 1);
LK.gui.bottom.addChild(upgradeTxt);
// --- Ground ---
var ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: groundY
});
game.addChild(ground);
// --- Functions ---
function resetRun() {
// Remove old objects
if (geek) geek.destroy();
if (bat) bat.destroy();
for (var i = 0; i < rocks.length; i++) rocks[i].destroy();
for (var i = 0; i < springs.length; i++) springs[i].destroy();
rocks = [];
springs = [];
runDistance = 0;
runCoins = 0;
aimPower = 0;
aimAngle = -Math.PI / 4;
aimDir = 1;
aimTimer = 0;
gameState = 'aim';
// Geek
geek = new Geek();
geek.x = 350;
geek.y = groundY - 120;
geek.rotation = 0;
game.addChild(geek);
// Bat
bat = new Bat();
bat.x = geek.x - 80;
bat.y = groundY - 120;
bat.setAngle(-Math.PI / 4);
game.addChild(bat);
// Obstacles
for (var i = 0; i < 3; i++) {
var rock = new Rock();
rock.x = 900 + 700 * i + Math.random() * 200;
rock.y = groundY - 30;
rocks.push(rock);
game.addChild(rock);
}
// Power-ups
for (var i = 0; i < 2; i++) {
var spring = new Spring();
spring.x = 1200 + 1000 * i + Math.random() * 300;
spring.y = groundY - 20;
springs.push(spring);
game.addChild(spring);
}
// GUI
scoreTxt.setText('0 m');
coinTxt.setText('' + coins);
bestTxt.setText('Best: ' + bestDistance + ' m');
upgradeTxt.setText('Tap bottom to upgrade: Power(' + upgrades.power + '), Bounce(' + upgrades.bounce + ')');
}
function onGeekStopped() {
// End of run
runDistance = Math.floor(geek.distance / 10);
if (runDistance > bestDistance) {
bestDistance = runDistance;
storage.bestDistance = bestDistance;
}
coins += Math.floor(runDistance / 10) + runCoins;
storage.coins = coins;
// Show game over
LK.effects.flashScreen(0x000000, 600);
LK.showGameOver();
}
function launchGeek(power, angle) {
// Bat swing animation
bat.swing(function () {
// Launch
var p = 38 * power * (1 + 0.15 * upgrades.power);
geek.vx = p * Math.cos(angle);
geek.vy = p * Math.sin(angle) - 10;
geek.rotationSpeed = 0.2 + 0.1 * power;
geek.isFlying = true;
gameState = 'flying';
LK.getSound('hit').play();
// Remove bat after swing
LK.setTimeout(function () {
bat.destroy();
}, 300);
});
}
// --- Input handling ---
game.down = function (x, y, obj) {
if (gameState === 'aim') {
isAiming = true;
aimTimer = 0;
} else if (gameState === 'stopped') {
// Check if bottom area tapped for upgrades
if (y > 2732 - 300) {
// Alternate upgrades: tap left half for power, right half for bounce
if (x < 2048 / 2) {
// Power upgrade
var cost = 10 + upgrades.power * 10;
if (coins >= cost) {
upgrades.power++;
coins -= cost;
storage.upgrades = upgrades;
storage.coins = coins;
LK.effects.flashObject(upgradeTxt, 0x00ff00, 400);
} else {
LK.effects.flashObject(upgradeTxt, 0xff0000, 400);
}
} else {
// Bounce upgrade
var cost = 10 + upgrades.bounce * 10;
if (coins >= cost) {
upgrades.bounce++;
coins -= cost;
storage.upgrades = upgrades;
storage.coins = coins;
LK.effects.flashObject(upgradeTxt, 0x00ff00, 400);
} else {
LK.effects.flashObject(upgradeTxt, 0xff0000, 400);
}
}
upgradeTxt.setText('Tap bottom to upgrade: Power(' + upgrades.power + '), Bounce(' + upgrades.bounce + ')');
coinTxt.setText('' + coins);
}
}
};
game.up = function (x, y, obj) {
if (gameState === 'aim' && isAiming) {
isAiming = false;
// Launch!
launchGeek(aimPower, aimAngle);
}
};
function checkCollision(a, b) {
var ab = a.getBounds();
var bb = b.getBounds();
return ab.x < bb.x + bb.width && ab.x + ab.width > bb.x && ab.y < bb.y + bb.height && ab.y + ab.height > bb.y;
}
// --- Main update loop ---
game.update = function () {
// Aiming phase
if (gameState === 'aim' && isAiming) {
// Power oscillates up and down
aimTimer++;
aimPower = 0.5 + 0.5 * Math.abs(Math.sin(aimTimer * 0.05));
// Angle oscillates between min and max
aimAngle += aimDir * 0.012;
if (aimAngle > aimMaxAngle) aimDir = -1;
if (aimAngle < aimMinAngle) aimDir = 1;
bat.setAngle(aimAngle);
// Bat color flashes with power
var color = 0x964b00 + Math.floor(aimPower * 0x002200);
bat.children[0].tint = color;
}
// Update geek
if (geek) geek.update();
// Camera follow: move all objects left as geek moves
if (geek && geek.isFlying) {
var camX = Math.max(0, geek.x - 350);
// Move all except GUI and ground
for (var i = 0; i < rocks.length; i++) rocks[i].x -= camX - (rocks[i].camX || 0);
for (var i = 0; i < springs.length; i++) springs[i].x -= camX - (springs[i].camX || 0);
if (bat && !bat.destroyed) bat.x -= camX - (bat.camX || 0);
geek.x -= camX - (geek.camX || 0);
// Store camX for next frame
for (var i = 0; i < rocks.length; i++) rocks[i].camX = camX;
for (var i = 0; i < springs.length; i++) springs[i].camX = camX;
if (bat && !bat.destroyed) bat.camX = camX;
geek.camX = camX;
}
// Collisions: obstacles
if (geek && geek.isFlying && !geek.isStopped) {
for (var i = 0; i < rocks.length; i++) {
var rock = rocks[i];
if (!rock.hit && checkCollision(geek, rock)) {
// Hit rock: lose speed, bounce up
geek.vx *= 0.6;
geek.vy = -Math.abs(geek.vy) * 0.7 - 8;
geek.rotationSpeed *= 0.7;
rock.hit = true;
LK.effects.flashObject(rock, 0xff0000, 400);
LK.getSound('bounce').play();
}
}
// Collisions: power-ups
for (var i = 0; i < springs.length; i++) {
var spring = springs[i];
if (!spring.used && checkCollision(geek, spring)) {
// Hit spring: big bounce, gain coins
geek.vy = -32 - 8 * upgrades.bounce;
geek.vx *= 1.12;
geek.rotationSpeed += 0.2;
spring.used = true;
runCoins += 5;
LK.effects.flashObject(spring, 0xffd700, 500);
LK.getSound('powerup').play();
}
}
}
// Update GUI
if (geek) {
var dist = Math.floor(geek.distance / 10);
scoreTxt.setText(dist + ' m');
}
coinTxt.setText('' + coins);
// If geek stopped, allow upgrades and restart
if (geek && geek.isStopped && gameState !== 'stopped') {
gameState = 'stopped';
upgradeTxt.setText('Tap bottom to upgrade: Power(' + upgrades.power + '), Bounce(' + upgrades.bounce + ')');
}
};
// --- Game over handler ---
LK.on('gameover', function () {
// Reset run for next play
resetRun();
});
// --- Music ---
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
// --- Start game ---
resetRun(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
bestDistance: 0,
coins: 0,
upgrades: {
power: 1,
bounce: 1
}
});
/****
* Classes
****/
// Bat class: the weapon to hit the geek
var Bat = Container.expand(function () {
var self = Container.call(this);
var batSprite = self.attachAsset('bat', {
anchorX: 0.1,
anchorY: 0.5
});
self.swinging = false;
self.angle = -Math.PI / 4; // resting angle
self.power = 0;
self.maxPower = 1;
self.swingTween = null;
self.setAngle = function (a) {
self.rotation = a;
self.angle = a;
};
self.swing = function (onHit) {
if (self.swinging) return;
self.swinging = true;
// Animate swing
tween(self, {
rotation: Math.PI / 2
}, {
duration: 180,
easing: tween.cubicOut,
onFinish: function onFinish() {
self.swinging = false;
self.setAngle(-Math.PI / 4);
if (onHit) onHit();
}
});
};
return self;
});
// Geek class: the character to launch
var Geek = Container.expand(function () {
var self = Container.call(this);
var geekSprite = self.attachAsset('geek', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = geekSprite.width / 2;
self.vx = 0; // velocity x
self.vy = 0; // velocity y
self.rotationSpeed = 0;
self.isFlying = false;
self.isStopped = false;
self.distance = 0;
self.bounceCount = 0;
// For collision detection
self.getBounds = function () {
return {
x: self.x - self.radius,
y: self.y - self.radius,
width: self.radius * 2,
height: self.radius * 2
};
};
// Called every tick
self.update = function () {
if (!self.isFlying || self.isStopped) return;
// Physics
self.x += self.vx;
self.y += self.vy;
self.vy += 1.2; // gravity
// Air friction
self.vx *= 0.995;
self.vy *= 0.995;
// Rotation
self.rotation += self.rotationSpeed;
// Distance tracking
self.distance += self.vx;
// Ground collision
if (self.y + self.radius >= groundY) {
self.y = groundY - self.radius;
if (Math.abs(self.vy) > 8) {
// Bounce
self.vy = -Math.abs(self.vy) * (0.45 + 0.05 * upgrades.bounce);
self.vx *= 0.92;
self.rotationSpeed *= 0.7;
self.bounceCount++;
LK.getSound('bounce').play();
// Small upward nudge to avoid sticking
self.y -= 2;
} else {
// Stop
self.vy = 0;
self.vx = 0;
self.isStopped = true;
self.isFlying = false;
onGeekStopped();
}
}
};
return self;
});
// Obstacle (rock)
var Rock = Container.expand(function () {
var self = Container.call(this);
var rockSprite = self.attachAsset('rock', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = rockSprite.width / 2;
self.getBounds = function () {
return {
x: self.x - self.radius,
y: self.y - self.radius,
width: self.radius * 2,
height: self.radius * 2
};
};
return self;
});
// Power-up (spring)
var Spring = Container.expand(function () {
var self = Container.call(this);
var springSprite = self.attachAsset('spring', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = springSprite.width / 2;
self.getBounds = function () {
return {
x: self.x - self.radius,
y: self.y - self.radius,
width: self.radius * 2,
height: self.radius * 2
};
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Music
// Sound effects
// Power-up (spring)
// Obstacle (rock)
// Ground
// Bat (the weapon)
// Geek (the character to launch)
// --- Global variables ---
var groundY = 2732 - 80; // ground top
var geek, bat;
var rocks = [];
var springs = [];
var upgrades = storage.upgrades || {
power: 1,
bounce: 1
};
var coins = storage.coins || 0;
var bestDistance = storage.bestDistance || 0;
var runDistance = 0;
var runCoins = 0;
var isAiming = false;
var aimPower = 0;
var aimAngle = -Math.PI / 4;
var aimMaxPower = 1.5 + 0.2 * upgrades.power;
var aimMinAngle = -Math.PI / 3;
var aimMaxAngle = -Math.PI / 8;
var aimDir = 1;
var aimTimer = 0;
var gameState = 'aim'; // 'aim', 'flying', 'stopped'
// --- GUI ---
var scoreTxt = new Text2('0 m', {
size: 100,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var coinTxt = new Text2('0', {
size: 70,
fill: 0xFFD700
});
coinTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(coinTxt);
var bestTxt = new Text2('Best: 0 m', {
size: 60,
fill: "#fff"
});
bestTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(bestTxt);
var upgradeTxt = new Text2('', {
size: 60,
fill: "#fff"
});
upgradeTxt.anchor.set(0.5, 1);
LK.gui.bottom.addChild(upgradeTxt);
// --- Ground ---
var ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: groundY
});
game.addChild(ground);
// --- Functions ---
function resetRun() {
// Remove old objects
if (geek) geek.destroy();
if (bat) bat.destroy();
for (var i = 0; i < rocks.length; i++) rocks[i].destroy();
for (var i = 0; i < springs.length; i++) springs[i].destroy();
rocks = [];
springs = [];
runDistance = 0;
runCoins = 0;
aimPower = 0;
aimAngle = -Math.PI / 4;
aimDir = 1;
aimTimer = 0;
gameState = 'aim';
// Geek
geek = new Geek();
geek.x = 350;
geek.y = groundY - 120;
geek.rotation = 0;
game.addChild(geek);
// Bat
bat = new Bat();
bat.x = geek.x - 80;
bat.y = groundY - 120;
bat.setAngle(-Math.PI / 4);
game.addChild(bat);
// Obstacles
for (var i = 0; i < 3; i++) {
var rock = new Rock();
rock.x = 900 + 700 * i + Math.random() * 200;
rock.y = groundY - 30;
rocks.push(rock);
game.addChild(rock);
}
// Power-ups
for (var i = 0; i < 2; i++) {
var spring = new Spring();
spring.x = 1200 + 1000 * i + Math.random() * 300;
spring.y = groundY - 20;
springs.push(spring);
game.addChild(spring);
}
// GUI
scoreTxt.setText('0 m');
coinTxt.setText('' + coins);
bestTxt.setText('Best: ' + bestDistance + ' m');
upgradeTxt.setText('Tap bottom to upgrade: Power(' + upgrades.power + '), Bounce(' + upgrades.bounce + ')');
}
function onGeekStopped() {
// End of run
runDistance = Math.floor(geek.distance / 10);
if (runDistance > bestDistance) {
bestDistance = runDistance;
storage.bestDistance = bestDistance;
}
coins += Math.floor(runDistance / 10) + runCoins;
storage.coins = coins;
// Show game over
LK.effects.flashScreen(0x000000, 600);
LK.showGameOver();
}
function launchGeek(power, angle) {
// Bat swing animation
bat.swing(function () {
// Launch
var p = 38 * power * (1 + 0.15 * upgrades.power);
geek.vx = p * Math.cos(angle);
geek.vy = p * Math.sin(angle) - 10;
geek.rotationSpeed = 0.2 + 0.1 * power;
geek.isFlying = true;
gameState = 'flying';
LK.getSound('hit').play();
// Remove bat after swing
LK.setTimeout(function () {
bat.destroy();
}, 300);
});
}
// --- Input handling ---
game.down = function (x, y, obj) {
if (gameState === 'aim') {
isAiming = true;
aimTimer = 0;
} else if (gameState === 'stopped') {
// Check if bottom area tapped for upgrades
if (y > 2732 - 300) {
// Alternate upgrades: tap left half for power, right half for bounce
if (x < 2048 / 2) {
// Power upgrade
var cost = 10 + upgrades.power * 10;
if (coins >= cost) {
upgrades.power++;
coins -= cost;
storage.upgrades = upgrades;
storage.coins = coins;
LK.effects.flashObject(upgradeTxt, 0x00ff00, 400);
} else {
LK.effects.flashObject(upgradeTxt, 0xff0000, 400);
}
} else {
// Bounce upgrade
var cost = 10 + upgrades.bounce * 10;
if (coins >= cost) {
upgrades.bounce++;
coins -= cost;
storage.upgrades = upgrades;
storage.coins = coins;
LK.effects.flashObject(upgradeTxt, 0x00ff00, 400);
} else {
LK.effects.flashObject(upgradeTxt, 0xff0000, 400);
}
}
upgradeTxt.setText('Tap bottom to upgrade: Power(' + upgrades.power + '), Bounce(' + upgrades.bounce + ')');
coinTxt.setText('' + coins);
}
}
};
game.up = function (x, y, obj) {
if (gameState === 'aim' && isAiming) {
isAiming = false;
// Launch!
launchGeek(aimPower, aimAngle);
}
};
function checkCollision(a, b) {
var ab = a.getBounds();
var bb = b.getBounds();
return ab.x < bb.x + bb.width && ab.x + ab.width > bb.x && ab.y < bb.y + bb.height && ab.y + ab.height > bb.y;
}
// --- Main update loop ---
game.update = function () {
// Aiming phase
if (gameState === 'aim' && isAiming) {
// Power oscillates up and down
aimTimer++;
aimPower = 0.5 + 0.5 * Math.abs(Math.sin(aimTimer * 0.05));
// Angle oscillates between min and max
aimAngle += aimDir * 0.012;
if (aimAngle > aimMaxAngle) aimDir = -1;
if (aimAngle < aimMinAngle) aimDir = 1;
bat.setAngle(aimAngle);
// Bat color flashes with power
var color = 0x964b00 + Math.floor(aimPower * 0x002200);
bat.children[0].tint = color;
}
// Update geek
if (geek) geek.update();
// Camera follow: move all objects left as geek moves
if (geek && geek.isFlying) {
var camX = Math.max(0, geek.x - 350);
// Move all except GUI and ground
for (var i = 0; i < rocks.length; i++) rocks[i].x -= camX - (rocks[i].camX || 0);
for (var i = 0; i < springs.length; i++) springs[i].x -= camX - (springs[i].camX || 0);
if (bat && !bat.destroyed) bat.x -= camX - (bat.camX || 0);
geek.x -= camX - (geek.camX || 0);
// Store camX for next frame
for (var i = 0; i < rocks.length; i++) rocks[i].camX = camX;
for (var i = 0; i < springs.length; i++) springs[i].camX = camX;
if (bat && !bat.destroyed) bat.camX = camX;
geek.camX = camX;
}
// Collisions: obstacles
if (geek && geek.isFlying && !geek.isStopped) {
for (var i = 0; i < rocks.length; i++) {
var rock = rocks[i];
if (!rock.hit && checkCollision(geek, rock)) {
// Hit rock: lose speed, bounce up
geek.vx *= 0.6;
geek.vy = -Math.abs(geek.vy) * 0.7 - 8;
geek.rotationSpeed *= 0.7;
rock.hit = true;
LK.effects.flashObject(rock, 0xff0000, 400);
LK.getSound('bounce').play();
}
}
// Collisions: power-ups
for (var i = 0; i < springs.length; i++) {
var spring = springs[i];
if (!spring.used && checkCollision(geek, spring)) {
// Hit spring: big bounce, gain coins
geek.vy = -32 - 8 * upgrades.bounce;
geek.vx *= 1.12;
geek.rotationSpeed += 0.2;
spring.used = true;
runCoins += 5;
LK.effects.flashObject(spring, 0xffd700, 500);
LK.getSound('powerup').play();
}
}
}
// Update GUI
if (geek) {
var dist = Math.floor(geek.distance / 10);
scoreTxt.setText(dist + ' m');
}
coinTxt.setText('' + coins);
// If geek stopped, allow upgrades and restart
if (geek && geek.isStopped && gameState !== 'stopped') {
gameState = 'stopped';
upgradeTxt.setText('Tap bottom to upgrade: Power(' + upgrades.power + '), Bounce(' + upgrades.bounce + ')');
}
};
// --- Game over handler ---
LK.on('gameover', function () {
// Reset run for next play
resetRun();
});
// --- Music ---
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
// --- Start game ---
resetRun();