User prompt
Make so that you need magnet evolution to pull yellow orbs on long range if player do not have it use base magnet range
User prompt
when picking evolution only red star should be filled
User prompt
make less enemys
User prompt
change magnet evolution I to "can pull yellow xp orbs"
User prompt
tiny bit lower upgrades
User prompt
put the upgrades little bit more up
User prompt
make the gray background behind the upgrades bigger
User prompt
make the background of upgrade chosies bigger
User prompt
make all enemys a bit faster
User prompt
make on wave 5 a new heavy enemy appears having more hp and is slower and drop yellow xp orb that is little bigger and worth 3 times the blue orbs xp
User prompt
make evolution upgrade box darker
User prompt
make the red star be below the first star on the left
User prompt
when the first magnet upgrade have been picked after evolution next upgrade the red star dissapears and 2 yellow stars are there when the red star should remain and only be 1 yellow star
User prompt
When doing evolution only the red star should be active and make it same bright as yellow stars
User prompt
make so when having evolution I the star below the middle gets red and after having evolution I the name and color of the upgrade turns normal
User prompt
make so when having evolution on magnet the 5 first stars will be as having 0 stars but the upgrades remain and 5 more levels
User prompt
make the red little darker like the other boxes
User prompt
rename level 6 of magnet from magnet to magnet evolution I and make the box red when the evolution is
User prompt
make the 6th star only show when have 5 stars and make little space between all stars
User prompt
make the 6 star below the one in the middle
User prompt
Make the magnet evolution the 6 level of magnet
User prompt
make a new magnet evolution after having 5 stars on magnet. Magnet pulling speed + 100%
User prompt
make enemys spawn faster
User prompt
make speedy appear on wave 3 first and 20% less hp and 20% more speed
User prompt
Make them go in same direction
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Arrow = Container.expand(function () {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = baseArrowDamage;
self.directionX = 0;
self.directionY = 0;
self.lastEnemyCollisions = [];
self.setDirection = function (dx, dy) {
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
self.rotation = Math.atan2(dy, dx);
}
};
self.update = function () {
var actualSpeed = self.speed * arrowSpeedMultiplier;
self.x += self.directionX * actualSpeed;
self.y += self.directionY * actualSpeed;
// Check collisions with enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var currentCollision = self.intersects(enemy);
var lastCollision = self.lastEnemyCollisions[i] || false;
if (!lastCollision && currentCollision) {
// Hit enemy
LK.getSound('enemyHit').play();
LK.effects.flashObject(enemy, 0xFFFFFF, 200);
// Damage enemy
var isDead = enemy.takeDamage(self.damage);
if (isDead) {
// Remove enemy
enemies.splice(i, 1);
enemy.destroy();
}
// Remove arrow
if (arrows.indexOf(self) !== -1) {
arrows.splice(arrows.indexOf(self), 1);
self.destroy();
}
return;
}
self.lastEnemyCollisions[i] = currentCollision;
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.damage = 10;
self.targetX = 0;
self.targetY = 0;
self.lastPlayerCollision = false;
self.maxHealth = 30;
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.3
});
healthBarBg.y = -40;
// Create health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.3
});
healthBar.y = -40;
self.healthBar = healthBar;
self.healthBarBg = healthBarBg;
self.update = function () {
// Don't move when game is paused for upgrades
if (gamePaused) return;
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
player.takeDamage(self.damage);
}
self.lastPlayerCollision = currentCollision;
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
self.health = 0;
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// Add tween animation for orb spawn
tween(xpOrb, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(xpOrb, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
return true; // Enemy is dead
}
return false; // Enemy is still alive
};
self.updateHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
self.healthBar.scaleX = 0.15 * healthPercentage;
if (healthPercentage > 0.6) {
self.healthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
self.healthBar.tint = 0xFFEB3B;
} else {
self.healthBar.tint = 0xFF5722;
}
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('fastEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2.4;
self.damage = 10;
self.targetX = 0;
self.targetY = 0;
self.lastPlayerCollision = false;
self.maxHealth = 24;
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.12,
scaleY: 0.25
});
healthBarBg.y = -35;
// Create health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.12,
scaleY: 0.25
});
healthBar.y = -35;
self.healthBar = healthBar;
self.healthBarBg = healthBarBg;
self.update = function () {
// Don't move when game is paused for upgrades
if (gamePaused) return;
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
player.takeDamage(self.damage);
}
self.lastPlayerCollision = currentCollision;
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
self.health = 0;
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// Add tween animation for orb spawn
tween(xpOrb, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(xpOrb, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
return true; // Enemy is dead
}
return false; // Enemy is still alive
};
self.updateHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
self.healthBar.scaleX = 0.12 * healthPercentage;
if (healthPercentage > 0.6) {
self.healthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
self.healthBar.tint = 0xFFEB3B;
} else {
self.healthBar.tint = 0xFF5722;
}
};
return self;
});
var HeavyEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('heavyEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.6; // Slower than regular enemies
self.damage = 15;
self.targetX = 0;
self.targetY = 0;
self.lastPlayerCollision = false;
self.maxHealth = 80; // More HP than regular enemies
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.35
});
healthBarBg.y = -50;
// Create health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.35
});
healthBar.y = -50;
self.healthBar = healthBar;
self.healthBarBg = healthBarBg;
self.update = function () {
// Don't move when game is paused for upgrades
if (gamePaused) return;
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
player.takeDamage(self.damage);
}
self.lastPlayerCollision = currentCollision;
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
self.health = 0;
// Drop Yellow XP orb worth 3x normal XP
var xpOrb = new YellowXPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// Add tween animation for orb spawn
tween(xpOrb, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(xpOrb, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
return true; // Enemy is dead
}
return false; // Enemy is still alive
};
self.updateHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
self.healthBar.scaleX = 0.2 * healthPercentage;
if (healthPercentage > 0.6) {
self.healthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
self.healthBar.tint = 0xFFEB3B;
} else {
self.healthBar.tint = 0xFF5722;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
// Create player health bar background
var playerHealthBarBg = self.attachAsset('playerHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
playerHealthBarBg.y = -50;
// Create player health bar
var playerHealthBar = self.attachAsset('playerHealthBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
playerHealthBar.y = -50;
self.playerHealthBar = playerHealthBar;
self.playerHealthBarBg = playerHealthBarBg;
self.speed = 1;
self.invulnerable = false;
self.invulnerableTime = 0;
self.takeDamage = function (damage) {
if (self.invulnerable) {
return;
}
self.health -= damage;
self.updatePlayerHealthBar();
self.invulnerable = true;
self.invulnerableTime = 60; // 1 second of invulnerability
LK.getSound('playerDamage').play();
LK.effects.flashObject(self, 0xFF0000, 500);
if (self.health <= 0) {
self.health = 0;
gameOver = true;
}
};
self.heal = function (amount) {
self.health = Math.min(self.maxHealth, self.health + amount);
self.updatePlayerHealthBar();
};
self.updatePlayerHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
self.playerHealthBar.scaleX = 0.6 * healthPercentage;
if (healthPercentage > 0.6) {
self.playerHealthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
self.playerHealthBar.tint = 0xFFEB3B;
} else {
self.playerHealthBar.tint = 0xFF5722;
}
};
self.update = function () {
if (self.invulnerable) {
self.invulnerableTime--;
if (self.invulnerableTime <= 0) {
self.invulnerable = false;
}
}
};
return self;
});
var XPOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('xpOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.xpValue = 10;
self.attractDistance = baseMagnetRange;
self.attractSpeed = baseMagnetSpeed;
self.lastPlayerCollision = false;
self.update = function () {
// Don't attract when game is paused for upgrades
if (gamePaused) return;
// Check distance to player for attraction
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Attract to player if within range
if (distance < self.attractDistance && distance > 0) {
var moveSpeed = Math.min(self.attractSpeed, distance);
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
// Check collision with player
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
// Collect XP
playerXP += self.xpValue;
checkLevelUp();
LK.getSound('xpCollect').play();
// Remove orb
if (xpOrbs.indexOf(self) !== -1) {
xpOrbs.splice(xpOrbs.indexOf(self), 1);
self.destroy();
}
}
self.lastPlayerCollision = currentCollision;
};
return self;
});
var YellowXPOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('yellowXpOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.xpValue = 30; // 3x the normal XP value (normal is 10)
self.attractDistance = baseMagnetRange;
self.attractSpeed = baseMagnetSpeed;
self.lastPlayerCollision = false;
self.update = function () {
// Don't attract when game is paused for upgrades
if (gamePaused) return;
// Check distance to player for attraction
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Attract to player if within range
if (distance < self.attractDistance && distance > 0) {
var moveSpeed = Math.min(self.attractSpeed, distance);
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
// Check collision with player
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
// Collect XP
playerXP += self.xpValue;
checkLevelUp();
LK.getSound('xpCollect').play();
// Remove orb
if (xpOrbs.indexOf(self) !== -1) {
xpOrbs.splice(xpOrbs.indexOf(self), 1);
self.destroy();
}
}
self.lastPlayerCollision = currentCollision;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
var player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
player.updatePlayerHealthBar();
var enemies = [];
var arrows = [];
var xpOrbs = [];
var gameOver = false;
var lastShootTime = 0;
var shootCooldown = 90; // 50% slower shooting rate
var waveNumber = 1;
var enemiesSpawned = 0;
var enemiesPerWave = 8;
var spawnTimer = 0;
var survivalTime = 0;
var dragNode = null;
var playerXP = 0;
var playerLevel = 1;
var xpToNextLevel = 10;
var healthRegenTimer = 0;
var healthRegenCooldown = 60; // 60 ticks = 1 second at 60 FPS
var gamePaused = false;
var upgradeChoices = [];
var upgradeButtons = [];
var upgradeLevels = [0, 0, 0, 0, 0, 0, 0]; // Track levels for each upgrade type
// Base arrow damage that will be used for all new arrows
var baseArrowDamage = 15;
// Base magnet range that will be used for all new XP orbs
var baseMagnetRange = 50;
// Base magnet speed that will be used for all new XP orbs
var baseMagnetSpeed = 8;
// Bow upgrade variables
var arrowsPerBurst = 1;
var arrowSpeedMultiplier = 1.0;
// Keyboard input state
var keys = {
w: false,
a: false,
s: false,
d: false
};
// UI Elements
var healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0
});
var healthBar = LK.getAsset('healthBar', {
anchorX: 0.5,
anchorY: 0
});
LK.gui.top.addChild(healthBarBg);
LK.gui.top.addChild(healthBar);
var waveText = new Text2('Wave: 1', {
size: 80,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var timeText = new Text2('Time: 0s', {
size: 60,
fill: 0xFFFFFF
});
timeText.anchor.set(1, 0);
LK.gui.topRight.addChild(timeText);
var levelText = new Text2('Level: 1', {
size: 70,
fill: 0xFFD700
});
levelText.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelText);
var xpText = new Text2('XP: 0/10', {
size: 50,
fill: 0x00BCD4
});
xpText.anchor.set(0, 0);
LK.gui.topLeft.addChild(xpText);
// Position UI elements
healthBarBg.y = 120;
healthBar.y = 120;
waveText.y = 200;
timeText.y = 280;
timeText.x = -20;
levelText.x = 120;
levelText.y = 20;
xpText.x = 120;
xpText.y = 100;
function checkLevelUp() {
if (playerXP >= xpToNextLevel) {
playerLevel++;
playerXP -= xpToNextLevel;
xpToNextLevel = Math.floor(xpToNextLevel * 1.2);
// Level up effects
LK.effects.flashScreen(0xFFD700, 800);
player.heal(20);
// Pause game and show upgrade choices
gamePaused = true;
showUpgradeChoices();
}
}
function showUpgradeChoices() {
// Clear any existing upgrade choices
clearUpgradeChoices();
// Create upgrade background
var upgradeBackground = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 8
});
upgradeBackground.x = 1024;
upgradeBackground.y = 1366;
upgradeBackground.alpha = 0.9;
game.addChild(upgradeBackground);
upgradeButtons.push(upgradeBackground);
// Create title
var titleText = new Text2('LEVEL UP!', {
size: 100,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1100;
game.addChild(titleText);
upgradeButtons.push(titleText);
// Define possible upgrades
var allUpgrades = [{
name: 'Health Boost',
description: '+20 Max Health',
index: 0,
effect: function effect() {
player.maxHealth += 20;
player.heal(20);
upgradeLevels[0]++;
}
}, {
name: 'Faster Shooting',
description: 'Shoot 25% Faster',
index: 1,
effect: function effect() {
shootCooldown = Math.max(30, shootCooldown - 15);
upgradeLevels[1]++;
}
}, {
name: 'More Damage',
description: '+50% Arrow Damage',
index: 2,
effect: function effect() {
baseArrowDamage = Math.floor(baseArrowDamage * 1.5);
upgradeLevels[2]++;
}
}, {
name: 'Speed Boost',
description: 'Move 20% Faster',
index: 3,
effect: function effect() {
player.speed += 0.2;
upgradeLevels[3]++;
}
}, {
name: 'Health Regen',
description: 'Heal 2HP per second',
index: 4,
effect: function effect() {
healthRegenCooldown = Math.max(20, healthRegenCooldown - 10);
upgradeLevels[4]++;
}
}, {
name: upgradeLevels[5] === 5 ? 'Magnet Evolution I' : 'Magnet',
description: getMagnetUpgradeDescription(),
index: 5,
effect: function effect() {
applyMagnetUpgrade();
upgradeLevels[5]++;
}
}, {
name: 'Bow Upgrade',
description: getBowUpgradeDescription(),
index: 6,
effect: function effect() {
applyBowUpgrade();
upgradeLevels[6]++;
}
}];
// Select 3 random upgrades, excluding those with 5 stars
upgradeChoices = [];
var availableUpgrades = [];
// Filter out upgrades that have reached maximum level (11 levels for magnet, 5 for others)
for (var u = 0; u < allUpgrades.length; u++) {
var upgrade = allUpgrades[u];
var maxLevel = upgrade.index === 5 ? 11 : 5; // Magnet has 11 levels (6 + 5 evolution), others have 5
if (upgradeLevels[upgrade.index] < maxLevel) {
availableUpgrades.push(upgrade);
}
}
// If we have available upgrades, select up to 3 random ones
var upgradeCount = Math.min(3, availableUpgrades.length);
for (var i = 0; i < upgradeCount; i++) {
var randomIndex = Math.floor(Math.random() * availableUpgrades.length);
upgradeChoices.push(availableUpgrades[randomIndex]);
availableUpgrades.splice(randomIndex, 1);
}
// Create upgrade buttons
for (var i = 0; i < upgradeChoices.length; i++) {
var upgrade = upgradeChoices[i];
var buttonX = 350 + i * 700; // Horizontal spacing from left to right
var buttonY = 1400;
// Button background
var buttonBg = LK.getAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 3
});
buttonBg.x = buttonX;
buttonBg.y = buttonY;
// Make button red only if it's magnet evolution level 6 (evolution I)
if (upgrade.index === 5 && upgradeLevels[5] === 5) {
buttonBg.tint = 0xCC0000;
buttonBg.alpha = 0.7; // Make evolution upgrade box darker
} else {
buttonBg.tint = 0x4CAF50;
}
buttonBg.upgradeIndex = i;
game.addChild(buttonBg);
upgradeButtons.push(buttonBg);
// Button text
var buttonText = new Text2(upgrade.name, {
size: 80,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = buttonX;
buttonText.y = buttonY - 30;
game.addChild(buttonText);
upgradeButtons.push(buttonText);
// Description text
var descText = new Text2(upgrade.description, {
size: 60,
fill: 0xCCCCCC
});
descText.anchor.set(0.5, 0.5);
descText.x = buttonX;
descText.y = buttonY + 30;
game.addChild(descText);
upgradeButtons.push(descText);
// Add stars below button
var upgradeLevel = upgradeLevels[upgrade.index];
var starY = buttonY + 100;
var maxStars = upgrade.index === 5 ? 6 : 5; // Magnet has 6 stars, others have 5
var starsToShow = maxStars;
// For magnet upgrade, calculate display stars based on evolution
var displayStars = upgradeLevel;
if (upgrade.index === 5) {
// For magnet evolution: levels 6-10 show as stars 1-5, but with 6th star visible
if (upgradeLevel >= 6) {
displayStars = upgradeLevel - 5; // Convert level 6-10 to display stars 1-5
starsToShow = 6; // Always show 6 stars when in evolution
} else if (upgradeLevel < 5) {
starsToShow = 5; // Only show 5 stars before evolution
}
}
for (var s = 0; s < starsToShow; s++) {
var star;
// Special handling for magnet evolution (level 6 and above)
if (upgrade.index === 5 && upgradeLevel >= 6) {
// When magnet evolution is active, the 6th star should always be red
if (s === 5) {
star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
star.tint = 0xFF0000; // Red color for evolution I
} else if (s < displayStars) {
// Yellow stars for evolution progress
star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
// Dark stars for remaining slots
star = LK.getAsset('starDark', {
anchorX: 0.5,
anchorY: 0.5
});
}
} else {
// Normal star display logic for all other cases
if (s < displayStars) {
star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
star = LK.getAsset('starDark', {
anchorX: 0.5,
anchorY: 0.5
});
}
}
// Position stars - for magnet (6 stars), put 6th star below first star
if (upgrade.index === 5 && s === 5) {
// 6th star for magnet - position below the first star (star 0)
star.x = buttonX - 100 + 0 * 50; // Same x as first star
star.y = starY + 60; // Below the other stars
} else {
// Normal positioning for first 5 stars with increased spacing
star.x = buttonX - 100 + s * 50;
star.y = starY;
}
game.addChild(star);
upgradeButtons.push(star);
}
}
}
function getMagnetUpgradeDescription() {
var magnetLevel = upgradeLevels[5];
switch (magnetLevel) {
case 0:
case 1:
case 2:
case 3:
case 4:
return '+100% Magnet Range';
case 5:
return '+100% Magnet Pulling Speed';
case 6:
case 7:
case 8:
case 9:
case 10:
return '+100% Magnet Range';
default:
return 'Max Level';
}
}
function getBowUpgradeDescription() {
var bowLevel = upgradeLevels[6];
switch (bowLevel) {
case 0:
return '+1 Arrow (Burst)';
case 1:
return '+100% Arrow Speed';
case 2:
return '+50% Arrow Damage';
case 3:
return '+25% Arrow Speed';
case 4:
return '+1 Arrow (Burst)';
default:
return 'Max Level';
}
}
function applyMagnetUpgrade() {
var magnetLevel = upgradeLevels[5];
switch (magnetLevel) {
case 0:
case 1:
case 2:
case 3:
case 4:
// Levels 1-5: Double magnet range for all existing and future XP orbs
for (var o = 0; o < xpOrbs.length; o++) {
xpOrbs[o].attractDistance *= 2;
}
// Double base magnet range for new orbs
baseMagnetRange *= 2;
break;
case 5:
// Level 6: Double magnet pulling speed for all existing and future XP orbs
for (var o = 0; o < xpOrbs.length; o++) {
xpOrbs[o].attractSpeed *= 2;
}
// Double base magnet speed for new orbs
baseMagnetSpeed *= 2;
break;
case 6:
case 7:
case 8:
case 9:
case 10:
// Evolution levels 7-11: Double magnet range for all existing and future XP orbs
for (var o = 0; o < xpOrbs.length; o++) {
xpOrbs[o].attractDistance *= 2;
}
// Double base magnet range for new orbs
baseMagnetRange *= 2;
break;
}
}
function applyBowUpgrade() {
var bowLevel = upgradeLevels[6];
switch (bowLevel) {
case 0:
// Level 1: +1 arrow (burst)
arrowsPerBurst = 2;
break;
case 1:
// Level 2: +100% arrow speed
arrowSpeedMultiplier *= 2.0;
break;
case 2:
// Level 3: +50% arrow damage
baseArrowDamage = Math.floor(baseArrowDamage * 1.5);
break;
case 3:
// Level 4: +25% arrow speed
arrowSpeedMultiplier *= 1.25;
break;
case 4:
// Level 5: +1 arrow (burst)
arrowsPerBurst = 3;
break;
}
}
function clearUpgradeChoices() {
for (var i = 0; i < upgradeButtons.length; i++) {
upgradeButtons[i].destroy();
}
upgradeButtons = [];
upgradeChoices = [];
}
function selectUpgrade(index) {
if (index >= 0 && index < upgradeChoices.length) {
// Apply upgrade effect
upgradeChoices[index].effect();
// Clear upgrade UI
clearUpgradeChoices();
// Resume game
gamePaused = false;
}
}
function spawnEnemy() {
var enemy;
if (waveNumber >= 5 && Math.random() < 0.15) {
enemy = new HeavyEnemy();
} else if (waveNumber >= 3 && Math.random() < 0.3) {
enemy = new FastEnemy();
} else {
enemy = new Enemy();
}
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 1:
// Right
enemy.x = 2098;
enemy.y = Math.random() * 2732;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = 2782;
break;
case 3:
// Left
enemy.x = -50;
enemy.y = Math.random() * 2732;
break;
}
enemy.targetX = player.x;
enemy.targetY = player.y;
enemy.speed += Math.floor(waveNumber / 3) * 0.5;
// Scale enemy health by 1.2x per wave
var healthMultiplier = Math.pow(1.2, waveNumber - 1);
enemy.maxHealth = Math.floor(enemy.maxHealth * healthMultiplier);
enemy.health = enemy.maxHealth;
enemy.updateHealthBar();
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
function updateHealthBar() {
var healthPercentage = player.health / player.maxHealth;
healthBar.width = 400 * healthPercentage;
if (healthPercentage > 0.6) {
healthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
healthBar.tint = 0xFFEB3B;
} else {
healthBar.tint = 0xFF5722;
}
}
function handleMove(x, y, obj) {
if (dragNode && !gameOver) {
var newX = Math.max(40, Math.min(2008, x));
var newY = Math.max(40, Math.min(2692, y));
var dx = newX - dragNode.x;
var dy = newY - dragNode.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var moveDistance = Math.min(distance, 8 * dragNode.speed);
dragNode.x += dx / distance * moveDistance;
dragNode.y += dy / distance * moveDistance;
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (!gameOver) {
// Check if we're in upgrade selection mode
if (gamePaused && upgradeButtons.length > 0) {
// Check if clicked on an upgrade button
for (var i = 0; i < upgradeButtons.length; i++) {
var button = upgradeButtons[i];
if (button.upgradeIndex !== undefined) {
// Check if click position is within button bounds
// Button is scaled 6x horizontally and 3x vertically from base enemy size (60x60)
var buttonWidth = 60 * 6; // 360
var buttonHeight = 60 * 3; // 180
var buttonLeft = button.x - buttonWidth / 2;
var buttonRight = button.x + buttonWidth / 2;
var buttonTop = button.y - buttonHeight / 2;
var buttonBottom = button.y + buttonHeight / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
selectUpgrade(button.upgradeIndex);
return;
}
}
}
} else {
dragNode = player;
handleMove(x, y, obj);
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Keyboard event listeners
LK.on('keydown', function (event) {
switch (event.key.toLowerCase()) {
case 'w':
keys.w = true;
break;
case 'a':
keys.a = true;
break;
case 's':
keys.s = true;
break;
case 'd':
keys.d = true;
break;
}
});
LK.on('keyup', function (event) {
switch (event.key.toLowerCase()) {
case 'w':
keys.w = false;
break;
case 'a':
keys.a = false;
break;
case 's':
keys.s = false;
break;
case 'd':
keys.d = false;
break;
}
});
game.update = function () {
if (gameOver) return;
// Check pause state before any updates
if (gamePaused) return;
survivalTime++;
// Handle WASD movement
var moveSpeed = 5;
if (keys.w) {
player.y = Math.max(40, player.y - moveSpeed);
}
if (keys.s) {
player.y = Math.min(2692, player.y + moveSpeed);
}
if (keys.a) {
player.x = Math.max(40, player.x - moveSpeed);
}
if (keys.d) {
player.x = Math.min(2008, player.x + moveSpeed);
}
// Health regeneration
healthRegenTimer++;
if (healthRegenTimer >= healthRegenCooldown && player.health < player.maxHealth) {
player.heal(1);
healthRegenTimer = 0;
}
// Update UI
updateHealthBar();
waveText.setText('Wave: ' + waveNumber);
timeText.setText('Time: ' + Math.floor(survivalTime / 60) + 's');
levelText.setText('Level: ' + playerLevel);
xpText.setText('XP: ' + playerXP + '/' + xpToNextLevel);
// Enemy spawning
spawnTimer++;
var spawnRate = Math.max(15, 60 - waveNumber * 3);
if (spawnTimer >= spawnRate && enemiesSpawned < enemiesPerWave) {
spawnEnemy();
spawnTimer = 0;
}
// Auto-shoot arrows at nearest enemy
lastShootTime++;
if (lastShootTime >= shootCooldown && enemies.length > 0) {
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var e = 0; e < enemies.length; e++) {
var enemy = enemies[e];
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
if (nearestEnemy) {
var baseDx = nearestEnemy.x - player.x;
var baseDy = nearestEnemy.y - player.y;
// Fire multiple arrows in a burst
for (var b = 0; b < arrowsPerBurst; b++) {
// Add delay for burst arrows so they fire sequentially
if (b > 0) {
LK.setTimeout(function (burstIndex) {
return function () {
var arrow = new Arrow();
arrow.x = player.x;
arrow.y = player.y;
var dx = baseDx;
var dy = baseDy;
// All arrows fire in same direction
arrow.setDirection(dx, dy);
arrows.push(arrow);
game.addChild(arrow);
};
}(b), b * 100); // 100ms delay between each arrow
} else {
// Fire first arrow immediately
var arrow = new Arrow();
arrow.x = player.x;
arrow.y = player.y;
var dx = baseDx;
var dy = baseDy;
// All arrows fire in same direction
arrow.setDirection(dx, dy);
arrows.push(arrow);
game.addChild(arrow);
}
}
LK.getSound('arrowShoot').play();
lastShootTime = 0;
}
}
// Update arrows
for (var a = arrows.length - 1; a >= 0; a--) {
var arrow = arrows[a];
// Remove arrows that are off screen
if (arrow.x < -100 || arrow.x > 2148 || arrow.y < -100 || arrow.y > 2832) {
arrows.splice(a, 1);
arrow.destroy();
}
}
// Update XP orbs
for (var x = xpOrbs.length - 1; x >= 0; x--) {
var xpOrb = xpOrbs[x];
// Remove orbs that are too far off screen
if (xpOrb.x < -200 || xpOrb.x > 2248 || xpOrb.y < -200 || xpOrb.y > 2932) {
xpOrbs.splice(x, 1);
xpOrb.destroy();
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.targetX = player.x;
enemy.targetY = player.y;
// Remove enemies that are too far off screen
if (enemy.x < -200 || enemy.x > 2248 || enemy.y < -200 || enemy.y > 2932) {
enemies.splice(i, 1);
enemy.destroy();
}
}
// Check wave completion
if (enemiesSpawned >= enemiesPerWave && enemies.length === 0) {
waveNumber++;
enemiesSpawned = 0;
enemiesPerWave = Math.min(25, 8 + waveNumber * 3);
// Bonus health for completing wave
player.heal(10);
LK.effects.flashScreen(0x4CAF50, 500);
}
// Game over check
if (player.health <= 0) {
gameOver = true;
// Save best survival time
var bestTime = storage.bestTime || 0;
if (survivalTime > bestTime) {
storage.bestTime = survivalTime;
}
// Save total waves completed
var totalWaves = storage.totalWaves || 0;
storage.totalWaves = totalWaves + (waveNumber - 1);
LK.setScore(Math.floor(survivalTime / 60) + (waveNumber - 1) * 10);
LK.effects.flashScreen(0xFF0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
}; ===================================================================
--- original.js
+++ change.js
@@ -241,8 +241,100 @@
}
};
return self;
});
+var HeavyEnemy = Container.expand(function () {
+ var self = Container.call(this);
+ var enemyGraphics = self.attachAsset('heavyEnemy', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 0.6; // Slower than regular enemies
+ self.damage = 15;
+ self.targetX = 0;
+ self.targetY = 0;
+ self.lastPlayerCollision = false;
+ self.maxHealth = 80; // More HP than regular enemies
+ self.health = self.maxHealth;
+ // Create health bar background
+ var healthBarBg = self.attachAsset('healthBarBg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.2,
+ scaleY: 0.35
+ });
+ healthBarBg.y = -50;
+ // Create health bar
+ var healthBar = self.attachAsset('healthBar', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.2,
+ scaleY: 0.35
+ });
+ healthBar.y = -50;
+ self.healthBar = healthBar;
+ self.healthBarBg = healthBarBg;
+ self.update = function () {
+ // Don't move when game is paused for upgrades
+ if (gamePaused) return;
+ var dx = self.targetX - self.x;
+ var dy = self.targetY - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance > 0) {
+ self.x += dx / distance * self.speed;
+ self.y += dy / distance * self.speed;
+ }
+ var currentCollision = self.intersects(player);
+ if (!self.lastPlayerCollision && currentCollision) {
+ player.takeDamage(self.damage);
+ }
+ self.lastPlayerCollision = currentCollision;
+ };
+ self.takeDamage = function (damage) {
+ self.health -= damage;
+ self.updateHealthBar();
+ if (self.health <= 0) {
+ self.health = 0;
+ // Drop Yellow XP orb worth 3x normal XP
+ var xpOrb = new YellowXPOrb();
+ xpOrb.x = self.x;
+ xpOrb.y = self.y;
+ xpOrbs.push(xpOrb);
+ game.addChild(xpOrb);
+ // Add tween animation for orb spawn
+ tween(xpOrb, {
+ scaleX: 1.5,
+ scaleY: 1.5
+ }, {
+ duration: 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(xpOrb, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 150,
+ easing: tween.easeIn
+ });
+ }
+ });
+ return true; // Enemy is dead
+ }
+ return false; // Enemy is still alive
+ };
+ self.updateHealthBar = function () {
+ var healthPercentage = self.health / self.maxHealth;
+ self.healthBar.scaleX = 0.2 * healthPercentage;
+ if (healthPercentage > 0.6) {
+ self.healthBar.tint = 0x4CAF50;
+ } else if (healthPercentage > 0.3) {
+ self.healthBar.tint = 0xFFEB3B;
+ } else {
+ self.healthBar.tint = 0xFF5722;
+ }
+ };
+ return self;
+});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
@@ -350,8 +442,48 @@
self.lastPlayerCollision = currentCollision;
};
return self;
});
+var YellowXPOrb = Container.expand(function () {
+ var self = Container.call(this);
+ var orbGraphics = self.attachAsset('yellowXpOrb', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.xpValue = 30; // 3x the normal XP value (normal is 10)
+ self.attractDistance = baseMagnetRange;
+ self.attractSpeed = baseMagnetSpeed;
+ self.lastPlayerCollision = false;
+ self.update = function () {
+ // Don't attract when game is paused for upgrades
+ if (gamePaused) return;
+ // Check distance to player for attraction
+ var dx = player.x - self.x;
+ var dy = player.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ // Attract to player if within range
+ if (distance < self.attractDistance && distance > 0) {
+ var moveSpeed = Math.min(self.attractSpeed, distance);
+ self.x += dx / distance * moveSpeed;
+ self.y += dy / distance * moveSpeed;
+ }
+ // Check collision with player
+ var currentCollision = self.intersects(player);
+ if (!self.lastPlayerCollision && currentCollision) {
+ // Collect XP
+ playerXP += self.xpValue;
+ checkLevelUp();
+ LK.getSound('xpCollect').play();
+ // Remove orb
+ if (xpOrbs.indexOf(self) !== -1) {
+ xpOrbs.splice(xpOrbs.indexOf(self), 1);
+ self.destroy();
+ }
+ }
+ self.lastPlayerCollision = currentCollision;
+ };
+ return self;
+});
/****
* Initialize Game
****/
@@ -794,9 +926,11 @@
}
}
function spawnEnemy() {
var enemy;
- if (waveNumber >= 3 && Math.random() < 0.3) {
+ if (waveNumber >= 5 && Math.random() < 0.15) {
+ enemy = new HeavyEnemy();
+ } else if (waveNumber >= 3 && Math.random() < 0.3) {
enemy = new FastEnemy();
} else {
enemy = new Enemy();
}