User prompt
add ammo system
User prompt
add cheats tab
User prompt
deleate asste from classic menu
User prompt
add new asset to main menu
User prompt
add clasic menu
User prompt
remove main menu and add clasic menu
User prompt
add main menu
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'setText')' in or related to this line: 'scoreTxt.setText(score);' Line Number: 320
User prompt
remove character sellenct menu
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'toGlobal')' in or related to this line: 'var local = menuOverlay.toLocal(obj.parent.toGlobal({' Line Number: 384
User prompt
add character sellect menu
User prompt
Please fix the bug: 'Uncaught ReferenceError: menuActive is not defined' in or related to this line: 'if (menuActive) {' Line Number: 406
User prompt
remove menu
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'fill')' in or related to this line: 'skinLabelNodes[i].style.fill = i === selectedHeroSkin ? "#F7E733" : "#fff";' Line Number: 415
User prompt
add sellect character menu
User prompt
add healt bar
User prompt
add healt system
User prompt
add more zombies and assets
User prompt
add healt bar
User prompt
make wanes and stronger zombies
User prompt
add new asset to gun
User prompt
give a gun to characters hand
User prompt
add a menu
Code edit (1 edits merged)
Please save this source code
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); var bulletSprite = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.radius = bulletSprite.width / 2; self.vx = 0; self.vy = 0; self.lifetime = 60; // frames self.update = function () { self.x += self.vx; self.y += self.vy; self.lifetime--; }; return self; }); // Hero class var Hero = Container.expand(function () { var self = Container.call(this); var heroSprite = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); self.heroSprite = heroSprite; // Add gun sprite to hero's hand var gunSprite = self.attachAsset('gun', { anchorX: 0.2, // grip of gun anchorY: 0.5, width: heroSprite.width * 0.45, height: heroSprite.height * 0.22 }); gunSprite.x = heroSprite.width * 0.32; // offset to right hand gunSprite.y = 0; self.radius = heroSprite.width / 2; self.speed = 18; // pixels per move self.lastShotTick = 0; self.shootCooldown = 18; // frames between shots // Allow skin change self.setSkin = function (skinId) { if (!skinId || skinId === "hero") { // Already default return; } // Remove old sprite if (self.heroSprite && self.heroSprite.parent) { self.removeChild(self.heroSprite); } // Add new sprite var newSprite = self.attachAsset(skinId, { anchorX: 0.5, anchorY: 0.5, width: heroSprite.width, height: heroSprite.height }); self.heroSprite = newSprite; // Move gun to top if (gunSprite && gunSprite.parent) { self.removeChild(gunSprite); self.addChild(gunSprite); } // Update radius self.radius = newSprite.width / 2; }; self.update = function () {}; return self; }); // Powerup class var Powerup = Container.expand(function () { var self = Container.call(this); var powerupSprite = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.radius = powerupSprite.width / 2; self.type = 'rapid'; // only one type for MVP self.update = function () {}; return self; }); // Zombie class var Zombie = Container.expand(function () { var self = Container.call(this); // Default to normal zombie asset var zombieSprite = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); self.zombieSprite = zombieSprite; self.radius = zombieSprite.width / 2; self.baseSpeed = 3 + Math.random() * 2; // base speed, will be increased by wave self.speed = self.baseSpeed; self.target = null; // set to hero self.maxHp = 1; self.hp = 1; self.wave = 1; self.type = "normal"; // can be "normal", "fast", "tank", "crawler" self.setWave = function (wave) { self.wave = wave; // Remove old sprite if present if (self.zombieSprite && self.zombieSprite.parent) { self.removeChild(self.zombieSprite); } // Decide type var r = Math.random(); if (wave >= 7 && r < 0.18) { // Crawler: slow, small, hard to hit self.type = "crawler"; self.speed = 1.7 + 0.12 * wave; self.maxHp = 2 + Math.floor(wave / 3); self.hp = self.maxHp; self.zombieSprite = self.attachAsset('zombie_crawler', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.zombieSprite.width / 2; self.zombieSprite.tint = 0x8e8e8e; // grayish } else if (wave >= 6 && r < 0.38) { // Tank zombie: slow but high HP self.type = "tank"; self.speed = 2 + 0.15 * wave; self.maxHp = 3 + Math.floor(wave / 2); self.hp = self.maxHp; self.zombieSprite = self.attachAsset('zombie_tank', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.zombieSprite.width / 2; self.zombieSprite.tint = 0x6e4e2e; // brownish } else if (wave >= 3 && r < 0.63) { // Fast zombie: high speed, low HP self.type = "fast"; self.speed = 5 + 0.4 * wave; self.maxHp = 1; self.hp = 1; self.zombieSprite = self.attachAsset('zombie_fast', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.zombieSprite.width / 2; self.zombieSprite.tint = 0x7cf442; // bright green } else { // Normal zombie self.type = "normal"; self.speed = self.baseSpeed + (wave - 1) * 0.5; self.maxHp = 1 + Math.floor(wave / 4); self.hp = self.maxHp; self.zombieSprite = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.zombieSprite.width / 2; self.zombieSprite.tint = 0x7bbf3f; // normal green } }; // Health bar setup var healthBarW = zombieSprite.width * 0.7; var healthBarH = 16; var healthBarBg = LK.getAsset('hero', { anchorX: 0, anchorY: 0, width: healthBarW, height: healthBarH, color: 0x222222 }); healthBarBg.alpha = 0.7; var healthBarFill = LK.getAsset('hero', { anchorX: 0, anchorY: 0, width: healthBarW, height: healthBarH, color: 0x3FA34D }); healthBarFill.alpha = 0.92; self.addChild(healthBarBg); self.addChild(healthBarFill); self.update = function () { if (!self.target) return; var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += self.speed * dx / dist; self.y += self.speed * dy / dist; } // Update health bar position and fill var barY = -self.radius - 30; healthBarBg.x = -healthBarW / 2; healthBarBg.y = barY; healthBarFill.x = -healthBarW / 2; healthBarFill.y = barY; var ratio = Math.max(0, Math.min(1, self.hp / self.maxHp)); healthBarFill.width = healthBarW * ratio; if (ratio > 0.6) { healthBarFill.tint = 0x3FA34D; } else if (ratio > 0.3) { healthBarFill.tint = 0xF7E733; } else { healthBarFill.tint = 0xD83318; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Game area // Hero: red box // Zombie: green ellipse // Bullet: yellow box // Powerup: blue ellipse // Sound effects // Music // new gun asset var GAME_W = 2048; var GAME_H = 2732; // State var hero = null; var zombies = []; var bullets = []; var powerups = []; var dragNode = null; var lastIntersecting = false; var score = 0; var highScore = storage.highScore || 0; var wave = 1; var ticksSinceStart = 0; var zombieSpawnTick = 0; var zombieSpawnInterval = 90; // frames var rapidFireTicks = 0; // --- HEALTH SYSTEM --- var heroMaxHp = 5; var heroHp = heroMaxHp; // --- AMMO SYSTEM --- var heroMaxAmmo = 12; var heroAmmo = heroMaxAmmo; var heroReloading = false; var heroReloadTicks = 0; var heroReloadTime = 60; // frames to reload // Ammo bar UI var ammoBarBg = new Container(); var ammoBarWidth = 420; var ammoBarHeight = 28; var ammoBarBgRect = LK.getAsset('hero', { anchorX: 0, anchorY: 0, width: ammoBarWidth, height: ammoBarHeight, color: 0x222222 }); ammoBarBgRect.alpha = 0.7; ammoBarBg.addChild(ammoBarBgRect); var ammoBarFill = LK.getAsset('hero', { anchorX: 0, anchorY: 0, width: ammoBarWidth, height: ammoBarHeight, color: 0x3B7DD8 }); ammoBarFill.alpha = 0.92; ammoBarBg.addChild(ammoBarFill); ammoBarBg.x = (GAME_W - ammoBarWidth) / 2; ammoBarBg.y = 170; LK.gui.top.addChild(ammoBarBg); var ammoTxt = new Text2('', { size: 60, fill: "#fff" }); ammoTxt.anchor.set(0.5, 0); ammoTxt.x = GAME_W / 2; ammoTxt.y = 210; LK.gui.top.addChild(ammoTxt); function updateAmmoBar() { var ratio = Math.max(0, Math.min(1, heroAmmo / heroMaxAmmo)); ammoBarFill.width = ammoBarWidth * ratio; if (heroReloading) { ammoBarFill.tint = 0xF7E733; ammoTxt.setText('RELOADING...'); } else { ammoBarFill.tint = 0x3B7DD8; ammoTxt.setText(heroAmmo + ' / ' + heroMaxAmmo); } } updateAmmoBar(); // Health bar UI var healthBarBg = new Container(); var healthBarWidth = 520; var healthBarHeight = 38; var healthBarBgRect = LK.getAsset('hero', { anchorX: 0, anchorY: 0, width: healthBarWidth, height: healthBarHeight, color: 0x333333 }); healthBarBgRect.alpha = 0.7; healthBarBg.addChild(healthBarBgRect); var healthBarFill = LK.getAsset('hero', { anchorX: 0, anchorY: 0, width: healthBarWidth, height: healthBarHeight, color: 0x3FA34D }); healthBarFill.alpha = 0.92; healthBarBg.addChild(healthBarFill); healthBarBg.x = (GAME_W - healthBarWidth) / 2; healthBarBg.y = 110; LK.gui.top.addChild(healthBarBg); function updateHealthBar() { var ratio = Math.max(0, Math.min(1, heroHp / heroMaxHp)); healthBarFill.width = healthBarWidth * ratio; if (ratio > 0.6) { healthBarFill.tint = 0x3FA34D; } else if (ratio > 0.3) { healthBarFill.tint = 0xF7E733; } else { healthBarFill.tint = 0xD83318; } } updateHealthBar(); // Spawn hero at game start menuActive = false; if (hero) hero.destroy(); hero = new Hero(); hero.x = GAME_W / 2; hero.y = GAME_H / 2; game.addChild(hero); // Reset state // Move UI text declarations above their first use var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // High score text var highScoreTxt = new Text2('Best: ' + highScore, { size: 60, fill: "#fff" }); highScoreTxt.anchor.set(0.5, 0); highScoreTxt.y = 120; LK.gui.top.addChild(highScoreTxt); // Powerup text var powerupTxt = new Text2('', { size: 70, fill: 0x3B7DD8 }); powerupTxt.anchor.set(0.5, 0); powerupTxt.y = 200; LK.gui.top.addChild(powerupTxt); heroHp = heroMaxHp; updateHealthBar(); heroAmmo = heroMaxAmmo; heroReloading = false; heroReloadTicks = 0; updateAmmoBar(); score = 0; scoreTxt.setText(score); wave = 1; ticksSinceStart = 0; zombieSpawnTick = 0; zombieSpawnInterval = 90; rapidFireTicks = 0; for (var i = zombies.length - 1; i >= 0; i--) { zombies[i].destroy(); zombies.splice(i, 1); } for (var i = bullets.length - 1; i >= 0; i--) { bullets[i].destroy(); bullets.splice(i, 1); } for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].destroy(); powerups.splice(i, 1); } powerupTxt.setText(''); // --- CLASSIC MENU --- // Classic menu overlay and logic var classicMenuOverlay = new Container(); var menuBg = LK.getAsset('hero', { anchorX: 0.5, anchorY: 0.5, width: 900, height: 900, color: 0x222222 }); menuBg.alpha = 0.92; classicMenuOverlay.addChild(menuBg); classicMenuOverlay.x = GAME_W / 2; classicMenuOverlay.y = GAME_H / 2; // Title var menuTitle = new Text2('Zombie Survival', { size: 120, fill: "#fff" }); menuTitle.anchor.set(0.5, 0); menuTitle.y = -320; classicMenuOverlay.addChild(menuTitle); // Play button var playBtn = LK.getAsset('powerup', { anchorX: 0.5, anchorY: 0.5, width: 320, height: 120 }); playBtn.y = 80; classicMenuOverlay.addChild(playBtn); var playBtnText = new Text2('PLAY', { size: 90, fill: "#fff" }); playBtnText.anchor.set(0.5, 0.5); playBtnText.x = playBtn.x; playBtnText.y = playBtn.y; classicMenuOverlay.addChild(playBtnText); // Cheats tab button var cheatsBtn = LK.getAsset('powerup', { anchorX: 0.5, anchorY: 0.5, width: 320, height: 100, color: 0x4444aa }); cheatsBtn.y = 240; classicMenuOverlay.addChild(cheatsBtn); var cheatsBtnText = new Text2('CHEATS', { size: 70, fill: "#fff" }); cheatsBtnText.anchor.set(0.5, 0.5); cheatsBtnText.x = cheatsBtn.x; cheatsBtnText.y = cheatsBtn.y; classicMenuOverlay.addChild(cheatsBtnText); // High score display var menuHighScore = new Text2('Best: ' + (storage.highScore || 0), { size: 70, fill: "#fff" }); menuHighScore.anchor.set(0.5, 0); menuHighScore.y = -120; classicMenuOverlay.addChild(menuHighScore); var menuActive = true; game.addChild(classicMenuOverlay); // Cheats tab overlay var cheatsOverlay = new Container(); var cheatsBg = LK.getAsset('hero', { anchorX: 0.5, anchorY: 0.5, width: 800, height: 900, color: 0x222244 }); cheatsBg.alpha = 0.97; cheatsOverlay.addChild(cheatsBg); cheatsOverlay.x = GAME_W / 2; cheatsOverlay.y = GAME_H / 2; // Cheats title var cheatsTitle = new Text2('Cheats', { size: 100, fill: "#fff" }); cheatsTitle.anchor.set(0.5, 0); cheatsTitle.y = -340; cheatsOverlay.addChild(cheatsTitle); // Example cheat: Add 100 score var cheatScoreBtn = LK.getAsset('powerup', { anchorX: 0.5, anchorY: 0.5, width: 340, height: 110, color: 0x3B7DD8 }); cheatScoreBtn.y = -120; cheatsOverlay.addChild(cheatScoreBtn); var cheatScoreBtnText = new Text2('Add 100 Score', { size: 60, fill: "#fff" }); cheatScoreBtnText.anchor.set(0.5, 0.5); cheatScoreBtnText.x = cheatScoreBtn.x; cheatScoreBtnText.y = cheatScoreBtn.y; cheatsOverlay.addChild(cheatScoreBtnText); // Example cheat: Heal to full var cheatHealBtn = LK.getAsset('powerup', { anchorX: 0.5, anchorY: 0.5, width: 340, height: 110, color: 0x3FA34D }); cheatHealBtn.y = 40; cheatsOverlay.addChild(cheatHealBtn); var cheatHealBtnText = new Text2('Full Heal', { size: 60, fill: "#fff" }); cheatHealBtnText.anchor.set(0.5, 0.5); cheatHealBtnText.x = cheatHealBtn.x; cheatHealBtnText.y = cheatHealBtn.y; cheatsOverlay.addChild(cheatHealBtnText); // Close cheats tab var closeCheatsBtn = LK.getAsset('powerup', { anchorX: 0.5, anchorY: 0.5, width: 220, height: 90, color: 0xD83318 }); closeCheatsBtn.y = 300; cheatsOverlay.addChild(closeCheatsBtn); var closeCheatsBtnText = new Text2('CLOSE', { size: 55, fill: "#fff" }); closeCheatsBtnText.anchor.set(0.5, 0.5); closeCheatsBtnText.x = closeCheatsBtn.x; closeCheatsBtnText.y = closeCheatsBtn.y; cheatsOverlay.addChild(closeCheatsBtnText); cheatsOverlay.visible = false; game.addChild(cheatsOverlay); // Show/hide logic function showClassicMenu() { menuActive = true; classicMenuOverlay.visible = true; cheatsOverlay.visible = false; // Update high score display menuHighScore.setText('Best: ' + (storage.highScore || 0)); } function hideClassicMenu() { menuActive = false; classicMenuOverlay.visible = false; cheatsOverlay.visible = false; } // Cheats tab button handler cheatsBtn.interactive = true; cheatsBtn.down = function () { classicMenuOverlay.visible = false; cheatsOverlay.visible = true; }; // Close cheats tab handler closeCheatsBtn.interactive = true; closeCheatsBtn.down = function () { cheatsOverlay.visible = false; classicMenuOverlay.visible = true; }; // Cheat: Add 100 score cheatScoreBtn.interactive = true; cheatScoreBtn.down = function () { score += 100; scoreTxt.setText(score); if (score > highScore) { highScore = score; highScoreTxt.setText('Best: ' + highScore); storage.highScore = highScore; menuHighScore.setText('Best: ' + highScore); } }; // Cheat: Full heal cheatHealBtn.interactive = true; cheatHealBtn.down = function () { heroHp = heroMaxHp; updateHealthBar(); }; // Play button handler playBtn.interactive = true; playBtn.down = function () { hideClassicMenu(); // Reset game state if (hero) hero.destroy(); hero = new Hero(); hero.x = GAME_W / 2; hero.y = GAME_H / 2; game.addChild(hero); heroHp = heroMaxHp; updateHealthBar(); heroAmmo = heroMaxAmmo; heroReloading = false; heroReloadTicks = 0; updateAmmoBar(); score = 0; scoreTxt.setText(score); wave = 1; ticksSinceStart = 0; zombieSpawnTick = 0; zombieSpawnInterval = 90; rapidFireTicks = 0; for (var i = zombies.length - 1; i >= 0; i--) { zombies[i].destroy(); zombies.splice(i, 1); } for (var i = bullets.length - 1; i >= 0; i--) { bullets[i].destroy(); bullets.splice(i, 1); } for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].destroy(); powerups.splice(i, 1); } powerupTxt.setText(''); }; showClassicMenu(); // Helper: spawn zombie at random edge function spawnZombie() { var z = new Zombie(); // Pick edge: 0=top,1=bottom,2=left,3=right var edge = Math.floor(Math.random() * 4); var margin = 80; if (edge === 0) { // top z.x = margin + Math.random() * (GAME_W - 2 * margin); z.y = -z.radius; } else if (edge === 1) { // bottom z.x = margin + Math.random() * (GAME_W - 2 * margin); z.y = GAME_H + z.radius; } else if (edge === 2) { // left z.x = -z.radius; z.y = margin + Math.random() * (GAME_H - 2 * margin); } else { // right z.x = GAME_W + z.radius; z.y = margin + Math.random() * (GAME_H - 2 * margin); } // Set wave and type if (typeof z.setWave === "function") { z.setWave(wave); } z.target = hero; zombies.push(z); game.addChild(z); } // Helper: spawn powerup function spawnPowerup() { var p = new Powerup(); p.x = 200 + Math.random() * (GAME_W - 400); p.y = 300 + Math.random() * (GAME_H - 600); powerups.push(p); game.addChild(p); } // Helper: shoot bullet towards (tx,ty) function shootBullet(tx, ty) { if (heroReloading) return; if (heroAmmo <= 0) { // Start reload if not already heroReloading = true; heroReloadTicks = 0; updateAmmoBar(); return; } if (LK.ticks - hero.lastShotTick < (rapidFireTicks > 0 ? 6 : hero.shootCooldown)) return; var b = new Bullet(); b.x = hero.x; b.y = hero.y; var dx = tx - hero.x; var dy = ty - hero.y; var dist = Math.sqrt(dx * dx + dy * dy); var speed = 38; b.vx = speed * dx / dist; b.vy = speed * dy / dist; bullets.push(b); game.addChild(b); hero.lastShotTick = LK.ticks; heroAmmo--; if (heroAmmo <= 0) { heroReloading = true; heroReloadTicks = 0; } updateAmmoBar(); LK.getSound('shoot').play(); } // Helper: distance between two objects function dist2(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; return Math.sqrt(dx * dx + dy * dy); } // Dragging function handleMove(x, y, obj) { if (dragNode) { // Clamp hero inside game area var r = hero.radius; dragNode.x = Math.max(r, Math.min(GAME_W - r, x)); dragNode.y = Math.max(r, Math.min(GAME_H - r, y)); } } game.move = handleMove; game.down = function (x, y, obj) { // Only drag if menu is not active and touch is on hero if (!menuActive && dist2({ x: x, y: y }, hero) <= hero.radius * 1.2) { dragNode = hero; } }; game.up = function (x, y, obj) { dragNode = null; if (menuActive) return; // Shoot bullet towards release point if not dragging if (dist2({ x: x, y: y }, hero) > hero.radius * 1.2) { shootBullet(x, y); } }; // Main update loop game.update = function () { if (menuActive) return; // No menuActive check; game always runs ticksSinceStart++; // Increase wave every 900 ticks (~15s) if (ticksSinceStart % 900 === 0) { wave++; if (zombieSpawnInterval > 30) zombieSpawnInterval -= 8; } // Spawn zombies if (LK.ticks - zombieSpawnTick > zombieSpawnInterval) { // More zombies per spawn as wave increases var zombiesToSpawn = 1 + Math.floor(wave / 4); for (var n = 0; n < zombiesToSpawn; n++) { spawnZombie(); } zombieSpawnTick = LK.ticks; } // Maybe spawn powerup if (powerups.length === 0 && Math.random() < 0.002) { spawnPowerup(); } // Ammo reload logic if (heroReloading) { heroReloadTicks++; if (heroReloadTicks >= heroReloadTime) { heroAmmo = heroMaxAmmo; heroReloading = false; heroReloadTicks = 0; updateAmmoBar(); } else { updateAmmoBar(); } } // Update hero (nothing for now) hero.update(); // Update zombies for (var i = zombies.length - 1; i >= 0; i--) { var z = zombies[i]; z.update(); // Check collision with hero if (dist2(z, hero) < z.radius + hero.radius - 10) { LK.effects.flashScreen(0xff0000, 400); heroHp--; updateHealthBar(); if (heroHp <= 0) { if (score > highScore) { storage.highScore = score; } heroAmmo = heroMaxAmmo; heroReloading = false; heroReloadTicks = 0; updateAmmoBar(); LK.showGameOver(); showClassicMenu(); return; } // Remove zombie on hit to prevent instant double hit z.destroy(); zombies.splice(i, 1); continue; } } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); // Remove if out of bounds or expired if (b.x < -100 || b.x > GAME_W + 100 || b.y < -100 || b.y > GAME_H + 100 || b.lifetime <= 0) { b.destroy(); bullets.splice(i, 1); continue; } // Check collision with zombies for (var j = zombies.length - 1; j >= 0; j--) { var z = zombies[j]; if (dist2(b, z) < b.radius + z.radius - 10) { // Damage zombie if (typeof z.hp === "number") { z.hp--; LK.effects.flashObject(z, 0xffffff, 120); if (z.hp <= 0) { LK.getSound('zombie_die').play(); score++; scoreTxt.setText(score); if (score > highScore) { highScore = score; highScoreTxt.setText('Best: ' + highScore); storage.highScore = highScore; } z.destroy(); zombies.splice(j, 1); } } else { // fallback: destroy if no hp LK.getSound('zombie_die').play(); score++; scoreTxt.setText(score); if (score > highScore) { highScore = score; highScoreTxt.setText('Best: ' + highScore); storage.highScore = highScore; } z.destroy(); zombies.splice(j, 1); } b.destroy(); bullets.splice(i, 1); break; } } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { var p = powerups[i]; // Check collision with hero if (dist2(p, hero) < p.radius + hero.radius - 10) { LK.getSound('powerup').play(); rapidFireTicks = 360; // 6 seconds powerupTxt.setText('Rapid Fire!'); LK.effects.flashObject(hero, 0x3b7dd8, 400); p.destroy(); powerups.splice(i, 1); } } // Powerup timer if (rapidFireTicks > 0) { rapidFireTicks--; if (rapidFireTicks === 0) { powerupTxt.setText(''); } } // Update powerup text alpha for effect if (rapidFireTicks > 0) { powerupTxt.alpha = 0.7 + 0.3 * Math.sin(LK.ticks / 6); } else { powerupTxt.alpha = 1; } }; // Start music LK.playMusic('bgmusic', { fade: { start: 0, end: 0.7, duration: 1200 } });
===================================================================
--- original.js
+++ change.js
@@ -245,11 +245,62 @@
var ticksSinceStart = 0;
var zombieSpawnTick = 0;
var zombieSpawnInterval = 90; // frames
var rapidFireTicks = 0;
-// --- HEALTH SYSTEM ---
+// --- HEALTH SYSTEM ---
var heroMaxHp = 5;
var heroHp = heroMaxHp;
+// --- AMMO SYSTEM ---
+var heroMaxAmmo = 12;
+var heroAmmo = heroMaxAmmo;
+var heroReloading = false;
+var heroReloadTicks = 0;
+var heroReloadTime = 60; // frames to reload
+// Ammo bar UI
+var ammoBarBg = new Container();
+var ammoBarWidth = 420;
+var ammoBarHeight = 28;
+var ammoBarBgRect = LK.getAsset('hero', {
+ anchorX: 0,
+ anchorY: 0,
+ width: ammoBarWidth,
+ height: ammoBarHeight,
+ color: 0x222222
+});
+ammoBarBgRect.alpha = 0.7;
+ammoBarBg.addChild(ammoBarBgRect);
+var ammoBarFill = LK.getAsset('hero', {
+ anchorX: 0,
+ anchorY: 0,
+ width: ammoBarWidth,
+ height: ammoBarHeight,
+ color: 0x3B7DD8
+});
+ammoBarFill.alpha = 0.92;
+ammoBarBg.addChild(ammoBarFill);
+ammoBarBg.x = (GAME_W - ammoBarWidth) / 2;
+ammoBarBg.y = 170;
+LK.gui.top.addChild(ammoBarBg);
+var ammoTxt = new Text2('', {
+ size: 60,
+ fill: "#fff"
+});
+ammoTxt.anchor.set(0.5, 0);
+ammoTxt.x = GAME_W / 2;
+ammoTxt.y = 210;
+LK.gui.top.addChild(ammoTxt);
+function updateAmmoBar() {
+ var ratio = Math.max(0, Math.min(1, heroAmmo / heroMaxAmmo));
+ ammoBarFill.width = ammoBarWidth * ratio;
+ if (heroReloading) {
+ ammoBarFill.tint = 0xF7E733;
+ ammoTxt.setText('RELOADING...');
+ } else {
+ ammoBarFill.tint = 0x3B7DD8;
+ ammoTxt.setText(heroAmmo + ' / ' + heroMaxAmmo);
+ }
+}
+updateAmmoBar();
// Health bar UI
var healthBarBg = new Container();
var healthBarWidth = 520;
var healthBarHeight = 38;
@@ -318,8 +369,12 @@
powerupTxt.y = 200;
LK.gui.top.addChild(powerupTxt);
heroHp = heroMaxHp;
updateHealthBar();
+heroAmmo = heroMaxAmmo;
+heroReloading = false;
+heroReloadTicks = 0;
+updateAmmoBar();
score = 0;
scoreTxt.setText(score);
wave = 1;
ticksSinceStart = 0;
@@ -537,8 +592,12 @@
hero.y = GAME_H / 2;
game.addChild(hero);
heroHp = heroMaxHp;
updateHealthBar();
+ heroAmmo = heroMaxAmmo;
+ heroReloading = false;
+ heroReloadTicks = 0;
+ updateAmmoBar();
score = 0;
scoreTxt.setText(score);
wave = 1;
ticksSinceStart = 0;
@@ -600,8 +659,16 @@
game.addChild(p);
}
// Helper: shoot bullet towards (tx,ty)
function shootBullet(tx, ty) {
+ if (heroReloading) return;
+ if (heroAmmo <= 0) {
+ // Start reload if not already
+ heroReloading = true;
+ heroReloadTicks = 0;
+ updateAmmoBar();
+ return;
+ }
if (LK.ticks - hero.lastShotTick < (rapidFireTicks > 0 ? 6 : hero.shootCooldown)) return;
var b = new Bullet();
b.x = hero.x;
b.y = hero.y;
@@ -613,8 +680,14 @@
b.vy = speed * dy / dist;
bullets.push(b);
game.addChild(b);
hero.lastShotTick = LK.ticks;
+ heroAmmo--;
+ if (heroAmmo <= 0) {
+ heroReloading = true;
+ heroReloadTicks = 0;
+ }
+ updateAmmoBar();
LK.getSound('shoot').play();
}
// Helper: distance between two objects
function dist2(a, b) {
@@ -674,8 +747,20 @@
// Maybe spawn powerup
if (powerups.length === 0 && Math.random() < 0.002) {
spawnPowerup();
}
+ // Ammo reload logic
+ if (heroReloading) {
+ heroReloadTicks++;
+ if (heroReloadTicks >= heroReloadTime) {
+ heroAmmo = heroMaxAmmo;
+ heroReloading = false;
+ heroReloadTicks = 0;
+ updateAmmoBar();
+ } else {
+ updateAmmoBar();
+ }
+ }
// Update hero (nothing for now)
hero.update();
// Update zombies
for (var i = zombies.length - 1; i >= 0; i--) {
@@ -689,8 +774,12 @@
if (heroHp <= 0) {
if (score > highScore) {
storage.highScore = score;
}
+ heroAmmo = heroMaxAmmo;
+ heroReloading = false;
+ heroReloadTicks = 0;
+ updateAmmoBar();
LK.showGameOver();
showClassicMenu();
return;
}
zombie. In-Game asset. 2d. High contrast. No shadows
bullet. In-Game asset. 2d. High contrast. No shadows
power up. In-Game asset. 2d. High contrast. No shadows
pistol. In-Game asset. 2d. High contrast. No shadows
crawler zombie. In-Game asset. 2d. High contrast. No shadows
runner zombie. In-Game asset. 2d. High contrast. No shadows
tank zombie. In-Game asset. 2d. High contrast. No shadows
man. In-Game asset. 2d. High contrast. No shadows