/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
selectedSkin: 0,
maxWaveCompleted: 0
});
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 15;
self.health = 15;
self.attackPower = 15;
self.speed = 1;
self.lastAttackTime = 0;
self.attackCooldown = 120; // 2 seconds at 60fps
self.attackRange = 80;
self.takeDamage = function (damage) {
self.health = Math.max(0, self.health - damage);
LK.effects.flashObject(self, 0xffffff, 100);
LK.getSound('enemyHit').play();
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
enemies.splice(enemies.indexOf(self), 1);
self.destroy();
checkWaveComplete();
};
self.update = function () {
// Move towards player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.attackRange) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Keep enemy in arena bounds
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var arenaRadius = Math.min(1024, 1366); // Use full screen dimensions
var distFromCenter = Math.sqrt((newX - centerX) * (newX - centerX) + (newY - centerY) * (newY - centerY));
if (distFromCenter <= arenaRadius) {
self.x = newX;
self.y = newY;
}
} else {
// Attack player if in range and cooldown is over
if (LK.ticks - self.lastAttackTime >= self.attackCooldown) {
player.takeDamage(self.attackPower);
self.lastAttackTime = LK.ticks;
}
}
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('fastEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 10;
self.health = 10;
self.attackPower = 10;
self.speed = 2.5;
self.lastAttackTime = 0;
self.attackCooldown = 90; // 1.5 seconds at 60fps
self.attackRange = 60;
self.takeDamage = function (damage) {
self.health = Math.max(0, self.health - damage);
LK.effects.flashObject(self, 0xffffff, 100);
LK.getSound('enemyHit').play();
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
enemies.splice(enemies.indexOf(self), 1);
self.destroy();
checkWaveComplete();
};
self.update = function () {
// Move towards player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.attackRange) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Keep enemy in arena bounds
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var arenaRadius = Math.min(1024, 1366); // Use full screen dimensions
var distFromCenter = Math.sqrt((newX - centerX) * (newX - centerX) + (newY - centerY) * (newY - centerY));
if (distFromCenter <= arenaRadius) {
self.x = newX;
self.y = newY;
}
} else {
// Attack player if in range and cooldown is over
if (LK.ticks - self.lastAttackTime >= self.attackCooldown) {
player.takeDamage(self.attackPower);
self.lastAttackTime = LK.ticks;
}
}
};
return self;
});
var NarrativeText = Container.expand(function () {
var self = Container.call(this);
self.textDisplay = new Text2('', {
size: 40,
fill: 0xFFFFFF
});
self.textDisplay.anchor.set(0.5, 0.5);
self.addChild(self.textDisplay);
self.messages = ["Fight bravely!", "Enemies approach!", "Stay alert!", "Collect power-ups!", "Victory is near!", "Survive the wave!", "Show your strength!", "Battle continues!"];
self.currentMessage = 0;
self.messageTimer = 0;
self.messageDuration = 180; // 3 seconds at 60fps
self.showMessage = function (message) {
self.textDisplay.setText(message);
self.messageTimer = self.messageDuration;
};
self.update = function () {
if (self.messageTimer > 0) {
self.messageTimer--;
self.textDisplay.alpha = Math.min(1, self.messageTimer / 60);
}
// Show random narrative messages
if (LK.ticks % 300 === 0 && Math.random() < 0.3) {
var message = self.messages[Math.floor(Math.random() * self.messages.length)];
self.showMessage(message);
}
};
return self;
});
var Player = Container.expand(function (skinIndex) {
var self = Container.call(this);
var skinAssets = ['player', 'playerSkin1', 'playerSkin2', 'playerSkin3'];
var selectedSkin = skinAssets[skinIndex || 0];
var playerGraphics = self.attachAsset(selectedSkin, {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.health = 100;
self.attackPower = 30;
self.attackBoostTime = 0;
self.lastAttackTime = 0;
self.attackCooldown = 300; // 300ms cooldown between attacks
self.takeDamage = function (damage) {
self.health = Math.max(0, self.health - damage);
LK.effects.flashObject(self, 0xff0000, 200);
LK.getSound('hit').play();
updatePlayerHealthBar();
if (narrativeText) {
narrativeText.showMessage("You take damage!");
}
if (self.health <= 0) {
if (narrativeText) {
narrativeText.showMessage("Game Over!");
}
LK.showGameOver();
}
};
self.heal = function (amount) {
self.health = Math.min(self.maxHealth, self.health + amount);
updatePlayerHealthBar();
};
self.boostAttack = function () {
self.attackBoostTime = LK.ticks + 300; // 5 second boost at 60fps
playerGraphics.tint = 0xffd700;
};
self.attack = function (enemy) {
if (LK.ticks - self.lastAttackTime < self.attackCooldown / (1000 / 60)) return false;
var damage = self.attackPower;
if (LK.ticks < self.attackBoostTime) {
damage *= 2;
}
enemy.takeDamage(damage);
self.lastAttackTime = LK.ticks;
return true;
};
self.update = function () {
if (LK.ticks >= self.attackBoostTime) {
playerGraphics.tint = 0xffffff;
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
var assetName = type === 'health' ? 'healthPotion' : 'attackBooster';
var powerUpGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 600; // 10 seconds at 60fps
self.age = 0;
self.collect = function () {
if (self.type === 'health') {
player.heal(30);
if (narrativeText) {
narrativeText.showMessage("Health restored!");
}
} else {
player.boostAttack();
if (narrativeText) {
narrativeText.showMessage("Attack boosted!");
}
}
LK.getSound('powerup').play();
powerUps.splice(powerUps.indexOf(self), 1);
self.destroy();
};
self.update = function () {
self.age++;
// Pulse effect
var pulse = Math.sin(self.age * 0.2) * 0.2 + 1;
powerUpGraphics.scaleX = pulse;
powerUpGraphics.scaleY = pulse;
// Remove if expired
if (self.age >= self.lifeTime) {
powerUps.splice(powerUps.indexOf(self), 1);
self.destroy();
}
};
return self;
});
var YellowEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('yellowEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
enemyGraphics.tint = 0xffff00; // Yellow tint
self.maxHealth = 25;
self.health = 25;
self.attackPower = 12;
self.speed = 1.5;
self.lastAttackTime = 0;
self.attackCooldown = 150; // 2.5 seconds at 60fps
self.attackRange = 75;
self.takeDamage = function (damage) {
self.health = Math.max(0, self.health - damage);
LK.effects.flashObject(self, 0xffffff, 100);
LK.getSound('enemyHit').play();
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
enemies.splice(enemies.indexOf(self), 1);
self.destroy();
checkWaveComplete();
};
self.update = function () {
// Move towards player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.attackRange) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Keep enemy in arena bounds
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var arenaRadius = Math.min(1024, 1366);
var distFromCenter = Math.sqrt((newX - centerX) * (newX - centerX) + (newY - centerY) * (newY - centerY));
if (distFromCenter <= arenaRadius) {
self.x = newX;
self.y = newY;
}
} else {
// Attack player if in range and cooldown is over
if (LK.ticks - self.lastAttackTime >= self.attackCooldown) {
player.takeDamage(self.attackPower);
self.lastAttackTime = LK.ticks;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var powerUps = [];
var currentWave = 1;
var dragNode = null;
var lastPowerUpSpawn = 0;
var narrativeText;
var startMenu;
var gameStarted = false;
var selectedSkin = storage.selectedSkin || 0;
var skinMenu;
var showingSkins = false;
// UI elements
var waveText;
var playerHealthBar;
var playerHealthBarBg;
// Create arena
var arena = game.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
// Create player
player = game.addChild(new Player(selectedSkin));
player.x = 2048 / 2;
player.y = 2732 / 2;
// Create UI
waveText = new Text2('Wave 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
waveText.y = 100;
// Health bar background
playerHealthBarBg = LK.gui.bottomLeft.addChild(LK.getAsset('healthBarBg', {
x: 100,
y: -100
}));
// Health bar
playerHealthBar = LK.gui.bottomLeft.addChild(LK.getAsset('healthBar', {
x: 100,
y: -100
}));
// Initialize narrative system
narrativeText = new NarrativeText();
narrativeText.x = 2048 / 2;
narrativeText.y = 200;
LK.gui.center.addChild(narrativeText);
// Create start menu
startMenu = new Container();
game.addChild(startMenu);
// Menu background
var menuBg = startMenu.addChild(LK.getAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
// Game title image
var titleImage = startMenu.addChild(LK.getAsset('gameTitle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 800
}));
// Play button image
var playButtonImage = startMenu.addChild(LK.getAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1500,
scaleX: 1.5,
scaleY: 1.5
}));
// Skins button image
var skinsButtonImage = startMenu.addChild(LK.getAsset('skinsButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1650,
scaleX: 1.5,
scaleY: 1.5
}));
// Instructions text
var instructionsText = new Text2('Drag to move • Touch enemies to attack\nCollect power-ups • Survive the waves!', {
size: 40,
fill: 0xCCCCCC
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 2048 / 2;
instructionsText.y = 1950;
startMenu.addChild(instructionsText);
// Create skin selection menu
skinMenu = new Container();
game.addChild(skinMenu);
// Skin menu background
var skinMenuBg = skinMenu.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0.9
}));
// Skin menu title
var skinTitleText = new Text2('SELECT SKIN', {
size: 100,
fill: 0xFFD700
});
skinTitleText.anchor.set(0.5, 0.5);
skinTitleText.x = 2048 / 2;
skinTitleText.y = 600;
skinMenu.addChild(skinTitleText);
// Create skin options
var skinOptions = [];
var skinNames = ['Default', 'Warrior', 'Speed', 'Power'];
var skinAssets = ['player', 'playerSkin1', 'playerSkin2', 'playerSkin3'];
for (var s = 0; s < 4; s++) {
var skinOption = new Container();
skinOption.skinIndex = s;
// Skin preview
var skinPreview = skinOption.addChild(LK.getAsset(skinAssets[s], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
}));
// Skin name
var skinNameText = new Text2(skinNames[s], {
size: 50,
fill: 0xFFFFFF
});
skinNameText.anchor.set(0.5, 0.5);
skinNameText.y = 150;
skinOption.addChild(skinNameText);
// Locked text (only for skin 3)
if (s === 3) {
var lockedText = new Text2('Complete Wave 6', {
size: 30,
fill: 0xFF6666
});
lockedText.anchor.set(0.5, 0.5);
lockedText.y = 200;
skinOption.addChild(lockedText);
skinOption.lockedText = lockedText;
}
// Selection border
var selectionBorder = skinOption.addChild(LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
alpha: 0
}));
skinOption.selectionBorder = selectionBorder;
// Position skin options in a 2x2 grid
var col = s % 2;
var row = Math.floor(s / 2);
skinOption.x = 2048 / 2 + (col - 0.5) * 400;
skinOption.y = 1000 + row * 300;
skinMenu.addChild(skinOption);
skinOptions.push(skinOption);
}
// Back button
var backButtonBg = skinMenu.addChild(LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2200,
scaleX: 3,
scaleY: 2
}));
var backButtonText = new Text2('BACK', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 2048 / 2;
backButtonText.y = 2200;
skinMenu.addChild(backButtonText);
// Update selection borders
function isSkinUnlocked(skinIndex) {
if (skinIndex <= 2) return true; // First 3 skins always unlocked
if (skinIndex === 3) return storage.maxWaveCompleted >= 6; // Player 3 unlocked after wave 6
return false;
}
function updateSkinSelection() {
for (var i = 0; i < skinOptions.length; i++) {
var isUnlocked = isSkinUnlocked(i);
var skinOption = skinOptions[i];
// Update locked text visibility
if (skinOption.lockedText) {
skinOption.lockedText.visible = !isUnlocked;
}
// Update visual appearance based on unlock status
if (!isUnlocked) {
skinOption.alpha = 0.5;
skinOption.selectionBorder.alpha = 0.3;
skinOption.selectionBorder.tint = 0xFF0000;
} else {
skinOption.alpha = 1.0;
if (i === selectedSkin) {
skinOption.selectionBorder.alpha = 0.8;
skinOption.selectionBorder.tint = 0x00FF00;
} else {
skinOption.selectionBorder.alpha = 0;
}
}
}
}
updateSkinSelection();
skinMenu.visible = false;
// Hide game elements initially
arena.visible = false;
player.visible = false;
waveText.visible = false;
playerHealthBar.visible = false;
playerHealthBarBg.visible = false;
narrativeText.visible = false;
function startGame() {
gameStarted = true;
startMenu.visible = false;
// Show game elements
arena.visible = true;
player.visible = true;
waveText.visible = true;
playerHealthBar.visible = true;
playerHealthBarBg.visible = true;
narrativeText.visible = true;
// Play battle music
LK.playMusic('Musicadebatalla');
// Start first wave
spawnWave(currentWave);
}
function updatePlayerHealthBar() {
var healthPercent = player.health / player.maxHealth;
playerHealthBar.scaleX = healthPercent;
}
function spawnWave(waveNumber) {
// Change arena starting from wave 5
if (waveNumber >= 5) {
arena.destroy();
arena = game.addChild(LK.getAsset('arena2', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
}
var enemyCount = Math.min(4 + waveNumber * 2, 15);
var fastEnemyCount = Math.max(0, Math.floor(waveNumber / 2) + waveNumber - 1);
var yellowEnemyCount = 0;
if (waveNumber >= 4) {
yellowEnemyCount = 3;
}
for (var i = 0; i < enemyCount; i++) {
spawnEnemy();
}
for (var j = 0; j < fastEnemyCount; j++) {
spawnFastEnemy();
}
for (var l = 0; l < yellowEnemyCount; l++) {
spawnYellowEnemy();
}
waveText.setText('Wave ' + waveNumber);
narrativeText.showMessage("Wave " + waveNumber + " begins!");
}
function spawnEnemy() {
var enemy = game.addChild(new Enemy());
// Spawn at random position on arena edge
var angle = Math.random() * Math.PI * 2;
var radius = Math.min(1000, 1300); // Spawn near fullscreen edge
var centerX = 2048 / 2;
var centerY = 2732 / 2;
enemy.x = centerX + Math.cos(angle) * radius;
enemy.y = centerY + Math.sin(angle) * radius;
enemies.push(enemy);
}
function spawnFastEnemy() {
var enemy = game.addChild(new FastEnemy());
// Spawn at random position on arena edge
var angle = Math.random() * Math.PI * 2;
var radius = Math.min(1000, 1300); // Spawn near fullscreen edge
var centerX = 2048 / 2;
var centerY = 2732 / 2;
enemy.x = centerX + Math.cos(angle) * radius;
enemy.y = centerY + Math.sin(angle) * radius;
enemies.push(enemy);
}
function spawnPowerUp() {
var type = Math.random() < 0.6 ? 'health' : 'attack';
var powerUp = game.addChild(new PowerUp(type));
// Spawn at random position in arena
var angle = Math.random() * Math.PI * 2;
var radius = Math.random() * Math.min(1000, 1300); // Use fullscreen dimensions
var centerX = 2048 / 2;
var centerY = 2732 / 2;
powerUp.x = centerX + Math.cos(angle) * radius;
powerUp.y = centerY + Math.sin(angle) * radius;
powerUps.push(powerUp);
}
function checkWaveComplete() {
if (enemies.length === 0) {
currentWave++;
LK.setScore(currentWave - 1);
// Update max wave completed in storage
if (currentWave - 1 > storage.maxWaveCompleted) {
storage.maxWaveCompleted = currentWave - 1;
}
// Small delay before next wave
LK.setTimeout(function () {
spawnWave(currentWave);
}, 2000);
}
}
function isInArena(x, y) {
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var distance = Math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY));
return distance <= Math.min(1024, 1366); // Use fullscreen dimensions
}
// Touch controls
game.down = function (x, y, obj) {
if (!gameStarted) {
if (showingSkins) {
// Handle skin menu interactions
// Check skin selections
for (var i = 0; i < skinOptions.length; i++) {
var option = skinOptions[i];
var distance = Math.sqrt((x - option.x) * (x - option.x) + (y - option.y) * (y - option.y));
if (distance < 120) {
// Only allow selection if skin is unlocked
if (isSkinUnlocked(option.skinIndex)) {
selectedSkin = option.skinIndex;
storage.selectedSkin = selectedSkin;
updateSkinSelection();
// Recreate player with new skin
player.destroy();
player = game.addChild(new Player(selectedSkin));
player.x = 2048 / 2;
player.y = 2732 / 2;
player.visible = false;
}
return;
}
}
// Check back button
var backButtonCenterX = 2048 / 2;
var backButtonCenterY = 2200;
var backButtonWidth = 200 * 3;
var backButtonHeight = 20 * 2;
if (x >= backButtonCenterX - backButtonWidth / 2 && x <= backButtonCenterX + backButtonWidth / 2 && y >= backButtonCenterY - backButtonHeight / 2 && y <= backButtonCenterY + backButtonHeight / 2) {
showingSkins = false;
skinMenu.visible = false;
startMenu.visible = true;
return;
}
} else {
// Check if play button was clicked
var buttonCenterX = 2048 / 2;
var buttonCenterY = 1500;
var buttonWidth = 400 * 1.5; // play button image width scaled up
var buttonHeight = 120 * 1.5; // play button image height scaled up
if (x >= buttonCenterX - buttonWidth / 2 && x <= buttonCenterX + buttonWidth / 2 && y >= buttonCenterY - buttonHeight / 2 && y <= buttonCenterY + buttonHeight / 2) {
startGame();
return;
}
// Check if skins button was clicked
var skinsButtonCenterX = 2048 / 2;
var skinsButtonCenterY = 1650;
var skinsButtonWidth = 600 * 1.5; // skins button image width scaled up
var skinsButtonHeight = 150 * 1.5; // skins button image height scaled up
if (x >= skinsButtonCenterX - skinsButtonWidth / 2 && x <= skinsButtonCenterX + skinsButtonWidth / 2 && y >= skinsButtonCenterY - skinsButtonHeight / 2 && y <= skinsButtonCenterY + skinsButtonHeight / 2) {
showingSkins = true;
startMenu.visible = false;
skinMenu.visible = true;
return;
}
}
return;
}
if (isInArena(x, y)) {
dragNode = player;
player.x = x;
player.y = y;
}
};
game.move = function (x, y, obj) {
if (dragNode && isInArena(x, y)) {
dragNode.x = x;
dragNode.y = y;
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game loop
game.update = function () {
if (!gameStarted) return;
// Update narrative system
narrativeText.update();
// Check player attacks on enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var distance = Math.sqrt((player.x - enemy.x) * (player.x - enemy.x) + (player.y - enemy.y) * (player.y - enemy.y));
if (distance < 70) {
player.attack(enemy);
}
}
// Check power-up collection
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
var distance = Math.sqrt((player.x - powerUp.x) * (player.x - powerUp.x) + (player.y - powerUp.y) * (player.y - powerUp.y));
if (distance < 50) {
powerUp.collect();
}
}
// Spawn power-ups occasionally
if (LK.ticks - lastPowerUpSpawn > 300 && Math.random() < 0.02) {
if (powerUps.length < 3) {
spawnPowerUp();
lastPowerUpSpawn = LK.ticks;
}
}
};
function spawnYellowEnemy() {
var enemy = game.addChild(new YellowEnemy());
// Spawn at random position on arena edge
var angle = Math.random() * Math.PI * 2;
var radius = Math.min(1000, 1300); // Spawn near fullscreen edge
var centerX = 2048 / 2;
var centerY = 2732 / 2;
enemy.x = centerX + Math.cos(angle) * radius;
enemy.y = centerY + Math.sin(angle) * radius;
enemies.push(enemy);
} /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
selectedSkin: 0,
maxWaveCompleted: 0
});
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 15;
self.health = 15;
self.attackPower = 15;
self.speed = 1;
self.lastAttackTime = 0;
self.attackCooldown = 120; // 2 seconds at 60fps
self.attackRange = 80;
self.takeDamage = function (damage) {
self.health = Math.max(0, self.health - damage);
LK.effects.flashObject(self, 0xffffff, 100);
LK.getSound('enemyHit').play();
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
enemies.splice(enemies.indexOf(self), 1);
self.destroy();
checkWaveComplete();
};
self.update = function () {
// Move towards player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.attackRange) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Keep enemy in arena bounds
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var arenaRadius = Math.min(1024, 1366); // Use full screen dimensions
var distFromCenter = Math.sqrt((newX - centerX) * (newX - centerX) + (newY - centerY) * (newY - centerY));
if (distFromCenter <= arenaRadius) {
self.x = newX;
self.y = newY;
}
} else {
// Attack player if in range and cooldown is over
if (LK.ticks - self.lastAttackTime >= self.attackCooldown) {
player.takeDamage(self.attackPower);
self.lastAttackTime = LK.ticks;
}
}
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('fastEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 10;
self.health = 10;
self.attackPower = 10;
self.speed = 2.5;
self.lastAttackTime = 0;
self.attackCooldown = 90; // 1.5 seconds at 60fps
self.attackRange = 60;
self.takeDamage = function (damage) {
self.health = Math.max(0, self.health - damage);
LK.effects.flashObject(self, 0xffffff, 100);
LK.getSound('enemyHit').play();
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
enemies.splice(enemies.indexOf(self), 1);
self.destroy();
checkWaveComplete();
};
self.update = function () {
// Move towards player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.attackRange) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Keep enemy in arena bounds
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var arenaRadius = Math.min(1024, 1366); // Use full screen dimensions
var distFromCenter = Math.sqrt((newX - centerX) * (newX - centerX) + (newY - centerY) * (newY - centerY));
if (distFromCenter <= arenaRadius) {
self.x = newX;
self.y = newY;
}
} else {
// Attack player if in range and cooldown is over
if (LK.ticks - self.lastAttackTime >= self.attackCooldown) {
player.takeDamage(self.attackPower);
self.lastAttackTime = LK.ticks;
}
}
};
return self;
});
var NarrativeText = Container.expand(function () {
var self = Container.call(this);
self.textDisplay = new Text2('', {
size: 40,
fill: 0xFFFFFF
});
self.textDisplay.anchor.set(0.5, 0.5);
self.addChild(self.textDisplay);
self.messages = ["Fight bravely!", "Enemies approach!", "Stay alert!", "Collect power-ups!", "Victory is near!", "Survive the wave!", "Show your strength!", "Battle continues!"];
self.currentMessage = 0;
self.messageTimer = 0;
self.messageDuration = 180; // 3 seconds at 60fps
self.showMessage = function (message) {
self.textDisplay.setText(message);
self.messageTimer = self.messageDuration;
};
self.update = function () {
if (self.messageTimer > 0) {
self.messageTimer--;
self.textDisplay.alpha = Math.min(1, self.messageTimer / 60);
}
// Show random narrative messages
if (LK.ticks % 300 === 0 && Math.random() < 0.3) {
var message = self.messages[Math.floor(Math.random() * self.messages.length)];
self.showMessage(message);
}
};
return self;
});
var Player = Container.expand(function (skinIndex) {
var self = Container.call(this);
var skinAssets = ['player', 'playerSkin1', 'playerSkin2', 'playerSkin3'];
var selectedSkin = skinAssets[skinIndex || 0];
var playerGraphics = self.attachAsset(selectedSkin, {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.health = 100;
self.attackPower = 30;
self.attackBoostTime = 0;
self.lastAttackTime = 0;
self.attackCooldown = 300; // 300ms cooldown between attacks
self.takeDamage = function (damage) {
self.health = Math.max(0, self.health - damage);
LK.effects.flashObject(self, 0xff0000, 200);
LK.getSound('hit').play();
updatePlayerHealthBar();
if (narrativeText) {
narrativeText.showMessage("You take damage!");
}
if (self.health <= 0) {
if (narrativeText) {
narrativeText.showMessage("Game Over!");
}
LK.showGameOver();
}
};
self.heal = function (amount) {
self.health = Math.min(self.maxHealth, self.health + amount);
updatePlayerHealthBar();
};
self.boostAttack = function () {
self.attackBoostTime = LK.ticks + 300; // 5 second boost at 60fps
playerGraphics.tint = 0xffd700;
};
self.attack = function (enemy) {
if (LK.ticks - self.lastAttackTime < self.attackCooldown / (1000 / 60)) return false;
var damage = self.attackPower;
if (LK.ticks < self.attackBoostTime) {
damage *= 2;
}
enemy.takeDamage(damage);
self.lastAttackTime = LK.ticks;
return true;
};
self.update = function () {
if (LK.ticks >= self.attackBoostTime) {
playerGraphics.tint = 0xffffff;
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
var assetName = type === 'health' ? 'healthPotion' : 'attackBooster';
var powerUpGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 600; // 10 seconds at 60fps
self.age = 0;
self.collect = function () {
if (self.type === 'health') {
player.heal(30);
if (narrativeText) {
narrativeText.showMessage("Health restored!");
}
} else {
player.boostAttack();
if (narrativeText) {
narrativeText.showMessage("Attack boosted!");
}
}
LK.getSound('powerup').play();
powerUps.splice(powerUps.indexOf(self), 1);
self.destroy();
};
self.update = function () {
self.age++;
// Pulse effect
var pulse = Math.sin(self.age * 0.2) * 0.2 + 1;
powerUpGraphics.scaleX = pulse;
powerUpGraphics.scaleY = pulse;
// Remove if expired
if (self.age >= self.lifeTime) {
powerUps.splice(powerUps.indexOf(self), 1);
self.destroy();
}
};
return self;
});
var YellowEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('yellowEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
enemyGraphics.tint = 0xffff00; // Yellow tint
self.maxHealth = 25;
self.health = 25;
self.attackPower = 12;
self.speed = 1.5;
self.lastAttackTime = 0;
self.attackCooldown = 150; // 2.5 seconds at 60fps
self.attackRange = 75;
self.takeDamage = function (damage) {
self.health = Math.max(0, self.health - damage);
LK.effects.flashObject(self, 0xffffff, 100);
LK.getSound('enemyHit').play();
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
enemies.splice(enemies.indexOf(self), 1);
self.destroy();
checkWaveComplete();
};
self.update = function () {
// Move towards player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.attackRange) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Keep enemy in arena bounds
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var arenaRadius = Math.min(1024, 1366);
var distFromCenter = Math.sqrt((newX - centerX) * (newX - centerX) + (newY - centerY) * (newY - centerY));
if (distFromCenter <= arenaRadius) {
self.x = newX;
self.y = newY;
}
} else {
// Attack player if in range and cooldown is over
if (LK.ticks - self.lastAttackTime >= self.attackCooldown) {
player.takeDamage(self.attackPower);
self.lastAttackTime = LK.ticks;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var powerUps = [];
var currentWave = 1;
var dragNode = null;
var lastPowerUpSpawn = 0;
var narrativeText;
var startMenu;
var gameStarted = false;
var selectedSkin = storage.selectedSkin || 0;
var skinMenu;
var showingSkins = false;
// UI elements
var waveText;
var playerHealthBar;
var playerHealthBarBg;
// Create arena
var arena = game.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
// Create player
player = game.addChild(new Player(selectedSkin));
player.x = 2048 / 2;
player.y = 2732 / 2;
// Create UI
waveText = new Text2('Wave 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
waveText.y = 100;
// Health bar background
playerHealthBarBg = LK.gui.bottomLeft.addChild(LK.getAsset('healthBarBg', {
x: 100,
y: -100
}));
// Health bar
playerHealthBar = LK.gui.bottomLeft.addChild(LK.getAsset('healthBar', {
x: 100,
y: -100
}));
// Initialize narrative system
narrativeText = new NarrativeText();
narrativeText.x = 2048 / 2;
narrativeText.y = 200;
LK.gui.center.addChild(narrativeText);
// Create start menu
startMenu = new Container();
game.addChild(startMenu);
// Menu background
var menuBg = startMenu.addChild(LK.getAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
// Game title image
var titleImage = startMenu.addChild(LK.getAsset('gameTitle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 800
}));
// Play button image
var playButtonImage = startMenu.addChild(LK.getAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1500,
scaleX: 1.5,
scaleY: 1.5
}));
// Skins button image
var skinsButtonImage = startMenu.addChild(LK.getAsset('skinsButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1650,
scaleX: 1.5,
scaleY: 1.5
}));
// Instructions text
var instructionsText = new Text2('Drag to move • Touch enemies to attack\nCollect power-ups • Survive the waves!', {
size: 40,
fill: 0xCCCCCC
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 2048 / 2;
instructionsText.y = 1950;
startMenu.addChild(instructionsText);
// Create skin selection menu
skinMenu = new Container();
game.addChild(skinMenu);
// Skin menu background
var skinMenuBg = skinMenu.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0.9
}));
// Skin menu title
var skinTitleText = new Text2('SELECT SKIN', {
size: 100,
fill: 0xFFD700
});
skinTitleText.anchor.set(0.5, 0.5);
skinTitleText.x = 2048 / 2;
skinTitleText.y = 600;
skinMenu.addChild(skinTitleText);
// Create skin options
var skinOptions = [];
var skinNames = ['Default', 'Warrior', 'Speed', 'Power'];
var skinAssets = ['player', 'playerSkin1', 'playerSkin2', 'playerSkin3'];
for (var s = 0; s < 4; s++) {
var skinOption = new Container();
skinOption.skinIndex = s;
// Skin preview
var skinPreview = skinOption.addChild(LK.getAsset(skinAssets[s], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
}));
// Skin name
var skinNameText = new Text2(skinNames[s], {
size: 50,
fill: 0xFFFFFF
});
skinNameText.anchor.set(0.5, 0.5);
skinNameText.y = 150;
skinOption.addChild(skinNameText);
// Locked text (only for skin 3)
if (s === 3) {
var lockedText = new Text2('Complete Wave 6', {
size: 30,
fill: 0xFF6666
});
lockedText.anchor.set(0.5, 0.5);
lockedText.y = 200;
skinOption.addChild(lockedText);
skinOption.lockedText = lockedText;
}
// Selection border
var selectionBorder = skinOption.addChild(LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
alpha: 0
}));
skinOption.selectionBorder = selectionBorder;
// Position skin options in a 2x2 grid
var col = s % 2;
var row = Math.floor(s / 2);
skinOption.x = 2048 / 2 + (col - 0.5) * 400;
skinOption.y = 1000 + row * 300;
skinMenu.addChild(skinOption);
skinOptions.push(skinOption);
}
// Back button
var backButtonBg = skinMenu.addChild(LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2200,
scaleX: 3,
scaleY: 2
}));
var backButtonText = new Text2('BACK', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 2048 / 2;
backButtonText.y = 2200;
skinMenu.addChild(backButtonText);
// Update selection borders
function isSkinUnlocked(skinIndex) {
if (skinIndex <= 2) return true; // First 3 skins always unlocked
if (skinIndex === 3) return storage.maxWaveCompleted >= 6; // Player 3 unlocked after wave 6
return false;
}
function updateSkinSelection() {
for (var i = 0; i < skinOptions.length; i++) {
var isUnlocked = isSkinUnlocked(i);
var skinOption = skinOptions[i];
// Update locked text visibility
if (skinOption.lockedText) {
skinOption.lockedText.visible = !isUnlocked;
}
// Update visual appearance based on unlock status
if (!isUnlocked) {
skinOption.alpha = 0.5;
skinOption.selectionBorder.alpha = 0.3;
skinOption.selectionBorder.tint = 0xFF0000;
} else {
skinOption.alpha = 1.0;
if (i === selectedSkin) {
skinOption.selectionBorder.alpha = 0.8;
skinOption.selectionBorder.tint = 0x00FF00;
} else {
skinOption.selectionBorder.alpha = 0;
}
}
}
}
updateSkinSelection();
skinMenu.visible = false;
// Hide game elements initially
arena.visible = false;
player.visible = false;
waveText.visible = false;
playerHealthBar.visible = false;
playerHealthBarBg.visible = false;
narrativeText.visible = false;
function startGame() {
gameStarted = true;
startMenu.visible = false;
// Show game elements
arena.visible = true;
player.visible = true;
waveText.visible = true;
playerHealthBar.visible = true;
playerHealthBarBg.visible = true;
narrativeText.visible = true;
// Play battle music
LK.playMusic('Musicadebatalla');
// Start first wave
spawnWave(currentWave);
}
function updatePlayerHealthBar() {
var healthPercent = player.health / player.maxHealth;
playerHealthBar.scaleX = healthPercent;
}
function spawnWave(waveNumber) {
// Change arena starting from wave 5
if (waveNumber >= 5) {
arena.destroy();
arena = game.addChild(LK.getAsset('arena2', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
}
var enemyCount = Math.min(4 + waveNumber * 2, 15);
var fastEnemyCount = Math.max(0, Math.floor(waveNumber / 2) + waveNumber - 1);
var yellowEnemyCount = 0;
if (waveNumber >= 4) {
yellowEnemyCount = 3;
}
for (var i = 0; i < enemyCount; i++) {
spawnEnemy();
}
for (var j = 0; j < fastEnemyCount; j++) {
spawnFastEnemy();
}
for (var l = 0; l < yellowEnemyCount; l++) {
spawnYellowEnemy();
}
waveText.setText('Wave ' + waveNumber);
narrativeText.showMessage("Wave " + waveNumber + " begins!");
}
function spawnEnemy() {
var enemy = game.addChild(new Enemy());
// Spawn at random position on arena edge
var angle = Math.random() * Math.PI * 2;
var radius = Math.min(1000, 1300); // Spawn near fullscreen edge
var centerX = 2048 / 2;
var centerY = 2732 / 2;
enemy.x = centerX + Math.cos(angle) * radius;
enemy.y = centerY + Math.sin(angle) * radius;
enemies.push(enemy);
}
function spawnFastEnemy() {
var enemy = game.addChild(new FastEnemy());
// Spawn at random position on arena edge
var angle = Math.random() * Math.PI * 2;
var radius = Math.min(1000, 1300); // Spawn near fullscreen edge
var centerX = 2048 / 2;
var centerY = 2732 / 2;
enemy.x = centerX + Math.cos(angle) * radius;
enemy.y = centerY + Math.sin(angle) * radius;
enemies.push(enemy);
}
function spawnPowerUp() {
var type = Math.random() < 0.6 ? 'health' : 'attack';
var powerUp = game.addChild(new PowerUp(type));
// Spawn at random position in arena
var angle = Math.random() * Math.PI * 2;
var radius = Math.random() * Math.min(1000, 1300); // Use fullscreen dimensions
var centerX = 2048 / 2;
var centerY = 2732 / 2;
powerUp.x = centerX + Math.cos(angle) * radius;
powerUp.y = centerY + Math.sin(angle) * radius;
powerUps.push(powerUp);
}
function checkWaveComplete() {
if (enemies.length === 0) {
currentWave++;
LK.setScore(currentWave - 1);
// Update max wave completed in storage
if (currentWave - 1 > storage.maxWaveCompleted) {
storage.maxWaveCompleted = currentWave - 1;
}
// Small delay before next wave
LK.setTimeout(function () {
spawnWave(currentWave);
}, 2000);
}
}
function isInArena(x, y) {
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var distance = Math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY));
return distance <= Math.min(1024, 1366); // Use fullscreen dimensions
}
// Touch controls
game.down = function (x, y, obj) {
if (!gameStarted) {
if (showingSkins) {
// Handle skin menu interactions
// Check skin selections
for (var i = 0; i < skinOptions.length; i++) {
var option = skinOptions[i];
var distance = Math.sqrt((x - option.x) * (x - option.x) + (y - option.y) * (y - option.y));
if (distance < 120) {
// Only allow selection if skin is unlocked
if (isSkinUnlocked(option.skinIndex)) {
selectedSkin = option.skinIndex;
storage.selectedSkin = selectedSkin;
updateSkinSelection();
// Recreate player with new skin
player.destroy();
player = game.addChild(new Player(selectedSkin));
player.x = 2048 / 2;
player.y = 2732 / 2;
player.visible = false;
}
return;
}
}
// Check back button
var backButtonCenterX = 2048 / 2;
var backButtonCenterY = 2200;
var backButtonWidth = 200 * 3;
var backButtonHeight = 20 * 2;
if (x >= backButtonCenterX - backButtonWidth / 2 && x <= backButtonCenterX + backButtonWidth / 2 && y >= backButtonCenterY - backButtonHeight / 2 && y <= backButtonCenterY + backButtonHeight / 2) {
showingSkins = false;
skinMenu.visible = false;
startMenu.visible = true;
return;
}
} else {
// Check if play button was clicked
var buttonCenterX = 2048 / 2;
var buttonCenterY = 1500;
var buttonWidth = 400 * 1.5; // play button image width scaled up
var buttonHeight = 120 * 1.5; // play button image height scaled up
if (x >= buttonCenterX - buttonWidth / 2 && x <= buttonCenterX + buttonWidth / 2 && y >= buttonCenterY - buttonHeight / 2 && y <= buttonCenterY + buttonHeight / 2) {
startGame();
return;
}
// Check if skins button was clicked
var skinsButtonCenterX = 2048 / 2;
var skinsButtonCenterY = 1650;
var skinsButtonWidth = 600 * 1.5; // skins button image width scaled up
var skinsButtonHeight = 150 * 1.5; // skins button image height scaled up
if (x >= skinsButtonCenterX - skinsButtonWidth / 2 && x <= skinsButtonCenterX + skinsButtonWidth / 2 && y >= skinsButtonCenterY - skinsButtonHeight / 2 && y <= skinsButtonCenterY + skinsButtonHeight / 2) {
showingSkins = true;
startMenu.visible = false;
skinMenu.visible = true;
return;
}
}
return;
}
if (isInArena(x, y)) {
dragNode = player;
player.x = x;
player.y = y;
}
};
game.move = function (x, y, obj) {
if (dragNode && isInArena(x, y)) {
dragNode.x = x;
dragNode.y = y;
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game loop
game.update = function () {
if (!gameStarted) return;
// Update narrative system
narrativeText.update();
// Check player attacks on enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var distance = Math.sqrt((player.x - enemy.x) * (player.x - enemy.x) + (player.y - enemy.y) * (player.y - enemy.y));
if (distance < 70) {
player.attack(enemy);
}
}
// Check power-up collection
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
var distance = Math.sqrt((player.x - powerUp.x) * (player.x - powerUp.x) + (player.y - powerUp.y) * (player.y - powerUp.y));
if (distance < 50) {
powerUp.collect();
}
}
// Spawn power-ups occasionally
if (LK.ticks - lastPowerUpSpawn > 300 && Math.random() < 0.02) {
if (powerUps.length < 3) {
spawnPowerUp();
lastPowerUpSpawn = LK.ticks;
}
}
};
function spawnYellowEnemy() {
var enemy = game.addChild(new YellowEnemy());
// Spawn at random position on arena edge
var angle = Math.random() * Math.PI * 2;
var radius = Math.min(1000, 1300); // Spawn near fullscreen edge
var centerX = 2048 / 2;
var centerY = 2732 / 2;
enemy.x = centerX + Math.cos(angle) * radius;
enemy.y = centerY + Math.sin(angle) * radius;
enemies.push(enemy);
}
Dio. In-Game asset. 2d. High contrast. No shadows
Star platinum jojo. In-Game asset. 2d. High contrast. No shadows
Un hombre con pelo largo color rosado con manchas negras y sin camisa con pantalón morado jojo's. In-Game asset. 2d. High contrast. No shadows
Jotaro con cuerpo y que se vea su cabeza jojo's. In-Game asset. 2d. High contrast. No shadows
Egipto Scenery. In-Game asset. 2d. High contrast. No shadows
Point. In-Game asset. 2d. High contrast. No shadows
Barra de vida jojo's. In-Game asset. 2d. High contrast. No shadows
Star platinum jotaro con cuerpo completo jojo's. In-Game asset. 2d. High contrast. No shadows
Bala. In-Game asset. 2d. High contrast. No shadows
Kars cuerpo completo jojo's. In-Game asset. 2d. High contrast. No shadows
Jolyne cuerpo completo jojo's. In-Game asset. 2d. High contrast. No shadows
Kakyoin cuerpo completo jojo's. In-Game asset. 2d. High contrast. No shadows
Un pueblo con casa y un piso café jojo's. In-Game asset. 2d. High contrast. No shadows
Hazlo grande