Code edit (4 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: bomb is not defined' in or related to this line: 'bomb.destroy();' Line Number: 275
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: bomb is not defined' in or related to this line: 'bomb.destroy();' Line Number: 278
Code edit (10 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: highScore is not defined' in or related to this line: 'if (score > highScore) {' Line Number: 734 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: noun is not defined' in or related to this line: 'explosionGraphics.scaleX = 0.2 + progress * noun;' Line Number: 189
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: _CRYPTO_ is not defined' in or related to this line: 'var dx = _CRYPTO_ - self.x;' Line Number: 80
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'setTimeout is not a function' in or related to this line: 'setTimeout(function () {' Line Number: 497
User prompt
Please fix the bug: 'Graphics is not a constructor' in or related to this line: 'var waveProgressBg = LK.gui.top.addChild(new Graphics());' Line Number: 413
Code edit (1 edits merged)
Please save this source code
User prompt
Grandma Click Fury
Initial prompt
Create a 2D pixel art arcade-style action game titled “Grandma Click Fury”. The main character is Grandma Turbo, a wild old lady riding a rocket-powered shopping cart through chaotic food-themed worlds while battling evil cyber pigeons. Grandma follows the mouse cursor slowly, and all actions are triggered with clicks. Clicking makes her attack, holding click charges a turbo boost, and double-clicking throws a food bomb. The game is fast-paced, full of funny sound effects and over-the-top animations. Grandma has sassy voice lines like “Click me harder, baby!”, “That’s how grandma rolls!”, and “Pigeon trash, back off!”. 🎮 Game Mechanics: Grandma rolls toward the mouse cursor. Click to swing her cane. Hold click to charge a forward turbo boost. Double-click to throw a ketchup bomb. Power-ups appear on the ground and activate with a single click. 🌍 Worlds: Syrup Street – A sticky breakfast world with waffle bridges, toast traps, and syrup waterfalls. Pizza Parade – A lunch-themed level where cheese slows you down, and flying pineapple drones shoot pepperoni lasers. Microwave Mountain – The final world, filled with floating forks, bouncing meatballs, and the evil boss Microwave Overlord. 🦅 Enemies: Cyber pigeons that swoop in quickly. Egg-throwing pigeons that stay at range. Hover drones dropping mustard bombs. Mini-bosses like The Burger Bomber and The Bacon Snake. 💥 Power-Ups: Click-Coffee: Temporarily increases movement speed. Cookie Shield: Blocks the next hit. Bingo Blast: Summons a squad of old ladies who do an area attack with knitting needles. 📦 UI: Health bar: Yarn balls. Energy meter: Fills while holding click. Score: Number of pies collected. Funny text when power-ups activate: “¡Turbo Granny Time!” or “Bingo Blitz Ready!” The art should be vibrant, cartoonish pixel style, with exaggerated squash-and-stretch animations, food explosions, and chaotic action. Add juicy sound effects and a retro-style upbeat soundtrack. The game should be fun, silly, satisfying to click, and visually explosive — designed to be addictive and hilarious.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BossPigeon = Container.expand(function () {
var self = Container.call(this);
var pigeonGraphics = self.attachAsset('cyberPigeon', {
anchorX: 0.5,
anchorY: 0.5
});
pigeonGraphics.scaleX = 2;
pigeonGraphics.scaleY = 2;
self.health = Math.min(240 + 20 * wave, 1000);
self.maxHealth = self.health;
self.speed = 1.2;
self.attackCooldown = 0;
self.specialAttackCooldown = 0;
self.startX = 1024;
self.isBoss = true;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
var damageText = new Text2('-' + damage, {
size: 60,
fill: 0xffff00
});
damageText.x = self.x;
damageText.y = self.y - 50;
game.addChild(damageText);
tween(damageText, {
y: damageText.y - 80,
alpha: 0
}, {
duration: 1000,
onComplete: function onComplete() {
damageText.destroy();
}
});
if (self.health <= 0) {
score += 200;
for (var i = 0; i < 4; i++) {
LK.setTimeout(function () {
var explosion = new Explosion();
explosion.x = self.x + (Math.random() - 0.5) * 120;
explosion.y = self.y + (Math.random() - 0.5) * 120;
game.addChild(explosion);
explosions.push(explosion);
LK.getSound('explosion').play();
}, i * 150);
}
for (var i = 0; i < 4; i++) {
spawnPowerUpAt(self.x + (Math.random() - 0.5) * 100, self.y + (Math.random() - 0.5) * 150);
}
return true;
}
return false;
};
self.update = function () {
var dy = 1366 - self.y;
var distance = Math.abs(dy);
if (distance > 300) {
self.y += self.speed;
self.x = self.startX + Math.sin(LK.ticks * 0.05) * 400;
} else {
self.x = self.startX + Math.sin(LK.ticks * 0.05) * 400;
}
if (self.specialAttackCooldown <= 0) {
for (var i = 0; i < 3; i++) {
var miniPigeon = new CyberPigeon();
miniPigeon.x = self.x + (i - 1.5) * 100; // Fila horizontal, espaciado de 100 píxeles
miniPigeon.y = self.y;
miniPigeon.health = 20;
cyberPigeons.push(miniPigeon);
game.addChild(miniPigeon);
}
self.specialAttackCooldown = 180;
} else {
self.specialAttackCooldown--;
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
pigeonGraphics.rotation = Math.atan2(dy, 1024 - self.x);
};
return self;
});
var CyberPigeon = Container.expand(function () {
var self = Container.call(this);
var type = Math.random() < 0.15 ? 'rotating' : Math.random() < 0.8235 ? 'normal' : 'fast';
var assetName = type === 'fast' ? 'fastPigeon' : type === 'rotating' ? 'rotatingPigeon' : 'cyberPigeon';
var pigeonGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.health = Math.min(35 + 4 * Math.sqrt(wave), 75);
self.maxHealth = self.health;
self.speed = Math.min(1.8 + 0.3 * Math.sqrt(wave), 8);
self.attackCooldown = 0;
self.type = type;
if (self.type === 'fast') {
self.speed *= 1.8;
self.health *= 0.6;
} else if (self.type === 'rotating') {
self.speed *= 1.1;
self.health *= 0.8;
self.orbitRadius = 100;
self.orbitAngle = Math.random() * Math.PI * 2;
self.orbitSpeed = 0.1;
}
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 150);
var damageText = new Text2('-' + damage, {
size: 40,
fill: 0xff0000
});
damageText.x = self.x;
damageText.y = self.y - 30;
game.addChild(damageText);
tween(damageText, {
y: damageText.y - 60,
alpha: 0
}, {
duration: 800,
onComplete: function onComplete() {
damageText.destroy();
}
});
if (self.health <= 0) {
score += self.type === 'fast' ? 20 : self.type === 'rotating' ? 25 : 15;
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
game.addChild(explosion);
explosions.push(explosion);
LK.getSound('explosion').play();
return true;
}
return false;
};
self.update = function () {
var dx = 1024 - self.x;
var dy = 1366 - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
if (self.type === 'rotating') {
self.orbitAngle += self.orbitSpeed;
var orbitX = dx / distance * self.speed;
var orbitY = dy / distance * self.speed;
self.x += orbitX + Math.cos(self.orbitAngle) * self.orbitRadius * 0.1;
self.y += orbitY + Math.sin(self.orbitAngle) * self.orbitRadius * 0.1;
} else {
var wobble = self.type === 'fast' ? Math.sin(LK.ticks * 0.25) * 25 : 0;
self.x += dx / distance * self.speed + Math.sin(LK.ticks * 0.12) * 0.6;
self.y += dy / distance * self.speed + wobble * 0.12;
}
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
pigeonGraphics.rotation = Math.atan2(dy, dx);
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 35;
self.radius = 100;
explosionGraphics.scaleX = 0.2;
explosionGraphics.scaleY = 0.2;
self.update = function () {
self.lifeTime--;
var progress = 1 - self.lifeTime / 35;
explosionGraphics.scaleX = 0.2 + progress * 2.8;
explosionGraphics.scaleY = 0.2 + progress * 2.8;
explosionGraphics.alpha = 1 - progress;
explosionGraphics.rotation += 0.15;
return self.lifeTime <= 0;
};
return self;
});
var Grandma = Container.expand(function () {
var self = Container.call(this);
var grandmaGraphics = self.attachAsset('grandma', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 120;
self.maxHealth = 120;
self.bombDamage = 60;
self.shotCooldown = 0;
self.speedBoost = 0;
self.damageBoost = 0;
self.multishot = 0;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 300);
game.x = (Math.random() - 0.5) * 25;
game.y = (Math.random() - 0.5) * 25;
LK.setTimeout(function () {
game.x = 0;
game.y = 0;
}, 120);
if (self.health <= 0) {
LK.showGameOver();
}
};
self.update = function () {
self.x = 1024;
self.y = 1366;
if (self.health < self.maxHealth && LK.ticks % (wave > 10 ? 400 : 500) === 0) {
self.health = Math.min(self.health + (wave > 10 ? 3 : 2), self.maxHealth);
}
if (self.shotCooldown > 0) {
self.shotCooldown--;
}
};
return self;
});
var KetchupBomb = Container.expand(function () {
var self = Container.call(this);
var bombGraphics = self.attachAsset('ketchupBomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.lifeTime = 140;
self.damage = grandma.bombDamage + grandma.damageBoost;
self.trail = [];
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifeTime--;
bombGraphics.rotation += 0.25;
self.trail.push({
x: self.x,
y: self.y,
alpha: 1
});
if (self.trail.length > 6) {
self.trail.shift();
}
if (self.lifeTime <= 0) {
self.destroy();
return true;
}
return false;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var rand = Math.random();
var types = rand < 0.1 ? 'multishot' : rand < 0.4 ? 'speed' : rand < 0.7 ? 'health' : 'damage';
self.type = types;
var assetName = 'powerUp' + self.type.charAt(0).toUpperCase() + self.type.slice(1);
var powerUpGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 800;
self.update = function () {
self.lifeTime--;
self.y += Math.sin(LK.ticks * 0.18) * 1.2;
powerUpGraphics.rotation += 0.001;
powerUpGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.12) * 0.25;
powerUpGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.12) * 0.25;
if (self.lifeTime < 160) {
powerUpGraphics.alpha = Math.sin(LK.ticks * 0.35) * 0.5 + 0.5;
}
return self.lifeTime <= 0;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var background = game.addChild(LK.getAsset('background', {
x: 0,
y: 0
}));
/****
* Game Variables
****/
var grandma;
var cyberPigeons = [];
var ketchupBombs = [];
var explosions = [];
var powerUps = [];
var score = 0;
var wave = 1;
var enemiesKilled = 0;
var enemiesThisWave = 0;
var totalEnemiesThisWave = 0;
var lastClickTime = 0;
var comboCounter = 0;
var comboTimer = 0;
var bossWave = false;
/****
* UI Elements
****/
var scoreText = new Text2('Score: 0', {
size: 50,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
scoreText.x = 50;
scoreText.y = 50;
LK.gui.topLeft.addChild(scoreText);
var healthText = new Text2('Health: 120/120', {
size: 50,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 3
});
healthText.anchor.set(1, 0);
LK.gui.topRight.addChild(healthText);
var waveText = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 3
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var bossHealthBg = LK.getAsset('chargeBarBg', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
x: 0,
y: 100
});
LK.gui.top.addChild(bossHealthBg);
bossHealthBg.visible = false;
var bossHealthBar = LK.getAsset('chargeBar', {
anchorX: 0,
anchorY: 0,
scaleX: 0,
x: -150,
y: 100
});
LK.gui.top.addChild(bossHealthBar);
bossHealthBar.visible = false;
var comboText = new Text2('', {
size: 60,
fill: 0x00FFFF,
stroke: 0x000000,
strokeThickness: 3
});
comboText.anchor.set(0.5, 0);
comboText.x = 1024;
comboText.y = 200;
game.addChild(comboText);
var waveProgressBg = LK.getAsset('chargeBarBg', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
x: 0,
y: 60
});
LK.gui.top.addChild(waveProgressBg);
var waveProgressBar = LK.getAsset('chargeBar', {
anchorX: 0,
anchorY: 0,
scaleX: 0,
x: -150,
y: 60
});
LK.gui.top.addChild(waveProgressBar);
/****
* Game Functions
****/
function createGrandma() {
grandma = game.addChild(new Grandma());
grandma.x = 1024;
grandma.y = 1366;
}
function throwKetchupBomb(targetX, targetY) {
if (grandma.shotCooldown > 0) {
return;
}
LK.getSound('attack').play();
LK.effects.flashObject(grandma, 0xffff00, 150);
var shots = grandma.multishot > 0 ? 3 : 1;
var angles = [0];
if (shots > 1) {
angles = [-15, 0, 15];
}
var enemiesHit = 0;
for (var i = 0; i < shots; i++) {
var bomb = new KetchupBomb();
bomb.x = grandma.x;
bomb.y = grandma.y;
var angle = Math.atan2(targetY - grandma.y, targetX - grandma.x) + angles[i] * Math.PI / 180;
var dx = Math.cos(angle);
var dy = Math.sin(angle);
var speed = 12;
bomb.velocityX = dx * speed;
bomb.velocityY = dy * speed;
bomb.damage = grandma.bombDamage + grandma.damageBoost;
ketchupBombs.push(bomb);
game.addChild(bomb);
enemiesHit += checkImmediateHits(bomb, angle);
}
if (enemiesHit > 0) {
comboCounter += enemiesHit;
comboTimer = 150;
if (comboCounter >= 3) {
score += comboCounter * 6;
}
}
grandma.shotCooldown = 20 - Math.min(grandma.speedBoost * 2, 12);
}
function checkImmediateHits(bomb, angle) {
var enemiesHit = 0;
var range = 200;
for (var j = cyberPigeons.length - 1; j >= 0; j--) {
var pigeon = cyberPigeons[j];
var pdx = pigeon.x - grandma.x;
var pdy = pigeon.y - grandma.y;
var distance = Math.sqrt(pdx * pdx + pdy * pdy);
if (distance < range && Math.abs(Math.atan2(pdy, pdx) - angle) < 0.3) {
if (pigeon.takeDamage(bomb.damage)) {
pigeon.destroy();
cyberPigeons.splice(j, 1);
enemiesKilled++;
enemiesThisWave++;
enemiesHit++;
}
}
}
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
var pdx = powerUp.x - grandma.x;
var pdy = powerUp.y - grandma.y;
var distance = Math.sqrt(pdx * pdx + pdy * pdy);
if (distance < range && Math.abs(Math.atan2(pdy, pdx) - angle) < 0.3) {
collectPowerUp(powerUp);
powerUp.destroy();
powerUps.splice(j, 1);
}
}
return enemiesHit;
}
function spawnEnemies() {
bossWave = wave % 5 === 0;
if (bossWave) {
var boss = new BossPigeon();
boss.x = 1024;
boss.y = -150;
cyberPigeons.push(boss);
game.addChild(boss);
totalEnemiesThisWave = 1;
} else {
var maxEnemies = Math.min(15 + Math.floor(wave / 5), 70);
var enemiesToSpawn = Math.min(4 + wave, maxEnemies);
totalEnemiesThisWave = enemiesToSpawn;
for (var i = 0; i < enemiesToSpawn; i++) {
LK.setTimeout(function () {
var pigeon = new CyberPigeon();
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
pigeon.x = Math.random() * 2048;
pigeon.y = -50;
break;
case 1:
pigeon.x = 2098;
pigeon.y = Math.random() * 2732;
break;
case 2:
pigeon.x = Math.random() * 2048;
pigeon.y = 2782;
break;
case 3:
pigeon.x = -50;
pigeon.y = Math.random() * 2732;
break;
}
cyberPigeons.push(pigeon);
game.addChild(pigeon);
}, i * (wave > 10 ? 300 : 400));
}
}
enemiesThisWave = 0;
}
function spawnPowerUpAt(x, y) {
var powerUp = new PowerUp();
powerUp.x = x;
powerUp.y = y;
powerUps.push(powerUp);
game.addChild(powerUp);
}
function collectPowerUp(powerUp) {
LK.getSound('powerup').play();
LK.effects.flashObject(grandma, 0x00ff00, 400);
var bonusText = new Text2('', {
size: 50,
fill: 0x00ff00
});
bonusText.x = grandma.x;
bonusText.y = grandma.y - 60;
game.addChild(bonusText);
switch (powerUp.type) {
case 'speed':
grandma.speedBoost += 2;
bonusText.setText('FIRE RATE UP!');
break;
case 'health':
grandma.health = Math.min(grandma.health + 30 + 2 * wave, grandma.maxHealth);
bonusText.setText('HEALTH +' + (30 + 2 * wave) + '!');
break;
case 'damage':
grandma.damageBoost += 12;
bonusText.setText('DAMAGE UP!');
break;
case 'multishot':
grandma.multishot = 180;
bonusText.setText('MULTISHOT!');
break;
}
tween(bonusText, {
y: bonusText.y - 100,
alpha: 0
}, {
duration: 1200,
onComplete: function onComplete() {
bonusText.destroy();
}
});
}
/****
* Event Handlers
****/
game.down = function (x, y, obj) {
throwKetchupBomb(x, y);
};
/****
* Game Loop
****/
createGrandma();
LK.playMusic('gameMusic');
spawnEnemies();
game.update = function () {
if (comboTimer > 0) {
comboTimer--;
if (comboCounter >= 3) {
comboText.setText('COMBO x' + comboCounter + '!');
} else {
comboText.setText('');
}
} else {
comboCounter = 0;
comboText.setText('');
}
for (var i = cyberPigeons.length - 1; i >= 0; i--) {
var pigeon = cyberPigeons[i];
pigeon.update();
if (pigeon.intersects(grandma) && pigeon.attackCooldown <= 0) {
var damage = pigeon.isBoss ? 20 : 10;
grandma.takeDamage(damage);
pigeon.attackCooldown = 50;
}
if (pigeon.x < -200 || pigeon.x > 2248 || pigeon.y < -200 || pigeon.y > 2932) {
pigeon.destroy();
cyberPigeons.splice(i, 1);
}
}
for (var i = ketchupBombs.length - 1; i >= 0; i--) {
var bomb = ketchupBombs[i];
var shouldRemove = bomb.update();
if (shouldRemove || bomb.x < -100 || bomb.x > 2248 || bomb.y < -100 || bomb.y > 2832) {
bomb.destroy();
ketchupBombs.splice(i, 1);
} else {
for (var j = cyberPigeons.length - 1; j >= 0; j--) {
var pigeon = cyberPigeons[j];
if (bomb.intersects(pigeon)) {
if (pigeon.takeDamage(bomb.damage)) {
pigeon.destroy();
cyberPigeons.splice(j, 1);
enemiesKilled++;
enemiesThisWave++;
}
bomb.destroy();
ketchupBombs.splice(i, 1);
break;
}
}
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
if (bomb.intersects(powerUp)) {
collectPowerUp(powerUp);
powerUp.destroy();
powerUps.splice(j, 1);
bomb.destroy();
ketchupBombs.splice(i, 1);
break;
}
}
}
}
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
var shouldRemove = explosion.update();
if (shouldRemove) {
explosion.destroy();
explosions.splice(i, 1);
}
}
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
var shouldRemove = powerUp.update();
if (shouldRemove) {
powerUp.destroy();
powerUps.splice(i, 1);
}
}
if (grandma.multishot > 0) {
grandma.multishot--;
}
grandma.update();
if (cyberPigeons.length === 0) {
wave++;
spawnEnemies();
if (Math.random() < 1) {
spawnPowerUpAt(Math.random() * 1600 + 200, Math.random() * 2200 + 200);
}
}
scoreText.setText('Score: ' + score);
healthText.setText('Health: ' + grandma.health + '/' + grandma.maxHealth);
waveText.setText('Wave: ' + wave + (bossWave ? ' (BOSS)' : ''));
// Actualizar barra de vida del jefe
if (bossWave && cyberPigeons.length > 0) {
var boss = cyberPigeons.find(function (p) {
return p.isBoss;
});
if (boss) {
bossHealthBg.visible = true;
bossHealthBar.visible = true;
bossHealthBar.scaleX = boss.health / boss.maxHealth * 1.5;
}
} else {
bossHealthBg.visible = false;
bossHealthBar.visible = false;
}
var progress = totalEnemiesThisWave > 0 ? enemiesThisWave / totalEnemiesThisWave : 0;
waveProgressBar.scaleX = progress * 1.5;
LK.setScore(score);
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BossPigeon = Container.expand(function () {
var self = Container.call(this);
var pigeonGraphics = self.attachAsset('cyberPigeon', {
anchorX: 0.5,
anchorY: 0.5
});
pigeonGraphics.scaleX = 2;
pigeonGraphics.scaleY = 2;
self.health = Math.min(240 + 20 * wave, 1000);
self.maxHealth = self.health;
self.speed = 1.2;
self.attackCooldown = 0;
self.specialAttackCooldown = 0;
self.startX = 1024;
self.isBoss = true;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
var damageText = new Text2('-' + damage, {
size: 60,
fill: 0xffff00
});
damageText.x = self.x;
damageText.y = self.y - 50;
game.addChild(damageText);
tween(damageText, {
y: damageText.y - 80,
alpha: 0
}, {
duration: 1000,
onComplete: function onComplete() {
damageText.destroy();
}
});
if (self.health <= 0) {
score += 200;
for (var i = 0; i < 4; i++) {
LK.setTimeout(function () {
var explosion = new Explosion();
explosion.x = self.x + (Math.random() - 0.5) * 120;
explosion.y = self.y + (Math.random() - 0.5) * 120;
game.addChild(explosion);
explosions.push(explosion);
LK.getSound('explosion').play();
}, i * 150);
}
for (var i = 0; i < 4; i++) {
spawnPowerUpAt(self.x + (Math.random() - 0.5) * 100, self.y + (Math.random() - 0.5) * 150);
}
return true;
}
return false;
};
self.update = function () {
var dy = 1366 - self.y;
var distance = Math.abs(dy);
if (distance > 300) {
self.y += self.speed;
self.x = self.startX + Math.sin(LK.ticks * 0.05) * 400;
} else {
self.x = self.startX + Math.sin(LK.ticks * 0.05) * 400;
}
if (self.specialAttackCooldown <= 0) {
for (var i = 0; i < 3; i++) {
var miniPigeon = new CyberPigeon();
miniPigeon.x = self.x + (i - 1.5) * 100; // Fila horizontal, espaciado de 100 píxeles
miniPigeon.y = self.y;
miniPigeon.health = 20;
cyberPigeons.push(miniPigeon);
game.addChild(miniPigeon);
}
self.specialAttackCooldown = 180;
} else {
self.specialAttackCooldown--;
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
pigeonGraphics.rotation = Math.atan2(dy, 1024 - self.x);
};
return self;
});
var CyberPigeon = Container.expand(function () {
var self = Container.call(this);
var type = Math.random() < 0.15 ? 'rotating' : Math.random() < 0.8235 ? 'normal' : 'fast';
var assetName = type === 'fast' ? 'fastPigeon' : type === 'rotating' ? 'rotatingPigeon' : 'cyberPigeon';
var pigeonGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.health = Math.min(35 + 4 * Math.sqrt(wave), 75);
self.maxHealth = self.health;
self.speed = Math.min(1.8 + 0.3 * Math.sqrt(wave), 8);
self.attackCooldown = 0;
self.type = type;
if (self.type === 'fast') {
self.speed *= 1.8;
self.health *= 0.6;
} else if (self.type === 'rotating') {
self.speed *= 1.1;
self.health *= 0.8;
self.orbitRadius = 100;
self.orbitAngle = Math.random() * Math.PI * 2;
self.orbitSpeed = 0.1;
}
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 150);
var damageText = new Text2('-' + damage, {
size: 40,
fill: 0xff0000
});
damageText.x = self.x;
damageText.y = self.y - 30;
game.addChild(damageText);
tween(damageText, {
y: damageText.y - 60,
alpha: 0
}, {
duration: 800,
onComplete: function onComplete() {
damageText.destroy();
}
});
if (self.health <= 0) {
score += self.type === 'fast' ? 20 : self.type === 'rotating' ? 25 : 15;
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
game.addChild(explosion);
explosions.push(explosion);
LK.getSound('explosion').play();
return true;
}
return false;
};
self.update = function () {
var dx = 1024 - self.x;
var dy = 1366 - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
if (self.type === 'rotating') {
self.orbitAngle += self.orbitSpeed;
var orbitX = dx / distance * self.speed;
var orbitY = dy / distance * self.speed;
self.x += orbitX + Math.cos(self.orbitAngle) * self.orbitRadius * 0.1;
self.y += orbitY + Math.sin(self.orbitAngle) * self.orbitRadius * 0.1;
} else {
var wobble = self.type === 'fast' ? Math.sin(LK.ticks * 0.25) * 25 : 0;
self.x += dx / distance * self.speed + Math.sin(LK.ticks * 0.12) * 0.6;
self.y += dy / distance * self.speed + wobble * 0.12;
}
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
pigeonGraphics.rotation = Math.atan2(dy, dx);
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 35;
self.radius = 100;
explosionGraphics.scaleX = 0.2;
explosionGraphics.scaleY = 0.2;
self.update = function () {
self.lifeTime--;
var progress = 1 - self.lifeTime / 35;
explosionGraphics.scaleX = 0.2 + progress * 2.8;
explosionGraphics.scaleY = 0.2 + progress * 2.8;
explosionGraphics.alpha = 1 - progress;
explosionGraphics.rotation += 0.15;
return self.lifeTime <= 0;
};
return self;
});
var Grandma = Container.expand(function () {
var self = Container.call(this);
var grandmaGraphics = self.attachAsset('grandma', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 120;
self.maxHealth = 120;
self.bombDamage = 60;
self.shotCooldown = 0;
self.speedBoost = 0;
self.damageBoost = 0;
self.multishot = 0;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 300);
game.x = (Math.random() - 0.5) * 25;
game.y = (Math.random() - 0.5) * 25;
LK.setTimeout(function () {
game.x = 0;
game.y = 0;
}, 120);
if (self.health <= 0) {
LK.showGameOver();
}
};
self.update = function () {
self.x = 1024;
self.y = 1366;
if (self.health < self.maxHealth && LK.ticks % (wave > 10 ? 400 : 500) === 0) {
self.health = Math.min(self.health + (wave > 10 ? 3 : 2), self.maxHealth);
}
if (self.shotCooldown > 0) {
self.shotCooldown--;
}
};
return self;
});
var KetchupBomb = Container.expand(function () {
var self = Container.call(this);
var bombGraphics = self.attachAsset('ketchupBomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.lifeTime = 140;
self.damage = grandma.bombDamage + grandma.damageBoost;
self.trail = [];
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifeTime--;
bombGraphics.rotation += 0.25;
self.trail.push({
x: self.x,
y: self.y,
alpha: 1
});
if (self.trail.length > 6) {
self.trail.shift();
}
if (self.lifeTime <= 0) {
self.destroy();
return true;
}
return false;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var rand = Math.random();
var types = rand < 0.1 ? 'multishot' : rand < 0.4 ? 'speed' : rand < 0.7 ? 'health' : 'damage';
self.type = types;
var assetName = 'powerUp' + self.type.charAt(0).toUpperCase() + self.type.slice(1);
var powerUpGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 800;
self.update = function () {
self.lifeTime--;
self.y += Math.sin(LK.ticks * 0.18) * 1.2;
powerUpGraphics.rotation += 0.001;
powerUpGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.12) * 0.25;
powerUpGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.12) * 0.25;
if (self.lifeTime < 160) {
powerUpGraphics.alpha = Math.sin(LK.ticks * 0.35) * 0.5 + 0.5;
}
return self.lifeTime <= 0;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var background = game.addChild(LK.getAsset('background', {
x: 0,
y: 0
}));
/****
* Game Variables
****/
var grandma;
var cyberPigeons = [];
var ketchupBombs = [];
var explosions = [];
var powerUps = [];
var score = 0;
var wave = 1;
var enemiesKilled = 0;
var enemiesThisWave = 0;
var totalEnemiesThisWave = 0;
var lastClickTime = 0;
var comboCounter = 0;
var comboTimer = 0;
var bossWave = false;
/****
* UI Elements
****/
var scoreText = new Text2('Score: 0', {
size: 50,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
scoreText.x = 50;
scoreText.y = 50;
LK.gui.topLeft.addChild(scoreText);
var healthText = new Text2('Health: 120/120', {
size: 50,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 3
});
healthText.anchor.set(1, 0);
LK.gui.topRight.addChild(healthText);
var waveText = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 3
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var bossHealthBg = LK.getAsset('chargeBarBg', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
x: 0,
y: 100
});
LK.gui.top.addChild(bossHealthBg);
bossHealthBg.visible = false;
var bossHealthBar = LK.getAsset('chargeBar', {
anchorX: 0,
anchorY: 0,
scaleX: 0,
x: -150,
y: 100
});
LK.gui.top.addChild(bossHealthBar);
bossHealthBar.visible = false;
var comboText = new Text2('', {
size: 60,
fill: 0x00FFFF,
stroke: 0x000000,
strokeThickness: 3
});
comboText.anchor.set(0.5, 0);
comboText.x = 1024;
comboText.y = 200;
game.addChild(comboText);
var waveProgressBg = LK.getAsset('chargeBarBg', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
x: 0,
y: 60
});
LK.gui.top.addChild(waveProgressBg);
var waveProgressBar = LK.getAsset('chargeBar', {
anchorX: 0,
anchorY: 0,
scaleX: 0,
x: -150,
y: 60
});
LK.gui.top.addChild(waveProgressBar);
/****
* Game Functions
****/
function createGrandma() {
grandma = game.addChild(new Grandma());
grandma.x = 1024;
grandma.y = 1366;
}
function throwKetchupBomb(targetX, targetY) {
if (grandma.shotCooldown > 0) {
return;
}
LK.getSound('attack').play();
LK.effects.flashObject(grandma, 0xffff00, 150);
var shots = grandma.multishot > 0 ? 3 : 1;
var angles = [0];
if (shots > 1) {
angles = [-15, 0, 15];
}
var enemiesHit = 0;
for (var i = 0; i < shots; i++) {
var bomb = new KetchupBomb();
bomb.x = grandma.x;
bomb.y = grandma.y;
var angle = Math.atan2(targetY - grandma.y, targetX - grandma.x) + angles[i] * Math.PI / 180;
var dx = Math.cos(angle);
var dy = Math.sin(angle);
var speed = 12;
bomb.velocityX = dx * speed;
bomb.velocityY = dy * speed;
bomb.damage = grandma.bombDamage + grandma.damageBoost;
ketchupBombs.push(bomb);
game.addChild(bomb);
enemiesHit += checkImmediateHits(bomb, angle);
}
if (enemiesHit > 0) {
comboCounter += enemiesHit;
comboTimer = 150;
if (comboCounter >= 3) {
score += comboCounter * 6;
}
}
grandma.shotCooldown = 20 - Math.min(grandma.speedBoost * 2, 12);
}
function checkImmediateHits(bomb, angle) {
var enemiesHit = 0;
var range = 200;
for (var j = cyberPigeons.length - 1; j >= 0; j--) {
var pigeon = cyberPigeons[j];
var pdx = pigeon.x - grandma.x;
var pdy = pigeon.y - grandma.y;
var distance = Math.sqrt(pdx * pdx + pdy * pdy);
if (distance < range && Math.abs(Math.atan2(pdy, pdx) - angle) < 0.3) {
if (pigeon.takeDamage(bomb.damage)) {
pigeon.destroy();
cyberPigeons.splice(j, 1);
enemiesKilled++;
enemiesThisWave++;
enemiesHit++;
}
}
}
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
var pdx = powerUp.x - grandma.x;
var pdy = powerUp.y - grandma.y;
var distance = Math.sqrt(pdx * pdx + pdy * pdy);
if (distance < range && Math.abs(Math.atan2(pdy, pdx) - angle) < 0.3) {
collectPowerUp(powerUp);
powerUp.destroy();
powerUps.splice(j, 1);
}
}
return enemiesHit;
}
function spawnEnemies() {
bossWave = wave % 5 === 0;
if (bossWave) {
var boss = new BossPigeon();
boss.x = 1024;
boss.y = -150;
cyberPigeons.push(boss);
game.addChild(boss);
totalEnemiesThisWave = 1;
} else {
var maxEnemies = Math.min(15 + Math.floor(wave / 5), 70);
var enemiesToSpawn = Math.min(4 + wave, maxEnemies);
totalEnemiesThisWave = enemiesToSpawn;
for (var i = 0; i < enemiesToSpawn; i++) {
LK.setTimeout(function () {
var pigeon = new CyberPigeon();
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
pigeon.x = Math.random() * 2048;
pigeon.y = -50;
break;
case 1:
pigeon.x = 2098;
pigeon.y = Math.random() * 2732;
break;
case 2:
pigeon.x = Math.random() * 2048;
pigeon.y = 2782;
break;
case 3:
pigeon.x = -50;
pigeon.y = Math.random() * 2732;
break;
}
cyberPigeons.push(pigeon);
game.addChild(pigeon);
}, i * (wave > 10 ? 300 : 400));
}
}
enemiesThisWave = 0;
}
function spawnPowerUpAt(x, y) {
var powerUp = new PowerUp();
powerUp.x = x;
powerUp.y = y;
powerUps.push(powerUp);
game.addChild(powerUp);
}
function collectPowerUp(powerUp) {
LK.getSound('powerup').play();
LK.effects.flashObject(grandma, 0x00ff00, 400);
var bonusText = new Text2('', {
size: 50,
fill: 0x00ff00
});
bonusText.x = grandma.x;
bonusText.y = grandma.y - 60;
game.addChild(bonusText);
switch (powerUp.type) {
case 'speed':
grandma.speedBoost += 2;
bonusText.setText('FIRE RATE UP!');
break;
case 'health':
grandma.health = Math.min(grandma.health + 30 + 2 * wave, grandma.maxHealth);
bonusText.setText('HEALTH +' + (30 + 2 * wave) + '!');
break;
case 'damage':
grandma.damageBoost += 12;
bonusText.setText('DAMAGE UP!');
break;
case 'multishot':
grandma.multishot = 180;
bonusText.setText('MULTISHOT!');
break;
}
tween(bonusText, {
y: bonusText.y - 100,
alpha: 0
}, {
duration: 1200,
onComplete: function onComplete() {
bonusText.destroy();
}
});
}
/****
* Event Handlers
****/
game.down = function (x, y, obj) {
throwKetchupBomb(x, y);
};
/****
* Game Loop
****/
createGrandma();
LK.playMusic('gameMusic');
spawnEnemies();
game.update = function () {
if (comboTimer > 0) {
comboTimer--;
if (comboCounter >= 3) {
comboText.setText('COMBO x' + comboCounter + '!');
} else {
comboText.setText('');
}
} else {
comboCounter = 0;
comboText.setText('');
}
for (var i = cyberPigeons.length - 1; i >= 0; i--) {
var pigeon = cyberPigeons[i];
pigeon.update();
if (pigeon.intersects(grandma) && pigeon.attackCooldown <= 0) {
var damage = pigeon.isBoss ? 20 : 10;
grandma.takeDamage(damage);
pigeon.attackCooldown = 50;
}
if (pigeon.x < -200 || pigeon.x > 2248 || pigeon.y < -200 || pigeon.y > 2932) {
pigeon.destroy();
cyberPigeons.splice(i, 1);
}
}
for (var i = ketchupBombs.length - 1; i >= 0; i--) {
var bomb = ketchupBombs[i];
var shouldRemove = bomb.update();
if (shouldRemove || bomb.x < -100 || bomb.x > 2248 || bomb.y < -100 || bomb.y > 2832) {
bomb.destroy();
ketchupBombs.splice(i, 1);
} else {
for (var j = cyberPigeons.length - 1; j >= 0; j--) {
var pigeon = cyberPigeons[j];
if (bomb.intersects(pigeon)) {
if (pigeon.takeDamage(bomb.damage)) {
pigeon.destroy();
cyberPigeons.splice(j, 1);
enemiesKilled++;
enemiesThisWave++;
}
bomb.destroy();
ketchupBombs.splice(i, 1);
break;
}
}
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
if (bomb.intersects(powerUp)) {
collectPowerUp(powerUp);
powerUp.destroy();
powerUps.splice(j, 1);
bomb.destroy();
ketchupBombs.splice(i, 1);
break;
}
}
}
}
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
var shouldRemove = explosion.update();
if (shouldRemove) {
explosion.destroy();
explosions.splice(i, 1);
}
}
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
var shouldRemove = powerUp.update();
if (shouldRemove) {
powerUp.destroy();
powerUps.splice(i, 1);
}
}
if (grandma.multishot > 0) {
grandma.multishot--;
}
grandma.update();
if (cyberPigeons.length === 0) {
wave++;
spawnEnemies();
if (Math.random() < 1) {
spawnPowerUpAt(Math.random() * 1600 + 200, Math.random() * 2200 + 200);
}
}
scoreText.setText('Score: ' + score);
healthText.setText('Health: ' + grandma.health + '/' + grandma.maxHealth);
waveText.setText('Wave: ' + wave + (bossWave ? ' (BOSS)' : ''));
// Actualizar barra de vida del jefe
if (bossWave && cyberPigeons.length > 0) {
var boss = cyberPigeons.find(function (p) {
return p.isBoss;
});
if (boss) {
bossHealthBg.visible = true;
bossHealthBar.visible = true;
bossHealthBar.scaleX = boss.health / boss.maxHealth * 1.5;
}
} else {
bossHealthBg.visible = false;
bossHealthBar.visible = false;
}
var progress = totalEnemiesThisWave > 0 ? enemiesThisWave / totalEnemiesThisWave : 0;
waveProgressBar.scaleX = progress * 1.5;
LK.setScore(score);
};
Pixel art sprite of a fierce old lady wearing sunglasses and a scarf, riding a rocket-powered shopping cart. She’s holding a glowing cane like a weapon. Side view, colorful retro 2D style. PNG. In-Game asset. 2d. High contrast. No shadows
Pixel art of an evil pigeon with robotic parts, red glowing eyes, and tiny armor. Flying pose, side view, 2D pixel sprite for an arcade game. In-Game asset. 2d. High contrast. No shadows
Pixel art of a red ketchup bottle turned into a bomb, with a fuse and tomato sauce leaking out. Small item, cartoonish and fun, pixel style. In-Game asset. 2d. High contrast. No shadows
pixel art dog. In-Game asset. 2d. High contrast. No shadows
explosion. In-Game asset. 2d. High contrast. No shadows
background pixel art cielo azul. In-Game asset. 2d. High contrast. No shadows
Pixel art of a smaller robotic pigeon with jet wings and a streamlined shape. Fast enemy type in a 2D arcade game. Side view, green metal feathers. In-Game asset. 2d. High contrast. No shadows
Pixel art of a purple power-up icon with a spiked fist symbol or explosion inside. Represents bonus attack damage in a retro game. In-Game asset. 2d. High contrast. No shadows
Pixel art of a dark purple robotic pigeon spinning in midair, wings blurred in motion. Enemy type in a 2D arcade game, side view. In-Game asset. 2d. High contrast. No shadows
Pixel art of a green power-up icon with a heart or medical cross symbol inside. Represents healing in a 2D pixel arcade game. Glowing green, square icon. In-Game asset. 2d. High contrast. No shadows
Pixel art of a red power-up icon with a bold lightning bolt symbol inside. Represents a temporary speed boost in a retro-style arcade game. Glowing red, square icon. In-Game asset. 2d. High contrast. No shadows
Pixel art of a violet power-up icon with three small arrows or projectiles spreading outward. Represents multishot power in a retro-style game. Glowing, pixelated square icon. In-Game asset. 2d. High contrast. No shadows