User prompt
Can you also add a design for the bosses, Place one bomb in a different location on the map for each wave — only one bomb per wave. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The game is almost finished now! But can you remove the overpower from the pistol during the final boss fight? Make it strong, but not too much. Also, make the enemies much tougher in the last wave.
User prompt
Perfect! Can you add a better design for the zombies and the main character, place health pickups on the map, and decorate the map with visual details?” ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Code it, and put a character design ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Zombie Waves: Key to Survival
Initial prompt
Zombie Waves Fight zombies through five rounds. At the end of each round, there is a strong enemy that’s different from the regular ones. After defeating it, you get a key that leads you to the next round, and so on. In the final round, you face a very powerful enemy, and the player is given a strong weapon to fight him. The game should have classic-style graphics, with control buttons, and a designed character appearance.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Boss = Container.expand(function (type) { var self = Container.call(this); var bossAsset = type === 5 ? 'finalBoss' : 'boss' + type; var bossGraphics = self.attachAsset(bossAsset, { anchorX: 0.5, anchorY: 0.5 }); self.type = type; self.health = 150 + type * 50; self.maxHealth = self.health; self.speed = 0.8 + type * 0.2; self.damage = 15 + type * 5; self.lastAttack = 0; self.attackCooldown = 90 - type * 10; self.lastSpecial = 0; self.specialCooldown = 300; self.update = function () { if (player) { var dx = player.x - self.x; var dy = player.y - 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; } if (distance < 80 && LK.ticks - self.lastAttack > self.attackCooldown) { player.takeDamage(self.damage); self.lastAttack = LK.ticks; LK.effects.flashScreen(0xff0000, 200); } if (LK.ticks - self.lastSpecial > self.specialCooldown) { self.specialAttack(); self.lastSpecial = LK.ticks; } } }; self.specialAttack = function () { if (self.type === 1) { self.speed *= 2; tween(self, { speed: 0.8 }, { duration: 2000 }); } else if (self.type === 2) { for (var i = 0; i < 3; i++) { var minion = new Zombie(); minion.x = self.x + (Math.random() - 0.5) * 200; minion.y = self.y + (Math.random() - 0.5) * 200; minion.health = 25; zombies.push(minion); game.addChild(minion); } } else if (self.type === 3) { LK.effects.flashScreen(0x800080, 500); player.takeDamage(20); } else if (self.type === 4) { self.health += 25; self.health = Math.min(self.health, self.maxHealth); LK.effects.flashObject(self, 0x00ff00, 500); } else if (self.type === 5) { for (var i = 0; i < 8; i++) { var angle = i / 8 * Math.PI * 2; var shockwave = new Zombie(); shockwave.x = self.x; shockwave.y = self.y; shockwave.speed = 3; shockwave.moveAngle = angle; shockwave.health = 1; shockwave.damage = 25; shockwave.update = function () { this.x += Math.cos(this.moveAngle) * this.speed; this.y += Math.sin(this.moveAngle) * this.speed; if (this.x < 0 || this.x > 2048 || this.y < 0 || this.y > 2732) { this.destroy(); var index = zombies.indexOf(this); if (index > -1) zombies.splice(index, 1); } }; zombies.push(shockwave); game.addChild(shockwave); } } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 150); return self.health <= 0; }; return self; }); var Bullet = Container.expand(function (isSuper) { var self = Container.call(this); var bulletAsset = isSuper ? 'superBullet' : 'bullet'; var bulletGraphics = self.attachAsset(bulletAsset, { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = isSuper ? 50 : 25; self.dx = 0; self.dy = 0; self.update = function () { self.x += self.dx * self.speed; self.y += self.dy * self.speed; if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.destroy(); var index = bullets.indexOf(self); if (index > -1) bullets.splice(index, 1); } }; return self; }); var Key = Container.expand(function () { var self = Container.call(this); var keyGraphics = self.attachAsset('key', { anchorX: 0.5, anchorY: 0.5 }); self.collected = false; self.update = function () { self.rotation += 0.05; if (player && !self.collected && self.intersects(player)) { self.collected = true; keys++; LK.getSound('keyCollect').play(); LK.effects.flashObject(self, 0xffffff, 300); self.destroy(); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); // Create character design with multiple parts var playerBase = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); var playerBody = self.attachAsset('playerBody', { anchorX: 0.5, anchorY: 0.5, y: -5 }); var playerHead = self.attachAsset('playerHead', { anchorX: 0.5, anchorY: 0.5, y: -25 }); self.health = 100; self.maxHealth = 100; self.speed = 5; self.lastShot = 0; self.shootCooldown = 15; self.weaponLevel = 1; self.velocityX = 0; self.velocityY = 0; self.friction = 0.85; self.smoothMove = function (moveX, moveY) { // Add acceleration instead of instant movement self.velocityX += moveX * 0.3; self.velocityY += moveY * 0.3; // Cap maximum velocity var maxVel = self.speed; if (Math.abs(self.velocityX) > maxVel) self.velocityX = self.velocityX > 0 ? maxVel : -maxVel; if (Math.abs(self.velocityY) > maxVel) self.velocityY = self.velocityY > 0 ? maxVel : -maxVel; }; self.updateMovement = function () { // Apply velocity to position self.x += self.velocityX; self.y += self.velocityY; // Apply friction when not moving self.velocityX *= self.friction; self.velocityY *= self.friction; // Keep player in bounds self.x = Math.max(40, Math.min(2008, self.x)); self.y = Math.max(40, Math.min(2692, self.y)); // Rotate character slightly based on movement direction if (Math.abs(self.velocityX) > 0.1 || Math.abs(self.velocityY) > 0.1) { var targetRotation = Math.atan2(self.velocityY, self.velocityX) * 0.1; tween(playerBase, { rotation: targetRotation }, { duration: 200 }); } }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.health = 0; LK.showGameOver(); } LK.effects.flashObject(self, 0xff0000, 300); }; self.upgrade = function () { self.weaponLevel++; self.shootCooldown = Math.max(5, self.shootCooldown - 2); if (self.weaponLevel >= 5) { self.shootCooldown = 3; } // Visual upgrade feedback tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); }; return self; }); var Zombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); self.health = 50; self.speed = 1.5; self.damage = 10; self.lastAttack = 0; self.attackCooldown = 60; self.update = function () { if (player) { var dx = player.x - self.x; var dy = player.y - 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; } if (distance < 50 && LK.ticks - self.lastAttack > self.attackCooldown) { player.takeDamage(self.damage); self.lastAttack = LK.ticks; } } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 100); return self.health <= 0; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2d1b1b }); /**** * Game Code ****/ var player; var zombies = []; var bullets = []; var boss = null; var keys = 0; var currentWave = 1; var waveInProgress = false; var zombiesSpawned = 0; var zombiesToSpawn = 0; var spawnTimer = 0; var moveButton, shootButton, joystickKnob; var isDragging = false; var isShootPressed = false; var joystickRadius = 120; var joystickCenterX = 200; var joystickCenterY = 2500; var currentMoveX = 0; var currentMoveY = 0; // UI Elements var waveText = new Text2('Wave 1', { size: 80, fill: 0xFFFFFF }); waveText.anchor.set(0.5, 0); LK.gui.top.addChild(waveText); var healthText = new Text2('Health: 100', { size: 60, fill: 0xFF0000 }); healthText.anchor.set(0, 0); healthText.x = 120; healthText.y = 20; LK.gui.topLeft.addChild(healthText); var keysText = new Text2('Keys: 0', { size: 60, fill: 0xFFD700 }); keysText.anchor.set(1, 0); LK.gui.topRight.addChild(keysText); var instructionText = new Text2('Survive the zombie waves!\nDefeat bosses to get keys!', { size: 50, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 0; instructionText.y = -200; LK.gui.center.addChild(instructionText); // Initialize player player = new Player(); player.x = 1024; player.y = 1366; game.addChild(player); // Control buttons with enhanced design moveButton = game.addChild(LK.getAsset('moveButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.6, scaleY: 1.6 })); moveButton.x = joystickCenterX; moveButton.y = joystickCenterY; moveButton.alpha = 0.4; // Add joystick knob joystickKnob = game.addChild(LK.getAsset('joystickKnob', { anchorX: 0.5, anchorY: 0.5 })); joystickKnob.x = joystickCenterX; joystickKnob.y = joystickCenterY; joystickKnob.alpha = 0.8; shootButton = game.addChild(LK.getAsset('shootButton', { anchorX: 0.5, anchorY: 0.5 })); shootButton.x = 1850; shootButton.y = 2500; shootButton.alpha = 0.6; function startWave() { if (currentWave > 5) { LK.showYouWin(); return; } waveInProgress = true; zombiesSpawned = 0; zombiesToSpawn = 5 + currentWave * 3; spawnTimer = 0; waveText.setText('Wave ' + currentWave); instructionText.setText(''); if (currentWave > 1) { player.upgrade(); } } 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 = -30; break; case 1: // Right zombie.x = 2078; zombie.y = Math.random() * 2732; break; case 2: // Bottom zombie.x = Math.random() * 2048; zombie.y = 2762; break; case 3: // Left zombie.x = -30; zombie.y = Math.random() * 2732; break; } zombie.health = 50 + currentWave * 10; zombie.speed = 1.5 + currentWave * 0.3; zombies.push(zombie); game.addChild(zombie); } function spawnBoss() { boss = new Boss(currentWave); boss.x = 1024; boss.y = 200; game.addChild(boss); } function shootBullet() { if (LK.ticks - player.lastShot < player.shootCooldown) return; var isSuper = player.weaponLevel >= 5; var bullet = new Bullet(isSuper); bullet.x = player.x; bullet.y = player.y; var nearestEnemy = null; var minDistance = Infinity; for (var i = 0; i < zombies.length; i++) { var distance = Math.sqrt(Math.pow(zombies[i].x - player.x, 2) + Math.pow(zombies[i].y - player.y, 2)); if (distance < minDistance) { minDistance = distance; nearestEnemy = zombies[i]; } } if (boss) { var bossDistance = Math.sqrt(Math.pow(boss.x - player.x, 2) + Math.pow(boss.y - player.y, 2)); if (bossDistance < minDistance) { nearestEnemy = boss; } } if (nearestEnemy) { var dx = nearestEnemy.x - bullet.x; var dy = nearestEnemy.y - bullet.y; var distance = Math.sqrt(dx * dx + dy * dy); bullet.dx = dx / distance; bullet.dy = dy / distance; } else { bullet.dx = 0; bullet.dy = -1; } bullets.push(bullet); game.addChild(bullet); player.lastShot = LK.ticks; LK.getSound('shoot').play(); } // Touch controls with smooth analog movement moveButton.down = function (x, y, obj) { isDragging = true; // Visual feedback - make joystick base slightly larger tween(moveButton, { scaleX: 1.8, scaleY: 1.8, alpha: 0.6 }, { duration: 150 }); }; shootButton.down = function (x, y, obj) { isShootPressed = true; // Visual feedback for shoot button tween(shootButton, { scaleX: 0.9, scaleY: 0.9, tint: 0xffaa00 }, { duration: 100 }); shootBullet(); }; shootButton.up = function (x, y, obj) { isShootPressed = false; // Return shoot button to normal tween(shootButton, { scaleX: 1, scaleY: 1, tint: 0xffffff }, { duration: 150 }); }; game.move = function (x, y, obj) { if (isDragging) { var dx = x - joystickCenterX; var dy = y - joystickCenterY; var distance = Math.sqrt(dx * dx + dy * dy); // Limit knob position within joystick radius if (distance > joystickRadius) { dx = dx / distance * joystickRadius; dy = dy / distance * joystickRadius; distance = joystickRadius; } // Update knob position smoothly joystickKnob.x = joystickCenterX + dx; joystickKnob.y = joystickCenterY + dy; // Calculate movement with smooth analog control var intensity = distance / joystickRadius; currentMoveX = dx / joystickRadius * player.speed * intensity; currentMoveY = dy / joystickRadius * player.speed * intensity; // Apply smooth movement to player if (player) { player.smoothMove(currentMoveX, currentMoveY); } } }; game.up = function (x, y, obj) { if (isDragging) { isDragging = false; currentMoveX = 0; currentMoveY = 0; // Return joystick to center with smooth animation tween(joystickKnob, { x: joystickCenterX, y: joystickCenterY }, { duration: 200, easing: tween.easeOut }); tween(moveButton, { scaleX: 1.6, scaleY: 1.6, alpha: 0.4 }, { duration: 200 }); } isShootPressed = false; }; // Start first wave startWave(); LK.playMusic('gameMusic'); game.update = function () { // Update UI healthText.setText('Health: ' + player.health); keysText.setText('Keys: ' + keys); // Update player movement if (player) { player.updateMovement(); } // Smooth continuous shooting when button held if (isShootPressed) { shootBullet(); } // Spawn zombies during wave if (waveInProgress && zombiesSpawned < zombiesToSpawn) { spawnTimer++; if (spawnTimer >= 60) { spawnZombie(); zombiesSpawned++; spawnTimer = 0; } } // Check if wave is complete if (waveInProgress && zombiesSpawned >= zombiesToSpawn && zombies.length === 0 && !boss) { spawnBoss(); } // Bullet collision detection for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; var hit = false; // Check zombie collisions for (var j = zombies.length - 1; j >= 0; j--) { if (bullet.intersects(zombies[j])) { if (zombies[j].takeDamage(bullet.damage)) { LK.getSound('zombieDeath').play(); LK.setScore(LK.getScore() + 10); zombies[j].destroy(); zombies.splice(j, 1); } bullet.destroy(); bullets.splice(i, 1); hit = true; break; } } // Check boss collision if (!hit && boss && bullet.intersects(boss)) { if (boss.takeDamage(bullet.damage)) { LK.getSound('bossDefeat').play(); LK.setScore(LK.getScore() + 100); // Drop key var key = new Key(); key.x = boss.x; key.y = boss.y; game.addChild(key); boss.destroy(); boss = null; waveInProgress = false; currentWave++; LK.setTimeout(function () { if (currentWave <= 5) { startWave(); } else { instructionText.setText('Congratulations!\nYou survived all waves!'); LK.setTimeout(function () { LK.showYouWin(); }, 3000); } }, 2000); } bullet.destroy(); bullets.splice(i, 1); } } };
===================================================================
--- original.js
+++ change.js
@@ -139,18 +139,61 @@
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
- var playerGraphics = self.attachAsset('player', {
+ // Create character design with multiple parts
+ var playerBase = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
+ var playerBody = self.attachAsset('playerBody', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ y: -5
+ });
+ var playerHead = self.attachAsset('playerHead', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ y: -25
+ });
self.health = 100;
self.maxHealth = 100;
self.speed = 5;
self.lastShot = 0;
self.shootCooldown = 15;
self.weaponLevel = 1;
+ self.velocityX = 0;
+ self.velocityY = 0;
+ self.friction = 0.85;
+ self.smoothMove = function (moveX, moveY) {
+ // Add acceleration instead of instant movement
+ self.velocityX += moveX * 0.3;
+ self.velocityY += moveY * 0.3;
+ // Cap maximum velocity
+ var maxVel = self.speed;
+ if (Math.abs(self.velocityX) > maxVel) self.velocityX = self.velocityX > 0 ? maxVel : -maxVel;
+ if (Math.abs(self.velocityY) > maxVel) self.velocityY = self.velocityY > 0 ? maxVel : -maxVel;
+ };
+ self.updateMovement = function () {
+ // Apply velocity to position
+ self.x += self.velocityX;
+ self.y += self.velocityY;
+ // Apply friction when not moving
+ self.velocityX *= self.friction;
+ self.velocityY *= self.friction;
+ // Keep player in bounds
+ self.x = Math.max(40, Math.min(2008, self.x));
+ self.y = Math.max(40, Math.min(2692, self.y));
+ // Rotate character slightly based on movement direction
+ if (Math.abs(self.velocityX) > 0.1 || Math.abs(self.velocityY) > 0.1) {
+ var targetRotation = Math.atan2(self.velocityY, self.velocityX) * 0.1;
+ tween(playerBase, {
+ rotation: targetRotation
+ }, {
+ duration: 200
+ });
+ }
+ };
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
@@ -163,8 +206,23 @@
self.shootCooldown = Math.max(5, self.shootCooldown - 2);
if (self.weaponLevel >= 5) {
self.shootCooldown = 3;
}
+ // Visual upgrade feedback
+ tween(self, {
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ tween(self, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200
+ });
+ }
+ });
};
return self;
});
var Zombie = Container.expand(function () {
@@ -220,11 +278,16 @@
var waveInProgress = false;
var zombiesSpawned = 0;
var zombiesToSpawn = 0;
var spawnTimer = 0;
-var moveButton, shootButton;
+var moveButton, shootButton, joystickKnob;
var isDragging = false;
var isShootPressed = false;
+var joystickRadius = 120;
+var joystickCenterX = 200;
+var joystickCenterY = 2500;
+var currentMoveX = 0;
+var currentMoveY = 0;
// UI Elements
var waveText = new Text2('Wave 1', {
size: 80,
fill: 0xFFFFFF
@@ -257,16 +320,26 @@
player = new Player();
player.x = 1024;
player.y = 1366;
game.addChild(player);
-// Control buttons
+// Control buttons with enhanced design
moveButton = game.addChild(LK.getAsset('moveButton', {
anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 1.6,
+ scaleY: 1.6
+}));
+moveButton.x = joystickCenterX;
+moveButton.y = joystickCenterY;
+moveButton.alpha = 0.4;
+// Add joystick knob
+joystickKnob = game.addChild(LK.getAsset('joystickKnob', {
+ anchorX: 0.5,
anchorY: 0.5
}));
-moveButton.x = 200;
-moveButton.y = 2500;
-moveButton.alpha = 0.6;
+joystickKnob.x = joystickCenterX;
+joystickKnob.y = joystickCenterY;
+joystickKnob.alpha = 0.8;
shootButton = game.addChild(LK.getAsset('shootButton', {
anchorX: 0.5,
anchorY: 0.5
}));
@@ -359,36 +432,88 @@
game.addChild(bullet);
player.lastShot = LK.ticks;
LK.getSound('shoot').play();
}
-// Touch controls
+// Touch controls with smooth analog movement
moveButton.down = function (x, y, obj) {
isDragging = true;
+ // Visual feedback - make joystick base slightly larger
+ tween(moveButton, {
+ scaleX: 1.8,
+ scaleY: 1.8,
+ alpha: 0.6
+ }, {
+ duration: 150
+ });
};
shootButton.down = function (x, y, obj) {
isShootPressed = true;
+ // Visual feedback for shoot button
+ tween(shootButton, {
+ scaleX: 0.9,
+ scaleY: 0.9,
+ tint: 0xffaa00
+ }, {
+ duration: 100
+ });
shootBullet();
};
shootButton.up = function (x, y, obj) {
isShootPressed = false;
+ // Return shoot button to normal
+ tween(shootButton, {
+ scaleX: 1,
+ scaleY: 1,
+ tint: 0xffffff
+ }, {
+ duration: 150
+ });
};
game.move = function (x, y, obj) {
if (isDragging) {
- var dx = x - moveButton.x;
- var dy = y - moveButton.y;
+ var dx = x - joystickCenterX;
+ var dy = y - joystickCenterY;
var distance = Math.sqrt(dx * dx + dy * dy);
- if (distance > 75) {
- dx = dx / distance * 75;
- dy = dy / distance * 75;
+ // Limit knob position within joystick radius
+ if (distance > joystickRadius) {
+ dx = dx / distance * joystickRadius;
+ dy = dy / distance * joystickRadius;
+ distance = joystickRadius;
}
- var moveX = dx / 75 * player.speed;
- var moveY = dy / 75 * player.speed;
- player.x = Math.max(40, Math.min(2008, player.x + moveX));
- player.y = Math.max(40, Math.min(2692, player.y + moveY));
+ // Update knob position smoothly
+ joystickKnob.x = joystickCenterX + dx;
+ joystickKnob.y = joystickCenterY + dy;
+ // Calculate movement with smooth analog control
+ var intensity = distance / joystickRadius;
+ currentMoveX = dx / joystickRadius * player.speed * intensity;
+ currentMoveY = dy / joystickRadius * player.speed * intensity;
+ // Apply smooth movement to player
+ if (player) {
+ player.smoothMove(currentMoveX, currentMoveY);
+ }
}
};
game.up = function (x, y, obj) {
- isDragging = false;
+ if (isDragging) {
+ isDragging = false;
+ currentMoveX = 0;
+ currentMoveY = 0;
+ // Return joystick to center with smooth animation
+ tween(joystickKnob, {
+ x: joystickCenterX,
+ y: joystickCenterY
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ tween(moveButton, {
+ scaleX: 1.6,
+ scaleY: 1.6,
+ alpha: 0.4
+ }, {
+ duration: 200
+ });
+ }
isShootPressed = false;
};
// Start first wave
startWave();
@@ -396,10 +521,14 @@
game.update = function () {
// Update UI
healthText.setText('Health: ' + player.health);
keysText.setText('Keys: ' + keys);
- // Auto shoot when button held
- if (isShootPressed && LK.ticks % 10 === 0) {
+ // Update player movement
+ if (player) {
+ player.updateMovement();
+ }
+ // Smooth continuous shooting when button held
+ if (isShootPressed) {
shootBullet();
}
// Spawn zombies during wave
if (waveInProgress && zombiesSpawned < zombiesToSpawn) {