/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Balloon class (player)
var Balloon = Container.expand(function () {
var self = Container.call(this);
// Shadow
var shadow = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
y: 180
});
shadow.alpha = 0.18;
// Balloon body
var balloon = self.attachAsset('balloon', {
anchorX: 0.5,
anchorY: 0.5
});
// For a little bounce effect on move
self.bounce = function () {
tween(self, {
scaleX: 1.08,
scaleY: 0.92
}, {
duration: 80,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.cubicIn
});
}
});
};
// For a little shake on hit
self.shake = function () {
tween(self, {
x: self.x + 30
}, {
duration: 60,
easing: tween.linear,
onFinish: function onFinish() {
tween(self, {
x: self.x - 60
}, {
duration: 80,
easing: tween.linear,
onFinish: function onFinish() {
tween(self, {
x: self.x + 30
}, {
duration: 60,
easing: tween.linear
});
}
});
}
});
};
return self;
});
// Spike class (obstacle)
var Spike = Container.expand(function () {
var self = Container.call(this);
var spike = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 0.5
});
// For a little rotation
self.rotationSpeed = (Math.random() - 0.5) * 0.04;
// Speed will be set on spawn
self.speedY = 8;
// Update method
self.update = function () {
self.y += self.speedY;
spike.rotation += self.rotationSpeed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// LK.init.sound('spike_spawn', {volume: 0.4});
// Sound for spike spawn (optional, can be omitted if not wanted)
// Shadow for balloon
// Spike (obstacle)
// Balloon (player)
// Game area
var GAME_W = 2048;
var GAME_H = 2732;
// Balloon spawn position (centered horizontally, 80% down)
var BALLOON_START_X = GAME_W / 2;
var BALLOON_START_Y = GAME_H * 0.8;
// Balloon instance
var balloon = new Balloon();
balloon.x = BALLOON_START_X;
balloon.y = BALLOON_START_Y;
game.addChild(balloon);
// Obstacles array
var spikes = [];
// Score
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Time survived (for increasing difficulty)
var elapsedTicks = 0;
// Dragging
var dragNode = null;
// For collision detection
var lastColliding = false;
// For spike spawn timing
var spikeSpawnTick = 0;
var spikeSpawnInterval = 90; // Initial interval (ticks)
// Move handler (drag balloon)
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp balloon inside game area (with margin)
var margin = 100;
var bx = Math.max(margin, Math.min(GAME_W - margin, x));
var by = Math.max(margin + 100, Math.min(GAME_H - margin, y));
dragNode.x = bx;
dragNode.y = by;
dragNode.bounce();
}
// Collision detection
var colliding = false;
for (var i = 0; i < spikes.length; i++) {
if (balloon.intersects(spikes[i])) {
colliding = true;
break;
}
}
// Always check collision, not just when dragging
if (!lastColliding && colliding) {
// Hit!
balloon.shake();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
lastColliding = colliding;
}
// Touch/drag events
game.down = function (x, y, obj) {
// Only start drag if touch is on balloon or close to it
var dx = x - balloon.x;
var dy = y - balloon.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 180) {
dragNode = balloon;
handleMove(x, y, obj);
}
};
game.move = handleMove;
game.up = function (x, y, obj) {
dragNode = null;
};
// Main update loop
game.update = function () {
elapsedTicks++;
// Increase difficulty over time
if (elapsedTicks % 600 === 0 && spikeSpawnInterval > 30) {
spikeSpawnInterval -= 8; // Spikes spawn more often
}
// Extra difficulty after score 10
if (score >= 10) {
spikeSpawnInterval = Math.max(18, spikeSpawnInterval - 1); // Faster spawn
}
// Spawn spikes
spikeSpawnTick++;
if (spikeSpawnTick >= spikeSpawnInterval) {
spikeSpawnTick = 0;
// Random X position (avoid spawning at extreme edges)
var margin = 160;
var sx = margin + Math.random() * (GAME_W - 2 * margin);
// Create spike
var spike = new Spike();
spike.x = sx;
spike.y = -60;
// Speed increases with time
var minSpeed = 10 + Math.floor(elapsedTicks / 600) * 2;
var maxSpeed = 18 + Math.floor(elapsedTicks / 600) * 2;
if (score >= 10) {
minSpeed += 6;
maxSpeed += 8;
}
spike.speedY = minSpeed + Math.random() * (maxSpeed - minSpeed);
spikes.push(spike);
game.addChild(spike);
// Optionally play sound
// LK.getSound('spike_spawn').play();
}
// Update spikes
for (var i = spikes.length - 1; i >= 0; i--) {
var s = spikes[i];
s.update();
// If spike goes off screen, remove and increase score
if (s.y > GAME_H + 100) {
s.destroy();
spikes.splice(i, 1);
score++;
scoreTxt.setText(score);
}
}
;
// Also check collision if not dragging (so player can't avoid game over by not touching)
var colliding = false;
for (var i = 0; i < spikes.length; i++) {
if (balloon.intersects(spikes[i])) {
colliding = true;
break;
}
}
if (!lastColliding && colliding) {
balloon.shake();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
lastColliding = colliding;
};
// Center score text horizontally
scoreTxt.setText(score);
scoreTxt.anchor.set(0.5, 0);
// Place score at top center, but not in top 100px (menu area)
scoreTxt.y = 40;
// Set background color (already set in init, but can be changed here if needed)
// game.setBackgroundColor(0xb3e0ff); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Balloon class (player)
var Balloon = Container.expand(function () {
var self = Container.call(this);
// Shadow
var shadow = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
y: 180
});
shadow.alpha = 0.18;
// Balloon body
var balloon = self.attachAsset('balloon', {
anchorX: 0.5,
anchorY: 0.5
});
// For a little bounce effect on move
self.bounce = function () {
tween(self, {
scaleX: 1.08,
scaleY: 0.92
}, {
duration: 80,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.cubicIn
});
}
});
};
// For a little shake on hit
self.shake = function () {
tween(self, {
x: self.x + 30
}, {
duration: 60,
easing: tween.linear,
onFinish: function onFinish() {
tween(self, {
x: self.x - 60
}, {
duration: 80,
easing: tween.linear,
onFinish: function onFinish() {
tween(self, {
x: self.x + 30
}, {
duration: 60,
easing: tween.linear
});
}
});
}
});
};
return self;
});
// Spike class (obstacle)
var Spike = Container.expand(function () {
var self = Container.call(this);
var spike = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 0.5
});
// For a little rotation
self.rotationSpeed = (Math.random() - 0.5) * 0.04;
// Speed will be set on spawn
self.speedY = 8;
// Update method
self.update = function () {
self.y += self.speedY;
spike.rotation += self.rotationSpeed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// LK.init.sound('spike_spawn', {volume: 0.4});
// Sound for spike spawn (optional, can be omitted if not wanted)
// Shadow for balloon
// Spike (obstacle)
// Balloon (player)
// Game area
var GAME_W = 2048;
var GAME_H = 2732;
// Balloon spawn position (centered horizontally, 80% down)
var BALLOON_START_X = GAME_W / 2;
var BALLOON_START_Y = GAME_H * 0.8;
// Balloon instance
var balloon = new Balloon();
balloon.x = BALLOON_START_X;
balloon.y = BALLOON_START_Y;
game.addChild(balloon);
// Obstacles array
var spikes = [];
// Score
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Time survived (for increasing difficulty)
var elapsedTicks = 0;
// Dragging
var dragNode = null;
// For collision detection
var lastColliding = false;
// For spike spawn timing
var spikeSpawnTick = 0;
var spikeSpawnInterval = 90; // Initial interval (ticks)
// Move handler (drag balloon)
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp balloon inside game area (with margin)
var margin = 100;
var bx = Math.max(margin, Math.min(GAME_W - margin, x));
var by = Math.max(margin + 100, Math.min(GAME_H - margin, y));
dragNode.x = bx;
dragNode.y = by;
dragNode.bounce();
}
// Collision detection
var colliding = false;
for (var i = 0; i < spikes.length; i++) {
if (balloon.intersects(spikes[i])) {
colliding = true;
break;
}
}
// Always check collision, not just when dragging
if (!lastColliding && colliding) {
// Hit!
balloon.shake();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
lastColliding = colliding;
}
// Touch/drag events
game.down = function (x, y, obj) {
// Only start drag if touch is on balloon or close to it
var dx = x - balloon.x;
var dy = y - balloon.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 180) {
dragNode = balloon;
handleMove(x, y, obj);
}
};
game.move = handleMove;
game.up = function (x, y, obj) {
dragNode = null;
};
// Main update loop
game.update = function () {
elapsedTicks++;
// Increase difficulty over time
if (elapsedTicks % 600 === 0 && spikeSpawnInterval > 30) {
spikeSpawnInterval -= 8; // Spikes spawn more often
}
// Extra difficulty after score 10
if (score >= 10) {
spikeSpawnInterval = Math.max(18, spikeSpawnInterval - 1); // Faster spawn
}
// Spawn spikes
spikeSpawnTick++;
if (spikeSpawnTick >= spikeSpawnInterval) {
spikeSpawnTick = 0;
// Random X position (avoid spawning at extreme edges)
var margin = 160;
var sx = margin + Math.random() * (GAME_W - 2 * margin);
// Create spike
var spike = new Spike();
spike.x = sx;
spike.y = -60;
// Speed increases with time
var minSpeed = 10 + Math.floor(elapsedTicks / 600) * 2;
var maxSpeed = 18 + Math.floor(elapsedTicks / 600) * 2;
if (score >= 10) {
minSpeed += 6;
maxSpeed += 8;
}
spike.speedY = minSpeed + Math.random() * (maxSpeed - minSpeed);
spikes.push(spike);
game.addChild(spike);
// Optionally play sound
// LK.getSound('spike_spawn').play();
}
// Update spikes
for (var i = spikes.length - 1; i >= 0; i--) {
var s = spikes[i];
s.update();
// If spike goes off screen, remove and increase score
if (s.y > GAME_H + 100) {
s.destroy();
spikes.splice(i, 1);
score++;
scoreTxt.setText(score);
}
}
;
// Also check collision if not dragging (so player can't avoid game over by not touching)
var colliding = false;
for (var i = 0; i < spikes.length; i++) {
if (balloon.intersects(spikes[i])) {
colliding = true;
break;
}
}
if (!lastColliding && colliding) {
balloon.shake();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
lastColliding = colliding;
};
// Center score text horizontally
scoreTxt.setText(score);
scoreTxt.anchor.set(0.5, 0);
// Place score at top center, but not in top 100px (menu area)
scoreTxt.y = 40;
// Set background color (already set in init, but can be changed here if needed)
// game.setBackgroundColor(0xb3e0ff);