/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Explosion = Container.expand(function () { var self = Container.call(this); // Attach the explosion sprite var explosionSprite = self.attachAsset('Explosion', { anchorX: 0.5, anchorY: 0.5 }); // Animation properties self.animationTimer = 500; // Animation duration in ms self.initialScale = 0.1; self.finalScale = 3.0; // Set initial scale explosionSprite.scaleX = self.initialScale; explosionSprite.scaleY = self.initialScale; // Start explosion animation tween(explosionSprite, { scaleX: self.finalScale, scaleY: self.finalScale, alpha: 0 }, { duration: self.animationTimer, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); return self; }); var Guerrero = Container.expand(function () { var self = Container.call(this); // Attach the warrior sprite var guerreroSprite = self.attachAsset('Guerrero', { anchorX: 0.5, anchorY: 0.5 }); // Movement properties self.speed = 600; // Speed for tween animation self.isAttacking = false; self.attackDuration = 300; // Attack animation duration in ms self.attackTimer = 0; // Target position for automatic movement self.targetX = null; self.targetY = null; self.isMoving = false; // Track last movement direction for slash attacks self.lastDirection = { x: 1, y: 0 }; // Default direction (right) // Update method called every frame self.update = function () { // Handle attack animation if (self.isAttacking) { self.attackTimer -= 16; // Approximate 60fps if (self.attackTimer <= 0) { self.isAttacking = false; guerreroSprite.rotation = 0; guerreroSprite.scaleX = 1; } else { // Simple attack animation - rotate and scale var progress = 1 - self.attackTimer / self.attackDuration; guerreroSprite.rotation = Math.sin(progress * Math.PI) * 0.5; guerreroSprite.scaleX = 1 + Math.sin(progress * Math.PI) * 0.3; } } }; // Move to target position using tween self.moveToTarget = function (targetX, targetY) { // Stop any current movement tween.stop(self, { x: true, y: true }); // Set new target self.targetX = targetX; self.targetY = targetY; self.isMoving = true; // Calculate distance for duration var distance = Math.sqrt(Math.pow(targetX - self.x, 2) + Math.pow(targetY - self.y, 2)); var duration = distance / self.speed * 1000; // Convert to milliseconds // Update last movement direction if (distance > 0) { self.lastDirection.x = (targetX - self.x) / distance; self.lastDirection.y = (targetY - self.y) / distance; } // Start continuous walking animation self.startWalkingAnimation(); // Start tween to target position tween(self, { x: targetX, y: targetY }, { duration: duration, easing: tween.linear, onFinish: function onFinish() { self.isMoving = false; self.targetX = null; self.targetY = null; // Stop walking animation and reset sprite to normal state tween.stop(guerreroSprite, { scaleX: true, scaleY: true }); guerreroSprite.scaleX = 1; guerreroSprite.scaleY = 1; // Hide joystick when target is reached if (joystickSprite) { joystickSprite.destroy(); joystickSprite = null; } } }); }; // Attack method self.attack = function () { if (!self.isAttacking) { self.isAttacking = true; self.attackTimer = self.attackDuration; // Create and launch slash in last movement direction self.createSlash(); } }; // Create slash method self.createSlash = function () { var slash = new Slash(); slash.x = self.x; slash.y = self.y; // Find the nearest enemy var nearestEnemy = null; var nearestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } // Set direction towards nearest enemy, or use last direction if no enemies exist if (nearestEnemy) { var dx = nearestEnemy.x - self.x; var dy = nearestEnemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { slash.setDirection(dx / distance, dy / distance); } else { slash.setDirection(self.lastDirection.x, self.lastDirection.y); } } else { slash.setDirection(self.lastDirection.x, self.lastDirection.y); } game.addChild(slash); }; // Start continuous walking animation self.startWalkingAnimation = function () { self.walkCycle(); }; // Continuous walking cycle animation self.walkCycle = function () { if (!self.isMoving) return; // Stop animation if not moving tween(guerreroSprite, { scaleX: 1.1, scaleY: 0.9 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { if (!self.isMoving) return; // Check again before next cycle tween(guerreroSprite, { scaleX: 0.9, scaleY: 1.1 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { if (self.isMoving) { self.walkCycle(); // Continue the loop } } }); } }); }; return self; }); var RedSlimeEnemy = Container.expand(function () { var self = Container.call(this); // Attach the red slime sprite var slimeSprite = self.attachAsset('Slime_Red', { anchorX: 0.5, anchorY: 0.5 }); // Health property - takes 1 hit to destroy self.health = 1; // Collision cooldown property - prevents taking damage for 1 second after hit self.canTakeDamage = true; // Movement properties self.speed = 320; // Four times the speed of blue slimes (80 * 4) // Update method called every frame self.update = function () { // Calculate direction towards player var dx = guerrero.x - self.x; var dy = guerrero.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Move towards player if distance > 0 if (distance > 0) { var normalizedX = dx / distance; var normalizedY = dy / distance; self.x += normalizedX * self.speed * (16 / 1000); // 16ms per frame at 60fps self.y += normalizedY * self.speed * (16 / 1000); } }; return self; }); var Slash = Container.expand(function () { var self = Container.call(this); // Attach the slash sprite var slashSprite = self.attachAsset('tajo', { anchorX: 0.5, anchorY: 0.5 }); // Movement properties self.speed = 3200; // Quadruple fast movement speed self.directionX = 1; // Movement direction X self.directionY = 0; // Movement direction Y // Update method called every frame self.update = function () { // Move in the specified direction self.x += self.directionX * self.speed * (16 / 1000); // 16ms per frame at 60fps self.y += self.directionY * self.speed * (16 / 1000); // Check if slash is off screen and destroy it if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) { self.destroy(); } }; // Set direction method self.setDirection = function (dirX, dirY) { self.directionX = dirX; self.directionY = dirY; // Rotate sprite to match direction slashSprite.rotation = Math.atan2(dirY, dirX); }; return self; }); var SlimeEnemy = Container.expand(function () { var self = Container.call(this); // Attach the slime sprite var slimeSprite = self.attachAsset('slime_blue', { anchorX: 0.5, anchorY: 0.5 }); // Movement properties self.speed = 80; // Slightly faster movement speed // Update method called every frame self.update = function () { // Calculate direction towards player var dx = guerrero.x - self.x; var dy = guerrero.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Move towards player if distance > 0 if (distance > 0) { var normalizedX = dx / distance; var normalizedY = dy / distance; self.x += normalizedX * self.speed * (16 / 1000); // 16ms per frame at 60fps self.y += normalizedY * self.speed * (16 / 1000); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Calculate how many tiles we need to cover the full screen (2048x2732) // Create ground background covering the entire screen var tileWidth = 100; var tileHeight = 100; var tilesX = Math.ceil(2048 / tileWidth); var tilesY = Math.ceil(2732 / tileHeight); // Create a container for all ground tiles var groundContainer = new Container(); game.addChild(groundContainer); // Fill the entire screen with ground tiles for (var x = 0; x < tilesX; x++) { for (var y = 0; y < tilesY; y++) { var groundTile = LK.getAsset('Suelo', { x: x * tileWidth, y: y * tileHeight }); groundContainer.addChild(groundTile); } ; // Game update loop game.update = function () { // Update enemy spawn timer enemySpawnTimer += 16; // 16ms per frame at 60fps // Spawn enemy every 8 seconds (only if game is not over) if (!gameOver && enemySpawnTimer >= enemySpawnInterval) { spawnEnemy(); enemySpawnTimer = 0; } // Update red slime spawn timer redSlimeSpawnTimer += 16; // 16ms per frame at 60fps // Spawn red slime every 7 seconds (only if game is not over) if (!gameOver && redSlimeSpawnTimer >= redSlimeSpawnInterval) { spawnRedSlime(); redSlimeSpawnTimer = 0; } // Update auto attack timer autoAttackTimer += 16; // 16ms per frame at 60fps // Auto attack every 4 seconds if (autoAttackTimer >= autoAttackInterval) { guerrero.attack(); autoAttackTimer = 0; } // Check for score milestones and reduce spawn intervals var currentScore = LK.getScore(); var currentCheckpoint = Math.floor(currentScore / 10) * 10; if (currentCheckpoint > lastScoreCheckpoint && currentCheckpoint > 0) { // Calculate how many 10-point milestones we've reached var reductionSteps = currentCheckpoint / 10; // Reduce intervals by 15% for each 10-point milestone var reductionFactor = Math.pow(0.85, reductionSteps); // Apply reduction to both spawn intervals enemySpawnInterval = Math.max(1000, initialBlueSlimeInterval * reductionFactor); // Minimum 1 second redSlimeSpawnInterval = Math.max(1000, initialRedSlimeInterval * reductionFactor); // Minimum 1 second // Update last checkpoint lastScoreCheckpoint = currentCheckpoint; } // Check slash-enemy collisions var slashes = []; for (var i = 0; i < game.children.length; i++) { if (game.children[i] instanceof Slash) { slashes.push(game.children[i]); } } for (var s = 0; s < slashes.length; s++) { var slash = slashes[s]; for (var e = enemies.length - 1; e >= 0; e--) { var enemy = enemies[e]; if (slash.intersects(enemy)) { // Check if enemy is a red slime with health system if (enemy instanceof RedSlimeEnemy && enemy.canTakeDamage) { enemy.health -= 1; // Start cooldown period - red slime cannot take damage for 1 second enemy.canTakeDamage = false; // Use closure to capture the current enemy instance (function (currentEnemy) { tween(currentEnemy, {}, { duration: 1000, onFinish: function onFinish() { currentEnemy.canTakeDamage = true; } }); })(enemy); // Add visual feedback during invulnerability (function (currentEnemy) { tween(currentEnemy, { alpha: 0.5 }, { duration: 100, onFinish: function onFinish() { tween(currentEnemy, { alpha: 1 }, { duration: 100 }); } }); })(enemy); if (enemy.health <= 0) { // Create explosion effect at enemy position var explosion = new Explosion(); explosion.x = enemy.x; explosion.y = enemy.y; game.addChild(explosion); // Award 2 points for red slime destruction LK.setScore(LK.getScore() + 2); scoreText.setText('Puntos: ' + LK.getScore()); // Destroy the red slime after 2 hits enemy.destroy(); enemies.splice(e, 1); } // Red slime takes damage but might survive, don't destroy slash } else { // Regular blue slime - destroy immediately var explosion = new Explosion(); explosion.x = enemy.x; explosion.y = enemy.y; game.addChild(explosion); // Award 1 point for blue slime destruction LK.setScore(LK.getScore() + 1); scoreText.setText('Puntos: ' + LK.getScore()); // Destroy only the enemy, keep the slash enemy.destroy(); enemies.splice(e, 1); } // Don't break here so slash can hit multiple enemies } } } // Check player-enemy collisions for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (guerrero.intersects(enemy)) { // Player loses 1 health point playerHealth -= 1; healthText.setText('Vida: ' + playerHealth.toString()); // Play damage sound LK.getSound('Damage').play(); // Create explosion effect at enemy position var explosion = new Explosion(); explosion.x = enemy.x; explosion.y = enemy.y; game.addChild(explosion); // Destroy the enemy enemy.destroy(); enemies.splice(i, 1); // Check for game over if (playerHealth <= 0) { // Set game over flag to prevent enemy spawning gameOver = true; // Destroy all sprites except health text // Destroy all game children (including player, enemies, ground, etc.) for (var i = game.children.length - 1; i >= 0; i--) { game.children[i].destroy(); } // Clear enemies array enemies = []; // Add Game_Over sprite var gameOverSprite = LK.getAsset('Game_Over', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChild(gameOverSprite); // Play Pierdes music LK.playMusic('Pierdes'); return; // Exit game update loop } } } // Clean up enemies that are too far off screen for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.x < -200 || enemy.x > 2248 || enemy.y < -200 || enemy.y > 2932) { enemy.destroy(); enemies.splice(i, 1); } } }; } // Start cavern background music LK.playMusic('cavern'); // Create the warrior player var guerrero = new Guerrero(); guerrero.x = 2048 / 2; // Center horizontally guerrero.y = 2732 / 2; // Center vertically game.addChild(guerrero); // Player health system var playerHealth = 5; // Score display in bottom right corner var scoreText = new Text2('Puntos: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(1, 1); // Bottom right anchor LK.gui.bottomRight.addChild(scoreText); // Health display in top right corner var healthText = new Text2('Vida: ' + playerHealth.toString(), { size: 60, fill: 0xFFFFFF }); healthText.anchor.set(1, 0); // Top right anchor LK.gui.topRight.addChild(healthText); // Joystick sprite for target indication var joystickSprite = null; // Auto attack timer (every 4 seconds = 4000ms) var autoAttackTimer = 0; var autoAttackInterval = 4000; // Enemy tracking array var enemies = []; // Enemy spawn timer (every 8 seconds = 8000ms) var enemySpawnTimer = 0; var enemySpawnInterval = 8000; // Red slime spawn timer (every 7 seconds = 7000ms) var redSlimeSpawnTimer = 0; var redSlimeSpawnInterval = 7000; // Score tracking for spawn interval reduction var lastScoreCheckpoint = 0; // Track last 10-point milestone var initialBlueSlimeInterval = 8000; // Store original blue slime interval var initialRedSlimeInterval = 7000; // Store original red slime interval // Game over flag to prevent enemy spawning var gameOver = false; // Function to spawn enemy at random edge function spawnEnemy() { var enemy = new SlimeEnemy(); // Choose random edge (0=top, 1=right, 2=bottom, 3=left) var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top edge enemy.x = Math.random() * 2048; enemy.y = -50; break; case 1: // Right edge enemy.x = 2048 + 50; enemy.y = Math.random() * 2732; break; case 2: // Bottom edge enemy.x = Math.random() * 2048; enemy.y = 2732 + 50; break; case 3: // Left edge enemy.x = -50; enemy.y = Math.random() * 2732; break; } enemies.push(enemy); game.addChild(enemy); } // Function to spawn red slime at random edge function spawnRedSlime() { var redSlime = new RedSlimeEnemy(); // Choose random edge (0=top, 1=right, 2=bottom, 3=left) var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top edge redSlime.x = Math.random() * 2048; redSlime.y = -50; break; case 1: // Right edge redSlime.x = 2048 + 50; redSlime.y = Math.random() * 2732; break; case 2: // Bottom edge redSlime.x = Math.random() * 2048; redSlime.y = 2732 + 50; break; case 3: // Left edge redSlime.x = -50; redSlime.y = Math.random() * 2732; break; } enemies.push(redSlime); game.addChild(redSlime); } // Handle touch/mouse down for movement only game.down = function (x, y, obj) { // Check if game is over and restart if clicked if (gameOver) { // Reset game state variables gameOver = false; playerHealth = 5; LK.setScore(0); enemies = []; enemySpawnTimer = 0; redSlimeSpawnTimer = 0; autoAttackTimer = 0; lastScoreCheckpoint = 0; enemySpawnInterval = 8000; redSlimeSpawnInterval = 7000; // Clear all game objects for (var i = game.children.length - 1; i >= 0; i--) { game.children[i].destroy(); } // Recreate ground tiles var groundContainer = new Container(); game.addChild(groundContainer); for (var x = 0; x < tilesX; x++) { for (var y = 0; y < tilesY; y++) { var groundTile = LK.getAsset('Suelo', { x: x * tileWidth, y: y * tileHeight }); groundContainer.addChild(groundTile); } } // Recreate player guerrero = new Guerrero(); guerrero.x = 2048 / 2; guerrero.y = 2732 / 2; game.addChild(guerrero); // Update UI texts scoreText.setText('Puntos: 0'); healthText.setText('Vida: ' + playerHealth.toString()); // Restart background music LK.playMusic('cavern'); return; } // Remove existing joystick if it exists if (joystickSprite) { joystickSprite.destroy(); joystickSprite = null; } // Create new joystick at clicked position joystickSprite = LK.getAsset('joystick', { anchorX: 0.5, anchorY: 0.5, x: x, y: y }); game.addChild(joystickSprite); // Make warrior move to clicked position guerrero.moveToTarget(x, y); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Explosion = Container.expand(function () {
var self = Container.call(this);
// Attach the explosion sprite
var explosionSprite = self.attachAsset('Explosion', {
anchorX: 0.5,
anchorY: 0.5
});
// Animation properties
self.animationTimer = 500; // Animation duration in ms
self.initialScale = 0.1;
self.finalScale = 3.0;
// Set initial scale
explosionSprite.scaleX = self.initialScale;
explosionSprite.scaleY = self.initialScale;
// Start explosion animation
tween(explosionSprite, {
scaleX: self.finalScale,
scaleY: self.finalScale,
alpha: 0
}, {
duration: self.animationTimer,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return self;
});
var Guerrero = Container.expand(function () {
var self = Container.call(this);
// Attach the warrior sprite
var guerreroSprite = self.attachAsset('Guerrero', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement properties
self.speed = 600; // Speed for tween animation
self.isAttacking = false;
self.attackDuration = 300; // Attack animation duration in ms
self.attackTimer = 0;
// Target position for automatic movement
self.targetX = null;
self.targetY = null;
self.isMoving = false;
// Track last movement direction for slash attacks
self.lastDirection = {
x: 1,
y: 0
}; // Default direction (right)
// Update method called every frame
self.update = function () {
// Handle attack animation
if (self.isAttacking) {
self.attackTimer -= 16; // Approximate 60fps
if (self.attackTimer <= 0) {
self.isAttacking = false;
guerreroSprite.rotation = 0;
guerreroSprite.scaleX = 1;
} else {
// Simple attack animation - rotate and scale
var progress = 1 - self.attackTimer / self.attackDuration;
guerreroSprite.rotation = Math.sin(progress * Math.PI) * 0.5;
guerreroSprite.scaleX = 1 + Math.sin(progress * Math.PI) * 0.3;
}
}
};
// Move to target position using tween
self.moveToTarget = function (targetX, targetY) {
// Stop any current movement
tween.stop(self, {
x: true,
y: true
});
// Set new target
self.targetX = targetX;
self.targetY = targetY;
self.isMoving = true;
// Calculate distance for duration
var distance = Math.sqrt(Math.pow(targetX - self.x, 2) + Math.pow(targetY - self.y, 2));
var duration = distance / self.speed * 1000; // Convert to milliseconds
// Update last movement direction
if (distance > 0) {
self.lastDirection.x = (targetX - self.x) / distance;
self.lastDirection.y = (targetY - self.y) / distance;
}
// Start continuous walking animation
self.startWalkingAnimation();
// Start tween to target position
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration,
easing: tween.linear,
onFinish: function onFinish() {
self.isMoving = false;
self.targetX = null;
self.targetY = null;
// Stop walking animation and reset sprite to normal state
tween.stop(guerreroSprite, {
scaleX: true,
scaleY: true
});
guerreroSprite.scaleX = 1;
guerreroSprite.scaleY = 1;
// Hide joystick when target is reached
if (joystickSprite) {
joystickSprite.destroy();
joystickSprite = null;
}
}
});
};
// Attack method
self.attack = function () {
if (!self.isAttacking) {
self.isAttacking = true;
self.attackTimer = self.attackDuration;
// Create and launch slash in last movement direction
self.createSlash();
}
};
// Create slash method
self.createSlash = function () {
var slash = new Slash();
slash.x = self.x;
slash.y = self.y;
// Find the nearest enemy
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
// Set direction towards nearest enemy, or use last direction if no enemies exist
if (nearestEnemy) {
var dx = nearestEnemy.x - self.x;
var dy = nearestEnemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
slash.setDirection(dx / distance, dy / distance);
} else {
slash.setDirection(self.lastDirection.x, self.lastDirection.y);
}
} else {
slash.setDirection(self.lastDirection.x, self.lastDirection.y);
}
game.addChild(slash);
};
// Start continuous walking animation
self.startWalkingAnimation = function () {
self.walkCycle();
};
// Continuous walking cycle animation
self.walkCycle = function () {
if (!self.isMoving) return; // Stop animation if not moving
tween(guerreroSprite, {
scaleX: 1.1,
scaleY: 0.9
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.isMoving) return; // Check again before next cycle
tween(guerreroSprite, {
scaleX: 0.9,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.isMoving) {
self.walkCycle(); // Continue the loop
}
}
});
}
});
};
return self;
});
var RedSlimeEnemy = Container.expand(function () {
var self = Container.call(this);
// Attach the red slime sprite
var slimeSprite = self.attachAsset('Slime_Red', {
anchorX: 0.5,
anchorY: 0.5
});
// Health property - takes 1 hit to destroy
self.health = 1;
// Collision cooldown property - prevents taking damage for 1 second after hit
self.canTakeDamage = true;
// Movement properties
self.speed = 320; // Four times the speed of blue slimes (80 * 4)
// Update method called every frame
self.update = function () {
// Calculate direction towards player
var dx = guerrero.x - self.x;
var dy = guerrero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move towards player if distance > 0
if (distance > 0) {
var normalizedX = dx / distance;
var normalizedY = dy / distance;
self.x += normalizedX * self.speed * (16 / 1000); // 16ms per frame at 60fps
self.y += normalizedY * self.speed * (16 / 1000);
}
};
return self;
});
var Slash = Container.expand(function () {
var self = Container.call(this);
// Attach the slash sprite
var slashSprite = self.attachAsset('tajo', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement properties
self.speed = 3200; // Quadruple fast movement speed
self.directionX = 1; // Movement direction X
self.directionY = 0; // Movement direction Y
// Update method called every frame
self.update = function () {
// Move in the specified direction
self.x += self.directionX * self.speed * (16 / 1000); // 16ms per frame at 60fps
self.y += self.directionY * self.speed * (16 / 1000);
// Check if slash is off screen and destroy it
if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) {
self.destroy();
}
};
// Set direction method
self.setDirection = function (dirX, dirY) {
self.directionX = dirX;
self.directionY = dirY;
// Rotate sprite to match direction
slashSprite.rotation = Math.atan2(dirY, dirX);
};
return self;
});
var SlimeEnemy = Container.expand(function () {
var self = Container.call(this);
// Attach the slime sprite
var slimeSprite = self.attachAsset('slime_blue', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement properties
self.speed = 80; // Slightly faster movement speed
// Update method called every frame
self.update = function () {
// Calculate direction towards player
var dx = guerrero.x - self.x;
var dy = guerrero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move towards player if distance > 0
if (distance > 0) {
var normalizedX = dx / distance;
var normalizedY = dy / distance;
self.x += normalizedX * self.speed * (16 / 1000); // 16ms per frame at 60fps
self.y += normalizedY * self.speed * (16 / 1000);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Calculate how many tiles we need to cover the full screen (2048x2732)
// Create ground background covering the entire screen
var tileWidth = 100;
var tileHeight = 100;
var tilesX = Math.ceil(2048 / tileWidth);
var tilesY = Math.ceil(2732 / tileHeight);
// Create a container for all ground tiles
var groundContainer = new Container();
game.addChild(groundContainer);
// Fill the entire screen with ground tiles
for (var x = 0; x < tilesX; x++) {
for (var y = 0; y < tilesY; y++) {
var groundTile = LK.getAsset('Suelo', {
x: x * tileWidth,
y: y * tileHeight
});
groundContainer.addChild(groundTile);
}
;
// Game update loop
game.update = function () {
// Update enemy spawn timer
enemySpawnTimer += 16; // 16ms per frame at 60fps
// Spawn enemy every 8 seconds (only if game is not over)
if (!gameOver && enemySpawnTimer >= enemySpawnInterval) {
spawnEnemy();
enemySpawnTimer = 0;
}
// Update red slime spawn timer
redSlimeSpawnTimer += 16; // 16ms per frame at 60fps
// Spawn red slime every 7 seconds (only if game is not over)
if (!gameOver && redSlimeSpawnTimer >= redSlimeSpawnInterval) {
spawnRedSlime();
redSlimeSpawnTimer = 0;
}
// Update auto attack timer
autoAttackTimer += 16; // 16ms per frame at 60fps
// Auto attack every 4 seconds
if (autoAttackTimer >= autoAttackInterval) {
guerrero.attack();
autoAttackTimer = 0;
}
// Check for score milestones and reduce spawn intervals
var currentScore = LK.getScore();
var currentCheckpoint = Math.floor(currentScore / 10) * 10;
if (currentCheckpoint > lastScoreCheckpoint && currentCheckpoint > 0) {
// Calculate how many 10-point milestones we've reached
var reductionSteps = currentCheckpoint / 10;
// Reduce intervals by 15% for each 10-point milestone
var reductionFactor = Math.pow(0.85, reductionSteps);
// Apply reduction to both spawn intervals
enemySpawnInterval = Math.max(1000, initialBlueSlimeInterval * reductionFactor); // Minimum 1 second
redSlimeSpawnInterval = Math.max(1000, initialRedSlimeInterval * reductionFactor); // Minimum 1 second
// Update last checkpoint
lastScoreCheckpoint = currentCheckpoint;
}
// Check slash-enemy collisions
var slashes = [];
for (var i = 0; i < game.children.length; i++) {
if (game.children[i] instanceof Slash) {
slashes.push(game.children[i]);
}
}
for (var s = 0; s < slashes.length; s++) {
var slash = slashes[s];
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
if (slash.intersects(enemy)) {
// Check if enemy is a red slime with health system
if (enemy instanceof RedSlimeEnemy && enemy.canTakeDamage) {
enemy.health -= 1;
// Start cooldown period - red slime cannot take damage for 1 second
enemy.canTakeDamage = false;
// Use closure to capture the current enemy instance
(function (currentEnemy) {
tween(currentEnemy, {}, {
duration: 1000,
onFinish: function onFinish() {
currentEnemy.canTakeDamage = true;
}
});
})(enemy);
// Add visual feedback during invulnerability
(function (currentEnemy) {
tween(currentEnemy, {
alpha: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(currentEnemy, {
alpha: 1
}, {
duration: 100
});
}
});
})(enemy);
if (enemy.health <= 0) {
// Create explosion effect at enemy position
var explosion = new Explosion();
explosion.x = enemy.x;
explosion.y = enemy.y;
game.addChild(explosion);
// Award 2 points for red slime destruction
LK.setScore(LK.getScore() + 2);
scoreText.setText('Puntos: ' + LK.getScore());
// Destroy the red slime after 2 hits
enemy.destroy();
enemies.splice(e, 1);
}
// Red slime takes damage but might survive, don't destroy slash
} else {
// Regular blue slime - destroy immediately
var explosion = new Explosion();
explosion.x = enemy.x;
explosion.y = enemy.y;
game.addChild(explosion);
// Award 1 point for blue slime destruction
LK.setScore(LK.getScore() + 1);
scoreText.setText('Puntos: ' + LK.getScore());
// Destroy only the enemy, keep the slash
enemy.destroy();
enemies.splice(e, 1);
}
// Don't break here so slash can hit multiple enemies
}
}
}
// Check player-enemy collisions
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (guerrero.intersects(enemy)) {
// Player loses 1 health point
playerHealth -= 1;
healthText.setText('Vida: ' + playerHealth.toString());
// Play damage sound
LK.getSound('Damage').play();
// Create explosion effect at enemy position
var explosion = new Explosion();
explosion.x = enemy.x;
explosion.y = enemy.y;
game.addChild(explosion);
// Destroy the enemy
enemy.destroy();
enemies.splice(i, 1);
// Check for game over
if (playerHealth <= 0) {
// Set game over flag to prevent enemy spawning
gameOver = true;
// Destroy all sprites except health text
// Destroy all game children (including player, enemies, ground, etc.)
for (var i = game.children.length - 1; i >= 0; i--) {
game.children[i].destroy();
}
// Clear enemies array
enemies = [];
// Add Game_Over sprite
var gameOverSprite = LK.getAsset('Game_Over', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
game.addChild(gameOverSprite);
// Play Pierdes music
LK.playMusic('Pierdes');
return; // Exit game update loop
}
}
}
// Clean up enemies that are too far off screen
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.x < -200 || enemy.x > 2248 || enemy.y < -200 || enemy.y > 2932) {
enemy.destroy();
enemies.splice(i, 1);
}
}
};
}
// Start cavern background music
LK.playMusic('cavern');
// Create the warrior player
var guerrero = new Guerrero();
guerrero.x = 2048 / 2; // Center horizontally
guerrero.y = 2732 / 2; // Center vertically
game.addChild(guerrero);
// Player health system
var playerHealth = 5;
// Score display in bottom right corner
var scoreText = new Text2('Puntos: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 1); // Bottom right anchor
LK.gui.bottomRight.addChild(scoreText);
// Health display in top right corner
var healthText = new Text2('Vida: ' + playerHealth.toString(), {
size: 60,
fill: 0xFFFFFF
});
healthText.anchor.set(1, 0); // Top right anchor
LK.gui.topRight.addChild(healthText);
// Joystick sprite for target indication
var joystickSprite = null;
// Auto attack timer (every 4 seconds = 4000ms)
var autoAttackTimer = 0;
var autoAttackInterval = 4000;
// Enemy tracking array
var enemies = [];
// Enemy spawn timer (every 8 seconds = 8000ms)
var enemySpawnTimer = 0;
var enemySpawnInterval = 8000;
// Red slime spawn timer (every 7 seconds = 7000ms)
var redSlimeSpawnTimer = 0;
var redSlimeSpawnInterval = 7000;
// Score tracking for spawn interval reduction
var lastScoreCheckpoint = 0; // Track last 10-point milestone
var initialBlueSlimeInterval = 8000; // Store original blue slime interval
var initialRedSlimeInterval = 7000; // Store original red slime interval
// Game over flag to prevent enemy spawning
var gameOver = false;
// Function to spawn enemy at random edge
function spawnEnemy() {
var enemy = new SlimeEnemy();
// Choose random edge (0=top, 1=right, 2=bottom, 3=left)
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top edge
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 1:
// Right edge
enemy.x = 2048 + 50;
enemy.y = Math.random() * 2732;
break;
case 2:
// Bottom edge
enemy.x = Math.random() * 2048;
enemy.y = 2732 + 50;
break;
case 3:
// Left edge
enemy.x = -50;
enemy.y = Math.random() * 2732;
break;
}
enemies.push(enemy);
game.addChild(enemy);
}
// Function to spawn red slime at random edge
function spawnRedSlime() {
var redSlime = new RedSlimeEnemy();
// Choose random edge (0=top, 1=right, 2=bottom, 3=left)
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top edge
redSlime.x = Math.random() * 2048;
redSlime.y = -50;
break;
case 1:
// Right edge
redSlime.x = 2048 + 50;
redSlime.y = Math.random() * 2732;
break;
case 2:
// Bottom edge
redSlime.x = Math.random() * 2048;
redSlime.y = 2732 + 50;
break;
case 3:
// Left edge
redSlime.x = -50;
redSlime.y = Math.random() * 2732;
break;
}
enemies.push(redSlime);
game.addChild(redSlime);
}
// Handle touch/mouse down for movement only
game.down = function (x, y, obj) {
// Check if game is over and restart if clicked
if (gameOver) {
// Reset game state variables
gameOver = false;
playerHealth = 5;
LK.setScore(0);
enemies = [];
enemySpawnTimer = 0;
redSlimeSpawnTimer = 0;
autoAttackTimer = 0;
lastScoreCheckpoint = 0;
enemySpawnInterval = 8000;
redSlimeSpawnInterval = 7000;
// Clear all game objects
for (var i = game.children.length - 1; i >= 0; i--) {
game.children[i].destroy();
}
// Recreate ground tiles
var groundContainer = new Container();
game.addChild(groundContainer);
for (var x = 0; x < tilesX; x++) {
for (var y = 0; y < tilesY; y++) {
var groundTile = LK.getAsset('Suelo', {
x: x * tileWidth,
y: y * tileHeight
});
groundContainer.addChild(groundTile);
}
}
// Recreate player
guerrero = new Guerrero();
guerrero.x = 2048 / 2;
guerrero.y = 2732 / 2;
game.addChild(guerrero);
// Update UI texts
scoreText.setText('Puntos: 0');
healthText.setText('Vida: ' + playerHealth.toString());
// Restart background music
LK.playMusic('cavern');
return;
}
// Remove existing joystick if it exists
if (joystickSprite) {
joystickSprite.destroy();
joystickSprite = null;
}
// Create new joystick at clicked position
joystickSprite = LK.getAsset('joystick', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y
});
game.addChild(joystickSprite);
// Make warrior move to clicked position
guerrero.moveToTarget(x, y);
};
Un suelo de una cueva pixelart visto desde arriba, por lo que cubre toda la pantalla. In-Game asset. High contrast. No shadows
Círculo grande con transparencia, dentro un círculo pequeño gris. In-Game asset. 2d. High contrast. No shadows
Retro pixel style
Un slime azul con ojos grandes brillantes. Cute. Pixelart. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Una explosión normal pixelart. In-Game asset. 2d. High contrast. No shadows
Cambia el color a rojo.
Un corazón rojo pixelart. Pixelart. No background. Transparent background. Blank background. 2d. In-Game asset. flat
Fondo negro con un texto rojo pixelart bonito que ponga "GAME OVER". In-Game asset. 2d. High contrast. cute