User prompt
Watermelon should fire less bullets, and banana and watermelon should deal 5 damage per bullet
User prompt
Banana should have a gun
User prompt
Game must have horizontal screen
Code edit (1 edits merged)
Please save this source code
User prompt
Banana vs. Watermelon Boss Battle
Initial prompt
Make me a Boss Fighting game like Cuphead. The main character is a banana, and the boss is big watermelon
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Banana = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('banana', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
var gun = self.attachAsset('gun', {
anchorX: 0,
anchorY: 0.5
});
gun.x = 30;
gun.y = 0;
self.maxHealth = 100;
self.health = self.maxHealth;
self.shootCooldown = 0;
self.invulnerable = false;
self.invulnerableTimer = 0;
self.potionEffectActive = false;
self.potionEffectTimer = 0;
self.potionEffectDuration = 300; // 5 seconds at 60fps
self.takeDamage = function (damage) {
if (self.invulnerable) return;
self.health -= damage;
self.invulnerable = true;
self.invulnerableTimer = 60; // 1 second at 60fps
// Flash effect
LK.effects.flashObject(self, 0xFF0000, 500);
LK.getSound('hit').play();
if (self.health <= 0) {
LK.showGameOver();
}
};
self.activatePotionEffect = function () {
self.potionEffectActive = true;
self.potionEffectTimer = self.potionEffectDuration;
// Visual effect - purple tint
self.tint = 0xFF88FF;
// Flash effect
LK.effects.flashObject(self, 0x9932cc, 800);
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.invulnerable && self.invulnerableTimer > 0) {
self.invulnerableTimer--;
if (self.invulnerableTimer <= 0) {
self.invulnerable = false;
}
}
// Handle potion effect
if (self.potionEffectActive) {
self.potionEffectTimer--;
if (self.potionEffectTimer <= 0) {
self.potionEffectActive = false;
// Remove visual effect
self.tint = 0xFFFFFF;
}
}
};
return self;
});
var BananaProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bananaProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 5;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
var cloudTypes = ['cloud1', 'cloud2', 'cloud3'];
var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)];
var graphics = self.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.5 + Math.random() * 1.5; // Random speed between 0.5 and 2
self.update = function () {
self.x -= self.speed;
// Reset cloud position when it goes off screen
if (self.x < -200) {
self.x = 2248; // Reset to right side of screen
self.y = Math.random() * 1000 + 200; // Random height
}
};
return self;
});
var HomingProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('homingProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 3;
self.enhanced = false;
self.target = null;
self.update = function () {
if (self.target && self.target.health > 0) {
// Calculate angle to target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var angle = Math.atan2(dy, dx);
// Move towards target
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
// Move forward if no target
self.x += self.speed;
}
};
return self;
});
var LaserProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('laserProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = 1;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
var WatermelonBoss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('watermelon', {
anchorX: 0.5,
anchorY: 0.5
});
self.graphics = graphics; // Store reference to graphics for phase switching
self.maxHealth = 500;
self.health = self.maxHealth;
self.attackTimer = 0;
self.attackCooldown = 180; // 3 seconds
self.phase = 1;
self.moveDirection = 1;
self.moveSpeed = 1;
self.potionsDroppedThisPhase = 0;
self.maxPotionsPerPhase = 1;
self.minPotionsPerPhase = 1;
self.mustDropPotion = false;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('bosshit').play();
// Change phase based on health
if (self.health <= self.maxHealth * 0.66 && self.phase === 1) {
self.phase = 2;
self.attackCooldown = 135; // Faster attacks
self.moveSpeed = 2; // Faster movement in phase 2
// Reset potion counters for new phase
self.potionsDroppedThisPhase = 0;
self.mustDropPotion = false;
} else if (self.health <= self.maxHealth * 0.33 && self.phase === 2) {
self.phase = 3;
self.attackCooldown = 90; // Even faster attacks
// Reset potion counters for new phase
self.potionsDroppedThisPhase = 0;
self.mustDropPotion = false;
}
if (self.health <= 0) {
if (self.phase < 4) {
// If not in final phase yet
// Transition to second phase
self.phase = 4; // Mark as second phase
self.maxHealth = 500;
self.health = 500;
self.attackCooldown = 60; // Much faster attacks
// Reset potion counters for new phase
self.potionsDroppedThisPhase = 0;
self.mustDropPotion = false;
// Switch to phase 2 asset
self.removeChild(self.graphics);
self.graphics = self.attachAsset('watermelonPhase2', {
anchorX: 0.5,
anchorY: 0.5
});
// Flash effect for phase transition
LK.effects.flashObject(self, 0x00FF00, 1000);
// Add dramatic animation for phase transition
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Keep the bigger size in phase 2, don't scale back down
}
});
// Add rotation animation
tween(self, {
rotation: Math.PI * 2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.rotation = 0;
}
});
} else {
// Explosion animation before showing You Win
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showYouWin();
}
});
}
}
};
self.seedAttack = function () {
var numSeeds;
if (self.phase === 1) {
// Calculate damage percentage (0 to 1, where 1 is most damaged)
var damagePercent = 1 - self.health / self.maxHealth;
// Base seeds + bonus based on damage, with a limit of 8 seeds max in phase 1
var bonusSeeds = Math.floor(damagePercent * 5); // Up to 5 bonus seeds
numSeeds = Math.min(3 + bonusSeeds, 8); // Base 3, max 8 total
} else {
numSeeds = self.phase === 2 ? 5 : self.phase === 3 ? 8 : 10; // More seeds in second phase
}
for (var i = 0; i < numSeeds; i++) {
var seed = new WatermelonSeed();
seed.x = self.x + (Math.random() - 0.5) * 100;
seed.y = self.y + 50;
var angle = Math.random() * Math.PI * 2;
var baseSpeed = self.phase === 4 ? 5 : 2; // Faster in second phase
var speed = baseSpeed + Math.random() * (self.phase === 4 ? 5 : 3); // Higher speed range in second phase
seed.speedX = Math.cos(angle) * speed;
seed.speedY = Math.sin(angle) * speed;
// Make seeds bigger in phase 1 and even bigger in second phase
if (self.phase === 4) {
seed.scaleX = 2.0;
seed.scaleY = 2.0;
} else {
seed.scaleX = 1.5;
seed.scaleY = 1.5;
}
watermelonSeeds.push(seed);
game.addChild(seed);
}
};
self.sliceAttack = function () {
var numSlices = 2; // Only 2 slices in phase 1
for (var i = 0; i < numSlices; i++) {
var slice = new WatermelonSlice();
// Spawn from outside screen edges
var side = Math.random() < 0.5 ? 'left' : 'right';
if (side === 'left') {
slice.x = -100; // Start from left edge
slice.y = Math.random() * 1500 + 400;
} else {
slice.x = 2148; // Start from right edge
slice.y = Math.random() * 1500 + 400;
}
// Calculate angle towards banana
var dx = banana.x - slice.x;
var dy = banana.y - slice.y;
var angle = Math.atan2(dy, dx);
var speed = 3 + Math.random() * 2; // Slower than seeds but still threatening
slice.speedX = Math.cos(angle) * speed;
slice.speedY = Math.sin(angle) * speed;
// Make slices bigger than seeds, even bigger in phase 4
if (self.phase === 4) {
slice.scaleX = 3.0;
slice.scaleY = 3.0;
} else {
slice.scaleX = 2.0;
slice.scaleY = 2.0;
}
watermelonSlices.push(slice);
game.addChild(slice);
}
};
self.potionAttack = function () {
var numPotions = self.phase === 4 ? 3 : 2; // More potions in second phase
for (var i = 0; i < numPotions; i++) {
var potion = new WatermelonPotion();
potion.x = self.x + (Math.random() - 0.5) * 80;
potion.y = self.y + 50;
// Calculate angle towards banana
var dx = banana.x - potion.x;
var dy = banana.y - potion.y;
var angle = Math.atan2(dy, dx);
var baseSpeed = self.phase === 4 ? 4 : 2;
var speed = baseSpeed + Math.random() * 2;
potion.speedX = Math.cos(angle) * speed;
potion.speedY = Math.sin(angle) * speed;
// Make potions bigger in second phase
if (self.phase === 4) {
potion.scaleX = 3.5;
potion.scaleY = 3.5;
} else {
potion.scaleX = 3.0;
potion.scaleY = 3.0;
}
// Add glowing effect to potions
tween(potion, {
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(potion, {
alpha: 1.0
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
watermelonPotions.push(potion);
game.addChild(potion);
}
};
self.update = function () {
// Movement - both vertical and horizontal
self.y += self.moveDirection * self.moveSpeed;
self.x += self.moveDirection * self.moveSpeed * 0.5; // Horizontal movement at half speed
if (self.y <= 300 || self.y >= 2400) {
self.moveDirection *= -1;
}
// No horizontal boundary restrictions - watermelon can move freely
// Attack logic
self.attackTimer++;
if (self.attackTimer >= self.attackCooldown) {
// Check if we need to force a potion drop
var healthPercent = self.health / self.maxHealth;
var shouldDropPotion = false;
// Force potion if we haven't dropped one yet and health is getting low
if (self.potionsDroppedThisPhase < self.minPotionsPerPhase && healthPercent < 0.3) {
self.mustDropPotion = true;
}
// Decide whether to drop potion (only if we haven't dropped one yet)
if (self.potionsDroppedThisPhase < self.maxPotionsPerPhase && (self.mustDropPotion || Math.random() < 0.05)) {
shouldDropPotion = true;
}
if (shouldDropPotion) {
self.potionAttack();
self.potionsDroppedThisPhase++;
self.mustDropPotion = false;
} else if (self.phase === 1 && Math.random() < 0.25) {
// In phase 1, throw larger watermelon slices more frequently instead of seeds
self.sliceAttack();
} else if (self.phase === 2 && Math.random() < 0.25) {
// In phase 2, also throw watermelon slices frequently
self.sliceAttack();
} else if (self.phase === 4 && Math.random() < 0.1) {
// In phase 4, throw watermelon slices very frequently
self.sliceAttack();
} else {
self.seedAttack();
}
self.attackTimer = 0;
}
};
return self;
});
var WatermelonPotion = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('potion', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WatermelonSeed = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('watermelonSeed', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 20;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WatermelonSlice = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('watermelonSlice', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 35; // Higher damage than seeds
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WideProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('wideProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.damage = 10;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
// Character assets
// Projectile assets
// Sound effects
// Music
var banana;
var watermelonBoss;
var bananaProjectiles = [];
var watermelonSeeds = [];
var watermelonSlices = [];
var watermelonPotions = [];
var clouds = [];
var dragNode = null;
// Bullet selection variables
var gameStarted = false;
var selectedBulletType = 'normal'; // 'normal', 'homing', 'wide', or 'laser'
var selectionScreen = null;
var normalBulletButton = null;
var homingBulletButton = null;
var wideBulletButton = null;
var laserBulletButton = null;
var selectionTitle = null;
var bulletDescription = null;
// Wide bullet specific cooldown
var wideBulletCooldown = 0;
var laserBulletCooldown = 0;
var mousePressed = false;
var laserUsageTimer = 0; // Timer for 1.5 second intervals
var laserUsageDuration = 0; // Timer for 0.3 second usage
var laserCanUse = true; // Flag to control when laser can be used
var laserPressUsed = false; // Flag to track if current press has been used for laser
var holdTimer = 0; // Timer to track how long mouse has been held down
// Create bullet selection screen
function createBulletSelectionScreen() {
selectionScreen = new Container();
game.addChild(selectionScreen);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.8
});
background.tint = 0x000000;
selectionScreen.addChild(background);
// Title
selectionTitle = new Text2('SELECT BULLET TYPE', {
size: 120,
fill: 0xFFFFFF
});
selectionTitle.anchor.set(0.5, 0.5);
selectionTitle.x = 1024;
selectionTitle.y = 600;
selectionScreen.addChild(selectionTitle);
// Normal bullet button
normalBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
normalBulletButton.tint = 0x4444FF;
normalBulletButton.x = 1024;
normalBulletButton.y = 1000;
selectionScreen.addChild(normalBulletButton);
var normalText = new Text2('NORMAL BULLET', {
size: 80,
fill: 0xFFFFFF
});
normalText.anchor.set(0.5, 0.5);
normalText.x = 1024;
normalText.y = 970;
selectionScreen.addChild(normalText);
var normalDesc = new Text2('5 Damage, Fast Speed', {
size: 50,
fill: 0xCCCCCC
});
normalDesc.anchor.set(0.5, 0.5);
normalDesc.x = 1024;
normalDesc.y = 1030;
selectionScreen.addChild(normalDesc);
// Homing bullet button
homingBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
homingBulletButton.tint = 0xFF4444;
homingBulletButton.x = 1024;
homingBulletButton.y = 1300;
selectionScreen.addChild(homingBulletButton);
var homingText = new Text2('HOMING BULLET', {
size: 80,
fill: 0xFFFFFF
});
homingText.anchor.set(0.5, 0.5);
homingText.x = 1024;
homingText.y = 1270;
selectionScreen.addChild(homingText);
var homingDesc = new Text2('3 Damage, Seeks Target', {
size: 50,
fill: 0xCCCCCC
});
homingDesc.anchor.set(0.5, 0.5);
homingDesc.x = 1024;
homingDesc.y = 1360;
selectionScreen.addChild(homingDesc);
// Wide bullet button
wideBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
wideBulletButton.tint = 0x44FF44;
wideBulletButton.x = 1024;
wideBulletButton.y = 1600;
selectionScreen.addChild(wideBulletButton);
var wideText = new Text2('WIDE BULLET', {
size: 80,
fill: 0xFFFFFF
});
wideText.anchor.set(0.5, 0.5);
wideText.x = 1024;
wideText.y = 1570;
selectionScreen.addChild(wideText);
var wideDesc = new Text2('10 Damage, Very Slow', {
size: 50,
fill: 0xCCCCCC
});
wideDesc.anchor.set(0.5, 0.5);
wideDesc.x = 1024;
wideDesc.y = 1630;
selectionScreen.addChild(wideDesc);
// Button event handlers
normalBulletButton.down = function (x, y, obj) {
selectedBulletType = 'normal';
startGame();
};
homingBulletButton.down = function (x, y, obj) {
selectedBulletType = 'homing';
startGame();
};
wideBulletButton.down = function (x, y, obj) {
selectedBulletType = 'wide';
startGame();
};
// Laser bullet button
laserBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
laserBulletButton.tint = 0xFF0080;
laserBulletButton.x = 1024;
laserBulletButton.y = 1900;
selectionScreen.addChild(laserBulletButton);
var laserText = new Text2('LASER BULLET', {
size: 80,
fill: 0xFFFFFF
});
laserText.anchor.set(0.5, 0.5);
laserText.x = 1024;
laserText.y = 1870;
selectionScreen.addChild(laserText);
var laserDesc = new Text2('1 damage, hold for attack', {
size: 50,
fill: 0xCCCCCC
});
laserDesc.anchor.set(0.5, 0.5);
laserDesc.x = 1024;
laserDesc.y = 1920;
selectionScreen.addChild(laserDesc);
var laserCooldownDesc = new Text2('wait 1.5 seconds to fire', {
size: 40,
fill: 0xFFFFFF
});
laserCooldownDesc.anchor.set(0.5, 0.5);
laserCooldownDesc.x = 1024;
laserCooldownDesc.y = 1960;
selectionScreen.addChild(laserCooldownDesc);
laserBulletButton.down = function (x, y, obj) {
selectedBulletType = 'laser';
startGame();
};
}
function startGame() {
gameStarted = true;
if (selectionScreen) {
selectionScreen.destroy();
selectionScreen = null;
}
// Create initial clouds
for (var c = 0; c < 8; c++) {
var cloud = new Cloud();
cloud.x = Math.random() * 2048;
cloud.y = Math.random() * 1000 + 200;
clouds.push(cloud);
game.addChild(cloud);
}
// Initialize game objects
banana = game.addChild(new Banana());
banana.x = 200;
banana.y = 1366;
watermelonBoss = game.addChild(new WatermelonBoss());
watermelonBoss.x = 1600;
watermelonBoss.y = 1366;
}
// Show bullet selection screen
createBulletSelectionScreen();
// UI Elements
var healthBar = new Text2('Health: 100', {
size: 80,
fill: 0xFFFFFF
});
healthBar.anchor.set(0.5, 0);
healthBar.y = 0;
LK.gui.top.addChild(healthBar);
var bossHealthBar = new Text2('Boss Health: 500', {
size: 80,
fill: 0xFF0000
});
bossHealthBar.anchor.set(0.5, 0);
bossHealthBar.y = 90;
LK.gui.top.addChild(bossHealthBar);
// Event handlers
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// No movement restrictions - banana can move freely anywhere
}
}
game.move = function (x, y, obj) {
if (!gameStarted) return;
handleMove(x, y, obj);
};
game.down = function (x, y, obj) {
if (!gameStarted) return;
mousePressed = true;
dragNode = banana;
handleMove(x, y, obj);
holdTimer = 0; // Reset hold timer when mouse is pressed
// Laser activation will be handled in update loop after 1 second hold requirement
// Only shoot non-laser bullets on down event
if (selectedBulletType !== 'laser') {
// Shoot projectile
var canShoot = false;
if (selectedBulletType === 'wide') {
canShoot = wideBulletCooldown <= 0;
} else {
canShoot = banana.shootCooldown <= 0;
}
if (canShoot) {
var projectile;
if (selectedBulletType === 'homing') {
projectile = new HomingProjectile();
projectile.target = watermelonBoss;
} else if (selectedBulletType === 'wide') {
projectile = new WideProjectile();
} else {
projectile = new BananaProjectile();
}
projectile.x = banana.x + 70;
projectile.y = banana.y;
// Check if potion effect is active
if (banana.potionEffectActive) {
projectile.enhanced = true;
projectile.damage = projectile.damage * 3; // Enhanced damage
projectile.scaleX = 1.5; // Make projectile bigger
projectile.scaleY = 1.5;
projectile.tint = 0xFF88FF; // Purple tint for enhanced projectiles
}
bananaProjectiles.push(projectile);
game.addChild(projectile);
if (selectedBulletType === 'wide') {
wideBulletCooldown = 60; // 1 second for wide bullets
} else {
banana.shootCooldown = 15; // 0.25 seconds for other bullets
}
LK.getSound('shoot').play();
}
}
};
game.up = function (x, y, obj) {
if (!gameStarted) return;
mousePressed = false;
dragNode = null;
laserPressUsed = false; // Reset laser press flag when mouse is released
holdTimer = 0; // Reset hold timer when mouse is released
};
// Main game loop
game.update = function () {
if (!gameStarted) return;
// Update wide bullet cooldown
if (wideBulletCooldown > 0) {
wideBulletCooldown--;
}
// Update laser bullet cooldown
if (laserBulletCooldown > 0) {
laserBulletCooldown--;
}
// Update laser usage timers
if (laserUsageTimer > 0) {
laserUsageTimer--;
if (laserUsageTimer <= 0) {
laserCanUse = true; // Reset ability to use laser after 1.5 seconds
laserPressUsed = false; // Reset press flag to allow firing again while holding
}
}
if (laserUsageDuration > 0) {
laserUsageDuration--;
if (laserUsageDuration <= 0) {
laserCanUse = false; // Stop laser usage after 0.2 seconds
laserUsageTimer = 90; // Start 1.5 second cooldown (90 ticks at 60fps)
}
}
// Update hold timer when mouse is pressed
if (mousePressed) {
holdTimer++;
// Start laser usage duration when hold timer reaches 1 second (60 ticks) or when laser becomes available again
if (selectedBulletType === 'laser' && holdTimer >= 60 && laserCanUse && !laserPressUsed) {
laserUsageDuration = 12; // 0.2 seconds at 60fps
laserPressUsed = true; // Mark this press as used
}
}
// Handle laser shooting while mouse is pressed and within usage window (requires 1 second hold)
if (selectedBulletType === 'laser' && mousePressed && holdTimer >= 60 && laserBulletCooldown <= 0 && laserCanUse && laserUsageDuration > 0) {
var projectile = new LaserProjectile();
projectile.x = banana.x + 70;
projectile.y = banana.y;
// Check if potion effect is active
if (banana.potionEffectActive) {
projectile.enhanced = true;
projectile.damage = projectile.damage * 3; // Enhanced damage
projectile.scaleX = 1.5; // Make projectile bigger
projectile.scaleY = 1.5;
projectile.tint = 0xFF88FF; // Purple tint for enhanced projectiles
}
bananaProjectiles.push(projectile);
game.addChild(projectile);
laserBulletCooldown = 1; // 50 bullets per second (60 FPS / 1 tick = 60 bullets per second, close to 50)
LK.getSound('shoot').play();
}
// Update UI
healthBar.setText('Health: ' + banana.health);
var phaseText = watermelonBoss.phase === 4 ? ' (Phase 2)' : '';
bossHealthBar.setText('Boss Health: ' + watermelonBoss.health + phaseText);
// Handle banana projectiles
for (var i = bananaProjectiles.length - 1; i >= 0; i--) {
var projectile = bananaProjectiles[i];
// Remove if off screen
if (projectile.x > 2098) {
projectile.destroy();
bananaProjectiles.splice(i, 1);
continue;
}
// Check collision with boss
if (projectile.intersects(watermelonBoss)) {
watermelonBoss.takeDamage(projectile.damage);
projectile.destroy();
bananaProjectiles.splice(i, 1);
continue;
}
}
// Handle watermelon seeds
for (var j = watermelonSeeds.length - 1; j >= 0; j--) {
var seed = watermelonSeeds[j];
// Remove if off screen
if (seed.x < -50 || seed.x > 2098 || seed.y < -50 || seed.y > 2782) {
seed.destroy();
watermelonSeeds.splice(j, 1);
continue;
}
// Check collision with banana
if (seed.intersects(banana)) {
banana.takeDamage(seed.damage);
seed.destroy();
watermelonSeeds.splice(j, 1);
continue;
}
}
// Handle watermelon slices
for (var s = watermelonSlices.length - 1; s >= 0; s--) {
var slice = watermelonSlices[s];
// Remove if off screen
if (slice.x < -100 || slice.x > 2148 || slice.y < -100 || slice.y > 2832) {
slice.destroy();
watermelonSlices.splice(s, 1);
continue;
}
// Check collision with banana
if (slice.intersects(banana)) {
banana.takeDamage(slice.damage);
slice.destroy();
watermelonSlices.splice(s, 1);
continue;
}
}
// Handle watermelon potions
for (var p = watermelonPotions.length - 1; p >= 0; p--) {
var potion = watermelonPotions[p];
// Remove if off screen
if (potion.x < -50 || potion.x > 2098 || potion.y < -50 || potion.y > 2782) {
potion.destroy();
watermelonPotions.splice(p, 1);
continue;
}
// Check collision with banana
if (potion.intersects(banana)) {
banana.activatePotionEffect();
potion.destroy();
watermelonPotions.splice(p, 1);
continue;
}
}
// Spawn new clouds occasionally
if (LK.ticks % 600 === 0) {
// Every 10 seconds
var newCloud = new Cloud();
newCloud.x = 2248;
newCloud.y = Math.random() * 1000 + 200;
clouds.push(newCloud);
game.addChild(newCloud);
}
// Clean up clouds that are too far off screen
for (var k = clouds.length - 1; k >= 0; k--) {
var cloud = clouds[k];
if (cloud.x < -300) {
cloud.destroy();
clouds.splice(k, 1);
}
}
};
// Start battle music
LK.playMusic('battle'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Banana = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('banana', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
var gun = self.attachAsset('gun', {
anchorX: 0,
anchorY: 0.5
});
gun.x = 30;
gun.y = 0;
self.maxHealth = 100;
self.health = self.maxHealth;
self.shootCooldown = 0;
self.invulnerable = false;
self.invulnerableTimer = 0;
self.potionEffectActive = false;
self.potionEffectTimer = 0;
self.potionEffectDuration = 300; // 5 seconds at 60fps
self.takeDamage = function (damage) {
if (self.invulnerable) return;
self.health -= damage;
self.invulnerable = true;
self.invulnerableTimer = 60; // 1 second at 60fps
// Flash effect
LK.effects.flashObject(self, 0xFF0000, 500);
LK.getSound('hit').play();
if (self.health <= 0) {
LK.showGameOver();
}
};
self.activatePotionEffect = function () {
self.potionEffectActive = true;
self.potionEffectTimer = self.potionEffectDuration;
// Visual effect - purple tint
self.tint = 0xFF88FF;
// Flash effect
LK.effects.flashObject(self, 0x9932cc, 800);
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.invulnerable && self.invulnerableTimer > 0) {
self.invulnerableTimer--;
if (self.invulnerableTimer <= 0) {
self.invulnerable = false;
}
}
// Handle potion effect
if (self.potionEffectActive) {
self.potionEffectTimer--;
if (self.potionEffectTimer <= 0) {
self.potionEffectActive = false;
// Remove visual effect
self.tint = 0xFFFFFF;
}
}
};
return self;
});
var BananaProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bananaProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 5;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
var cloudTypes = ['cloud1', 'cloud2', 'cloud3'];
var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)];
var graphics = self.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.5 + Math.random() * 1.5; // Random speed between 0.5 and 2
self.update = function () {
self.x -= self.speed;
// Reset cloud position when it goes off screen
if (self.x < -200) {
self.x = 2248; // Reset to right side of screen
self.y = Math.random() * 1000 + 200; // Random height
}
};
return self;
});
var HomingProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('homingProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 3;
self.enhanced = false;
self.target = null;
self.update = function () {
if (self.target && self.target.health > 0) {
// Calculate angle to target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var angle = Math.atan2(dy, dx);
// Move towards target
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
} else {
// Move forward if no target
self.x += self.speed;
}
};
return self;
});
var LaserProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('laserProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = 1;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
var WatermelonBoss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('watermelon', {
anchorX: 0.5,
anchorY: 0.5
});
self.graphics = graphics; // Store reference to graphics for phase switching
self.maxHealth = 500;
self.health = self.maxHealth;
self.attackTimer = 0;
self.attackCooldown = 180; // 3 seconds
self.phase = 1;
self.moveDirection = 1;
self.moveSpeed = 1;
self.potionsDroppedThisPhase = 0;
self.maxPotionsPerPhase = 1;
self.minPotionsPerPhase = 1;
self.mustDropPotion = false;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('bosshit').play();
// Change phase based on health
if (self.health <= self.maxHealth * 0.66 && self.phase === 1) {
self.phase = 2;
self.attackCooldown = 135; // Faster attacks
self.moveSpeed = 2; // Faster movement in phase 2
// Reset potion counters for new phase
self.potionsDroppedThisPhase = 0;
self.mustDropPotion = false;
} else if (self.health <= self.maxHealth * 0.33 && self.phase === 2) {
self.phase = 3;
self.attackCooldown = 90; // Even faster attacks
// Reset potion counters for new phase
self.potionsDroppedThisPhase = 0;
self.mustDropPotion = false;
}
if (self.health <= 0) {
if (self.phase < 4) {
// If not in final phase yet
// Transition to second phase
self.phase = 4; // Mark as second phase
self.maxHealth = 500;
self.health = 500;
self.attackCooldown = 60; // Much faster attacks
// Reset potion counters for new phase
self.potionsDroppedThisPhase = 0;
self.mustDropPotion = false;
// Switch to phase 2 asset
self.removeChild(self.graphics);
self.graphics = self.attachAsset('watermelonPhase2', {
anchorX: 0.5,
anchorY: 0.5
});
// Flash effect for phase transition
LK.effects.flashObject(self, 0x00FF00, 1000);
// Add dramatic animation for phase transition
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Keep the bigger size in phase 2, don't scale back down
}
});
// Add rotation animation
tween(self, {
rotation: Math.PI * 2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.rotation = 0;
}
});
} else {
// Explosion animation before showing You Win
tween(self, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.showYouWin();
}
});
}
}
};
self.seedAttack = function () {
var numSeeds;
if (self.phase === 1) {
// Calculate damage percentage (0 to 1, where 1 is most damaged)
var damagePercent = 1 - self.health / self.maxHealth;
// Base seeds + bonus based on damage, with a limit of 8 seeds max in phase 1
var bonusSeeds = Math.floor(damagePercent * 5); // Up to 5 bonus seeds
numSeeds = Math.min(3 + bonusSeeds, 8); // Base 3, max 8 total
} else {
numSeeds = self.phase === 2 ? 5 : self.phase === 3 ? 8 : 10; // More seeds in second phase
}
for (var i = 0; i < numSeeds; i++) {
var seed = new WatermelonSeed();
seed.x = self.x + (Math.random() - 0.5) * 100;
seed.y = self.y + 50;
var angle = Math.random() * Math.PI * 2;
var baseSpeed = self.phase === 4 ? 5 : 2; // Faster in second phase
var speed = baseSpeed + Math.random() * (self.phase === 4 ? 5 : 3); // Higher speed range in second phase
seed.speedX = Math.cos(angle) * speed;
seed.speedY = Math.sin(angle) * speed;
// Make seeds bigger in phase 1 and even bigger in second phase
if (self.phase === 4) {
seed.scaleX = 2.0;
seed.scaleY = 2.0;
} else {
seed.scaleX = 1.5;
seed.scaleY = 1.5;
}
watermelonSeeds.push(seed);
game.addChild(seed);
}
};
self.sliceAttack = function () {
var numSlices = 2; // Only 2 slices in phase 1
for (var i = 0; i < numSlices; i++) {
var slice = new WatermelonSlice();
// Spawn from outside screen edges
var side = Math.random() < 0.5 ? 'left' : 'right';
if (side === 'left') {
slice.x = -100; // Start from left edge
slice.y = Math.random() * 1500 + 400;
} else {
slice.x = 2148; // Start from right edge
slice.y = Math.random() * 1500 + 400;
}
// Calculate angle towards banana
var dx = banana.x - slice.x;
var dy = banana.y - slice.y;
var angle = Math.atan2(dy, dx);
var speed = 3 + Math.random() * 2; // Slower than seeds but still threatening
slice.speedX = Math.cos(angle) * speed;
slice.speedY = Math.sin(angle) * speed;
// Make slices bigger than seeds, even bigger in phase 4
if (self.phase === 4) {
slice.scaleX = 3.0;
slice.scaleY = 3.0;
} else {
slice.scaleX = 2.0;
slice.scaleY = 2.0;
}
watermelonSlices.push(slice);
game.addChild(slice);
}
};
self.potionAttack = function () {
var numPotions = self.phase === 4 ? 3 : 2; // More potions in second phase
for (var i = 0; i < numPotions; i++) {
var potion = new WatermelonPotion();
potion.x = self.x + (Math.random() - 0.5) * 80;
potion.y = self.y + 50;
// Calculate angle towards banana
var dx = banana.x - potion.x;
var dy = banana.y - potion.y;
var angle = Math.atan2(dy, dx);
var baseSpeed = self.phase === 4 ? 4 : 2;
var speed = baseSpeed + Math.random() * 2;
potion.speedX = Math.cos(angle) * speed;
potion.speedY = Math.sin(angle) * speed;
// Make potions bigger in second phase
if (self.phase === 4) {
potion.scaleX = 3.5;
potion.scaleY = 3.5;
} else {
potion.scaleX = 3.0;
potion.scaleY = 3.0;
}
// Add glowing effect to potions
tween(potion, {
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(potion, {
alpha: 1.0
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
watermelonPotions.push(potion);
game.addChild(potion);
}
};
self.update = function () {
// Movement - both vertical and horizontal
self.y += self.moveDirection * self.moveSpeed;
self.x += self.moveDirection * self.moveSpeed * 0.5; // Horizontal movement at half speed
if (self.y <= 300 || self.y >= 2400) {
self.moveDirection *= -1;
}
// No horizontal boundary restrictions - watermelon can move freely
// Attack logic
self.attackTimer++;
if (self.attackTimer >= self.attackCooldown) {
// Check if we need to force a potion drop
var healthPercent = self.health / self.maxHealth;
var shouldDropPotion = false;
// Force potion if we haven't dropped one yet and health is getting low
if (self.potionsDroppedThisPhase < self.minPotionsPerPhase && healthPercent < 0.3) {
self.mustDropPotion = true;
}
// Decide whether to drop potion (only if we haven't dropped one yet)
if (self.potionsDroppedThisPhase < self.maxPotionsPerPhase && (self.mustDropPotion || Math.random() < 0.05)) {
shouldDropPotion = true;
}
if (shouldDropPotion) {
self.potionAttack();
self.potionsDroppedThisPhase++;
self.mustDropPotion = false;
} else if (self.phase === 1 && Math.random() < 0.25) {
// In phase 1, throw larger watermelon slices more frequently instead of seeds
self.sliceAttack();
} else if (self.phase === 2 && Math.random() < 0.25) {
// In phase 2, also throw watermelon slices frequently
self.sliceAttack();
} else if (self.phase === 4 && Math.random() < 0.1) {
// In phase 4, throw watermelon slices very frequently
self.sliceAttack();
} else {
self.seedAttack();
}
self.attackTimer = 0;
}
};
return self;
});
var WatermelonPotion = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('potion', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WatermelonSeed = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('watermelonSeed', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 20;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WatermelonSlice = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('watermelonSlice', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 35; // Higher damage than seeds
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var WideProjectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('wideProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.damage = 10;
self.enhanced = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
// Character assets
// Projectile assets
// Sound effects
// Music
var banana;
var watermelonBoss;
var bananaProjectiles = [];
var watermelonSeeds = [];
var watermelonSlices = [];
var watermelonPotions = [];
var clouds = [];
var dragNode = null;
// Bullet selection variables
var gameStarted = false;
var selectedBulletType = 'normal'; // 'normal', 'homing', 'wide', or 'laser'
var selectionScreen = null;
var normalBulletButton = null;
var homingBulletButton = null;
var wideBulletButton = null;
var laserBulletButton = null;
var selectionTitle = null;
var bulletDescription = null;
// Wide bullet specific cooldown
var wideBulletCooldown = 0;
var laserBulletCooldown = 0;
var mousePressed = false;
var laserUsageTimer = 0; // Timer for 1.5 second intervals
var laserUsageDuration = 0; // Timer for 0.3 second usage
var laserCanUse = true; // Flag to control when laser can be used
var laserPressUsed = false; // Flag to track if current press has been used for laser
var holdTimer = 0; // Timer to track how long mouse has been held down
// Create bullet selection screen
function createBulletSelectionScreen() {
selectionScreen = new Container();
game.addChild(selectionScreen);
// Semi-transparent background
var background = LK.getAsset('shape', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
alpha: 0.8
});
background.tint = 0x000000;
selectionScreen.addChild(background);
// Title
selectionTitle = new Text2('SELECT BULLET TYPE', {
size: 120,
fill: 0xFFFFFF
});
selectionTitle.anchor.set(0.5, 0.5);
selectionTitle.x = 1024;
selectionTitle.y = 600;
selectionScreen.addChild(selectionTitle);
// Normal bullet button
normalBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
normalBulletButton.tint = 0x4444FF;
normalBulletButton.x = 1024;
normalBulletButton.y = 1000;
selectionScreen.addChild(normalBulletButton);
var normalText = new Text2('NORMAL BULLET', {
size: 80,
fill: 0xFFFFFF
});
normalText.anchor.set(0.5, 0.5);
normalText.x = 1024;
normalText.y = 970;
selectionScreen.addChild(normalText);
var normalDesc = new Text2('5 Damage, Fast Speed', {
size: 50,
fill: 0xCCCCCC
});
normalDesc.anchor.set(0.5, 0.5);
normalDesc.x = 1024;
normalDesc.y = 1030;
selectionScreen.addChild(normalDesc);
// Homing bullet button
homingBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
homingBulletButton.tint = 0xFF4444;
homingBulletButton.x = 1024;
homingBulletButton.y = 1300;
selectionScreen.addChild(homingBulletButton);
var homingText = new Text2('HOMING BULLET', {
size: 80,
fill: 0xFFFFFF
});
homingText.anchor.set(0.5, 0.5);
homingText.x = 1024;
homingText.y = 1270;
selectionScreen.addChild(homingText);
var homingDesc = new Text2('3 Damage, Seeks Target', {
size: 50,
fill: 0xCCCCCC
});
homingDesc.anchor.set(0.5, 0.5);
homingDesc.x = 1024;
homingDesc.y = 1360;
selectionScreen.addChild(homingDesc);
// Wide bullet button
wideBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
wideBulletButton.tint = 0x44FF44;
wideBulletButton.x = 1024;
wideBulletButton.y = 1600;
selectionScreen.addChild(wideBulletButton);
var wideText = new Text2('WIDE BULLET', {
size: 80,
fill: 0xFFFFFF
});
wideText.anchor.set(0.5, 0.5);
wideText.x = 1024;
wideText.y = 1570;
selectionScreen.addChild(wideText);
var wideDesc = new Text2('10 Damage, Very Slow', {
size: 50,
fill: 0xCCCCCC
});
wideDesc.anchor.set(0.5, 0.5);
wideDesc.x = 1024;
wideDesc.y = 1630;
selectionScreen.addChild(wideDesc);
// Button event handlers
normalBulletButton.down = function (x, y, obj) {
selectedBulletType = 'normal';
startGame();
};
homingBulletButton.down = function (x, y, obj) {
selectedBulletType = 'homing';
startGame();
};
wideBulletButton.down = function (x, y, obj) {
selectedBulletType = 'wide';
startGame();
};
// Laser bullet button
laserBulletButton = LK.getAsset('shape', {
width: 600,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
laserBulletButton.tint = 0xFF0080;
laserBulletButton.x = 1024;
laserBulletButton.y = 1900;
selectionScreen.addChild(laserBulletButton);
var laserText = new Text2('LASER BULLET', {
size: 80,
fill: 0xFFFFFF
});
laserText.anchor.set(0.5, 0.5);
laserText.x = 1024;
laserText.y = 1870;
selectionScreen.addChild(laserText);
var laserDesc = new Text2('1 damage, hold for attack', {
size: 50,
fill: 0xCCCCCC
});
laserDesc.anchor.set(0.5, 0.5);
laserDesc.x = 1024;
laserDesc.y = 1920;
selectionScreen.addChild(laserDesc);
var laserCooldownDesc = new Text2('wait 1.5 seconds to fire', {
size: 40,
fill: 0xFFFFFF
});
laserCooldownDesc.anchor.set(0.5, 0.5);
laserCooldownDesc.x = 1024;
laserCooldownDesc.y = 1960;
selectionScreen.addChild(laserCooldownDesc);
laserBulletButton.down = function (x, y, obj) {
selectedBulletType = 'laser';
startGame();
};
}
function startGame() {
gameStarted = true;
if (selectionScreen) {
selectionScreen.destroy();
selectionScreen = null;
}
// Create initial clouds
for (var c = 0; c < 8; c++) {
var cloud = new Cloud();
cloud.x = Math.random() * 2048;
cloud.y = Math.random() * 1000 + 200;
clouds.push(cloud);
game.addChild(cloud);
}
// Initialize game objects
banana = game.addChild(new Banana());
banana.x = 200;
banana.y = 1366;
watermelonBoss = game.addChild(new WatermelonBoss());
watermelonBoss.x = 1600;
watermelonBoss.y = 1366;
}
// Show bullet selection screen
createBulletSelectionScreen();
// UI Elements
var healthBar = new Text2('Health: 100', {
size: 80,
fill: 0xFFFFFF
});
healthBar.anchor.set(0.5, 0);
healthBar.y = 0;
LK.gui.top.addChild(healthBar);
var bossHealthBar = new Text2('Boss Health: 500', {
size: 80,
fill: 0xFF0000
});
bossHealthBar.anchor.set(0.5, 0);
bossHealthBar.y = 90;
LK.gui.top.addChild(bossHealthBar);
// Event handlers
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// No movement restrictions - banana can move freely anywhere
}
}
game.move = function (x, y, obj) {
if (!gameStarted) return;
handleMove(x, y, obj);
};
game.down = function (x, y, obj) {
if (!gameStarted) return;
mousePressed = true;
dragNode = banana;
handleMove(x, y, obj);
holdTimer = 0; // Reset hold timer when mouse is pressed
// Laser activation will be handled in update loop after 1 second hold requirement
// Only shoot non-laser bullets on down event
if (selectedBulletType !== 'laser') {
// Shoot projectile
var canShoot = false;
if (selectedBulletType === 'wide') {
canShoot = wideBulletCooldown <= 0;
} else {
canShoot = banana.shootCooldown <= 0;
}
if (canShoot) {
var projectile;
if (selectedBulletType === 'homing') {
projectile = new HomingProjectile();
projectile.target = watermelonBoss;
} else if (selectedBulletType === 'wide') {
projectile = new WideProjectile();
} else {
projectile = new BananaProjectile();
}
projectile.x = banana.x + 70;
projectile.y = banana.y;
// Check if potion effect is active
if (banana.potionEffectActive) {
projectile.enhanced = true;
projectile.damage = projectile.damage * 3; // Enhanced damage
projectile.scaleX = 1.5; // Make projectile bigger
projectile.scaleY = 1.5;
projectile.tint = 0xFF88FF; // Purple tint for enhanced projectiles
}
bananaProjectiles.push(projectile);
game.addChild(projectile);
if (selectedBulletType === 'wide') {
wideBulletCooldown = 60; // 1 second for wide bullets
} else {
banana.shootCooldown = 15; // 0.25 seconds for other bullets
}
LK.getSound('shoot').play();
}
}
};
game.up = function (x, y, obj) {
if (!gameStarted) return;
mousePressed = false;
dragNode = null;
laserPressUsed = false; // Reset laser press flag when mouse is released
holdTimer = 0; // Reset hold timer when mouse is released
};
// Main game loop
game.update = function () {
if (!gameStarted) return;
// Update wide bullet cooldown
if (wideBulletCooldown > 0) {
wideBulletCooldown--;
}
// Update laser bullet cooldown
if (laserBulletCooldown > 0) {
laserBulletCooldown--;
}
// Update laser usage timers
if (laserUsageTimer > 0) {
laserUsageTimer--;
if (laserUsageTimer <= 0) {
laserCanUse = true; // Reset ability to use laser after 1.5 seconds
laserPressUsed = false; // Reset press flag to allow firing again while holding
}
}
if (laserUsageDuration > 0) {
laserUsageDuration--;
if (laserUsageDuration <= 0) {
laserCanUse = false; // Stop laser usage after 0.2 seconds
laserUsageTimer = 90; // Start 1.5 second cooldown (90 ticks at 60fps)
}
}
// Update hold timer when mouse is pressed
if (mousePressed) {
holdTimer++;
// Start laser usage duration when hold timer reaches 1 second (60 ticks) or when laser becomes available again
if (selectedBulletType === 'laser' && holdTimer >= 60 && laserCanUse && !laserPressUsed) {
laserUsageDuration = 12; // 0.2 seconds at 60fps
laserPressUsed = true; // Mark this press as used
}
}
// Handle laser shooting while mouse is pressed and within usage window (requires 1 second hold)
if (selectedBulletType === 'laser' && mousePressed && holdTimer >= 60 && laserBulletCooldown <= 0 && laserCanUse && laserUsageDuration > 0) {
var projectile = new LaserProjectile();
projectile.x = banana.x + 70;
projectile.y = banana.y;
// Check if potion effect is active
if (banana.potionEffectActive) {
projectile.enhanced = true;
projectile.damage = projectile.damage * 3; // Enhanced damage
projectile.scaleX = 1.5; // Make projectile bigger
projectile.scaleY = 1.5;
projectile.tint = 0xFF88FF; // Purple tint for enhanced projectiles
}
bananaProjectiles.push(projectile);
game.addChild(projectile);
laserBulletCooldown = 1; // 50 bullets per second (60 FPS / 1 tick = 60 bullets per second, close to 50)
LK.getSound('shoot').play();
}
// Update UI
healthBar.setText('Health: ' + banana.health);
var phaseText = watermelonBoss.phase === 4 ? ' (Phase 2)' : '';
bossHealthBar.setText('Boss Health: ' + watermelonBoss.health + phaseText);
// Handle banana projectiles
for (var i = bananaProjectiles.length - 1; i >= 0; i--) {
var projectile = bananaProjectiles[i];
// Remove if off screen
if (projectile.x > 2098) {
projectile.destroy();
bananaProjectiles.splice(i, 1);
continue;
}
// Check collision with boss
if (projectile.intersects(watermelonBoss)) {
watermelonBoss.takeDamage(projectile.damage);
projectile.destroy();
bananaProjectiles.splice(i, 1);
continue;
}
}
// Handle watermelon seeds
for (var j = watermelonSeeds.length - 1; j >= 0; j--) {
var seed = watermelonSeeds[j];
// Remove if off screen
if (seed.x < -50 || seed.x > 2098 || seed.y < -50 || seed.y > 2782) {
seed.destroy();
watermelonSeeds.splice(j, 1);
continue;
}
// Check collision with banana
if (seed.intersects(banana)) {
banana.takeDamage(seed.damage);
seed.destroy();
watermelonSeeds.splice(j, 1);
continue;
}
}
// Handle watermelon slices
for (var s = watermelonSlices.length - 1; s >= 0; s--) {
var slice = watermelonSlices[s];
// Remove if off screen
if (slice.x < -100 || slice.x > 2148 || slice.y < -100 || slice.y > 2832) {
slice.destroy();
watermelonSlices.splice(s, 1);
continue;
}
// Check collision with banana
if (slice.intersects(banana)) {
banana.takeDamage(slice.damage);
slice.destroy();
watermelonSlices.splice(s, 1);
continue;
}
}
// Handle watermelon potions
for (var p = watermelonPotions.length - 1; p >= 0; p--) {
var potion = watermelonPotions[p];
// Remove if off screen
if (potion.x < -50 || potion.x > 2098 || potion.y < -50 || potion.y > 2782) {
potion.destroy();
watermelonPotions.splice(p, 1);
continue;
}
// Check collision with banana
if (potion.intersects(banana)) {
banana.activatePotionEffect();
potion.destroy();
watermelonPotions.splice(p, 1);
continue;
}
}
// Spawn new clouds occasionally
if (LK.ticks % 600 === 0) {
// Every 10 seconds
var newCloud = new Cloud();
newCloud.x = 2248;
newCloud.y = Math.random() * 1000 + 200;
clouds.push(newCloud);
game.addChild(newCloud);
}
// Clean up clouds that are too far off screen
for (var k = clouds.length - 1; k >= 0; k--) {
var cloud = clouds[k];
if (cloud.x < -300) {
cloud.destroy();
clouds.splice(k, 1);
}
}
};
// Start battle music
LK.playMusic('battle');