User prompt
give zombies a 10% chance to drop 1 Zoin, a Zoin is a coin used by player to purchase permanent upgrades that are not reset by player death ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make drops that self destroy autoPickup regardless of distance to player instead
User prompt
zombies should become slightly stronger per wave increasing the damage they do to player and the damage needed to destroy them
User prompt
change pickups to self destroy if not picked up in 10 seconds ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
zombies should not disappear while alive
User prompt
never spawn the same powerup 2 times in a row
User prompt
make zombie speed variable in range +/- 25% of normal
User prompt
fix enemies disappearing but not destroyed
User prompt
fix aim vector to only fire when enemy in range and always fire at closest enemy
User prompt
if tripleShot is true and player picks up another triple shot add 2 more bullets 10 degrees further out from center bullet and make max tripleshot level = 5
User prompt
hide ammo counters for powerups the player does not have any ammo for
User prompt
make tripleshot powerup permanent and use PowerAmmo when available or regular bullet when powerammo is not available, remove triple shot ammo counter
User prompt
Fix: FAILURE: Integration failed, target source not found. Please try again. Then: create tripleShot powerup that fires 3 bullets with the side bullets angled + and - 10 degrees from center bullet
User prompt
import and use @upit/tween.v1 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make it so that if no powerup has spawned in last 50 kills spawn random powerup from powerup list on 51st kill and reset counter
User prompt
reduce powerAmmo fire rate by 75%
User prompt
automatically pickup all drops within 50% of fire range
User prompt
make ammoPowerUP thatgive the player 100 rounds of 1 hit kill ammo with a slower fire rate and bullets that pierce enemies and fly 2 times as far as regular bullets ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
on click release hide control stick, on click hold show control stick
User prompt
on click move left thumb control to click location and lock in place for as long as the click is held
User prompt
remove right thumbstick make firing automatic at closest enemy in range
User prompt
remove ammo requirement
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var localPos = game.toLocal(obj.position);' Line Number: 327
Code edit (1 edits merged)
Please save this source code
User prompt
Zombie Wave Survivor
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AmmoBox = Container.expand(function () {
var self = Container.call(this);
var ammoGraphics = self.attachAsset('ammoBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.ammoAmount = 50;
self.update = function () {
self.rotation += 0.02;
};
return self;
});
var AmmoPowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('ammoPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.ammoAmount = 100;
self.update = function () {
self.rotation += 0.02;
// Add pulsing effect
self.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
self.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 20;
self.damage = 10;
self.vx = 0;
self.vy = 0;
self.piercing = false;
self.killHit = false;
self.maxDistance = 800;
self.travelDistance = 0;
self.update = function () {
var moveX = self.vx;
var moveY = self.vy;
var distance = Math.sqrt(moveX * moveX + moveY * moveY);
self.travelDistance += distance;
self.x += moveX;
self.y += moveY;
};
return self;
});
var HealthPack = Container.expand(function () {
var self = Container.call(this);
var healthGraphics = self.attachAsset('healthPack', {
anchorX: 0.5,
anchorY: 0.5
});
self.healAmount = 30;
self.update = function () {
self.rotation += 0.02;
};
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;
self.fireRate = 10;
self.fireCooldown = 0;
self.moveSpeed = 5;
self.invulnerable = 0;
self.takeDamage = function (amount) {
if (self.invulnerable > 0) return;
self.health -= amount;
self.invulnerable = 60;
LK.getSound('playerHurt').play();
LK.effects.flashObject(self, 0xFF0000, 500);
if (self.health <= 0) {
self.health = 0;
return true;
}
return false;
};
self.heal = function (amount) {
self.health = Math.min(self.health + amount, self.maxHealth);
};
self.update = function () {
if (self.fireCooldown > 0) self.fireCooldown--;
if (self.invulnerable > 0) {
self.invulnerable--;
self.alpha = Math.floor(self.invulnerable / 5) % 2 ? 0.5 : 1;
}
};
return self;
});
var TripleShot = Container.expand(function () {
var self = Container.call(this);
var tripleShotGraphics = self.attachAsset('tripleShot', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.rotation += 0.02;
// Add pulsing effect
self.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
self.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
};
return self;
});
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 0.5;
self.health = 20;
self.damage = 10;
self.attackCooldown = 0;
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
LK.getSound('zombieHit').play();
return true;
}
zombieGraphics.tint = 0xFF0000;
tween(zombieGraphics, {
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
zombieGraphics.tint = 0xFFFFFF;
}
});
return false;
};
self.update = function () {
if (self.attackCooldown > 0) self.attackCooldown--;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
var player;
var zombies = [];
var bullets = [];
var pickups = [];
var wave = 1;
var zombiesPerWave = 5;
var zombiesSpawned = 0;
var zombiesKilled = 0;
var spawnTimer = 0;
var scoreMultiplier = 1;
var killStreak = 0;
var powerAmmo = 0;
var lastPowerUpSpawn = 0;
var killsSinceLastPowerUp = 0;
var powerUpList = ['ammoPowerUp', 'healthPack', 'ammoBox', 'tripleShot'];
var hasTripleShot = false;
var moveControl;
var moveStick;
var isDraggingMove = false;
// UI Elements
var waveText = new Text2('Wave: 1', {
size: 80,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
scoreText.x = -20;
LK.gui.topRight.addChild(scoreText);
var healthText = new Text2('Health: 100/100', {
size: 50,
fill: 0xFF0000
});
healthText.anchor.set(1, 1);
healthText.x = -20;
healthText.y = -20;
LK.gui.bottomRight.addChild(healthText);
var powerAmmoText = new Text2('Power Ammo: 0', {
size: 45,
fill: 0xFFD700
});
powerAmmoText.anchor.set(1, 1);
powerAmmoText.x = -20;
powerAmmoText.y = -80;
LK.gui.bottomRight.addChild(powerAmmoText);
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Initialize controls
moveControl = LK.getAsset('moveControl', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
moveControl.x = 300;
moveControl.y = 2432;
game.addChild(moveControl);
moveStick = LK.getAsset('moveControl', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0
});
moveStick.x = moveControl.x;
moveStick.y = moveControl.y;
game.addChild(moveStick);
// Aim control removed - using automatic targeting
// Helper functions
function spawnZombie() {
var zombie = new Zombie();
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
zombie.x = Math.random() * 2048;
zombie.y = -50;
break;
case 1:
// Right
zombie.x = 2098;
zombie.y = Math.random() * 2732;
break;
case 2:
// Bottom
zombie.x = Math.random() * 2048;
zombie.y = 2782;
break;
case 3:
// Left
zombie.x = -50;
zombie.y = Math.random() * 2732;
break;
}
zombie.speed *= 1 + wave * 0.1;
zombie.health += wave * 5;
zombie.scaleX = 0;
zombie.scaleY = 0;
zombie.alpha = 0;
zombies.push(zombie);
game.addChild(zombie);
zombiesSpawned++;
// Animate zombie spawn
tween(zombie, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function spawnPickup(x, y) {
var shouldSpawn = false;
var pickup;
// Force powerup spawn if 50+ kills without powerup
if (killsSinceLastPowerUp >= 50) {
shouldSpawn = true;
var powerUpType = powerUpList[Math.floor(Math.random() * powerUpList.length)];
if (powerUpType === 'ammoPowerUp') {
pickup = new AmmoPowerUp();
} else if (powerUpType === 'ammoBox') {
pickup = new AmmoBox();
} else if (powerUpType === 'tripleShot') {
pickup = new TripleShot();
} else {
pickup = new HealthPack();
}
killsSinceLastPowerUp = 0;
if (pickup instanceof AmmoPowerUp) {
lastPowerUpSpawn = LK.ticks;
}
} else if (Math.random() < 0.3) {
shouldSpawn = true;
var rand = Math.random();
if (rand < 0.1 && LK.ticks - lastPowerUpSpawn > 1800) {
pickup = new AmmoPowerUp();
lastPowerUpSpawn = LK.ticks;
killsSinceLastPowerUp = 0;
} else if (rand < 0.15 && LK.ticks - lastPowerUpSpawn > 1800) {
pickup = new TripleShot();
lastPowerUpSpawn = LK.ticks;
killsSinceLastPowerUp = 0;
} else if (rand < 0.6) {
pickup = new AmmoBox();
} else {
pickup = new HealthPack();
}
}
if (shouldSpawn) {
pickup.x = x;
pickup.y = y;
pickup.scaleX = 0;
pickup.scaleY = 0;
pickups.push(pickup);
game.addChild(pickup);
// Animate pickup spawn with bounce effect
tween(pickup, {
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.elasticOut
});
}
}
function fireBullet() {
var fireRate = powerAmmo > 0 ? 80 : 10; // Much slower fire rate for power ammo (75% reduction)
if (player.fireCooldown > 0) return;
// Find closest zombie in range
var closestZombie = null;
var closestDistance = 500; // Maximum firing range
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
var dx = zombie.x - player.x;
var dy = zombie.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestZombie = zombie;
}
}
// Fire at closest zombie if found
if (closestZombie) {
var dx = closestZombie.x - player.x;
var dy = closestZombie.y - player.y;
var angle = Math.atan2(dy, dx);
player.rotation = angle; // Rotate player to face target
// Create bullets (1 for normal, 3 for triple shot)
var bulletCount = hasTripleShot ? 3 : 1;
var angleOffsets = hasTripleShot ? [-10 * Math.PI / 180, 0, 10 * Math.PI / 180] : [0];
for (var b = 0; b < bulletCount; b++) {
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y;
var bulletAngle = angle + angleOffsets[b];
bullet.vx = Math.cos(bulletAngle) * bullet.speed;
bullet.vy = Math.sin(bulletAngle) * bullet.speed;
bullet.rotation = bulletAngle;
if (powerAmmo > 0) {
bullet.piercing = true;
bullet.killHit = true;
bullet.maxDistance = 1600; // 2x distance
bullet.damage = 1000; // 1 hit kill
if (b === 0) powerAmmo--; // Only consume one power ammo per shot
// Visual effect for power bullet
tween(bullet, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100
});
bullet.tint = 0xFFD700;
} else {
bullet.maxDistance = 800;
}
bullets.push(bullet);
game.addChild(bullet);
}
player.fireCooldown = fireRate;
LK.getSound('shoot').play();
}
}
// Event handlers
game.down = function (x, y, obj) {
isDraggingMove = true;
// Move moveControl to click position
moveControl.x = x;
moveControl.y = y;
// Move moveStick to the same position (center of control)
moveStick.x = x;
moveStick.y = y;
// Show control stick with smooth animation
tween(moveControl, {
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut
});
tween(moveStick, {
alpha: 0.6
}, {
duration: 200,
easing: tween.easeOut
});
};
game.move = function (x, y, obj) {
if (isDraggingMove) {
moveStick.x = Math.max(moveControl.x - 150, Math.min(moveControl.x + 150, x));
moveStick.y = Math.max(moveControl.y - 150, Math.min(moveControl.y + 150, y));
}
};
game.up = function (x, y, obj) {
if (isDraggingMove) {
isDraggingMove = false;
moveStick.x = moveControl.x;
moveStick.y = moveControl.y;
// Hide control stick with smooth animation
tween(moveControl, {
alpha: 0
}, {
duration: 150,
easing: tween.easeIn
});
tween(moveStick, {
alpha: 0
}, {
duration: 150,
easing: tween.easeIn
});
}
};
// Main game loop
game.update = function () {
// Player movement
if (isDraggingMove) {
var moveX = (moveStick.x - moveControl.x) / 150;
var moveY = (moveStick.y - moveControl.y) / 150;
player.x += moveX * player.moveSpeed;
player.y += moveY * player.moveSpeed;
player.x = Math.max(40, Math.min(2008, player.x));
player.y = Math.max(40, Math.min(2692, player.y));
}
// Auto-fire at closest enemies
if (zombies.length > 0) {
fireBullet();
}
// Spawn zombies
if (zombiesSpawned < zombiesPerWave) {
spawnTimer++;
if (spawnTimer > 60) {
spawnZombie();
spawnTimer = 0;
}
} else if (zombies.length === 0) {
// Next wave
wave++;
zombiesPerWave = 5 + wave * 2;
zombiesSpawned = 0;
zombiesKilled = 0;
waveText.setText('Wave: ' + wave);
}
// Update zombies
for (var i = zombies.length - 1; i >= 0; i--) {
var zombie = zombies[i];
// Move towards player
var dx = player.x - zombie.x;
var dy = player.y - zombie.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
zombie.x += dx / dist * zombie.speed;
zombie.y += dy / dist * zombie.speed;
zombie.rotation = Math.atan2(dy, dx);
}
// Check collision with player
if (zombie.intersects(player) && zombie.attackCooldown === 0) {
if (player.takeDamage(zombie.damage)) {
LK.showGameOver();
}
zombie.attackCooldown = 60;
killStreak = 0;
scoreMultiplier = 1;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check if bullet is off screen or traveled max distance
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782 || bullet.travelDistance > bullet.maxDistance) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with zombies
var bulletDestroyed = false;
for (var j = zombies.length - 1; j >= 0; j--) {
var zombie = zombies[j];
if (bullet.intersects(zombie)) {
if (zombie.takeDamage(bullet.damage)) {
// Zombie died - add death animation
spawnPickup(zombie.x, zombie.y);
tween(zombie, {
scaleX: 0,
scaleY: 0,
alpha: 0,
rotation: zombie.rotation + Math.PI
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
zombie.destroy();
}
});
zombies.splice(j, 1);
zombiesKilled++;
killStreak++;
killsSinceLastPowerUp++;
if (killStreak % 5 === 0) {
scoreMultiplier = Math.min(scoreMultiplier + 1, 5);
}
LK.setScore(LK.getScore() + 10 * scoreMultiplier);
scoreText.setText('Score: ' + LK.getScore());
}
if (!bullet.piercing) {
bullet.destroy();
bullets.splice(i, 1);
bulletDestroyed = true;
break;
}
}
}
if (bulletDestroyed) continue;
}
// Update pickups
for (var i = pickups.length - 1; i >= 0; i--) {
var pickup = pickups[i];
var dx = player.x - pickup.x;
var dy = player.y - pickup.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var autoPickupRange = 250; // 50% of fire range (500 * 0.5)
if (pickup.intersects(player) || dist <= autoPickupRange) {
if (pickup instanceof HealthPack) {
player.heal(pickup.healAmount);
} else if (pickup instanceof AmmoPowerUp) {
powerAmmo += pickup.ammoAmount;
LK.effects.flashObject(player, 0xFFD700, 500);
} else if (pickup instanceof TripleShot) {
hasTripleShot = true;
LK.effects.flashObject(player, 0x00FF00, 500);
}
LK.getSound('pickup').play();
// Animate pickup collection
tween(pickup, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
pickup.destroy();
}
});
pickups.splice(i, 1);
}
}
// Update UI
healthText.setText('Health: ' + player.health + '/' + player.maxHealth);
powerAmmoText.setText('Power Ammo: ' + powerAmmo);
// Hide/show power ammo counter based on availability
powerAmmoText.visible = powerAmmo > 0;
// Despawn distant pickups
for (var i = pickups.length - 1; i >= 0; i--) {
var pickup = pickups[i];
var dx = player.x - pickup.x;
var dy = player.y - pickup.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 2000) {
pickup.destroy();
pickups.splice(i, 1);
}
}
};
// Start music
LK.playMusic('battleMusic'); ===================================================================
--- original.js
+++ change.js
@@ -577,8 +577,10 @@
}
// Update UI
healthText.setText('Health: ' + player.health + '/' + player.maxHealth);
powerAmmoText.setText('Power Ammo: ' + powerAmmo);
+ // Hide/show power ammo counter based on availability
+ powerAmmoText.visible = powerAmmo > 0;
// Despawn distant pickups
for (var i = pickups.length - 1; i >= 0; i--) {
var pickup = pickups[i];
var dx = player.x - pickup.x;