User prompt
Corrige , en vez de vertical cámbialo a horizontal
User prompt
Que la imagen de fondo duplicada este girada en vertical
User prompt
Que la imagen delfondo inferior principal se mueva hacia la izquierda lentamente y se duplique haciendo un efecto de movimiento infinito ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Que el fondo inferior se mueva hacia la izquierda lentamente y se duplique haciendo un efecto de movimiento infinito ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Agrega una segunda imagen de fondo que este por encima de todo pero que está este 4000 pixeles más abajo
User prompt
Quítale la transparencia y que deje de girar
User prompt
Agrega una nueva imagen de fondo que este por encima de todo y que también tenga movimiento dinámico ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Elimina el aumento de lluvia al pasar el tiempo
User prompt
Crea un nuevo power up, que al tomarlo cree a un aliado , este ayudará al jugador que lo tomo a eliminar a los jugadores contrincantes ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Agrega un nuevo power up , que como función haga que el jugador que lo tome se duplique ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
La barra de vida cambia a color verde cuando el jugador recibe daño, arreglalo por favor
User prompt
Cambia el color de la barra de vida a color azul
User prompt
Coloca la barra de vida por debajo del contador de vidas
User prompt
La barra de vida se vacía a pesar del que el jugador aún tiene vida , arreglalo
User prompt
Agrega una barra de vida en la parte superior de la pantalla, que tenga 200 de vida y que se reinicie cada que el jugador 1 es eliminado
User prompt
Agrega una barra de vida en la parte superior de la pantalla, que muestre la cantidad de vida que le queda al jugador 1
User prompt
Que las gotas de pintura sean de un solo tipo según del jugador que fue eliminado, y agrégale una imagen a las gotas de pintura diferentes para cada jugador único
User prompt
Cuando un jugador pierda una vida, hará una explosión de pintura, la pintura será exparcida en forma de círculo y las gotas de pintura se mantendrán donde caigan ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Si un jugador pierde una vida o es eliminado este creará una explosión de partículas que se exparsiran ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Cuando un jugador es eliminado este explotará en un montón de partículas que se esparcirán
User prompt
Que las partículas de daño recibido vallan hacia abajo
User prompt
Si un jugador recibe un golpe este desprenderá partículas
User prompt
Cuando un jugador ataque se desplase un poco hacia adelante ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Agrégale una imagen de fondo al contador de vidas
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var DuplicatePowerUp = Container.expand(function () {
var self = Container.call(this);
var duplicatePowerupGraphics = self.attachAsset('duplicatePowerup', {
anchorX: 0.5,
anchorY: 0.5
});
duplicatePowerupGraphics.tint = 0x00ff88; // Green tint to distinguish from other powerups
self.lifeTime = 0;
self.maxLifeTime = 600; // 10 seconds at 60fps
self.collected = false;
self.velocityY = 0; // Falling velocity
self.onGround = false; // Track if powerup has landed
self.update = function () {
self.lifeTime++;
self.rotation += 0.08;
// Apply gravity if not on ground
if (!self.onGround) {
self.velocityY += 0.8; // Gravity effect
self.y += self.velocityY;
// Check platform collision for landing
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platformLeft = platform.x - platform.width / 2;
var platformRight = platform.x + platform.width / 2;
var platformTop = platform.y - platform.height / 2;
var platformBottom = platform.y + platform.height / 2;
// Check if powerup is within platform bounds and landing on top
if (self.x >= platformLeft && self.x <= platformRight && self.y >= platformTop - 30 && self.y <= platformBottom && self.velocityY >= 0) {
self.y = platformTop - 30; // Position on top of platform
self.velocityY = 0;
self.onGround = true;
break;
}
}
// Remove if fallen off screen
if (self.y > 2800) {
self.destroy();
for (var j = duplicatePowerups.length - 1; j >= 0; j--) {
if (duplicatePowerups[j] === self) {
duplicatePowerups.splice(j, 1);
break;
}
}
return;
}
} else {
// Bounce effect when on ground
self.y += Math.sin(self.lifeTime * 0.12) * 0.7;
}
if (self.lifeTime > self.maxLifeTime) {
self.destroy();
for (var i = duplicatePowerups.length - 1; i >= 0; i--) {
if (duplicatePowerups[i] === self) {
duplicatePowerups.splice(i, 1);
break;
}
}
}
// Check collection by players
if (!self.collected) {
for (var i = 0; i < fighters.length; i++) {
var fighter = fighters[i];
var distance = Math.sqrt(Math.pow(fighter.x - self.x, 2) + Math.pow(fighter.y - self.y, 2));
if (distance < 80) {
self.collected = true;
// Create duplicate fighter
var duplicate = game.addChild(new Fighter(fighter.playerNumber));
duplicate.x = fighter.x + 100; // Position slightly offset
duplicate.y = fighter.y;
duplicate.powerupCount = fighter.powerupCount; // Copy powerup stats
duplicate.damage = fighter.damage; // Copy damage
fighters.push(duplicate);
// Visual effects for powerup collection
LK.getSound('powerup').play();
LK.effects.flashObject(fighter, 0x00ff88, 800);
// Create duplication animation effect
tween(duplicate, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.8
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Scale back to normal
tween(duplicate, {
scaleX: 1.0 + duplicate.powerupCount * 0.2,
scaleY: 1.0 + duplicate.powerupCount * 0.2,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
self.destroy();
for (var j = duplicatePowerups.length - 1; j >= 0; j--) {
if (duplicatePowerups[j] === self) {
duplicatePowerups.splice(j, 1);
break;
}
}
break;
}
}
}
};
return self;
});
var Fighter = Container.expand(function (playerNumber, color) {
var self = Container.call(this);
var assetName = 'player1';
if (playerNumber === 2) assetName = 'player2';else if (playerNumber === 3) assetName = 'player3';else if (playerNumber === 4) assetName = 'player4';
var fighterGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 1.0
});
self.playerNumber = playerNumber;
self.velocityX = 0;
self.velocityY = 0;
self.onGround = false;
self.jumpsRemaining = 2; // Allow double jump
self.health = 0;
self.maxHealth = 100;
self.damage = 0; // New damage accumulation property
self.moveSpeed = 8;
self.jumpPower = 25;
self.knockbackResistance = 1.0;
self.lastHitTime = 0;
self.invulnerable = false;
self.powerupCount = 0; // Track number of powerups collected
self.baseMoveSpeed = 8; // Store original move speed
self.baseJumpPower = 25; // Store original jump power
self.baseDamage = 15; // Store original damage
self.baseKnockback = 20; // Store original knockback
self.lastVelocityX = 0; // Track last velocity for rotation
self.isWheelMode = false; // Track if in wheel mode
self.wheelModeTimer = 0; // Timer for wheel mode duration
self.wheelGraphics = null; // Reference to wheel graphics
// Create damage bar background
var damageBarBg = self.addChild(LK.getAsset('platform', {
width: 100,
height: 12,
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -130
}));
damageBarBg.tint = 0x333333;
damageBarBg.scaleX = 0.8;
damageBarBg.scaleY = 0.3;
// Create damage bar fill
self.damageBar = self.addChild(LK.getAsset('platform', {
width: 100,
height: 12,
anchorX: 0,
anchorY: 1.0,
x: -40,
y: -130
}));
self.damageBar.tint = 0xff4444;
self.damageBar.scaleX = 0;
self.damageBar.scaleY = 0.3;
// Create damage text
self.damageText = self.addChild(new Text2('0%', {
size: 30,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
}));
self.damageText.anchor.set(0.5, 1);
self.damageText.x = 0;
self.damageText.y = -140;
self.takeDamage = function (damage, knockbackX, knockbackY) {
if (self.invulnerable) return;
self.health += damage;
self.damage += damage; // Accumulate damage for knockback scaling
// Cap damage at 999%
if (self.damage > 999) self.damage = 999;
// Update damage display
self.damageText.setText(Math.floor(self.damage) + '%');
// Reapply stroke properties to maintain black background texture
if (self.damageText.style) {
self.damageText.style.stroke = 0x000000;
self.damageText.style.strokeThickness = 4;
}
// Update damage bar scale (0 to 1 based on damage up to 200%)
var barScale = Math.min(self.damage / 200, 1);
self.damageBar.scaleX = barScale * 0.8;
// Change bar color based on damage level
if (self.damage < 50) {
self.damageBar.tint = 0x44ff44; // Green for low damage
} else if (self.damage < 100) {
self.damageBar.tint = 0xffff44; // Yellow for medium damage
} else if (self.damage < 150) {
self.damageBar.tint = 0xff8844; // Orange for high damage
} else {
self.damageBar.tint = 0xff4444; // Red for very high damage
}
// Check if player has reached 200 damage - explosion and life loss
if (self.damage >= 200) {
// Create paint explosion effect
var explosionCenter = {
x: self.x,
y: self.y
};
var numberOfDrops = 15 + Math.random() * 10; // 15-25 paint drops
for (var i = 0; i < numberOfDrops; i++) {
// Create circular spread pattern
var angle = i / numberOfDrops * Math.PI * 2 + (Math.random() - 0.5) * 0.5;
var speed = 8 + Math.random() * 12; // Random speed for variety
var velocityX = Math.cos(angle) * speed;
var velocityY = Math.sin(angle) * speed - 5; // Slight upward bias
// Create paint drop
var paintDrop = new PaintDrop(self.playerNumber, explosionCenter.x, explosionCenter.y, velocityX, velocityY);
game.addChild(paintDrop);
paintDrops.push(paintDrop);
}
// Create explosion effect with tween
tween(self, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Reset scale and alpha after explosion
self.scaleX = 1.0;
self.scaleY = 1.0;
self.alpha = 1.0;
// Trigger respawn which handles life loss
self.respawn();
}
});
// Flash screen effect for dramatic explosion
LK.effects.flashScreen(0xff8800, 600);
// Play explosion sound effect
LK.getSound('explosion').play();
// Reset damage to prevent multiple explosions
self.damage = 0;
return; // Exit early to prevent further processing this frame
}
// Knockback multiplier based on accumulated damage - exponential scaling for stronger hits at higher damage
var knockbackMultiplier = 1.5 + self.damage / 20 + Math.pow(self.damage / 100, 1.5); // Exponential scaling that increases dramatically with damage
self.velocityX += knockbackX * knockbackMultiplier / self.knockbackResistance;
self.velocityY += knockbackY * knockbackMultiplier / self.knockbackResistance;
// Flash effect when hit
LK.effects.flashObject(self, 0xff0000, 300);
self.invulnerable = true;
LK.setTimeout(function () {
self.invulnerable = false;
}, 500);
LK.getSound('hit').play();
};
self.attack = function (targetX, targetY) {
var attackRange = 150;
var damage = self.baseDamage + self.powerupCount * 8; // Increase damage by 8 per powerup
var baseKnockback = self.baseKnockback + self.powerupCount * 10; // Increase knockback by 10 per powerup
for (var i = 0; i < fighters.length; i++) {
var target = fighters[i];
if (target === self) continue;
var distance = Math.sqrt(Math.pow(target.x - self.x, 2) + Math.pow(target.y - self.y, 2));
if (distance <= attackRange) {
var angle = Math.atan2(target.y - self.y, target.x - self.x);
var knockbackX = Math.cos(angle) * baseKnockback;
var knockbackY = Math.sin(angle) * baseKnockback - 5; // Slight upward angle
target.takeDamage(damage, knockbackX, knockbackY);
}
}
};
self.update = function () {
// Handle wheel mode timer
if (self.isWheelMode) {
self.wheelModeTimer--;
if (self.wheelModeTimer <= 0) {
self.deactivateWheelMode();
}
}
// Update movement stats based on powerups
self.moveSpeed = self.baseMoveSpeed + self.powerupCount * 3; // Increase move speed by 3 per powerup
self.jumpPower = self.baseJumpPower + self.powerupCount * 5; // Increase jump power by 5 per powerup
// Apply wheel mode bonuses
if (self.isWheelMode) {
self.moveSpeed *= 1.5;
self.jumpPower *= 1.3;
}
// Apply gravity
if (!self.onGround) {
self.velocityY += 1.2;
}
// Apply friction
self.velocityX *= 0.85;
if (self.onGround) {
self.velocityX *= 0.75;
}
// Limit velocities to prevent teleportation
var maxVelocityX = 20;
var maxVelocityY = 30;
if (self.velocityX > maxVelocityX) {
self.velocityX = maxVelocityX;
}
if (self.velocityX < -maxVelocityX) {
self.velocityX = -maxVelocityX;
}
if (self.velocityY > maxVelocityY) {
self.velocityY = maxVelocityY;
}
if (self.velocityY < -maxVelocityY) {
self.velocityY = -maxVelocityY;
}
// Track last position for smoke trail
if (self.lastX === undefined) self.lastX = self.x;
if (self.lastY === undefined) self.lastY = self.y;
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Generate smoke trail when moving
var movementSpeed = Math.sqrt(Math.pow(self.x - self.lastX, 2) + Math.pow(self.y - self.lastY, 2));
if (movementSpeed > 3 && LK.ticks % 3 === 0) {
// Calculate movement direction
var movementDirectionX = self.x - self.lastX;
var movementDirectionY = self.y - self.lastY;
// Normalize the direction
var directionLength = Math.sqrt(movementDirectionX * movementDirectionX + movementDirectionY * movementDirectionY);
if (directionLength > 0) {
movementDirectionX /= directionLength;
movementDirectionY /= directionLength;
}
// Position smoke trail behind the movement direction
var smokeDistance = 30; // Distance behind the player
var smokeX = self.x - movementDirectionX * smokeDistance;
var smokeY = self.y - movementDirectionY * smokeDistance + 20;
var smoke = new SmokeTrail(self.playerNumber, smokeX, smokeY);
game.addChild(smoke);
smokeTrails.push(smoke);
}
// Update last position
self.lastX = self.x;
self.lastY = self.y;
// Update visual size based on powerup count
var targetScale = 1.0 + self.powerupCount * 0.2; // Increase size by 20% per powerup
if (Math.abs(fighterGraphics.scaleX) !== targetScale) {
var isFlipped = fighterGraphics.scaleX < 0;
fighterGraphics.scaleX = isFlipped ? -targetScale : targetScale;
fighterGraphics.scaleY = targetScale;
}
// Handle wheel mode rotation and physics
if (self.isWheelMode && self.wheelGraphics) {
// Rotate wheel image based on movement direction only
if (Math.abs(self.velocityX) > 1) {
self.wheelGraphics.rotation += self.velocityX * 0.1;
}
// Continuous bounce effect when hitting ground - jump every time touching ground
if (self.onGround) {
self.velocityY = -self.jumpPower; // Jump with same height as normal jump
}
// Enhanced friction for wheel mode
if (self.onGround) {
self.velocityX *= 0.95; // More responsive control
}
} else {
// Rotate player based on movement direction (normal mode)
if (Math.abs(self.velocityX) > 1) {
// Only rotate if moving with significant velocity
if (self.velocityX > 0) {
// Moving right - face right (normal orientation)
fighterGraphics.scaleX = Math.abs(fighterGraphics.scaleX);
} else {
// Moving left - face left (flip horizontally)
fighterGraphics.scaleX = -Math.abs(fighterGraphics.scaleX);
}
}
}
// Platform collision
var wasOnGround = self.onGround;
self.onGround = false;
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
// More precise collision detection with tighter bounds
var platformLeft = platform.x - platform.width / 2 + 10; // Add small margin
var platformRight = platform.x + platform.width / 2 - 10; // Add small margin
var platformTop = platform.y - platform.height / 2;
var platformBottom = platform.y + platform.height / 2;
// Check if player is within platform horizontal bounds and approaching from above
if (self.x >= platformLeft && self.x <= platformRight && self.y >= platformTop - 20 && self.y <= platformBottom + 5 && self.velocityY >= 0) {
// Adjust ground position for wheel mode to prevent clipping
var groundOffset = self.isWheelMode ? -60 : 0; // Offset wheel players higher to prevent clipping
// Snap player to exact platform surface
self.y = platformTop + groundOffset;
self.velocityY = 0;
// Play landing sound if just landed (wasn't on ground before)
if (!wasOnGround) {
LK.getSound('landing').play();
}
self.onGround = true;
self.jumpsRemaining = 2; // Reset jumps when landing
break;
}
}
// Check if fallen off screen
if (self.y > 2900) {
// Play fall sound effect
LK.getSound('fall').play();
self.respawn();
}
// Fighter-to-fighter collision detection and pushing
for (var i = 0; i < fighters.length; i++) {
var otherFighter = fighters[i];
if (otherFighter === self || otherFighter.destroyed) continue;
// Calculate distance between fighters
var deltaX = otherFighter.x - self.x;
var deltaY = otherFighter.y - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if fighters are colliding (within collision radius)
// Use larger radius for wheel mode players
var collisionRadius = 80; // Default collision radius
if (self.isWheelMode || otherFighter.isWheelMode) {
collisionRadius = 120; // Increased radius when either player is in wheel mode
}
if (distance < collisionRadius && distance > 0) {
// Check for wheel mode damage dealing
if (self.isWheelMode && !self.lastWheelDamageTime) {
self.lastWheelDamageTime = 0;
}
if (otherFighter.isWheelMode && !otherFighter.lastWheelDamageTime) {
otherFighter.lastWheelDamageTime = 0;
}
// Initialize lastWheelDamageTime if not set
if (self.lastWheelDamageTime === undefined) self.lastWheelDamageTime = 0;
if (otherFighter.lastWheelDamageTime === undefined) otherFighter.lastWheelDamageTime = 0;
// Deal damage if current player is in wheel mode and enough time has passed
if (self.isWheelMode && LK.ticks - self.lastWheelDamageTime > 60) {
var wheelDamage = 25 + self.powerupCount * 5; // Base wheel damage + powerup bonus
var angle = Math.atan2(deltaY, deltaX);
var knockbackX = Math.cos(angle) * 15;
var knockbackY = Math.sin(angle) * 15 - 3; // Slight upward angle
otherFighter.takeDamage(wheelDamage, knockbackX, knockbackY);
self.lastWheelDamageTime = LK.ticks;
}
// Deal damage if other player is in wheel mode and enough time has passed
if (otherFighter.isWheelMode && LK.ticks - otherFighter.lastWheelDamageTime > 60) {
var wheelDamage = 25 + otherFighter.powerupCount * 5; // Base wheel damage + powerup bonus
var angle = Math.atan2(-deltaY, -deltaX);
var knockbackX = Math.cos(angle) * 15;
var knockbackY = Math.sin(angle) * 15 - 3; // Slight upward angle
self.takeDamage(wheelDamage, knockbackX, knockbackY);
otherFighter.lastWheelDamageTime = LK.ticks;
}
// Calculate push force based on overlap
var overlap = collisionRadius - distance;
var pushStrength = overlap * 0.3; // Adjust push strength
// Normalize direction vector
var normalX = deltaX / distance;
var normalY = deltaY / distance;
// Apply push forces to both fighters
var pushX = normalX * pushStrength;
var pushY = normalY * pushStrength * 0.3; // Reduced vertical push
// Push both fighters apart
self.velocityX -= pushX;
self.velocityY -= pushY;
otherFighter.velocityX += pushX;
otherFighter.velocityY += pushY;
// Separate fighters to prevent overlap
var separationX = normalX * (overlap * 0.5);
var separationY = normalY * (overlap * 0.3);
self.x -= separationX;
self.y -= separationY;
otherFighter.x += separationX;
otherFighter.y += separationY;
}
}
// Screen boundaries (horizontal bouncing)
if (self.x < 60) {
self.x = 60;
if (self.isWheelMode) {
self.velocityX = Math.abs(self.velocityX) * 0.8; // Enhanced bounce in wheel mode
} else {
self.velocityX = Math.abs(self.velocityX) * 0.5;
}
}
if (self.x > 2700) {
self.x = 2700;
if (self.isWheelMode) {
self.velocityX = -Math.abs(self.velocityX) * 0.8; // Enhanced bounce in wheel mode
} else {
self.velocityX = -Math.abs(self.velocityX) * 0.5;
}
}
};
self.respawn = function () {
// Decrease lives for the player who died
if (self.playerNumber === 1) {
player1Lives--;
} else if (self.playerNumber === 2) {
player2Lives--;
} else if (self.playerNumber === 3) {
player3Lives--;
} else if (self.playerNumber === 4) {
player4Lives--;
}
updateScoreDisplay();
// Check if player is eliminated (no lives left)
var isEliminated = false;
if (self.playerNumber === 1 && player1Lives <= 0) {
isEliminated = true;
} else if (self.playerNumber === 2 && player2Lives <= 0) {
isEliminated = true;
} else if (self.playerNumber === 3 && player3Lives <= 0) {
isEliminated = true;
} else if (self.playerNumber === 4 && player4Lives <= 0) {
isEliminated = true;
}
if (isEliminated) {
// Track if player 1 defeated an enemy
if (self.playerNumber !== 1) {
player1EnemiesDefeated++;
}
// Remove player from the game completely
self.destroy();
// Remove from fighters array
for (var j = fighters.length - 1; j >= 0; j--) {
if (fighters[j] === self) {
fighters.splice(j, 1);
break;
}
}
activePlayers--;
// Check if only one player remains
if (activePlayers <= 1) {
// Find the winner
var winner = "";
if (player1Lives > 0) winner = "Player 1";else if (player2Lives > 0) winner = "Player 2";else if (player3Lives > 0) winner = "Player 3";else if (player4Lives > 0) winner = "Player 4";
LK.setScore(player1EnemiesDefeated);
LK.showGameOver();
}
} else {
// Player still has lives, respawn normally
if (self.playerNumber === 1) {
self.x = 1048; // Respawn on left platform
self.y = 1950; // Just above left platform surface
} else if (self.playerNumber === 2) {
self.x = 1648; // Respawn on main platform
self.y = 2300; // Just above main platform surface
} else if (self.playerNumber === 3) {
self.x = 1648; // Respawn on top platform
self.y = 1600; // Just above top platform surface
} else if (self.playerNumber === 4) {
self.x = 2248; // Respawn on right platform
self.y = 1950; // Just above right platform surface
}
self.velocityX = 0;
self.velocityY = 0;
self.health = 0;
self.damage = 0; // Reset damage on respawn
self.powerupCount = 0; // Reset powerup count on respawn
self.damageText.setText('0%');
// Reapply stroke properties to maintain black background texture
if (self.damageText.style) {
self.damageText.style.stroke = 0x000000;
self.damageText.style.strokeThickness = 4;
}
self.damageBar.scaleX = 0;
self.damageBar.tint = 0x44ff44;
self.jumpsRemaining = 2; // Reset jumps on respawn
}
};
self.activateWheelMode = function () {
if (self.isWheelMode) return; // Already in wheel mode
self.isWheelMode = true;
self.wheelModeTimer = 600; // 10 seconds at 60fps
// Hide original fighter graphics
fighterGraphics.visible = false;
// Create wheel graphics based on player number
var wheelAsset = 'wheel1';
if (self.playerNumber === 2) wheelAsset = 'wheel2';else if (self.playerNumber === 3) wheelAsset = 'wheel3';else if (self.playerNumber === 4) wheelAsset = 'wheel4';
self.wheelGraphics = self.attachAsset(wheelAsset, {
anchorX: 0.5,
anchorY: 0.5
});
// Increase move speed and add bounce physics
self.moveSpeed *= 1.5;
self.jumpPower *= 1.3;
};
self.deactivateWheelMode = function () {
if (!self.isWheelMode) return;
self.isWheelMode = false;
self.wheelModeTimer = 0;
// Show original fighter graphics
fighterGraphics.visible = true;
// Remove wheel graphics
if (self.wheelGraphics) {
self.wheelGraphics.destroy();
self.wheelGraphics = null;
}
// Reset move speed
self.moveSpeed = self.baseMoveSpeed + self.powerupCount * 3;
self.jumpPower = self.baseJumpPower + self.powerupCount * 5;
};
return self;
});
var Firefly = Container.expand(function () {
var self = Container.call(this);
// Create firefly body
var fireflyBody = self.attachAsset('firefly', {
anchorX: 0.5,
anchorY: 0.5
});
// Create glow effect with 200x200 illumination radius
var fireflyGlow = self.attachAsset('fireflyGlow', {
anchorX: 0.5,
anchorY: 0.5
});
fireflyGlow.alpha = 0.15; // Soft glow effect
fireflyGlow.scaleX = 1.0;
fireflyGlow.scaleY = 1.0;
self.lifeTime = 0;
self.maxLifeTime = 2400; // 40 seconds at 60fps - longer than max night cycle
self.velocityX = (Math.random() - 0.5) * 2;
self.velocityY = (Math.random() - 0.5) * 2;
self.glowIntensity = 0.15;
self.flickerTimer = 0;
self.update = function () {
self.lifeTime++;
self.flickerTimer++;
// Gentle movement pattern
self.velocityX += (Math.random() - 0.5) * 0.3;
self.velocityY += (Math.random() - 0.5) * 0.3;
// Limit velocity for gentle floating
if (self.velocityX > 1.5) self.velocityX = 1.5;
if (self.velocityX < -1.5) self.velocityX = -1.5;
if (self.velocityY > 1.5) self.velocityY = 1.5;
if (self.velocityY < -1.5) self.velocityY = -1.5;
self.x += self.velocityX;
self.y += self.velocityY;
// Flicker effect - vary glow intensity
var flickerValue = Math.sin(self.flickerTimer * 0.2) * 0.05;
fireflyGlow.alpha = self.glowIntensity + flickerValue;
fireflyBody.alpha = 0.8 + flickerValue;
// Keep within screen bounds
if (self.x < 100) {
self.x = 100;
self.velocityX = Math.abs(self.velocityX);
}
if (self.x > 1948) {
self.x = 1948;
self.velocityX = -Math.abs(self.velocityX);
}
if (self.y < 100) {
self.y = 100;
self.velocityY = Math.abs(self.velocityY);
}
if (self.y > 2632) {
self.y = 2632;
self.velocityY = -Math.abs(self.velocityY);
}
// Fade out when approaching end of life
if (self.lifeTime >= self.maxLifeTime - 180) {
// Start fading 3 seconds before end
var fadeProgress = (self.lifeTime - (self.maxLifeTime - 180)) / 180;
fireflyGlow.alpha = (self.glowIntensity + flickerValue) * (1 - fadeProgress);
fireflyBody.alpha = (0.8 + flickerValue) * (1 - fadeProgress);
}
// Remove when life time is over
if (self.lifeTime >= self.maxLifeTime) {
self.destroy();
for (var i = fireflies.length - 1; i >= 0; i--) {
if (fireflies[i] === self) {
fireflies.splice(i, 1);
break;
}
}
}
};
return self;
});
var Flower = Container.expand(function (x, y) {
var self = Container.call(this);
// Create flower stem
var stem = self.attachAsset('flowerStem', {
anchorX: 0.5,
anchorY: 1.0
});
// Create flower bloom
var bloom = self.attachAsset('flower', {
anchorX: 0.5,
anchorY: 1.0,
y: -30
});
self.x = x;
self.y = y;
self.lifeTime = 0;
self.maxLifeTime = 3600; // 60 seconds at 60fps
self.growthPhase = 0; // 0=growing, 1=blooming, 2=swaying
// Start small and grow
stem.scaleX = 0.1;
stem.scaleY = 0.1;
bloom.scaleX = 0.1;
bloom.scaleY = 0.1;
bloom.alpha = 0;
// Growth animation
tween(stem, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeOut
});
// Delayed bloom animation
LK.setTimeout(function () {
self.growthPhase = 1;
tween(bloom, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1.0
}, {
duration: 1500,
easing: tween.bounceOut,
onFinish: function onFinish() {
self.growthPhase = 2;
}
});
}, 800);
self.update = function () {
self.lifeTime++;
// Gentle swaying motion when fully grown
if (self.growthPhase === 2) {
var swayAmount = Math.sin(self.lifeTime * 0.05) * 0.1;
bloom.rotation = swayAmount;
stem.rotation = swayAmount * 0.3;
}
// Fade out before disappearing
if (self.lifeTime >= self.maxLifeTime - 300) {
var fadeProgress = (self.lifeTime - (self.maxLifeTime - 300)) / 300;
self.alpha = 1 - fadeProgress;
}
// Remove when life time is over
if (self.lifeTime >= self.maxLifeTime) {
self.destroy();
for (var i = flowers.length - 1; i >= 0; i--) {
if (flowers[i] === self) {
flowers.splice(i, 1);
break;
}
}
}
};
return self;
});
var Lightning = Container.expand(function () {
var self = Container.call(this);
var lightningGraphics = self.attachAsset('lightning', {
anchorX: 0.5,
anchorY: 0
});
self.lifeTime = 0;
self.maxLifeTime = 15; // Very short flash
lightningGraphics.alpha = 0.8;
self.update = function () {
self.lifeTime++;
// Flicker effect
lightningGraphics.alpha = 0.8 * Math.random();
// Remove after short time
if (self.lifeTime >= self.maxLifeTime) {
self.destroy();
for (var i = lightningBolts.length - 1; i >= 0; i--) {
if (lightningBolts[i] === self) {
lightningBolts.splice(i, 1);
break;
}
}
}
};
return self;
});
var PaintDrop = Container.expand(function (playerNumber, startX, startY, velocityX, velocityY) {
var self = Container.call(this);
// Choose paint drop asset based on player number
var assetName = 'paintDrop1';
if (playerNumber === 2) assetName = 'paintDrop2';else if (playerNumber === 3) assetName = 'paintDrop3';else if (playerNumber === 4) assetName = 'paintDrop4';
var paintGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = startX;
self.y = startY;
self.velocityX = velocityX;
self.velocityY = velocityY;
self.hasLanded = false;
self.lifeTime = 0;
self.maxLifeTime = 600; // Stay visible for 10 seconds after landing
self.update = function () {
if (!self.hasLanded) {
// Apply gravity and movement
self.velocityY += 0.8; // Gravity
self.velocityX *= 0.98; // Air resistance
self.x += self.velocityX;
self.y += self.velocityY;
// Check collision with platforms
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platformLeft = platform.x - platform.width / 2;
var platformRight = platform.x + platform.width / 2;
var platformTop = platform.y - platform.height / 2;
var platformBottom = platform.y + platform.height / 2;
if (self.x >= platformLeft && self.x <= platformRight && self.y >= platformTop - 10 && self.y <= platformBottom && self.velocityY >= 0) {
// Paint drop hit platform
self.y = platformTop - 6; // Position on top of platform
self.velocityX = 0;
self.velocityY = 0;
self.hasLanded = true;
break;
}
}
// Remove if fallen off screen
if (self.y > 2900) {
self.destroy();
for (var j = paintDrops.length - 1; j >= 0; j--) {
if (paintDrops[j] === self) {
paintDrops.splice(j, 1);
break;
}
}
return;
}
} else {
// Paint drop has landed, start fade timer
self.lifeTime++;
if (self.lifeTime >= self.maxLifeTime) {
// Fade out effect
var fadeProgress = (self.lifeTime - self.maxLifeTime) / 60; // 1 second fade
paintGraphics.alpha = Math.max(0, 1 - fadeProgress);
if (fadeProgress >= 1) {
self.destroy();
for (var j = paintDrops.length - 1; j >= 0; j--) {
if (paintDrops[j] === self) {
paintDrops.splice(j, 1);
break;
}
}
}
}
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 0;
self.maxLifeTime = 600; // 10 seconds at 60fps
self.collected = false;
self.velocityY = 0; // Falling velocity
self.onGround = false; // Track if powerup has landed
self.update = function () {
self.lifeTime++;
self.rotation += 0.05;
// Apply gravity if not on ground
if (!self.onGround) {
self.velocityY += 0.8; // Gravity effect
self.y += self.velocityY;
// Check platform collision for landing
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platformLeft = platform.x - platform.width / 2;
var platformRight = platform.x + platform.width / 2;
var platformTop = platform.y - platform.height / 2;
var platformBottom = platform.y + platform.height / 2;
// Check if powerup is within platform bounds and landing on top
if (self.x >= platformLeft && self.x <= platformRight && self.y >= platformTop - 30 && self.y <= platformBottom && self.velocityY >= 0) {
self.y = platformTop - 30; // Position on top of platform
self.velocityY = 0;
self.onGround = true;
break;
}
}
// Remove if fallen off screen
if (self.y > 2800) {
self.destroy();
for (var j = powerups.length - 1; j >= 0; j--) {
if (powerups[j] === self) {
powerups.splice(j, 1);
break;
}
}
return;
}
} else {
// Bounce effect when on ground
self.y += Math.sin(self.lifeTime * 0.1) * 0.5;
}
if (self.lifeTime > self.maxLifeTime) {
self.destroy();
for (var i = powerups.length - 1; i >= 0; i--) {
if (powerups[i] === self) {
powerups.splice(i, 1);
break;
}
}
}
// Check collection by players
if (!self.collected) {
for (var i = 0; i < fighters.length; i++) {
var fighter = fighters[i];
var distance = Math.sqrt(Math.pow(fighter.x - self.x, 2) + Math.pow(fighter.y - self.y, 2));
if (distance < 80) {
self.collected = true;
// Increase powerup count for stacking effects
fighter.powerupCount++;
// Visual effects for powerup collection
LK.getSound('powerup').play();
LK.effects.flashObject(fighter, 0xffd700, 800);
// Create scaling animation effect
tween(fighter, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Scale back down slightly
tween(fighter, {
scaleX: 1.0 + fighter.powerupCount * 0.2,
scaleY: 1.0 + fighter.powerupCount * 0.2
}, {
duration: 300,
easing: tween.easeOut
});
}
});
// Temporary knockback resistance boost (stacks with permanent effects)
var originalResistance = fighter.knockbackResistance;
fighter.knockbackResistance *= 0.7; // 30% less knockback temporarily
LK.setTimeout(function () {
fighter.knockbackResistance = originalResistance;
}, 3000);
self.destroy();
for (var j = powerups.length - 1; j >= 0; j--) {
if (powerups[j] === self) {
powerups.splice(j, 1);
break;
}
}
break;
}
}
}
};
return self;
});
var RainDrop = Container.expand(function () {
var self = Container.call(this);
var rainGraphics = self.attachAsset('rainDrop', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 15 + Math.random() * 10; // Fast falling speed
self.velocityX = -2 + Math.random() * 4; // Slight horizontal drift
self.lifeTime = 0;
self.maxLifeTime = 300; // 5 seconds max life
self.update = function () {
self.lifeTime++;
// Move the raindrop
self.x += self.velocityX;
self.y += self.velocityY;
// Check collision with platforms
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platformLeft = platform.x - platform.width / 2;
var platformRight = platform.x + platform.width / 2;
var platformTop = platform.y - platform.height / 2;
var platformBottom = platform.y + platform.height / 2;
// Check if raindrop hits platform
if (self.x >= platformLeft && self.x <= platformRight && self.y >= platformTop && self.y <= platformBottom && self.velocityY > 0) {
// Track rain drop location for flower spawning
rainDropLocations.push({
x: self.x,
y: platformTop - 20,
// Position flowers on top of platform
time: LK.ticks
});
// Rain drop hit platform, destroy it
self.destroy();
for (var j = rainDrops.length - 1; j >= 0; j--) {
if (rainDrops[j] === self) {
rainDrops.splice(j, 1);
break;
}
}
return; // Exit early to prevent further processing
}
}
// Check collision with players
for (var i = 0; i < fighters.length; i++) {
var fighter = fighters[i];
if (!fighter || fighter.destroyed) continue;
var distance = Math.sqrt(Math.pow(fighter.x - self.x, 2) + Math.pow(fighter.y - self.y, 2));
if (distance < 60) {
// Hit detection radius
// Reduce player size by 1.0%
var currentScale = Math.abs(fighter.children[0].scaleX);
var newScale = currentScale * 0.99; // Reduce by 1.0%
// Apply the scale reduction while maintaining orientation
var isFlipped = fighter.children[0].scaleX < 0;
fighter.children[0].scaleX = isFlipped ? -newScale : newScale;
fighter.children[0].scaleY = newScale;
// Destroy the rain drop
self.destroy();
for (var j = rainDrops.length - 1; j >= 0; j--) {
if (rainDrops[j] === self) {
rainDrops.splice(j, 1);
break;
}
}
return; // Exit early to prevent further processing
}
}
// Remove if off screen or exceeded life time
if (self.y > 2800 || self.x < -100 || self.x > 2148 || self.lifeTime >= self.maxLifeTime) {
self.destroy();
for (var i = rainDrops.length - 1; i >= 0; i--) {
if (rainDrops[i] === self) {
rainDrops.splice(i, 1);
break;
}
}
}
};
return self;
});
var SmokeTrail = Container.expand(function (playerNumber, x, y) {
var self = Container.call(this);
var assetName = 'smokeTrail1';
if (playerNumber === 2) assetName = 'smokeTrail2';else if (playerNumber === 3) assetName = 'smokeTrail3';else if (playerNumber === 4) assetName = 'smokeTrail4';
var smokeGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.lifeTime = 0;
self.maxLifeTime = 30; // 0.5 seconds at 60fps
self.startScale = 0.6 + Math.random() * 0.4;
self.endScale = 1.2 + Math.random() * 0.8;
smokeGraphics.scaleX = self.startScale;
smokeGraphics.scaleY = self.startScale;
smokeGraphics.alpha = 0.9;
self.velocityX = (Math.random() - 0.5) * 2;
self.velocityY = -2 - Math.random() * 3;
self.update = function () {
self.lifeTime++;
var progress = self.lifeTime / self.maxLifeTime;
// Move the smoke particle
self.x += self.velocityX;
self.y += self.velocityY;
// Fade out and scale up over time
smokeGraphics.alpha = 0.9 * (1 - progress);
var currentScale = self.startScale + (self.endScale - self.startScale) * progress;
smokeGraphics.scaleX = currentScale;
smokeGraphics.scaleY = currentScale;
// Remove when life time is over
if (self.lifeTime >= self.maxLifeTime) {
self.destroy();
for (var i = smokeTrails.length - 1; i >= 0; i--) {
if (smokeTrails[i] === self) {
smokeTrails.splice(i, 1);
break;
}
}
}
};
return self;
});
var WheelPowerUp = Container.expand(function () {
var self = Container.call(this);
var wheelPowerupGraphics = self.attachAsset('wheelPowerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 0;
self.maxLifeTime = 600; // 10 seconds at 60fps
self.collected = false;
self.velocityY = 0; // Falling velocity
self.onGround = false; // Track if powerup has landed
self.update = function () {
self.lifeTime++;
self.rotation += 0.05;
// Apply gravity if not on ground
if (!self.onGround) {
self.velocityY += 0.8; // Gravity effect
self.y += self.velocityY;
// Check platform collision for landing
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platformLeft = platform.x - platform.width / 2;
var platformRight = platform.x + platform.width / 2;
var platformTop = platform.y - platform.height / 2;
var platformBottom = platform.y + platform.height / 2;
// Check if powerup is within platform bounds and landing on top
if (self.x >= platformLeft && self.x <= platformRight && self.y >= platformTop - 30 && self.y <= platformBottom && self.velocityY >= 0) {
self.y = platformTop - 30; // Position on top of platform
self.velocityY = 0;
self.onGround = true;
break;
}
}
// Remove if fallen off screen
if (self.y > 2800) {
self.destroy();
for (var j = wheelPowerups.length - 1; j >= 0; j--) {
if (wheelPowerups[j] === self) {
wheelPowerups.splice(j, 1);
break;
}
}
return;
}
} else {
// Bounce effect when on ground
self.y += Math.sin(self.lifeTime * 0.1) * 0.5;
}
if (self.lifeTime > self.maxLifeTime) {
self.destroy();
for (var i = wheelPowerups.length - 1; i >= 0; i--) {
if (wheelPowerups[i] === self) {
wheelPowerups.splice(i, 1);
break;
}
}
}
// Check collection by players
if (!self.collected) {
for (var i = 0; i < fighters.length; i++) {
var fighter = fighters[i];
var distance = Math.sqrt(Math.pow(fighter.x - self.x, 2) + Math.pow(fighter.y - self.y, 2));
if (distance < 80) {
self.collected = true;
// Convert fighter to wheel mode
fighter.activateWheelMode();
// Visual effects for powerup collection
LK.getSound('powerup').play();
LK.effects.flashObject(fighter, 0x00ff00, 800);
self.destroy();
for (var j = wheelPowerups.length - 1; j >= 0; j--) {
if (wheelPowerups[j] === self) {
wheelPowerups.splice(j, 1);
break;
}
}
break;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game variables
var fighters = [];
var platforms = [];
var powerups = [];
var wheelPowerups = [];
var duplicatePowerups = [];
var smokeTrails = [];
var fireflies = [];
var rainDrops = [];
var lightningBolts = [];
var flowers = [];
var paintDrops = []; // Track paint drops from explosions
var rainDropLocations = []; // Track where rain drops have fallen
var player1Lives = 3;
var player2Lives = 3;
var player3Lives = 3;
var player4Lives = 3;
var activePlayers = 4;
var draggedFighter = null;
var lastTapTime = 0;
var powerupSpawnTimer = 0;
var player1EnemiesDefeated = 0; // Track enemies defeated by player 1
// Night mode variables
var nightModeTimer = 0;
var nightModeDuration = 1200 + Math.random() * 600; // 20-30 seconds at 60fps
var isNightMode = false;
var nightOverlay = null;
// Storm mode variables
var stormModeTimer = 0;
var stormStartTime = 300 + Math.random() * 2700; // Random time between 5-50 seconds
var isStormMode = false;
var stormHasTriggered = false;
var stormOverlay = null;
// Camera variables
var cameraX = 1024; // Center of screen
var cameraY = 1366; // Center of screen
var cameraScale = 1.0;
var targetCameraX = 1024;
var targetCameraY = 1366;
var targetCameraScale = 1.0;
var cameraUpdateTimer = 0;
// Add background image with parallax tracking
var backgroundImage = game.addChild(LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: 1648,
y: 2400
}));
backgroundImage.originalX = 1648;
backgroundImage.originalY = 2400;
// Add second background image on top of the first with parallax tracking
var backgroundOverlay = game.addChild(LK.getAsset('backgroundOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 1648,
y: 2400
}));
backgroundOverlay.originalX = 1648;
backgroundOverlay.originalY = 2400;
// Add third background image above the previous two with parallax tracking
var backgroundTop = game.addChild(LK.getAsset('backgroundTop', {
anchorX: 0.5,
anchorY: 0.5,
x: 1648,
y: 3200
}));
backgroundTop.originalX = 1648;
backgroundTop.originalY = 3200;
// Button press states
var leftButtonPressed = false;
var rightButtonPressed = false;
var jumpButtonPressed = false;
var attackButtonPressed = false;
// Create platforms
var mainPlatform = game.addChild(LK.getAsset('mainPlatform', {
anchorX: 0.5,
anchorY: 0.5,
x: 1648,
y: 2400
}));
platforms.push(mainPlatform);
var leftPlatform = game.addChild(LK.getAsset('platform', {
anchorX: 0.5,
anchorY: 0.5,
x: 1048,
y: 2050
}));
platforms.push(leftPlatform);
var rightPlatform = game.addChild(LK.getAsset('platform', {
anchorX: 0.5,
anchorY: 0.5,
x: 2248,
y: 2050
}));
platforms.push(rightPlatform);
var topPlatform = game.addChild(LK.getAsset('platform', {
anchorX: 0.5,
anchorY: 0.5,
x: 1648,
y: 1700
}));
platforms.push(topPlatform);
// Add decorative textured images directly on top of platforms
var mainPlatformTexture = game.addChild(LK.getAsset('platformTexture', {
anchorX: 0.5,
anchorY: 1.0,
x: 1648,
y: 2250
}));
mainPlatformTexture.scaleX = 2.5; // Scale to match main platform width
mainPlatformTexture.scaleY = 0.8;
var leftPlatformTexture = game.addChild(LK.getAsset('platformTexture', {
anchorX: 0.5,
anchorY: 1.0,
x: 1048,
y: 1950
}));
leftPlatformTexture.scaleX = 1.25; // Scale to match platform width
leftPlatformTexture.scaleY = 0.6;
var rightPlatformTexture = game.addChild(LK.getAsset('platformTexture', {
anchorX: 0.5,
anchorY: 1.0,
x: 2248,
y: 1950
}));
rightPlatformTexture.scaleX = 1.25; // Scale to match platform width
rightPlatformTexture.scaleY = 0.6;
var topPlatformTexture = game.addChild(LK.getAsset('platformTexture', {
anchorX: 0.5,
anchorY: 1.0,
x: 1648,
y: 1600
}));
topPlatformTexture.scaleX = 1.25; // Scale to match platform width
topPlatformTexture.scaleY = 0.6;
// Create night mode overlay
nightOverlay = game.addChild(LK.getAsset('platform', {
width: 3000,
height: 4000,
anchorX: 0.5,
anchorY: 0.5,
x: 1500,
y: 2000
}));
nightOverlay.tint = 0x000022; // Darker blue tint for stronger night effect
nightOverlay.alpha = 0; // Start invisible
nightOverlay.scaleX = 2;
nightOverlay.scaleY = 2;
// Create storm mode overlay
stormOverlay = game.addChild(LK.getAsset('platform', {
width: 3000,
height: 4000,
anchorX: 0.5,
anchorY: 0.5,
x: 1500,
y: 2000
}));
stormOverlay.tint = 0x444444; // Dark gray tint for storm atmosphere
stormOverlay.alpha = 0; // Start invisible
stormOverlay.scaleX = 2;
stormOverlay.scaleY = 2;
// Create fighters
var player1 = game.addChild(new Fighter(1));
player1.x = 1048; // Position on left platform
player1.y = 1950; // Just above the platform surface
fighters.push(player1);
var player2 = game.addChild(new Fighter(2));
player2.x = 1648; // Position on main platform
player2.y = 2300; // Just above the main platform surface
fighters.push(player2);
var player3 = game.addChild(new Fighter(3));
player3.x = 1648; // Position on top platform
player3.y = 1600; // Just above the top platform surface
fighters.push(player3);
var player4 = game.addChild(new Fighter(4));
player4.x = 2248; // Position on right platform
player4.y = 1950; // Just above the right platform surface
fighters.push(player4);
// UI Elements - Individual player displays
var player1Avatar = LK.getAsset('player1Avatar', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 100,
scaleX: 0.8,
scaleY: 0.8
});
LK.gui.topRight.addChild(player1Avatar);
var player1LivesBackground = LK.getAsset('livesBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 180,
scaleX: 0.8,
scaleY: 0.8
});
LK.gui.topRight.addChild(player1LivesBackground);
var player1LivesBackground;
var player1LivesImage = LK.getAsset('number3', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 180,
scaleX: 1.0,
scaleY: 1.0
});
LK.gui.topRight.addChild(player1LivesImage);
// Player 2, 3, and 4 UI elements are hidden - only Player 1 UI is visible
// Create left movement button for player 1
var leftButton = LK.getAsset('leftButtonIcon', {
anchorX: 0,
anchorY: 1,
x: 30,
y: -160,
scaleX: 3,
scaleY: 3
});
LK.gui.bottomLeft.addChild(leftButton);
// Create right movement button for player 1
var rightButton = LK.getAsset('rightButtonIcon', {
anchorX: 0,
anchorY: 1,
x: 320,
y: -160,
scaleX: 3,
scaleY: 3
});
LK.gui.bottomLeft.addChild(rightButton);
// Create jump button for player 1
var jumpButton = LK.getAsset('jumpButtonIcon', {
anchorX: 1,
anchorY: 1,
x: -100,
y: -300,
scaleX: 3,
scaleY: 3
});
LK.gui.bottomRight.addChild(jumpButton);
// Create attack button for player 1
var attackButton = LK.getAsset('attackButtonIcon', {
anchorX: 1,
anchorY: 1,
x: -100,
y: -160,
scaleX: 3,
scaleY: 3
});
LK.gui.bottomRight.addChild(attackButton);
function updateScoreDisplay() {
// Remove current lives image and background
LK.gui.topRight.removeChild(player1LivesImage);
LK.gui.topRight.removeChild(player1LivesBackground);
player1LivesImage.destroy();
player1LivesBackground.destroy();
// Recreate lives background
player1LivesBackground = LK.getAsset('livesBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 180,
scaleX: 0.8,
scaleY: 0.8
});
LK.gui.topRight.addChild(player1LivesBackground);
// Create new lives image based on current lives count
var numberAsset = 'number0';
if (player1Lives === 1) numberAsset = 'number1';else if (player1Lives === 2) numberAsset = 'number2';else if (player1Lives === 3) numberAsset = 'number3';
player1LivesImage = LK.getAsset(numberAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 180,
scaleX: 1.0,
scaleY: 1.0
});
LK.gui.topRight.addChild(player1LivesImage);
// Update avatar opacity based on lives remaining
player1Avatar.alpha = player1Lives > 0 ? 1.0 : 0.3;
// Update lives image opacity based on lives remaining
player1LivesImage.alpha = player1Lives > 0 ? 1.0 : 0.5;
// Update background opacity based on lives remaining
player1LivesBackground.alpha = player1Lives > 0 ? 1.0 : 0.5;
}
// Left button event handler
leftButton.down = function (x, y, obj) {
leftButtonPressed = true;
leftButton.alpha = 0.6;
tween(leftButton, {
scaleX: 2.7,
scaleY: 2.7
}, {
duration: 100
});
};
leftButton.up = function (x, y, obj) {
leftButtonPressed = false;
leftButton.alpha = 1.0;
tween(leftButton, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 100
});
};
// Right button event handler
rightButton.down = function (x, y, obj) {
rightButtonPressed = true;
rightButton.alpha = 0.6;
tween(rightButton, {
scaleX: 2.7,
scaleY: 2.7
}, {
duration: 100
});
};
rightButton.up = function (x, y, obj) {
rightButtonPressed = false;
rightButton.alpha = 1.0;
tween(rightButton, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 100
});
};
// Jump button event handler
jumpButton.down = function (x, y, obj) {
jumpButtonPressed = true;
jumpButton.alpha = 0.6;
tween(jumpButton, {
scaleX: 2.7,
scaleY: 2.7
}, {
duration: 100
});
};
jumpButton.up = function (x, y, obj) {
jumpButtonPressed = false;
jumpButton.alpha = 1.0;
tween(jumpButton, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 100
});
};
// Attack button event handler
attackButton.down = function (x, y, obj) {
attackButtonPressed = true;
attackButton.alpha = 0.6;
tween(attackButton, {
scaleX: 2.7,
scaleY: 2.7
}, {
duration: 100
});
};
attackButton.up = function (x, y, obj) {
attackButtonPressed = false;
attackButton.alpha = 1.0;
tween(attackButton, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 100
});
};
function updateCamera() {
// Only update camera if there are living fighters
var aliveFighters = [];
for (var i = 0; i < fighters.length; i++) {
var fighter = fighters[i];
if (fighter && !fighter.destroyed) {
// Check if fighter is alive based on lives
var isAlive = false;
if (fighter.playerNumber === 1 && player1Lives > 0) isAlive = true;else if (fighter.playerNumber === 2 && player2Lives > 0) isAlive = true;else if (fighter.playerNumber === 3 && player3Lives > 0) isAlive = true;else if (fighter.playerNumber === 4 && player4Lives > 0) isAlive = true;
if (isAlive) {
aliveFighters.push(fighter);
}
}
}
if (aliveFighters.length === 0) return;
// Calculate center point of all alive fighters
var minX = Infinity;
var maxX = -Infinity;
var minY = Infinity;
var maxY = -Infinity;
var totalX = 0;
var totalY = 0;
for (var i = 0; i < aliveFighters.length; i++) {
var fighter = aliveFighters[i];
totalX += fighter.x;
totalY += fighter.y;
if (fighter.x < minX) minX = fighter.x;
if (fighter.x > maxX) maxX = fighter.x;
if (fighter.y < minY) minY = fighter.y;
if (fighter.y > maxY) maxY = fighter.y;
}
// Calculate center point
targetCameraX = totalX / aliveFighters.length;
targetCameraY = totalY / aliveFighters.length;
// Calculate required zoom based on spread of players
var spreadX = maxX - minX;
var spreadY = maxY - minY;
// Base zoom calculation - zoom in more for closer view of players
var baseScale = 1.2; // Increased base scale for more zoom
var maxSpreadX = 400; // Further reduced max spread for tighter framing
var maxSpreadY = 300; // Further reduced max spread for tighter framing
var scaleX = maxSpreadX / Math.max(spreadX + 100, maxSpreadX); // Reduced padding for closer view
var scaleY = maxSpreadY / Math.max(spreadY + 100, maxSpreadY); // Reduced padding for closer view
// Use the smaller scale to ensure all players fit
targetCameraScale = Math.min(scaleX, scaleY, 1.3); // Increased max zoom to 1.3x for closer view
// Minimum zoom to prevent over-zooming - increased minimum for closer gameplay
if (targetCameraScale < 0.9) targetCameraScale = 0.9;
// Keep camera within reasonable bounds
var padding = 200;
if (targetCameraX < padding) targetCameraX = padding;
if (targetCameraX > 2048 - padding) targetCameraX = 2048 - padding;
if (targetCameraY < 400) targetCameraY = 400;
if (targetCameraY > 2400) targetCameraY = 2400;
}
function applyCameraSmoothing() {
// Smooth camera movement using tweening
var smoothingSpeed = 0.05; // How fast camera follows (0.01 = very slow, 0.1 = fast)
// Interpolate camera position
cameraX += (targetCameraX - cameraX) * smoothingSpeed;
cameraY += (targetCameraY - cameraY) * smoothingSpeed;
cameraScale += (targetCameraScale - cameraScale) * smoothingSpeed;
// Apply camera transformation to game
game.x = (1024 - cameraX) * cameraScale + 1024 * (1 - cameraScale);
game.y = (1366 - cameraY) * cameraScale + 1366 * (1 - cameraScale);
game.scaleX = cameraScale;
game.scaleY = cameraScale;
// Apply parallax scrolling to background layers
updateParallax();
}
function updateParallax() {
// Calculate camera movement offset from center
var cameraMoveX = cameraX - 1024; // How much camera moved from center horizontally
var cameraMoveY = cameraY - 1366; // How much camera moved from center vertically
// Background image (furthest back) - moves slowest (20% of camera movement)
backgroundImage.x = backgroundImage.originalX - cameraMoveX * 0.2;
backgroundImage.y = backgroundImage.originalY - cameraMoveY * 0.15;
// Background overlay (middle layer) - moves at medium speed (40% of camera movement)
backgroundOverlay.x = backgroundOverlay.originalX - cameraMoveX * 0.4;
backgroundOverlay.y = backgroundOverlay.originalY - cameraMoveY * 0.3;
// Background top (closest to foreground) - moves faster (60% of camera movement)
backgroundTop.x = backgroundTop.originalX - cameraMoveX * 0.6;
backgroundTop.y = backgroundTop.originalY - cameraMoveY * 0.45;
}
function spawnPowerUp() {
if (powerups.length + wheelPowerups.length + duplicatePowerups.length < 3) {
// 33% chance for each type of powerup
var powerupType = Math.random();
if (powerupType < 0.33) {
var powerup = game.addChild(new PowerUp());
// Spawn from random position above the screen aligned with new platform positions
powerup.x = 1048 + Math.random() * 1200; // Random X within extended platform bounds (left to right platform)
powerup.y = -100; // Start above screen
powerup.velocityY = 2 + Math.random() * 3; // Initial falling speed
powerups.push(powerup);
} else if (powerupType < 0.66) {
var wheelPowerup = game.addChild(new WheelPowerUp());
// Spawn from random position above the screen aligned with new platform positions
wheelPowerup.x = 1048 + Math.random() * 1200; // Random X within extended platform bounds (left to right platform)
wheelPowerup.y = -100; // Start above screen
wheelPowerup.velocityY = 2 + Math.random() * 3; // Initial falling speed
wheelPowerups.push(wheelPowerup);
} else {
var duplicatePowerup = game.addChild(new DuplicatePowerUp());
// Spawn from random position above the screen aligned with new platform positions
duplicatePowerup.x = 1048 + Math.random() * 1200; // Random X within extended platform bounds (left to right platform)
duplicatePowerup.y = -100; // Start above screen
duplicatePowerup.velocityY = 2 + Math.random() * 3; // Initial falling speed
duplicatePowerups.push(duplicatePowerup);
}
}
}
// Game controls
game.down = function (x, y, obj) {
var currentTime = LK.ticks;
var tapSpeed = 20; // frames between taps for double tap
// Find closest fighter to touch point (only player 1)
var closestFighter = null;
var closestDistance = Infinity;
for (var i = 0; i < fighters.length; i++) {
var fighter = fighters[i];
// Only allow touch control for player 1 if they're still alive
if (fighter.playerNumber !== 1 || player1Lives <= 0) continue;
var distance = Math.sqrt(Math.pow(fighter.x - x, 2) + Math.pow(fighter.y - y, 2));
if (distance < closestDistance && distance < 200) {
closestDistance = distance;
closestFighter = fighter;
}
}
if (closestFighter) {
// Check for double tap (attack)
if (currentTime - lastTapTime < tapSpeed) {
closestFighter.attack(x, y);
draggedFighter = null;
} else {
draggedFighter = closestFighter;
}
lastTapTime = currentTime;
}
};
game.move = function (x, y, obj) {
if (draggedFighter && draggedFighter.playerNumber === 1) {
var deltaX = x - draggedFighter.x;
var deltaY = y - draggedFighter.y;
// Move fighter towards touch point
draggedFighter.velocityX += deltaX * 0.3;
// Jump if dragging upward and has jumps remaining
if (deltaY < -50 && draggedFighter.jumpsRemaining > 0) {
draggedFighter.velocityY = -draggedFighter.jumpPower;
draggedFighter.jumpsRemaining--;
draggedFighter.onGround = false;
LK.getSound('jump').play();
}
}
};
game.up = function (x, y, obj) {
draggedFighter = null;
};
// Function to determine which platform a fighter is on
function getPlayerPlatform(fighter) {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platformLeft = platform.x - platform.width / 2;
var platformRight = platform.x + platform.width / 2;
var platformTop = platform.y - platform.height / 2;
var platformBottom = platform.y + platform.height / 2;
// Check if fighter is within platform bounds and close to platform surface
if (fighter.x >= platformLeft && fighter.x <= platformRight && fighter.y >= platformTop - 100 && fighter.y <= platformBottom + 50) {
return platform;
}
}
return null;
}
// Function to find closest target for AI with platform priority
function findClosestTarget(aiPlayer) {
var closestPlayer = null;
var closestDistance = Infinity;
var closestSamePlatformPlayer = null;
var closestSamePlatformDistance = Infinity;
var aiPlatform = getPlayerPlatform(aiPlayer);
for (var i = 0; i < fighters.length; i++) {
var fighter = fighters[i];
// Skip self, dead players, and destroyed fighters
if (fighter === aiPlayer) continue;
if (fighter.destroyed) continue;
if (fighter.playerNumber === 1 && player1Lives <= 0) continue;
if (fighter.playerNumber === 2 && player2Lives <= 0) continue;
if (fighter.playerNumber === 3 && player3Lives <= 0) continue;
if (fighter.playerNumber === 4 && player4Lives <= 0) continue;
var distance = Math.sqrt(Math.pow(fighter.x - aiPlayer.x, 2) + Math.pow(fighter.y - aiPlayer.y, 2));
var fighterPlatform = getPlayerPlatform(fighter);
var onSamePlatform = aiPlatform && fighterPlatform && aiPlatform === fighterPlatform;
// Track closest enemy on same platform
if (onSamePlatform && distance < closestSamePlatformDistance) {
closestSamePlatformDistance = distance;
closestSamePlatformPlayer = fighter;
}
// Track overall closest enemy
if (distance < closestDistance) {
closestDistance = distance;
closestPlayer = fighter;
}
}
// Prioritize same platform enemy if one exists
if (closestSamePlatformPlayer) {
return {
player: closestSamePlatformPlayer,
distance: closestSamePlatformDistance,
samePlatform: true
};
}
return {
player: closestPlayer,
distance: closestDistance,
samePlatform: false
};
}
// AI variables for player 2
var aiDecisionTimer = 0;
var aiAction = 'idle';
var aiTargetX = player2.x;
var aiCooldown = 0;
// AI variables for player 3
var ai3DecisionTimer = 0;
var ai3Action = 'idle';
var ai3TargetX = 1648;
var ai3Cooldown = 0;
// AI variables for player 4
var ai4DecisionTimer = 0;
var ai4Action = 'idle';
var ai4TargetX = 2248;
var ai4Cooldown = 0;
game.update = function () {
// Start background music on first update
if (LK.ticks === 1) {
LK.playMusic('backgroundMusic');
}
// Handle continuous button presses for player 1 (only if alive)
if (player1Lives > 0) {
if (leftButtonPressed) {
player1.velocityX -= player1.moveSpeed * 0.5;
}
if (rightButtonPressed) {
player1.velocityX += player1.moveSpeed * 0.5;
}
if (jumpButtonPressed && player1.jumpsRemaining > 0) {
player1.velocityY = -player1.jumpPower;
player1.jumpsRemaining--;
player1.onGround = false;
LK.getSound('jump').play();
jumpButtonPressed = false; // Prevent continuous jumping
}
if (attackButtonPressed) {
player1.attack(player1.x, player1.y);
attackButtonPressed = false; // Prevent continuous attacking
}
}
// Spawn power-ups occasionally
powerupSpawnTimer++;
if (powerupSpawnTimer > 120) {
// Every 2 seconds
if (Math.random() < 0.5) {
spawnPowerUp();
}
powerupSpawnTimer = 0;
}
// AI for player 2 (only if alive)
if (player2Lives > 0) {
aiDecisionTimer++;
if (aiCooldown > 0) {
aiCooldown--;
}
// Make AI decisions every 30 frames (half second)
if (aiDecisionTimer > 30) {
aiDecisionTimer = 0;
// Check if AI is below main platform and needs to move to center
var mainPlatformY = 2400; // Main platform Y position
var isBelowMainPlatform = player2.y > mainPlatformY + 200;
if (isBelowMainPlatform) {
// Force move to center platform to avoid falling
aiAction = 'moveToCenter';
aiTargetX = 1648; // Main platform center X
} else {
// Find closest target
var closestTarget = findClosestTarget(player2);
var distanceToClosest = closestTarget.distance;
// Check for nearby powerups
var nearestPowerup = null;
var nearestPowerupDistance = Infinity;
for (var i = 0; i < powerups.length; i++) {
var powerup = powerups[i];
var distance = Math.sqrt(Math.pow(powerup.x - player2.x, 2) + Math.pow(powerup.y - player2.y, 2));
if (distance < nearestPowerupDistance) {
nearestPowerupDistance = distance;
nearestPowerup = powerup;
}
}
// AI decision making with enhanced platform awareness
if (aiCooldown === 0 && closestTarget.player) {
if (distanceToClosest < 200 && Math.random() < 0.8) {
// Attack if close to closest target
aiAction = 'attack';
aiCooldown = 60; // Attack cooldown
} else if (nearestPowerup && nearestPowerupDistance < 300 && Math.random() < 0.3) {
// Go for powerup if nearby (lower priority)
aiAction = 'moveToPowerup';
aiTargetX = nearestPowerup.x;
} else if (closestTarget.samePlatform) {
// Same platform enemy detected - move towards closest enemy on same platform
aiAction = 'moveToPlayer';
aiTargetX = closestTarget.player.x;
} else if (!closestTarget.samePlatform && closestTarget.player) {
// Different platform - jump towards target
aiAction = 'jumpToPlayer';
aiTargetX = closestTarget.player.x;
} else {
// Random movement (rare)
aiAction = 'randomMove';
aiTargetX = 1200 + Math.random() * 900; // Random X within platform area
}
} else if (!closestTarget.player) {
aiAction = 'idle';
}
}
}
// Execute AI actions
if (aiAction === 'attack' && closestTarget.player) {
player2.attack(closestTarget.player.x, closestTarget.player.y);
aiAction = 'idle';
} else if (aiAction === 'moveToPowerup' || aiAction === 'moveToPlayer' || aiAction === 'randomMove' || aiAction === 'jumpToPlayer' || aiAction === 'moveToCenter') {
// Move towards target
var deltaX = aiTargetX - player2.x;
if (Math.abs(deltaX) > 50) {
player2.velocityX += deltaX * 0.25;
}
// Enhanced jumping logic for different platforms
if (aiAction === 'jumpToPlayer' && closestTarget && closestTarget.player) {
// Jump towards player on different platform
if (player2.jumpsRemaining > 0 && player2.onGround) {
player2.velocityY = -player2.jumpPower;
player2.jumpsRemaining--;
player2.onGround = false;
LK.getSound('jump').play();
// Add horizontal velocity towards target
player2.velocityX += deltaX * 0.15;
}
} else if (aiAction === 'moveToCenter') {
// Jump upward aggressively to get back to main platform
if (player2.jumpsRemaining > 0) {
player2.velocityY = -player2.jumpPower;
player2.jumpsRemaining--;
player2.onGround = false;
LK.getSound('jump').play();
}
} else if (aiAction === 'moveToPlayer' && closestTarget && closestTarget.player && closestTarget.player.y < player2.y - 100) {
// Jump if target is above on same platform
if (player2.jumpsRemaining > 0) {
player2.velocityY = -player2.jumpPower;
player2.jumpsRemaining--;
player2.onGround = false;
LK.getSound('jump').play();
}
} else if (Math.abs(player2.velocityX) < 1 && player2.onGround && Math.random() < 0.1) {
// Jump if stuck
if (player2.jumpsRemaining > 0) {
player2.velocityY = -player2.jumpPower;
player2.jumpsRemaining--;
player2.onGround = false;
LK.getSound('jump').play();
}
}
// Reset action if close enough to target
if (Math.abs(deltaX) < 100) {
aiAction = 'idle';
}
}
// AI logic: double jump if can't reach player who is much higher
var heightDifference = player2.y - player1.y;
var horizontalDistance = Math.abs(player2.x - player1.x);
if (heightDifference > 200 && horizontalDistance < 400 && player2.jumpsRemaining > 0) {
// Check if AI is below player and perform double jump to reach them
player2.velocityY = -player2.jumpPower;
player2.jumpsRemaining--;
player2.onGround = false;
LK.getSound('jump').play();
}
// AI emergency jump if falling off platform
if (player2.y > 2500 && player2.jumpsRemaining > 0) {
player2.velocityY = -player2.jumpPower;
player2.jumpsRemaining--;
player2.onGround = false;
LK.getSound('jump').play();
}
}
// AI for player 3 (only if alive)
if (player3Lives > 0) {
ai3DecisionTimer++;
if (ai3Cooldown > 0) {
ai3Cooldown--;
}
if (ai3DecisionTimer > 45) {
ai3DecisionTimer = 0;
// Check if AI is below main platform and needs to move to center
var mainPlatformY = 2400; // Main platform Y position
var isBelowMainPlatform = player3.y > mainPlatformY + 200;
if (isBelowMainPlatform) {
// Force move to center platform to avoid falling
ai3Action = 'moveToCenter';
ai3TargetX = 1648; // Main platform center X
} else {
// Find closest target
var closestTarget_3 = findClosestTarget(player3);
var closestDistance_3 = closestTarget_3.distance;
if (ai3Cooldown === 0 && closestTarget_3.player) {
if (closestDistance_3 < 200 && Math.random() < 0.7) {
ai3Action = 'attack';
ai3Cooldown = 70;
} else if (closestTarget_3.samePlatform) {
// Same platform enemy detected - move towards closest enemy on same platform
ai3Action = 'moveToPlayer';
ai3TargetX = closestTarget_3.player.x;
} else if (!closestTarget_3.samePlatform && closestTarget_3.player) {
// Different platform - jump towards target
ai3Action = 'jumpToPlayer';
ai3TargetX = closestTarget_3.player.x;
} else if (Math.random() < 0.3) {
ai3Action = 'randomMove';
ai3TargetX = 1200 + Math.random() * 900;
} else {
ai3Action = 'idle';
}
} else if (!closestTarget_3.player) {
ai3Action = 'idle';
}
}
}
if (ai3Action === 'attack' && closestTarget_3.player) {
player3.attack(closestTarget_3.player.x, closestTarget_3.player.y);
ai3Action = 'idle';
} else if (ai3Action === 'moveToPlayer' || ai3Action === 'randomMove' || ai3Action === 'jumpToPlayer' || ai3Action === 'moveToCenter') {
var deltaX_3 = ai3TargetX - player3.x;
if (Math.abs(deltaX_3) > 50) {
player3.velocityX += deltaX_3 * 0.22;
}
// Enhanced jumping logic for different platforms
if (ai3Action === 'jumpToPlayer' && closestTarget_3 && closestTarget_3.player) {
// Jump towards player on different platform
if (player3.jumpsRemaining > 0 && player3.onGround) {
player3.velocityY = -player3.jumpPower;
player3.jumpsRemaining--;
player3.onGround = false;
LK.getSound('jump').play();
// Add horizontal velocity towards target
player3.velocityX += deltaX_3 * 0.18;
}
} else if (ai3Action === 'moveToCenter') {
// Jump upward aggressively to get back to main platform
if (player3.jumpsRemaining > 0) {
player3.velocityY = -player3.jumpPower;
player3.jumpsRemaining--;
player3.onGround = false;
LK.getSound('jump').play();
}
} else if (Math.abs(deltaX_3) > 200 && player3.onGround && Math.random() < 0.15) {
if (player3.jumpsRemaining > 0) {
player3.velocityY = -player3.jumpPower;
player3.jumpsRemaining--;
player3.onGround = false;
LK.getSound('jump').play();
}
}
if (Math.abs(deltaX_3) < 100) {
ai3Action = 'idle';
}
}
if (player3.y > 2500 && player3.jumpsRemaining > 0) {
player3.velocityY = -player3.jumpPower;
player3.jumpsRemaining--;
player3.onGround = false;
LK.getSound('jump').play();
}
}
// AI for player 4 (only if alive)
if (player4Lives > 0) {
ai4DecisionTimer++;
if (ai4Cooldown > 0) {
ai4Cooldown--;
}
if (ai4DecisionTimer > 35) {
ai4DecisionTimer = 0;
// Check if AI is below main platform and needs to move to center
var mainPlatformY = 2400; // Main platform Y position
var isBelowMainPlatform = player4.y > mainPlatformY + 200;
if (isBelowMainPlatform) {
// Force move to center platform to avoid falling
ai4Action = 'moveToCenter';
ai4TargetX = 1648; // Main platform center X
} else {
// Find closest target
var closestTarget_4 = findClosestTarget(player4);
var closestDistance_4 = closestTarget_4.distance;
if (ai4Cooldown === 0 && closestTarget_4.player) {
if (closestDistance_4 < 180 && Math.random() < 0.85) {
ai4Action = 'attack';
ai4Cooldown = 50;
} else if (closestTarget_4.samePlatform) {
// Same platform enemy detected - move towards closest enemy on same platform aggressively
ai4Action = 'moveToPlayer';
ai4TargetX = closestTarget_4.player.x;
} else if (!closestTarget_4.samePlatform && closestTarget_4.player) {
// Different platform - jump towards target
ai4Action = 'jumpToPlayer';
ai4TargetX = closestTarget_4.player.x;
} else if (Math.random() < 0.4) {
ai4Action = 'randomMove';
ai4TargetX = 1200 + Math.random() * 900;
} else {
ai4Action = 'idle';
}
} else if (!closestTarget_4.player) {
ai4Action = 'idle';
}
}
}
if (ai4Action === 'attack' && closestTarget_4.player) {
player4.attack(closestTarget_4.player.x, closestTarget_4.player.y);
ai4Action = 'idle';
} else if (ai4Action === 'moveToPlayer' || ai4Action === 'randomMove' || ai4Action === 'jumpToPlayer' || ai4Action === 'moveToCenter') {
var deltaX_4 = ai4TargetX - player4.x;
if (Math.abs(deltaX_4) > 50) {
player4.velocityX += deltaX_4 * 0.28;
}
// Enhanced jumping logic for different platforms
if (ai4Action === 'jumpToPlayer' && closestTarget_4 && closestTarget_4.player) {
// Jump towards player on different platform
if (player4.jumpsRemaining > 0 && player4.onGround) {
player4.velocityY = -player4.jumpPower;
player4.jumpsRemaining--;
player4.onGround = false;
LK.getSound('jump').play();
// Add horizontal velocity towards target
player4.velocityX += deltaX_4 * 0.2;
}
} else if (ai4Action === 'moveToCenter') {
// Jump upward aggressively to get back to main platform
if (player4.jumpsRemaining > 0) {
player4.velocityY = -player4.jumpPower;
player4.jumpsRemaining--;
player4.onGround = false;
LK.getSound('jump').play();
}
} else if (Math.abs(deltaX_4) > 150 && player4.onGround && Math.random() < 0.2) {
if (player4.jumpsRemaining > 0) {
player4.velocityY = -player4.jumpPower;
player4.jumpsRemaining--;
player4.onGround = false;
LK.getSound('jump').play();
}
}
if (Math.abs(deltaX_4) < 100) {
ai4Action = 'idle';
}
}
if (player4.y > 2500 && player4.jumpsRemaining > 0) {
player4.velocityY = -player4.jumpPower;
player4.jumpsRemaining--;
player4.onGround = false;
LK.getSound('jump').play();
}
}
// Update all fighters
for (var i = fighters.length - 1; i >= 0; i--) {
if (fighters[i] && !fighters[i].destroyed) {
fighters[i].update();
}
}
// Update all powerups
for (var i = powerups.length - 1; i >= 0; i--) {
if (powerups[i] && !powerups[i].destroyed) {
powerups[i].update();
}
}
// Update all wheel powerups
for (var i = wheelPowerups.length - 1; i >= 0; i--) {
if (wheelPowerups[i] && !wheelPowerups[i].destroyed) {
wheelPowerups[i].update();
}
}
// Update all duplicate powerups
for (var i = duplicatePowerups.length - 1; i >= 0; i--) {
if (duplicatePowerups[i] && !duplicatePowerups[i].destroyed) {
duplicatePowerups[i].update();
}
}
// Update all smoke trails
for (var i = smokeTrails.length - 1; i >= 0; i--) {
if (smokeTrails[i] && !smokeTrails[i].destroyed) {
smokeTrails[i].update();
}
}
// Update all fireflies
for (var i = fireflies.length - 1; i >= 0; i--) {
if (fireflies[i] && !fireflies[i].destroyed) {
fireflies[i].update();
}
}
// Update all rain drops
for (var i = rainDrops.length - 1; i >= 0; i--) {
if (rainDrops[i] && !rainDrops[i].destroyed) {
rainDrops[i].update();
}
}
// Update all lightning bolts
for (var i = lightningBolts.length - 1; i >= 0; i--) {
if (lightningBolts[i] && !lightningBolts[i].destroyed) {
lightningBolts[i].update();
}
}
// Update all flowers
for (var i = flowers.length - 1; i >= 0; i--) {
if (flowers[i] && !flowers[i].destroyed) {
flowers[i].update();
}
}
// Update all paint drops
for (var i = paintDrops.length - 1; i >= 0; i--) {
if (paintDrops[i] && !paintDrops[i].destroyed) {
paintDrops[i].update();
}
}
// Update camera every 10 frames for smooth performance
cameraUpdateTimer++;
if (cameraUpdateTimer >= 10) {
cameraUpdateTimer = 0;
updateCamera();
}
// Storm mode cycle - triggers once at random time
if (!stormHasTriggered && !isNightMode) {
// Only start storm if night mode is not active
stormModeTimer++; // Only increment timer when night mode is not active
if (stormModeTimer >= stormStartTime) {
stormHasTriggered = true;
isStormMode = true;
// Start storm mode with dramatic darkening
tween(stormOverlay, {
alpha: 0.6
}, {
duration: 1500,
// 1.5 seconds to darken quickly
easing: tween.easeInOut
});
// Flash screen effect to simulate lightning
LK.effects.flashScreen(0xffffff, 300);
// End storm mode after 20 seconds
LK.setTimeout(function () {
isStormMode = false;
tween(stormOverlay, {
alpha: 0
}, {
duration: 2000,
// 2 seconds to clear
easing: tween.easeOut
});
// Spawn flowers where rain drops fell most frequently
var flowerSpawnAreas = [];
var gridSize = 150; // Size of each grid cell for density calculation
// Create density map based on rain drop locations
for (var r = 0; r < rainDropLocations.length; r++) {
var location = rainDropLocations[r];
var gridX = Math.floor(location.x / gridSize);
var gridY = Math.floor(location.y / gridSize);
var gridKey = gridX + "," + gridY;
if (!flowerSpawnAreas[gridKey]) {
flowerSpawnAreas[gridKey] = {
count: 0,
totalX: 0,
totalY: 0,
avgX: 0,
avgY: 0
};
}
flowerSpawnAreas[gridKey].count++;
flowerSpawnAreas[gridKey].totalX += location.x;
flowerSpawnAreas[gridKey].totalY += location.y;
}
// Calculate average positions and spawn flowers in high-density areas
for (var key in flowerSpawnAreas) {
var area = flowerSpawnAreas[key];
if (area.count >= 5) {
// Minimum 5 rain drops to spawn a flower
area.avgX = area.totalX / area.count;
area.avgY = area.totalY / area.count;
// Spawn multiple flowers based on density
var flowerCount = Math.min(Math.floor(area.count / 3), 4); // 1 flower per 3 rain drops, max 4
for (var f = 0; f < flowerCount; f++) {
var flower = game.addChild(new Flower(area.avgX + (Math.random() - 0.5) * 80,
// Small random offset
area.avgY + (Math.random() - 0.5) * 40));
// Position flower behind players but in front of background elements
// Count background elements (background, backgroundOverlay, backgroundTop) = 3
var backgroundElementCount = 3;
var platformCount = 4; // mainPlatform, leftPlatform, rightPlatform, topPlatform
var textureCount = 4; // platform textures
var overlayCount = 2; // nightOverlay, stormOverlay
var totalBackgroundElements = backgroundElementCount + platformCount + textureCount + overlayCount;
game.setChildIndex(flower, totalBackgroundElements);
flowers.push(flower);
}
}
}
// Clear rain drop tracking for next storm
rainDropLocations = [];
// Clear all rain and lightning when storm ends
for (var r = rainDrops.length - 1; r >= 0; r--) {
if (rainDrops[r]) {
rainDrops[r].destroy();
rainDrops.splice(r, 1);
}
}
for (var l = lightningBolts.length - 1; l >= 0; l--) {
if (lightningBolts[l]) {
lightningBolts[l].destroy();
lightningBolts.splice(l, 1);
}
}
}, 20000); // 20 seconds duration
}
}
// Storm rain and lightning effects
if (isStormMode) {
// Calculate storm duration in 5-second intervals for progressive intensity
var stormDuration = LK.ticks - (stormStartTime + stormModeTimer - stormStartTime);
var fiveSecondIntervals = Math.floor(stormDuration / 300); // 300 frames = 5 seconds at 60fps
// Base rain frequency starts at every 2 frames, gets more frequent as storm progresses
var rainFrequency = Math.max(1, 2 - Math.floor(fiveSecondIntervals / 2)); // Decreases spawn interval
// Additional rain drops - spawn extra drops every 5 seconds
var extraDrops = Math.min(fiveSecondIntervals, 10); // Cap at 10 extra drops per spawn
// Spawn rain drops continuously with increasing intensity
if (LK.ticks % rainFrequency === 0) {
// Spawn base rain drop plus additional drops based on storm duration
for (var dropCount = 0; dropCount <= extraDrops; dropCount++) {
var rainDrop = game.addChild(new RainDrop());
// Center rain drop spawn around main platform (1648 is main platform X center)
var mainPlatformX = 1648;
var spawnRadius = 800; // Spawn radius around main platform
// Calculate camera movement to spawn rain ahead of camera direction
var cameraDeltaX = targetCameraX - cameraX;
var cameraDeltaY = targetCameraY - cameraY;
// Base spawn area centered on main platform
var baseSpawnX = mainPlatformX - spawnRadius / 2 + Math.random() * spawnRadius;
var baseSpawnY = cameraY - 600;
// Offset spawn position based on camera movement direction
var movementMultiplier = 2.0; // How much to lead the camera movement
rainDrop.x = baseSpawnX + cameraDeltaX * movementMultiplier;
rainDrop.y = baseSpawnY + cameraDeltaY * movementMultiplier * 0.5;
// Ensure rain spawns within bounds centered around main platform
var minX = mainPlatformX - spawnRadius;
var maxX = mainPlatformX + spawnRadius;
if (rainDrop.x < minX) rainDrop.x = minX;
if (rainDrop.x > maxX) rainDrop.x = maxX;
if (rainDrop.y > -50) rainDrop.y = -50;
rainDrops.push(rainDrop);
}
}
// Random lightning strikes
if (Math.random() < 0.005) {
// 0.5% chance per frame for lightning
var lightning = game.addChild(new Lightning());
lightning.x = 200 + Math.random() * 1648; // Random X position
lightning.y = 0; // Start at top of screen
lightningBolts.push(lightning);
// Flash screen white for lightning effect
LK.effects.flashScreen(0xffffff, 200);
}
}
// Night mode cycle
if (!isStormMode) {
// Only increment timer when storm mode is not active
nightModeTimer++;
}
if (nightModeTimer >= nightModeDuration && !isStormMode) {
// Only proceed if storm mode is not active
nightModeTimer = 0;
// Reset duration for next cycle (20-30 seconds)
nightModeDuration = 1200 + Math.random() * 600;
if (!isNightMode) {
// Start night mode - darken slowly
isNightMode = true;
tween(nightOverlay, {
alpha: 0.75
}, {
duration: 3000,
// 3 seconds to darken
easing: tween.easeInOut
});
// Spawn fireflies when night mode starts - they appear from outside screen and move in
for (var f = 0; f < 5; f++) {
var firefly = game.addChild(new Firefly());
// Start fireflies outside the visible screen area
var side = Math.floor(Math.random() * 4); // 0=top, 1=right, 2=bottom, 3=left
var startX, startY, targetX, targetY;
if (side === 0) {
// From top
startX = Math.random() * 2048;
startY = -200;
targetX = startX + (Math.random() - 0.5) * 400; // Some horizontal drift
targetY = 200 + Math.random() * 1000;
} else if (side === 1) {
// From right
startX = 2248;
startY = Math.random() * 2732;
targetX = 1400 + Math.random() * 600;
targetY = startY + (Math.random() - 0.5) * 400; // Some vertical drift
} else if (side === 2) {
// From bottom
startX = Math.random() * 2048;
startY = 2932;
targetX = startX + (Math.random() - 0.5) * 400; // Some horizontal drift
targetY = 1800 + Math.random() * 800;
} else {
// From left
startX = -200;
startY = Math.random() * 2732;
targetX = 200 + Math.random() * 600;
targetY = startY + (Math.random() - 0.5) * 400; // Some vertical drift
}
// Ensure target positions are within reasonable scene bounds
if (targetX < 100) targetX = 100;
if (targetX > 1948) targetX = 1948;
if (targetY < 200) targetY = 200;
if (targetY > 2500) targetY = 2500;
// Set starting position
firefly.x = startX;
firefly.y = startY;
// Animate firefly moving into the scene
var duration = 2000 + Math.random() * 3000; // 2-5 seconds to enter
tween(firefly, {
x: targetX,
y: targetY
}, {
duration: duration,
easing: tween.easeOut
});
fireflies.push(firefly);
}
} else {
// End night mode - brighten slowly
isNightMode = false;
tween(nightOverlay, {
alpha: 0
}, {
duration: 2000,
// 2 seconds to brighten
easing: tween.easeInOut
});
// Fade out all fireflies when night mode ends
for (var f = fireflies.length - 1; f >= 0; f--) {
if (fireflies[f]) {
var firefly = fireflies[f];
tween(firefly, {
alpha: 0
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
firefly.destroy();
// Remove from array
for (var i = fireflies.length - 1; i >= 0; i--) {
if (fireflies[i] === firefly) {
fireflies.splice(i, 1);
break;
}
}
}
});
}
}
}
}
// Apply smooth camera movement
applyCameraSmoothing();
}; ===================================================================
--- original.js
+++ change.js
@@ -5,8 +5,117 @@
/****
* Classes
****/
+var DuplicatePowerUp = Container.expand(function () {
+ var self = Container.call(this);
+ var duplicatePowerupGraphics = self.attachAsset('duplicatePowerup', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ duplicatePowerupGraphics.tint = 0x00ff88; // Green tint to distinguish from other powerups
+ self.lifeTime = 0;
+ self.maxLifeTime = 600; // 10 seconds at 60fps
+ self.collected = false;
+ self.velocityY = 0; // Falling velocity
+ self.onGround = false; // Track if powerup has landed
+ self.update = function () {
+ self.lifeTime++;
+ self.rotation += 0.08;
+ // Apply gravity if not on ground
+ if (!self.onGround) {
+ self.velocityY += 0.8; // Gravity effect
+ self.y += self.velocityY;
+ // Check platform collision for landing
+ for (var i = 0; i < platforms.length; i++) {
+ var platform = platforms[i];
+ var platformLeft = platform.x - platform.width / 2;
+ var platformRight = platform.x + platform.width / 2;
+ var platformTop = platform.y - platform.height / 2;
+ var platformBottom = platform.y + platform.height / 2;
+ // Check if powerup is within platform bounds and landing on top
+ if (self.x >= platformLeft && self.x <= platformRight && self.y >= platformTop - 30 && self.y <= platformBottom && self.velocityY >= 0) {
+ self.y = platformTop - 30; // Position on top of platform
+ self.velocityY = 0;
+ self.onGround = true;
+ break;
+ }
+ }
+ // Remove if fallen off screen
+ if (self.y > 2800) {
+ self.destroy();
+ for (var j = duplicatePowerups.length - 1; j >= 0; j--) {
+ if (duplicatePowerups[j] === self) {
+ duplicatePowerups.splice(j, 1);
+ break;
+ }
+ }
+ return;
+ }
+ } else {
+ // Bounce effect when on ground
+ self.y += Math.sin(self.lifeTime * 0.12) * 0.7;
+ }
+ if (self.lifeTime > self.maxLifeTime) {
+ self.destroy();
+ for (var i = duplicatePowerups.length - 1; i >= 0; i--) {
+ if (duplicatePowerups[i] === self) {
+ duplicatePowerups.splice(i, 1);
+ break;
+ }
+ }
+ }
+ // Check collection by players
+ if (!self.collected) {
+ for (var i = 0; i < fighters.length; i++) {
+ var fighter = fighters[i];
+ var distance = Math.sqrt(Math.pow(fighter.x - self.x, 2) + Math.pow(fighter.y - self.y, 2));
+ if (distance < 80) {
+ self.collected = true;
+ // Create duplicate fighter
+ var duplicate = game.addChild(new Fighter(fighter.playerNumber));
+ duplicate.x = fighter.x + 100; // Position slightly offset
+ duplicate.y = fighter.y;
+ duplicate.powerupCount = fighter.powerupCount; // Copy powerup stats
+ duplicate.damage = fighter.damage; // Copy damage
+ fighters.push(duplicate);
+ // Visual effects for powerup collection
+ LK.getSound('powerup').play();
+ LK.effects.flashObject(fighter, 0x00ff88, 800);
+ // Create duplication animation effect
+ tween(duplicate, {
+ scaleX: 1.2,
+ scaleY: 1.2,
+ alpha: 0.8
+ }, {
+ duration: 300,
+ easing: tween.bounceOut,
+ onFinish: function onFinish() {
+ // Scale back to normal
+ tween(duplicate, {
+ scaleX: 1.0 + duplicate.powerupCount * 0.2,
+ scaleY: 1.0 + duplicate.powerupCount * 0.2,
+ alpha: 1.0
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ }
+ });
+ self.destroy();
+ for (var j = duplicatePowerups.length - 1; j >= 0; j--) {
+ if (duplicatePowerups[j] === self) {
+ duplicatePowerups.splice(j, 1);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ };
+ return self;
+});
var Fighter = Container.expand(function (playerNumber, color) {
var self = Container.call(this);
var assetName = 'player1';
if (playerNumber === 2) assetName = 'player2';else if (playerNumber === 3) assetName = 'player3';else if (playerNumber === 4) assetName = 'player4';
@@ -150,14 +259,8 @@
LK.setTimeout(function () {
self.invulnerable = false;
}, 500);
LK.getSound('hit').play();
- // Reduce player 1 health when they take damage
- if (self.playerNumber === 1) {
- player1Health -= damage;
- if (player1Health < 0) player1Health = 0;
- updateScoreDisplay(); // Update health bar display
- }
};
self.attack = function (targetX, targetY) {
var attackRange = 150;
var damage = self.baseDamage + self.powerupCount * 8; // Increase damage by 8 per powerup
@@ -443,11 +546,8 @@
// Player still has lives, respawn normally
if (self.playerNumber === 1) {
self.x = 1048; // Respawn on left platform
self.y = 1950; // Just above left platform surface
- // Reset player 1 health to maximum on respawn
- player1Health = player1MaxHealth;
- updateScoreDisplay(); // Update health bar display
} else if (self.playerNumber === 2) {
self.x = 1648; // Respawn on main platform
self.y = 2300; // Just above main platform surface
} else if (self.playerNumber === 3) {
@@ -1080,8 +1180,9 @@
var fighters = [];
var platforms = [];
var powerups = [];
var wheelPowerups = [];
+var duplicatePowerups = [];
var smokeTrails = [];
var fireflies = [];
var rainDrops = [];
var lightningBolts = [];
@@ -1096,12 +1197,8 @@
var draggedFighter = null;
var lastTapTime = 0;
var powerupSpawnTimer = 0;
var player1EnemiesDefeated = 0; // Track enemies defeated by player 1
-var player1Health = 200; // Player 1 health bar
-var player1MaxHealth = 200; // Maximum health for player 1
-var player1HealthBarBg; // Health bar background
-var player1HealthBarFill; // Health bar fill
// Night mode variables
var nightModeTimer = 0;
var nightModeDuration = 1200 + Math.random() * 600; // 20-30 seconds at 60fps
var isNightMode = false;
@@ -1285,27 +1382,8 @@
scaleX: 1.0,
scaleY: 1.0
});
LK.gui.topRight.addChild(player1LivesImage);
-// Create health bar for player 1
-player1HealthBarBg = LK.getAsset('player1HealthBarBg', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: -200,
- y: 250,
- scaleX: 1.0,
- scaleY: 1.0
-});
-LK.gui.topRight.addChild(player1HealthBarBg);
-player1HealthBarFill = LK.getAsset('player1HealthBarFill', {
- anchorX: 0,
- anchorY: 0.5,
- x: -300,
- y: 250,
- scaleX: 1.0,
- scaleY: 1.0
-});
-LK.gui.topRight.addChild(player1HealthBarFill);
// Player 2, 3, and 4 UI elements are hidden - only Player 1 UI is visible
// Create left movement button for player 1
var leftButton = LK.getAsset('leftButtonIcon', {
anchorX: 0,
@@ -1379,23 +1457,8 @@
// Update lives image opacity based on lives remaining
player1LivesImage.alpha = player1Lives > 0 ? 1.0 : 0.5;
// Update background opacity based on lives remaining
player1LivesBackground.alpha = player1Lives > 0 ? 1.0 : 0.5;
- // Don't reset health when player 1 is eliminated - health should only reset on respawn
- // Update health bar fill based on current health
- var healthPercentage = Math.max(0, Math.min(1, player1Health / player1MaxHealth));
- player1HealthBarFill.scaleX = healthPercentage;
- // Change health bar color based on health level
- if (healthPercentage > 0.6) {
- player1HealthBarFill.tint = 0x0099ff; // Blue for high health (matches original blue color)
- } else if (healthPercentage > 0.3) {
- player1HealthBarFill.tint = 0xffff44; // Yellow for medium health
- } else {
- player1HealthBarFill.tint = 0xff4444; // Red for low health
- }
- // Update health bar opacity based on player status
- player1HealthBarBg.alpha = player1Lives > 0 ? 1.0 : 0.5;
- player1HealthBarFill.alpha = player1Lives > 0 ? 1.0 : 0.5;
}
// Left button event handler
leftButton.down = function (x, y, obj) {
leftButtonPressed = true;
@@ -1563,24 +1626,32 @@
backgroundTop.x = backgroundTop.originalX - cameraMoveX * 0.6;
backgroundTop.y = backgroundTop.originalY - cameraMoveY * 0.45;
}
function spawnPowerUp() {
- if (powerups.length + wheelPowerups.length < 2) {
- // 50% chance for wheel powerup, 50% for regular powerup
- if (Math.random() < 0.5) {
+ if (powerups.length + wheelPowerups.length + duplicatePowerups.length < 3) {
+ // 33% chance for each type of powerup
+ var powerupType = Math.random();
+ if (powerupType < 0.33) {
var powerup = game.addChild(new PowerUp());
// Spawn from random position above the screen aligned with new platform positions
powerup.x = 1048 + Math.random() * 1200; // Random X within extended platform bounds (left to right platform)
powerup.y = -100; // Start above screen
powerup.velocityY = 2 + Math.random() * 3; // Initial falling speed
powerups.push(powerup);
- } else {
+ } else if (powerupType < 0.66) {
var wheelPowerup = game.addChild(new WheelPowerUp());
// Spawn from random position above the screen aligned with new platform positions
wheelPowerup.x = 1048 + Math.random() * 1200; // Random X within extended platform bounds (left to right platform)
wheelPowerup.y = -100; // Start above screen
wheelPowerup.velocityY = 2 + Math.random() * 3; // Initial falling speed
wheelPowerups.push(wheelPowerup);
+ } else {
+ var duplicatePowerup = game.addChild(new DuplicatePowerUp());
+ // Spawn from random position above the screen aligned with new platform positions
+ duplicatePowerup.x = 1048 + Math.random() * 1200; // Random X within extended platform bounds (left to right platform)
+ duplicatePowerup.y = -100; // Start above screen
+ duplicatePowerup.velocityY = 2 + Math.random() * 3; // Initial falling speed
+ duplicatePowerups.push(duplicatePowerup);
}
}
}
// Game controls
@@ -2058,8 +2129,14 @@
if (wheelPowerups[i] && !wheelPowerups[i].destroyed) {
wheelPowerups[i].update();
}
}
+ // Update all duplicate powerups
+ for (var i = duplicatePowerups.length - 1; i >= 0; i--) {
+ if (duplicatePowerups[i] && !duplicatePowerups[i].destroyed) {
+ duplicatePowerups[i].update();
+ }
+ }
// Update all smoke trails
for (var i = smokeTrails.length - 1; i >= 0; i--) {
if (smokeTrails[i] && !smokeTrails[i].destroyed) {
smokeTrails[i].update();
Slime azul, pixelart. In-Game asset. 2d. High contrast. No shadows
Slime rojo, pixelart. In-Game asset. 2d. High contrast. No shadows
Slime amarillo, pixelart. In-Game asset. 2d. High contrast. No shadows
Slime verde, pixelart. In-Game asset. 2d. High contrast. No shadows
Montañas en atardecer pixelart. In-Game asset. 2d. High contrast. No shadows
Elimina la montaña
Burbuja azul, una , pixelart. In-Game asset. 2d. High contrast. No shadows
Esfera amarilla con la letra P , pixelart. In-Game asset. 2d. High contrast. No shadows
Flecha azul de Slime , pixelart. In-Game asset. 2d. High contrast. No shadows
Cámbiale el color a rojo , pixelart
Cámbiale el color a amarillo, pixelart
Cámbiale el color a verde, pixelart
Apaga las luces de la ventanas
Luciérnaga, pixelart. In-Game asset. 2d. High contrast. No shadows
Cabeza de girasol, pixelart. In-Game asset. 2d. High contrast. No shadows
Número 1 azul , pixelart. In-Game asset. 2d. High contrast. No shadows
Número 0 azul, pixelart. In-Game asset. 2d. High contrast. No shadows
Número 3 azul, pixelart. In-Game asset. 2d. High contrast. No shadows
Retro, pixelart