/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Jahia (the bee) class
var Jahia = Container.expand(function () {
var self = Container.call(this);
// Attach bee asset (yellow ellipse with black stripes)
var beeBody = self.attachAsset('jahiaBody', {
anchorX: 0.5,
anchorY: 0.5
});
// Add stripes as separate shapes
var stripe1 = self.attachAsset('jahiaStripe1', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -20
});
var stripe2 = self.attachAsset('jahiaStripe2', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
var stripe3 = self.attachAsset('jahiaStripe3', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 20
});
// Add wings
var wingL = self.attachAsset('jahiaWingL', {
anchorX: 0.5,
anchorY: 0.5,
x: -40,
y: -30
});
var wingR = self.attachAsset('jahiaWingR', {
anchorX: 0.5,
anchorY: 0.5,
x: 40,
y: -30
});
self.vy = 0; // vertical speed
self.gravity = 1.5; // gravity
self.flapStrength = -32; // upward velocity on tap
self.alive = true;
self.update = function () {
if (!self.alive) return;
self.vy += self.gravity;
self.y += self.vy;
// Clamp rotation based on vy
self.rotation = Math.max(-0.5, Math.min(1.0, self.vy / 40));
// Prevent bee from going off the top
if (self.y < beeMinY) {
self.y = beeMinY;
self.vy = 0;
}
// If bee falls below screen, trigger game over
if (self.y > beeMaxY) {
self.y = beeMaxY;
self.vy = 0;
self.die();
}
};
self.flap = function () {
if (!self.alive) return;
self.vy = self.flapStrength;
// Animate wings
tween(wingL, {
rotation: -0.7
}, {
duration: 80,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(wingL, {
rotation: 0
}, {
duration: 120,
easing: tween.cubicIn
});
}
});
tween(wingR, {
rotation: 0.7
}, {
duration: 80,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(wingR, {
rotation: 0
}, {
duration: 120,
easing: tween.cubicIn
});
}
});
};
self.die = function () {
if (!self.alive) return;
self.alive = false;
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
};
return self;
});
// Pesticide enemy class
var Pesticide = Container.expand(function () {
var self = Container.call(this);
var pestBody = self.attachAsset('pestBody', {
anchorX: 0.5,
anchorY: 0.5
});
var pestSpray = self.attachAsset('pestSpray', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 40
});
self.vx = -pestSpeed;
self.vy = Math.random() > 0.5 ? 2 : -2;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Bounce off top/bottom
if (self.y < beeMinY + 80 || self.y > beeMaxY - 80) {
self.vy *= -1;
}
};
return self;
});
// Pipe class (top or bottom)
var Pipe = Container.expand(function () {
var self = Container.call(this);
// Attach pipe asset (pink box with flower)
var pipeBody = self.attachAsset('pipeBody', {
anchorX: 0.5,
anchorY: 0.0
});
var flower = self.attachAsset('pipeFlower', {
anchorX: 0.5,
anchorY: 0.0,
y: -40
});
self.passed = false; // Has bee passed this pipe pair?
self.update = function () {
self.x -= pipeSpeed;
};
return self;
});
// Wasp enemy class
var Wasp = Container.expand(function () {
var self = Container.call(this);
var waspBody = self.attachAsset('waspBody', {
anchorX: 0.5,
anchorY: 0.5
});
var waspWingL = self.attachAsset('waspWingL', {
anchorX: 0.5,
anchorY: 0.5,
x: -30,
y: -20
});
var waspWingR = self.attachAsset('waspWingR', {
anchorX: 0.5,
anchorY: 0.5,
x: 30,
y: -20
});
self.vx = -waspSpeed;
self.amp = 60 + Math.random() * 40;
self.phase = Math.random() * Math.PI * 2;
self.update = function () {
self.x += self.vx;
self.y += Math.sin(LK.ticks / 20 + self.phase) * 2;
// Animate wings
waspWingL.rotation = Math.sin(LK.ticks / 3) * 0.5;
waspWingR.rotation = -Math.sin(LK.ticks / 3) * 0.5;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xbee6e0 // Soft blue-green for forest sky
});
/****
* Game Code
****/
// Custom forest background asset (replace 'your_forest_asset_id' with your actual asset id)
// Game constants
var beeStartX = 500;
var beeStartY = 1366;
var beeMinY = 120;
var beeMaxY = 2732 - 120;
var pipeGap = 420;
var pipeMinY = 350;
var pipeMaxY = 2732 - 350 - pipeGap;
var pipeSpeed = 16;
var waspSpeed = 18;
var pestSpeed = 20;
var pipeInterval = 120; // frames between pipes
var pipes = [];
var wasps = [];
var pests = [];
var nextPipeTick = 0;
var nextWaspTick = 0;
var nextPestTick = 0;
var score = 0;
var level = 1;
var pipesToNextLevel = 3;
var pipesPassedThisLevel = 0;
var gameStarted = false;
// Add forest background image behind all gameplay elements
var forestBg = LK.getAsset('forestBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
game.addChild(forestBg);
// Create bee
var jahia = new Jahia();
game.addChild(jahia);
jahia.x = beeStartX;
jahia.y = beeStartY;
// Play looping background music
LK.playMusic('bgmusic');
// GUI: Score, Level, Pipes to next level
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFF000
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var levelTxt = new Text2('Niveau 1', {
size: 70,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 130;
var nextLevelTxt = new Text2('Tuyaux avant niveau suivant: 3', {
size: 60,
fill: 0xFFFFFF
});
nextLevelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(nextLevelTxt);
nextLevelTxt.y = 220;
// Helper: create a pipe pair (top and bottom)
function createPipePair() {
var gapY = pipeMinY + Math.random() * (pipeMaxY - pipeMinY);
// Top pipe
var topPipe = new Pipe();
topPipe.x = 2048 + 120;
topPipe.y = gapY - pipeGap / 2 - 600; // pipe height is 600
topPipe.isTop = true;
game.addChild(topPipe);
pipes.push(topPipe);
// Bottom pipe
var bottomPipe = new Pipe();
bottomPipe.x = 2048 + 120;
bottomPipe.y = gapY + pipeGap / 2;
bottomPipe.isTop = false;
game.addChild(bottomPipe);
pipes.push(bottomPipe);
}
// Helper: create a wasp
function createWasp() {
var y = beeMinY + 100 + Math.random() * (beeMaxY - beeMinY - 200);
var wasp = new Wasp();
wasp.x = 2048 + 120;
wasp.y = y;
game.addChild(wasp);
wasps.push(wasp);
}
// Helper: create a pesticide
function createPesticide() {
var y = beeMinY + 100 + Math.random() * (beeMaxY - beeMinY - 200);
var pest = new Pesticide();
pest.x = 2048 + 120;
pest.y = y;
game.addChild(pest);
pests.push(pest);
}
// Start game on first tap
function startGame() {
if (gameStarted) return;
gameStarted = true;
jahia.flap();
}
// Tap to flap
game.down = function (x, y, obj) {
if (!jahia.alive) return;
if (!gameStarted) {
startGame();
return;
}
jahia.flap();
};
// Main update loop
game.update = function () {
if (!jahia.alive) return;
// Only start spawning pipes after first tap
if (!gameStarted) return;
// Update bee
jahia.update();
// Spawn pipes
if (LK.ticks >= nextPipeTick) {
createPipePair();
nextPipeTick = LK.ticks + pipeInterval;
}
// Update pipes
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
pipe.update();
// Remove pipes off screen
if (pipe.x < -200) {
pipe.destroy();
pipes.splice(i, 1);
continue;
}
// Collision with bee
if (jahia.intersects(pipe)) {
jahia.die();
return;
}
// Score: only on bottom pipe, once per pair
if (!pipe.passed && !pipe.isTop && pipe.x + 80 < jahia.x) {
pipe.passed = true;
score += 1;
pipesPassedThisLevel += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Level up
if (pipesPassedThisLevel >= pipesToNextLevel) {
level += 1;
pipesPassedThisLevel = 0;
levelTxt.setText('Niveau ' + level);
// Double the number of pipes needed for next level, starting from 3 for level 1
if (level === 1) {
pipesToNextLevel = 3;
} else {
pipesToNextLevel = pipesToNextLevel * 2;
}
// Increase difficulty
if (level < 10) {
pipeSpeed += 1;
} else if (level < 20) {
pipeSpeed += 0.5;
}
// More frequent pipes
if (pipeInterval > 70) {
pipeInterval -= 4;
}
}
nextLevelTxt.setText('Tuyaux avant niveau suivant: ' + (pipesToNextLevel - pipesPassedThisLevel));
}
}
// Spawn wasps from level 5
if (level >= 5 && LK.ticks >= nextWaspTick) {
createWasp();
nextWaspTick = LK.ticks + Math.max(90, 300 - level * 10);
}
// Update wasps
for (var i = wasps.length - 1; i >= 0; i--) {
var wasp = wasps[i];
wasp.update();
if (wasp.x < -200) {
wasp.destroy();
wasps.splice(i, 1);
continue;
}
if (jahia.intersects(wasp)) {
jahia.die();
return;
}
}
// Spawn pesticides from level 20
if (level >= 20 && LK.ticks >= nextPestTick) {
createPesticide();
nextPestTick = LK.ticks + Math.max(120, 400 - (level - 20) * 8);
}
// Update pesticides
for (var i = pests.length - 1; i >= 0; i--) {
var pest = pests[i];
pest.update();
if (pest.x < -200) {
pest.destroy();
pests.splice(i, 1);
continue;
}
if (jahia.intersects(pest)) {
jahia.die();
return;
}
}
};
// Reset game state on game over (handled by LK, but clear arrays for safety)
game.onDestroy = function () {
pipes = [];
wasps = [];
pests = [];
score = 0;
level = 1;
pipesPassedThisLevel = 0;
pipesToNextLevel = 3;
pipeSpeed = 16;
pipeInterval = 120;
gameStarted = false;
};
/****
* Asset Definitions (for LK static analysis)
****/
// Bee body (yellow ellipse)
// Bee stripes (black boxes)
// Bee wings (white ellipses)
// Pipe body (pink box)
// Pipe flower (small yellow ellipse)
// Wasp body (black/yellow ellipse)
// Pesticide (green box with white spray) /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Jahia (the bee) class
var Jahia = Container.expand(function () {
var self = Container.call(this);
// Attach bee asset (yellow ellipse with black stripes)
var beeBody = self.attachAsset('jahiaBody', {
anchorX: 0.5,
anchorY: 0.5
});
// Add stripes as separate shapes
var stripe1 = self.attachAsset('jahiaStripe1', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -20
});
var stripe2 = self.attachAsset('jahiaStripe2', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
var stripe3 = self.attachAsset('jahiaStripe3', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 20
});
// Add wings
var wingL = self.attachAsset('jahiaWingL', {
anchorX: 0.5,
anchorY: 0.5,
x: -40,
y: -30
});
var wingR = self.attachAsset('jahiaWingR', {
anchorX: 0.5,
anchorY: 0.5,
x: 40,
y: -30
});
self.vy = 0; // vertical speed
self.gravity = 1.5; // gravity
self.flapStrength = -32; // upward velocity on tap
self.alive = true;
self.update = function () {
if (!self.alive) return;
self.vy += self.gravity;
self.y += self.vy;
// Clamp rotation based on vy
self.rotation = Math.max(-0.5, Math.min(1.0, self.vy / 40));
// Prevent bee from going off the top
if (self.y < beeMinY) {
self.y = beeMinY;
self.vy = 0;
}
// If bee falls below screen, trigger game over
if (self.y > beeMaxY) {
self.y = beeMaxY;
self.vy = 0;
self.die();
}
};
self.flap = function () {
if (!self.alive) return;
self.vy = self.flapStrength;
// Animate wings
tween(wingL, {
rotation: -0.7
}, {
duration: 80,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(wingL, {
rotation: 0
}, {
duration: 120,
easing: tween.cubicIn
});
}
});
tween(wingR, {
rotation: 0.7
}, {
duration: 80,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(wingR, {
rotation: 0
}, {
duration: 120,
easing: tween.cubicIn
});
}
});
};
self.die = function () {
if (!self.alive) return;
self.alive = false;
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
};
return self;
});
// Pesticide enemy class
var Pesticide = Container.expand(function () {
var self = Container.call(this);
var pestBody = self.attachAsset('pestBody', {
anchorX: 0.5,
anchorY: 0.5
});
var pestSpray = self.attachAsset('pestSpray', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 40
});
self.vx = -pestSpeed;
self.vy = Math.random() > 0.5 ? 2 : -2;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Bounce off top/bottom
if (self.y < beeMinY + 80 || self.y > beeMaxY - 80) {
self.vy *= -1;
}
};
return self;
});
// Pipe class (top or bottom)
var Pipe = Container.expand(function () {
var self = Container.call(this);
// Attach pipe asset (pink box with flower)
var pipeBody = self.attachAsset('pipeBody', {
anchorX: 0.5,
anchorY: 0.0
});
var flower = self.attachAsset('pipeFlower', {
anchorX: 0.5,
anchorY: 0.0,
y: -40
});
self.passed = false; // Has bee passed this pipe pair?
self.update = function () {
self.x -= pipeSpeed;
};
return self;
});
// Wasp enemy class
var Wasp = Container.expand(function () {
var self = Container.call(this);
var waspBody = self.attachAsset('waspBody', {
anchorX: 0.5,
anchorY: 0.5
});
var waspWingL = self.attachAsset('waspWingL', {
anchorX: 0.5,
anchorY: 0.5,
x: -30,
y: -20
});
var waspWingR = self.attachAsset('waspWingR', {
anchorX: 0.5,
anchorY: 0.5,
x: 30,
y: -20
});
self.vx = -waspSpeed;
self.amp = 60 + Math.random() * 40;
self.phase = Math.random() * Math.PI * 2;
self.update = function () {
self.x += self.vx;
self.y += Math.sin(LK.ticks / 20 + self.phase) * 2;
// Animate wings
waspWingL.rotation = Math.sin(LK.ticks / 3) * 0.5;
waspWingR.rotation = -Math.sin(LK.ticks / 3) * 0.5;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xbee6e0 // Soft blue-green for forest sky
});
/****
* Game Code
****/
// Custom forest background asset (replace 'your_forest_asset_id' with your actual asset id)
// Game constants
var beeStartX = 500;
var beeStartY = 1366;
var beeMinY = 120;
var beeMaxY = 2732 - 120;
var pipeGap = 420;
var pipeMinY = 350;
var pipeMaxY = 2732 - 350 - pipeGap;
var pipeSpeed = 16;
var waspSpeed = 18;
var pestSpeed = 20;
var pipeInterval = 120; // frames between pipes
var pipes = [];
var wasps = [];
var pests = [];
var nextPipeTick = 0;
var nextWaspTick = 0;
var nextPestTick = 0;
var score = 0;
var level = 1;
var pipesToNextLevel = 3;
var pipesPassedThisLevel = 0;
var gameStarted = false;
// Add forest background image behind all gameplay elements
var forestBg = LK.getAsset('forestBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
game.addChild(forestBg);
// Create bee
var jahia = new Jahia();
game.addChild(jahia);
jahia.x = beeStartX;
jahia.y = beeStartY;
// Play looping background music
LK.playMusic('bgmusic');
// GUI: Score, Level, Pipes to next level
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFF000
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var levelTxt = new Text2('Niveau 1', {
size: 70,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 130;
var nextLevelTxt = new Text2('Tuyaux avant niveau suivant: 3', {
size: 60,
fill: 0xFFFFFF
});
nextLevelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(nextLevelTxt);
nextLevelTxt.y = 220;
// Helper: create a pipe pair (top and bottom)
function createPipePair() {
var gapY = pipeMinY + Math.random() * (pipeMaxY - pipeMinY);
// Top pipe
var topPipe = new Pipe();
topPipe.x = 2048 + 120;
topPipe.y = gapY - pipeGap / 2 - 600; // pipe height is 600
topPipe.isTop = true;
game.addChild(topPipe);
pipes.push(topPipe);
// Bottom pipe
var bottomPipe = new Pipe();
bottomPipe.x = 2048 + 120;
bottomPipe.y = gapY + pipeGap / 2;
bottomPipe.isTop = false;
game.addChild(bottomPipe);
pipes.push(bottomPipe);
}
// Helper: create a wasp
function createWasp() {
var y = beeMinY + 100 + Math.random() * (beeMaxY - beeMinY - 200);
var wasp = new Wasp();
wasp.x = 2048 + 120;
wasp.y = y;
game.addChild(wasp);
wasps.push(wasp);
}
// Helper: create a pesticide
function createPesticide() {
var y = beeMinY + 100 + Math.random() * (beeMaxY - beeMinY - 200);
var pest = new Pesticide();
pest.x = 2048 + 120;
pest.y = y;
game.addChild(pest);
pests.push(pest);
}
// Start game on first tap
function startGame() {
if (gameStarted) return;
gameStarted = true;
jahia.flap();
}
// Tap to flap
game.down = function (x, y, obj) {
if (!jahia.alive) return;
if (!gameStarted) {
startGame();
return;
}
jahia.flap();
};
// Main update loop
game.update = function () {
if (!jahia.alive) return;
// Only start spawning pipes after first tap
if (!gameStarted) return;
// Update bee
jahia.update();
// Spawn pipes
if (LK.ticks >= nextPipeTick) {
createPipePair();
nextPipeTick = LK.ticks + pipeInterval;
}
// Update pipes
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
pipe.update();
// Remove pipes off screen
if (pipe.x < -200) {
pipe.destroy();
pipes.splice(i, 1);
continue;
}
// Collision with bee
if (jahia.intersects(pipe)) {
jahia.die();
return;
}
// Score: only on bottom pipe, once per pair
if (!pipe.passed && !pipe.isTop && pipe.x + 80 < jahia.x) {
pipe.passed = true;
score += 1;
pipesPassedThisLevel += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Level up
if (pipesPassedThisLevel >= pipesToNextLevel) {
level += 1;
pipesPassedThisLevel = 0;
levelTxt.setText('Niveau ' + level);
// Double the number of pipes needed for next level, starting from 3 for level 1
if (level === 1) {
pipesToNextLevel = 3;
} else {
pipesToNextLevel = pipesToNextLevel * 2;
}
// Increase difficulty
if (level < 10) {
pipeSpeed += 1;
} else if (level < 20) {
pipeSpeed += 0.5;
}
// More frequent pipes
if (pipeInterval > 70) {
pipeInterval -= 4;
}
}
nextLevelTxt.setText('Tuyaux avant niveau suivant: ' + (pipesToNextLevel - pipesPassedThisLevel));
}
}
// Spawn wasps from level 5
if (level >= 5 && LK.ticks >= nextWaspTick) {
createWasp();
nextWaspTick = LK.ticks + Math.max(90, 300 - level * 10);
}
// Update wasps
for (var i = wasps.length - 1; i >= 0; i--) {
var wasp = wasps[i];
wasp.update();
if (wasp.x < -200) {
wasp.destroy();
wasps.splice(i, 1);
continue;
}
if (jahia.intersects(wasp)) {
jahia.die();
return;
}
}
// Spawn pesticides from level 20
if (level >= 20 && LK.ticks >= nextPestTick) {
createPesticide();
nextPestTick = LK.ticks + Math.max(120, 400 - (level - 20) * 8);
}
// Update pesticides
for (var i = pests.length - 1; i >= 0; i--) {
var pest = pests[i];
pest.update();
if (pest.x < -200) {
pest.destroy();
pests.splice(i, 1);
continue;
}
if (jahia.intersects(pest)) {
jahia.die();
return;
}
}
};
// Reset game state on game over (handled by LK, but clear arrays for safety)
game.onDestroy = function () {
pipes = [];
wasps = [];
pests = [];
score = 0;
level = 1;
pipesPassedThisLevel = 0;
pipesToNextLevel = 3;
pipeSpeed = 16;
pipeInterval = 120;
gameStarted = false;
};
/****
* Asset Definitions (for LK static analysis)
****/
// Bee body (yellow ellipse)
// Bee stripes (black boxes)
// Bee wings (white ellipses)
// Pipe body (pink box)
// Pipe flower (small yellow ellipse)
// Wasp body (black/yellow ellipse)
// Pesticide (green box with white spray)