/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Broccoli enemy class var Broccoli = Container.expand(function () { var self = Container.call(this); var broccoliAsset = self.attachAsset('broccoli', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; // Moves down, will be randomized per instance self.update = function () { self.y += self.speed; }; return self; }); // Candy projectile class var Candy = Container.expand(function () { var self = Container.call(this); var candyAsset = self.attachAsset('candy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -32; // Moves up self.update = function () { self.y += self.speed; }; return self; }); // Cannon class var Cannon = Container.expand(function () { var self = Container.call(this); var cannonAsset = self.attachAsset('cannon', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Sound for shooting // Cannon (box, purple) // Broccoli enemy (ellipse, green) // Candy projectile (ellipse, pink) // Game area: 2048x2732 // Cannon position: bottom center, above bottom edge var cannon = new Cannon(); cannon.x = 2048 / 2; cannon.y = 2732 - 180; game.addChild(cannon); // Score display var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Shield status display var shieldTxt = new Text2('', { size: 80, fill: 0x00FFFF }); shieldTxt.anchor.set(1, 0); // Top right LK.gui.topRight.addChild(shieldTxt); // Update shield status text every frame LK.setInterval(function () { if (shieldActive) { shieldTxt.setText('š”ļø ' + Math.ceil(shieldTimer / 60)); } else { shieldTxt.setText(''); } }, 100); // Arrays to track candies and broccoli var candies = []; var broccolis = []; // --- Shield Lollipop Powerup State --- var shieldActive = false; var shieldTimer = 0; var shieldDuration = 300; // 5 seconds at 60fps // For drag-to-aim var isAiming = false; var aimX = cannon.x; // Prevent cannon from moving into top left 100x100 var minCannonX = 180 / 2 + 100; var maxCannonX = 2048 - 180 / 2; // Handle aiming and firing function handleMove(x, y, obj) { if (isAiming) { // Clamp aimX to stay within screen and not overlap top left aimX = Math.max(minCannonX, Math.min(maxCannonX, x)); cannon.x = aimX; } } game.move = handleMove; game.down = function (x, y, obj) { // Only allow firing if touch/click is on or near the cannon (bottom 400px) if (y > 2732 - 400) { isAiming = true; aimX = Math.max(minCannonX, Math.min(maxCannonX, x)); cannon.x = aimX; // Fire immediately on down fireCandy(); } }; game.up = function (x, y, obj) { isAiming = false; }; // Fire a candy from the cannon's current position function fireCandy() { var candy = new Candy(); candy.x = cannon.x; candy.y = cannon.y - 80; // Appear just above the cannon candies.push(candy); game.addChild(candy); LK.getSound('shoot').play(); } // --- Automatic shooting timer --- var autoShootInterval = 36; // frames between shots (about 1.6 shots/sec at 60fps) var autoShootTimer = 0; // Broccoli spawn timer var broccoliSpawnInterval = 60; // frames (1s at 60fps) var broccoliSpeedMin = 8; var broccoliSpeedMax = 16; var broccoliSpawnTimer = 0; // Difficulty ramping function getBroccoliSpeed() { // Increase speed as score increases var base = broccoliSpeedMin + Math.floor(LK.getScore() / 10) * 2; return Math.min(base + Math.random() * 4, broccoliSpeedMax + LK.getScore() * 0.5); } function getBroccoliInterval() { // Decrease interval as score increases return Math.max(20, broccoliSpawnInterval - Math.floor(LK.getScore() / 5) * 5); } // Main game update loop game.update = function () { // Update candies for (var i = candies.length - 1; i >= 0; i--) { var candy = candies[i]; candy.update(); // Remove if off screen if (candy.y < -100) { candy.destroy(); candies.splice(i, 1); } } // Update broccolis for (var j = broccolis.length - 1; j >= 0; j--) { var broccoli = broccolis[j]; broccoli.update(); // Check for collision with any candy var hit = false; for (var k = candies.length - 1; k >= 0; k--) { var candy = candies[k]; if (broccoli.intersects(candy)) { // --- Shield Lollipop Drop Chance --- // 1 in 10 chance to drop shield when broccoli is destroyed if (!shieldActive && Math.random() < 0.1) { shieldActive = true; shieldTimer = shieldDuration; // Optional: flash cannon or show effect LK.effects.flashObject(cannon, 0x00ffff, 500); } // Destroy both broccoli.destroy(); candy.destroy(); broccolis.splice(j, 1); candies.splice(k, 1); // Score up LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); hit = true; break; } } if (hit) continue; // Check for reaching cannon (game over or shield) if (broccoli.y + 60 >= cannon.y - 50 && Math.abs(broccoli.x - cannon.x) < 120) { if (shieldActive) { // Block game over, consume shield, destroy broccoli, flash blue shieldActive = false; shieldTimer = 0; LK.effects.flashScreen(0x00ffff, 500); broccoli.destroy(); broccolis.splice(j, 1); continue; } else { // Flash screen red LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } // Remove if off screen (bottom) if (broccoli.y > 2732 + 100) { broccoli.destroy(); broccolis.splice(j, 1); } } // Spawn broccoli broccoliSpawnTimer++; if (broccoliSpawnTimer >= getBroccoliInterval()) { broccoliSpawnTimer = 0; var broccoli = new Broccoli(); // Random x, avoid top left 100px var bx = 100 + 60 + Math.random() * (2048 - 200); broccoli.x = bx; broccoli.y = -60; broccoli.speed = getBroccoliSpeed(); broccolis.push(broccoli); game.addChild(broccoli); } // --- Automatic shooting logic --- autoShootTimer++; if (autoShootTimer >= autoShootInterval) { autoShootTimer = 0; fireCandy(); } // --- Shield Lollipop Timer --- if (shieldActive) { shieldTimer--; if (shieldTimer <= 0) { shieldActive = false; shieldTimer = 0; } } }; // Initial score LK.setScore(0); scoreTxt.setText('0');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Broccoli enemy class
var Broccoli = Container.expand(function () {
var self = Container.call(this);
var broccoliAsset = self.attachAsset('broccoli', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8; // Moves down, will be randomized per instance
self.update = function () {
self.y += self.speed;
};
return self;
});
// Candy projectile class
var Candy = Container.expand(function () {
var self = Container.call(this);
var candyAsset = self.attachAsset('candy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -32; // Moves up
self.update = function () {
self.y += self.speed;
};
return self;
});
// Cannon class
var Cannon = Container.expand(function () {
var self = Container.call(this);
var cannonAsset = self.attachAsset('cannon', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Sound for shooting
// Cannon (box, purple)
// Broccoli enemy (ellipse, green)
// Candy projectile (ellipse, pink)
// Game area: 2048x2732
// Cannon position: bottom center, above bottom edge
var cannon = new Cannon();
cannon.x = 2048 / 2;
cannon.y = 2732 - 180;
game.addChild(cannon);
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Shield status display
var shieldTxt = new Text2('', {
size: 80,
fill: 0x00FFFF
});
shieldTxt.anchor.set(1, 0); // Top right
LK.gui.topRight.addChild(shieldTxt);
// Update shield status text every frame
LK.setInterval(function () {
if (shieldActive) {
shieldTxt.setText('š”ļø ' + Math.ceil(shieldTimer / 60));
} else {
shieldTxt.setText('');
}
}, 100);
// Arrays to track candies and broccoli
var candies = [];
var broccolis = [];
// --- Shield Lollipop Powerup State ---
var shieldActive = false;
var shieldTimer = 0;
var shieldDuration = 300; // 5 seconds at 60fps
// For drag-to-aim
var isAiming = false;
var aimX = cannon.x;
// Prevent cannon from moving into top left 100x100
var minCannonX = 180 / 2 + 100;
var maxCannonX = 2048 - 180 / 2;
// Handle aiming and firing
function handleMove(x, y, obj) {
if (isAiming) {
// Clamp aimX to stay within screen and not overlap top left
aimX = Math.max(minCannonX, Math.min(maxCannonX, x));
cannon.x = aimX;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only allow firing if touch/click is on or near the cannon (bottom 400px)
if (y > 2732 - 400) {
isAiming = true;
aimX = Math.max(minCannonX, Math.min(maxCannonX, x));
cannon.x = aimX;
// Fire immediately on down
fireCandy();
}
};
game.up = function (x, y, obj) {
isAiming = false;
};
// Fire a candy from the cannon's current position
function fireCandy() {
var candy = new Candy();
candy.x = cannon.x;
candy.y = cannon.y - 80; // Appear just above the cannon
candies.push(candy);
game.addChild(candy);
LK.getSound('shoot').play();
}
// --- Automatic shooting timer ---
var autoShootInterval = 36; // frames between shots (about 1.6 shots/sec at 60fps)
var autoShootTimer = 0;
// Broccoli spawn timer
var broccoliSpawnInterval = 60; // frames (1s at 60fps)
var broccoliSpeedMin = 8;
var broccoliSpeedMax = 16;
var broccoliSpawnTimer = 0;
// Difficulty ramping
function getBroccoliSpeed() {
// Increase speed as score increases
var base = broccoliSpeedMin + Math.floor(LK.getScore() / 10) * 2;
return Math.min(base + Math.random() * 4, broccoliSpeedMax + LK.getScore() * 0.5);
}
function getBroccoliInterval() {
// Decrease interval as score increases
return Math.max(20, broccoliSpawnInterval - Math.floor(LK.getScore() / 5) * 5);
}
// Main game update loop
game.update = function () {
// Update candies
for (var i = candies.length - 1; i >= 0; i--) {
var candy = candies[i];
candy.update();
// Remove if off screen
if (candy.y < -100) {
candy.destroy();
candies.splice(i, 1);
}
}
// Update broccolis
for (var j = broccolis.length - 1; j >= 0; j--) {
var broccoli = broccolis[j];
broccoli.update();
// Check for collision with any candy
var hit = false;
for (var k = candies.length - 1; k >= 0; k--) {
var candy = candies[k];
if (broccoli.intersects(candy)) {
// --- Shield Lollipop Drop Chance ---
// 1 in 10 chance to drop shield when broccoli is destroyed
if (!shieldActive && Math.random() < 0.1) {
shieldActive = true;
shieldTimer = shieldDuration;
// Optional: flash cannon or show effect
LK.effects.flashObject(cannon, 0x00ffff, 500);
}
// Destroy both
broccoli.destroy();
candy.destroy();
broccolis.splice(j, 1);
candies.splice(k, 1);
// Score up
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
hit = true;
break;
}
}
if (hit) continue;
// Check for reaching cannon (game over or shield)
if (broccoli.y + 60 >= cannon.y - 50 && Math.abs(broccoli.x - cannon.x) < 120) {
if (shieldActive) {
// Block game over, consume shield, destroy broccoli, flash blue
shieldActive = false;
shieldTimer = 0;
LK.effects.flashScreen(0x00ffff, 500);
broccoli.destroy();
broccolis.splice(j, 1);
continue;
} else {
// Flash screen red
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Remove if off screen (bottom)
if (broccoli.y > 2732 + 100) {
broccoli.destroy();
broccolis.splice(j, 1);
}
}
// Spawn broccoli
broccoliSpawnTimer++;
if (broccoliSpawnTimer >= getBroccoliInterval()) {
broccoliSpawnTimer = 0;
var broccoli = new Broccoli();
// Random x, avoid top left 100px
var bx = 100 + 60 + Math.random() * (2048 - 200);
broccoli.x = bx;
broccoli.y = -60;
broccoli.speed = getBroccoliSpeed();
broccolis.push(broccoli);
game.addChild(broccoli);
}
// --- Automatic shooting logic ---
autoShootTimer++;
if (autoShootTimer >= autoShootInterval) {
autoShootTimer = 0;
fireCandy();
}
// --- Shield Lollipop Timer ---
if (shieldActive) {
shieldTimer--;
if (shieldTimer <= 0) {
shieldActive = false;
shieldTimer = 0;
}
}
};
// Initial score
LK.setScore(0);
scoreTxt.setText('0');