User prompt
When choosing a plugin, creatures should not cause damage, and add more plugins, add plugins that give area damage, etc., and add a background model, I will change it. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
They die without touching me. Add a bullet model and when choosing an add-on, the creatures should not cause damage.
User prompt
There is a level up tab, add it as a model, I will change it and the bullet model should go directly to the man, not as a straight png, but straight
User prompt
add a level screen to show how many levels we have or how much of the other level is left and add an assets screen compatible with the police
User prompt
The issue is that when we get a skill, it should not go to living beings, it should come only to us, and also to living beings with weapons in their hands, and it should slow down the very fast speeds of the living beings a little.
User prompt
Reduce the number of living creatures coming, but increase it by 1 click after 3 minutes, so that it constantly uses weapons, and the gun barrel points to living creatures.
User prompt
Let the gun barrel also look at the creatures, and while you buy the add-ons, the game should pause, and the creatures should be a little smarter, and the creatures should come in stages.
User prompt
Let the gun be visible in our hand and have a bullet model when firing
User prompt
Let the creatures come a little later and give us a weapon model
User prompt
Please fix the bug: 'prepareWave is not defined' in or related to this line: 'prepareWave();' Line Number: 758
User prompt
Knk, look, creatures should behave a little differently from each other because when creatures are gathered somewhere and revolve around them, they cannot do anything. Also, they should come continuously, not in waves, but continuously and without stopping. Also, the game should wait like this while purchasing add-ons.
User prompt
Knk, look, the creatures should behave a little differently from each other because when you gather the creatures somewhere, for example, they cannot do anything when they revolve around you. Also, they should come continuously, not in waves, but continuously and without stopping. Also, the game should wait like this while purchasing add-ons.
User prompt
Let it be a continuous live stream and add something like artificial intelligence to the creatures so that it is not so stupid
User prompt
Don't let the creatures come all at once, let them come continuously and expand the playing area a little.
User prompt
Don't let other creatures come so much, let them increase over time, and make sure that almost no bullets miss. Make a better weapon's mechanic to turn into creatures.
Code edit (1 edits merged)
Please save this source code
Initial prompt
Beast Survivors
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Creature projectile class with unique behaviors var CreatureProjectile = Container.expand(function () { var self = Container.call(this); var asset = self.attachAsset('bulletModel', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 32; self.speed = 32; self.angle = 0; self.damage = 1; // Assign a unique behavior type to each projectile var behaviorTypes = ['homing', 'zigzag', 'boomerang', 'spiral', 'dash', 'orbit', 'bounce']; self.behavior = behaviorTypes[Math.floor(Math.random() * behaviorTypes.length)]; self.behaviorSeed = Math.random() * 10000; self.behaviorTick = 0; self.originX = self.x; self.originY = self.y; self.maxDistance = 1200 + Math.random() * 400; self.orbitAngle = Math.random() * Math.PI * 2; self.bounceCount = 0; self.update = function () { self.behaviorTick++; // Always fly straight toward the nearest enemy (no random behaviors) var nearest = null; var minDist = 999999; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; var dx = e.x - self.x; var dy = e.y - self.y; var d = Math.sqrt(dx * dx + dy * dy); if (d < minDist) { minDist = d; nearest = e; } } if (nearest && minDist > 1) { // Always point directly at the nearest enemy self.angle = Math.atan2(nearest.y - self.y, nearest.x - self.x); } // Move forward in a straight line self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; // Save last position for AI self.lastX = self.x; self.lastY = self.y; // Remove projectile if it has traveled too far from its origin var dx0 = self.x - self.originX; var dy0 = self.y - self.originY; if (dx0 * dx0 + dy0 * dy0 > self.maxDistance * self.maxDistance) { self.destroy(); } }; return self; }); // Creature weapon class (auto-attacks for player) var CreatureWeapon = Container.expand(function () { var self = Container.call(this); // Attach asset (box, yellow) var asset = self.attachAsset('creature', { anchorX: 0.5, anchorY: 0.5 }); // Attach weapon model (sword) as a visual var weaponModel = self.attachAsset('weaponModel', { anchorX: 0.5, anchorY: 0.8 }); weaponModel.y = 60; // Offset so it appears in front of the player weaponModel.rotation = Math.PI / 8 * (Math.random() > 0.5 ? 1 : -1); // Slight random angle for variety weaponModel.alpha = 0.85; // Weapon stats self.damage = 1; self.speed = 32; self.cooldown = 60; // frames between shots self.timer = 0; self.projectileCount = 1; self.spread = 0.2; // radians // Update method: fires projectiles if timer is up self.update = function () { if (self.timer > 0) { self.timer--; } else { self.fire(); self.timer = self.cooldown; } }; // Fire projectiles in a spread self.fire = function () { // Projectiles orbit and launch from around the player var now = Date.now(); for (var i = 0; i < self.projectileCount; i++) { // Orbit offset for each projectile var orbitAngle = 2 * Math.PI / self.projectileCount * i + now % 1000 / 1000 * Math.PI * 2; var launchDist = 120 + Math.random() * 30; var px = player.x + Math.cos(orbitAngle) * launchDist; var py = player.y + Math.sin(orbitAngle) * launchDist; // Clamp projectile spawn to play area if (px < 0) px = 0; if (px > GAME_WIDTH) px = GAME_WIDTH; if (py < 0) py = 0; if (py > GAME_HEIGHT) py = GAME_HEIGHT; // Aim at nearest enemy if possible var target = null; var minDist = 999999; for (var j = 0; j < enemies.length; j++) { var e = enemies[j]; var dx = e.x - px; var dy = e.y - py; var d = Math.sqrt(dx * dx + dy * dy); if (d < minDist) { minDist = d; target = e; } } var angle; if (target) { angle = Math.atan2(target.y - py, target.x - px); } else { angle = orbitAngle; } var proj = new CreatureProjectile(); proj.x = px; proj.y = py; proj.angle = angle; proj.speed = self.speed; proj.damage = self.damage; projectiles.push(proj); game.addChild(proj); } }; // Upgrade weapon self.upgrade = function (type) { if (type === 'damage') self.damage++; if (type === 'speed') self.speed += 6; if (type === 'cooldown' && self.cooldown > 20) self.cooldown -= 8; if (type === 'projectile') self.projectileCount++; if (type === 'spread') self.spread += 0.1; if (type === 'area') { // Add area damage property if (!self.areaDamage) self.areaDamage = 1;else self.areaDamage += 1; } if (type === 'pierce') { // Add piercing property if (!self.pierce) self.pierce = 1;else self.pierce += 1; } if (type === 'regen') { // Add regen to player if (!player.regen) player.regen = 1;else player.regen += 1; } if (type === 'expBoost') { // Add exp boost to player if (!player.expBoost) player.expBoost = 0.2;else player.expBoost += 0.2; } }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); var asset = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 48; // Slow down very fast speeds of living beings (enemies) self.speed = 6 + Math.random() * 2.2; // reduced max speed from 9 to 8.2 if (self.speed > 8) self.speed = 8; // clamp to max 8 self.hp = 2 + Math.floor(wave * 0.5); self.maxHp = self.hp; // For movement self.update = function () { // Save last position for AI self.lastX = self.x; self.lastY = self.y; // Move towards player var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } }; // Take damage self.takeDamage = function (amount) { self.hp -= amount; LK.effects.flashObject(self, 0xffff00, 200); if (self.hp <= 0) { spawnExp(self.x, self.y, 1 + Math.floor(wave * 0.2)); self.destroy(); return true; } return false; }; return self; }); // Experience gem class var ExpGem = Container.expand(function () { var self = Container.call(this); var asset = self.attachAsset('expGem', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 28; self.value = 1; self.update = function () { // Move towards player if close var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); var moveTarget = null; var minDist = dist; if (dist < 300) { moveTarget = player; minDist = dist; } // Also move towards living beings (enemies) that have weapons in their hands for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; // Assume enemies with weapons have a property hasWeapon === true if (e.hasWeapon) { var edx = e.x - self.x; var edy = e.y - self.y; var edist = Math.sqrt(edx * edx + edy * edy); if (edist < 300 && edist < minDist) { moveTarget = e; minDist = edist; } } } if (moveTarget && minDist < 300) { var mdx = moveTarget.x - self.x; var mdy = moveTarget.y - self.y; var mlen = Math.sqrt(mdx * mdx + mdy * mdy); if (mlen > 0) { self.x += mdx / mlen * 18; self.y += mdy / mlen * 18; } } }; return self; }); // Player character class var Player = Container.expand(function () { var self = Container.call(this); // Attach player asset (ellipse, green) var playerAsset = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Attach weapon model (gun) to player's hand var gunModel = self.attachAsset('weaponModel', { anchorX: 0.2, // grip point anchorY: 0.7 }); gunModel.x = 38; // offset to player's right hand gunModel.y = 38; gunModel.rotation = Math.PI / 8; gunModel.alpha = 0.95; self.gunModel = gunModel; // Set up player stats self.radius = 60; // for collision self.speed = 18; // movement speed per frame self.level = 1; self.exp = 0; self.expToLevel = 10; self.hp = 3; self.maxHp = 3; // For movement smoothing self.targetX = GAME_WIDTH / 2; self.targetY = GAME_HEIGHT / 2; // For invulnerability after hit self.invulnTicks = 0; // Update method self.update = function () { // Smoothly move towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > self.speed) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } else { self.x = self.targetX; self.y = self.targetY; } // Clamp to game area if (self.x < self.radius) self.x = self.radius; if (self.x > GAME_WIDTH - self.radius) self.x = GAME_WIDTH - self.radius; if (self.y < self.radius) self.y = self.radius; if (self.y > GAME_HEIGHT - self.radius) self.y = GAME_HEIGHT - self.radius; // Invulnerability timer if (self.invulnTicks > 0) { self.invulnTicks--; playerAsset.alpha = self.invulnTicks % 10 < 5 ? 0.5 : 1; } else { playerAsset.alpha = 1; } // Update gun model to follow hand (right side of player) if (self.gunModel) { // Gun follows player's facing direction (right side) self.gunModel.x = self.radius * 0.55; self.gunModel.y = self.radius * 0.25; // Find nearest living creature (enemy) var nearest = null; var minDist = 999999; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; var dx = e.x - (self.x + self.gunModel.x); var dy = e.y - (self.y + self.gunModel.y); var d = Math.sqrt(dx * dx + dy * dy); if (d < minDist) { minDist = d; nearest = e; } } if (nearest) { // Point gun barrel at nearest enemy var dx = nearest.x - (self.x + self.gunModel.x); var dy = nearest.y - (self.y + self.gunModel.y); self.gunModel.rotation = Math.atan2(dy, dx); } else { // Optionally, add a little bobbing for effect if no enemy self.gunModel.rotation = Math.PI / 8 + Math.sin(LK.ticks * 0.08) * 0.08; } } }; // Level up self.gainExp = function (amount) { var gain = amount; if (self.expBoost) gain = Math.floor(amount * (1 + self.expBoost)); self.exp += gain; while (self.exp >= self.expToLevel) { self.exp -= self.expToLevel; self.level++; self.expToLevel = Math.floor(self.expToLevel * 1.3 + 5); showLevelUp(); } updateExpBar(); }; // Take damage self.takeDamage = function () { if (self.invulnTicks > 0) return; self.hp--; updateHpBar(); self.invulnTicks = 60; LK.effects.flashObject(self, 0xff0000, 500); if (self.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ // Level up tab model (for future customization) // Weapon model asset (simple sword shape) // --- GUI Elements --- var player; var creatureWeapon; var projectiles = []; var enemies = []; var expGems = []; var wave = 1; // still used for scaling difficulty var dragNode = null; // --- GUI Elements --- var scoreTxt = new Text2('0', { size: 100, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var expBar = new Text2('', { size: 60, fill: 0xAAFF00 }); expBar.anchor.set(0.5, 0); LK.gui.top.addChild(expBar); var hpBar = new Text2('', { size: 60, fill: 0xFF4444 }); hpBar.anchor.set(0.5, 0); LK.gui.top.addChild(hpBar); // --- Level Progress Bar --- var levelProgressBar = new Text2('', { size: 48, fill: 0x00EAFF }); levelProgressBar.anchor.set(0.5, 0); LK.gui.top.addChild(levelProgressBar); // --- Asset Screen Button --- var assetScreenBtn = new Text2('Assets', { size: 60, fill: "#fff" }); assetScreenBtn.anchor.set(0.5, 0.5); assetScreenBtn.x = 1800; assetScreenBtn.y = 80; LK.gui.top.addChild(assetScreenBtn); var assetScreenPopup = null; assetScreenBtn.down = function (x, y, obj) { if (assetScreenPopup) return; assetScreenPopup = new Container(); var bg = LK.getAsset('levelUpBg', { width: 1200, height: 1200, color: 0x222244, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); assetScreenPopup.addChild(bg); bg.x = 0; bg.y = 0; var title = new Text2('Assets', { size: 120, fill: "#fff" }); title.anchor.set(0.5, 0); title.x = 0; title.y = -520; assetScreenPopup.addChild(title); // Show player, gun, and police-compatible asset (enemy) var yStart = -320; var yStep = 320; var assetList = [{ id: 'player', label: 'Player' }, { id: 'weaponModel', label: 'Gun' }, { id: 'enemy', label: 'Police' }]; for (var i = 0; i < assetList.length; i++) { var assetInfo = assetList[i]; var assetIcon = LK.getAsset(assetInfo.id, { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); assetIcon.x = -300; assetIcon.y = yStart + i * yStep; assetScreenPopup.addChild(assetIcon); var label = new Text2(assetInfo.label, { size: 80, fill: "#fff" }); label.anchor.set(0, 0.5); label.x = -180; label.y = assetIcon.y; assetScreenPopup.addChild(label); } // Close button var closeBtn = LK.getAsset('levelUpBtnClose', { width: 300, height: 100, color: 0x4444aa, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); closeBtn.x = 0; closeBtn.y = 520; assetScreenPopup.addChild(closeBtn); var closeTxt = new Text2('Close', { size: 60, fill: "#fff" }); closeTxt.anchor.set(0.5, 0.5); closeTxt.x = 0; closeTxt.y = closeBtn.y; assetScreenPopup.addChild(closeTxt); closeBtn.down = function (x, y, obj) { LK.gui.center.removeChild(assetScreenPopup); assetScreenPopup = null; }; assetScreenPopup.x = 0; assetScreenPopup.y = 0; LK.gui.center.addChild(assetScreenPopup); }; function updateExpBar() { expBar.setText('LV ' + player.level + ' EXP: ' + player.exp + '/' + player.expToLevel); // Level progress bar var percent = Math.min(1, player.exp / player.expToLevel); var barLen = 600; var filled = Math.floor(barLen * percent); var empty = barLen - filled; var bar = ''; for (var i = 0; i < filled / 20; i++) bar += '█'; for (var i = 0; i < empty / 20; i++) bar += '░'; levelProgressBar.setText('Level Progress: ' + bar + ' ' + Math.floor(percent * 100) + '%'); } function updateHpBar() { hpBar.setText('HP: ' + player.hp + '/' + player.maxHp); } function updateScore() { scoreTxt.setText('Wave: ' + wave); } // --- Asset initialization (shapes) --- // --- Game setup --- // Add background model (for future customization) var backgroundModel = LK.getAsset('levelUpBg', { anchorX: 0.5, anchorY: 0.5, scaleX: GAME_WIDTH / 100, scaleY: GAME_HEIGHT / 100, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2 }); game.addChild(backgroundModel); player = new Player(); // Expanded play area var GAME_WIDTH = 3072; var GAME_HEIGHT = 4096; player.x = GAME_WIDTH / 2; player.y = GAME_HEIGHT / 2; game.addChild(player); creatureWeapon = new CreatureWeapon(); game.addChild(creatureWeapon); updateExpBar(); updateHpBar(); updateScore(); // --- Level up popup --- var levelUpPopup = null; function showLevelUp() { if (levelUpPopup) return; // Already showing // Randomly pick 3 upgrades var upgrades = [{ type: 'damage', label: 'Creature Damage +' }, { type: 'speed', label: 'Creature Speed +' }, { type: 'cooldown', label: 'Faster Attacks' }, { type: 'projectile', label: 'More Projectiles' }, { type: 'spread', label: 'Wider Spread' }, { type: 'area', label: 'Area Damage (AOE)' }, { type: 'pierce', label: 'Piercing Projectiles' }, { type: 'regen', label: 'Regenerate HP' }, { type: 'expBoost', label: 'EXP Gain +' }]; // Shuffle and pick 3 for (var i = upgrades.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var t = upgrades[i]; upgrades[i] = upgrades[j]; upgrades[j] = t; } var options = upgrades.slice(0, 3); // Popup container levelUpPopup = new Container(); var bg = LK.getAsset('levelUpTab', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.2, scaleY: 6 }); levelUpPopup.addChild(bg); bg.x = 0; bg.y = 0; var title = new Text2('LEVEL UP!', { size: 120, fill: "#fff" }); title.anchor.set(0.5, 0); title.x = 0; title.y = -300; levelUpPopup.addChild(title); // Option buttons for (var i = 0; i < 3; i++) { (function (idx) { var opt = options[idx]; var btn = LK.getAsset('levelUpBtn' + idx, { width: 700, height: 140, color: 0x4444aa, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); btn.x = 0; btn.y = -80 + idx * 180; levelUpPopup.addChild(btn); var txt = new Text2(opt.label, { size: 70, fill: "#fff" }); txt.anchor.set(0.5, 0.5); txt.x = 0; txt.y = btn.y; levelUpPopup.addChild(txt); btn.down = function (x, y, obj) { creatureWeapon.upgrade(opt.type); // Remove popup LK.gui.center.removeChild(levelUpPopup); levelUpPopup = null; }; })(i); } levelUpPopup.x = 0; levelUpPopup.y = 0; LK.gui.center.addChild(levelUpPopup); } // --- Spawn experience gem --- function spawnExp(x, y, value) { var gem = new ExpGem(); gem.x = x; gem.y = y; gem.value = value; expGems.push(gem); game.addChild(gem); } // --- Continuous enemy spawn system --- var spawnDelay = 32; // frames between spawns, will decrease as wave increases var spawnDelayTimer = 0; // Add a delay before the first enemy spawns var initialSpawnDelay = 120; // 2 seconds at 60fps var initialSpawnDelayTimer = 0; // Limit for max living enemies, starts low and increases over time var maxLivingEnemies = 3; var maxLivingEnemiesIncreaseInterval = 60 * 60 * 3; // 3 minutes at 60fps var lastMaxLivingEnemiesIncreaseTick = 0; function updateSpawnRate() { // Increase spawn rate over time, but clamp to a minimum spawnDelay = Math.max(4, 32 - Math.floor(wave * 1.2)); } function spawnEnemy() { if (enemies.length >= maxLivingEnemies) return; // Don't spawn if at max var enemy = new Enemy(); // Give some enemies weapons in their hands (e.g. 30% chance) enemy.hasWeapon = Math.random() < 0.3; // Spawn at random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { // top enemy.x = Math.random() * GAME_WIDTH; enemy.y = -100; } else if (edge === 1) { // bottom enemy.x = Math.random() * GAME_WIDTH; enemy.y = GAME_HEIGHT + 100; } else if (edge === 2) { // left enemy.x = -100; enemy.y = Math.random() * GAME_HEIGHT; } else { // right enemy.x = GAME_WIDTH + 100; enemy.y = Math.random() * GAME_HEIGHT; } enemies.push(enemy); game.addChild(enemy); } // --- Game move handler (touch/mouse drag to move player) --- function handleMove(x, y, obj) { // Don't allow movement if level up popup is open if (levelUpPopup) return; // Clamp to avoid top left menu if (x < 100) x = 100; if (y < 0) y = 0; player.targetX = x; player.targetY = y; } game.move = handleMove; game.down = function (x, y, obj) { handleMove(x, y, obj); }; game.up = function (x, y, obj) { // No dragNode needed, movement is always allowed }; // --- Main game update loop --- game.update = function () { // Pause all game logic except GUI and popup when level up popup is open if (levelUpPopup) { // Only update GUI, skip all gameplay logic return; } // Player regen if (player.regen && LK.ticks % 90 === 0 && player.hp < player.maxHp) { player.hp += player.regen; if (player.hp > player.maxHp) player.hp = player.maxHp; updateHpBar(); } // Update player player.update(); // Update weapon creatureWeapon.update(); // Update projectiles for (var i = projectiles.length - 1; i >= 0; i--) { var proj = projectiles[i]; proj.update(); // Remove if out of bounds if (proj.x < -100 || proj.x > GAME_WIDTH + 100 || proj.y < -100 || proj.y > GAME_HEIGHT + 100) { proj.destroy(); projectiles.splice(i, 1); continue; } // Check collision with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; var dx = proj.x - enemy.x; var dy = proj.y - enemy.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < proj.radius + enemy.radius) { var killed = enemy.takeDamage(proj.damage); // Area damage if (creatureWeapon.areaDamage) { for (var k = 0; k < enemies.length; k++) { if (k !== j) { var e2 = enemies[k]; var d2 = Math.sqrt((proj.x - e2.x) * (proj.x - e2.x) + (proj.y - e2.y) * (proj.y - e2.y)); if (d2 < 180) { e2.takeDamage(creatureWeapon.areaDamage); } } } } // Piercing if (creatureWeapon.pierce && proj.pierced === undefined) { proj.pierced = 1; } if (creatureWeapon.pierce && proj.pierced < creatureWeapon.pierce) { proj.pierced++; // Do not destroy, allow to hit more enemies } else { proj.destroy(); projectiles.splice(i, 1); } if (killed) { enemies.splice(j, 1); } break; } } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); // Check collision with player var dx = enemy.x - player.x; var dy = enemy.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); // If enemy is still alive and close enough to player, but projectiles should kill before touching if (dist < enemy.radius + player.radius) { // Check if any projectile is close enough to kill this enemy before it touches the player var killedByProjectile = false; for (var p = 0; p < projectiles.length; p++) { var proj = projectiles[p]; var pdx = proj.x - enemy.x; var pdy = proj.y - enemy.y; var pdist = Math.sqrt(pdx * pdx + pdy * pdy); if (pdist < proj.radius + enemy.radius) { var killed = enemy.takeDamage(proj.damage); proj.destroy(); projectiles.splice(p, 1); if (killed) { enemies.splice(i, 1); killedByProjectile = true; } break; } } // Only damage player if enemy was not killed by projectile and not during level up if (!killedByProjectile && !levelUpPopup) { player.takeDamage(); // Knockback enemy var angle = Math.atan2(dy, dx); enemy.x += Math.cos(angle) * 120; enemy.y += Math.sin(angle) * 120; } // Prevent creatures from causing damage while level up popup is open if (!killedByProjectile && levelUpPopup) { // Do not damage player or apply knockback } } } // Update exp gems for (var i = expGems.length - 1; i >= 0; i--) { var gem = expGems[i]; gem.update(); // Collect if close to player var dx = gem.x - player.x; var dy = gem.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < gem.radius + player.radius) { player.gainExp(gem.value); gem.destroy(); expGems.splice(i, 1); } } // Continuous enemy spawn (no waves) if (!levelUpPopup) { // Wait for initial spawn delay before starting enemy spawns if (initialSpawnDelayTimer < initialSpawnDelay) { initialSpawnDelayTimer++; } else { spawnDelayTimer++; if (spawnDelayTimer >= spawnDelay) { spawnEnemy(); spawnDelayTimer = 0; } // Increase difficulty over time, every 10 seconds if (LK.ticks % (60 * 10) === 0) { wave++; updateScore(); updateSpawnRate(); } // Increase maxLivingEnemies by 1 every 3 minutes if (LK.ticks - lastMaxLivingEnemiesIncreaseTick >= maxLivingEnemiesIncreaseInterval) { maxLivingEnemies++; lastMaxLivingEnemiesIncreaseTick = LK.ticks; } } } }; // --- GUI positioning --- scoreTxt.x = GAME_WIDTH / 2; scoreTxt.y = 20; expBar.x = GAME_WIDTH / 2; expBar.y = 140; levelProgressBar.x = GAME_WIDTH / 2; levelProgressBar.y = 200; hpBar.x = GAME_WIDTH / 2; hpBar.y = 280; assetScreenBtn.x = GAME_WIDTH - 200; assetScreenBtn.y = 80; // --- Start first wave --- // No prepareWave needed; enemy spawning is now continuous.
===================================================================
--- original.js
+++ change.js
@@ -143,8 +143,24 @@
if (type === 'speed') self.speed += 6;
if (type === 'cooldown' && self.cooldown > 20) self.cooldown -= 8;
if (type === 'projectile') self.projectileCount++;
if (type === 'spread') self.spread += 0.1;
+ if (type === 'area') {
+ // Add area damage property
+ if (!self.areaDamage) self.areaDamage = 1;else self.areaDamage += 1;
+ }
+ if (type === 'pierce') {
+ // Add piercing property
+ if (!self.pierce) self.pierce = 1;else self.pierce += 1;
+ }
+ if (type === 'regen') {
+ // Add regen to player
+ if (!player.regen) player.regen = 1;else player.regen += 1;
+ }
+ if (type === 'expBoost') {
+ // Add exp boost to player
+ if (!player.expBoost) player.expBoost = 0.2;else player.expBoost += 0.2;
+ }
};
return self;
});
// Enemy class
@@ -320,9 +336,11 @@
}
};
// Level up
self.gainExp = function (amount) {
- self.exp += amount;
+ var gain = amount;
+ if (self.expBoost) gain = Math.floor(amount * (1 + self.expBoost));
+ self.exp += gain;
while (self.exp >= self.expToLevel) {
self.exp -= self.expToLevel;
self.level++;
self.expToLevel = Math.floor(self.expToLevel * 1.3 + 5);
@@ -503,8 +521,18 @@
scoreTxt.setText('Wave: ' + wave);
}
// --- Asset initialization (shapes) ---
// --- Game setup ---
+// Add background model (for future customization)
+var backgroundModel = LK.getAsset('levelUpBg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: GAME_WIDTH / 100,
+ scaleY: GAME_HEIGHT / 100,
+ x: GAME_WIDTH / 2,
+ y: GAME_HEIGHT / 2
+});
+game.addChild(backgroundModel);
player = new Player();
// Expanded play area
var GAME_WIDTH = 3072;
var GAME_HEIGHT = 4096;
@@ -535,8 +563,20 @@
label: 'More Projectiles'
}, {
type: 'spread',
label: 'Wider Spread'
+ }, {
+ type: 'area',
+ label: 'Area Damage (AOE)'
+ }, {
+ type: 'pierce',
+ label: 'Piercing Projectiles'
+ }, {
+ type: 'regen',
+ label: 'Regenerate HP'
+ }, {
+ type: 'expBoost',
+ label: 'EXP Gain +'
}];
// Shuffle and pick 3
for (var i = upgrades.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
@@ -672,8 +712,14 @@
if (levelUpPopup) {
// Only update GUI, skip all gameplay logic
return;
}
+ // Player regen
+ if (player.regen && LK.ticks % 90 === 0 && player.hp < player.maxHp) {
+ player.hp += player.regen;
+ if (player.hp > player.maxHp) player.hp = player.maxHp;
+ updateHpBar();
+ }
// Update player
player.update();
// Update weapon
creatureWeapon.update();
@@ -694,10 +740,31 @@
var dy = proj.y - enemy.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < proj.radius + enemy.radius) {
var killed = enemy.takeDamage(proj.damage);
- proj.destroy();
- projectiles.splice(i, 1);
+ // Area damage
+ if (creatureWeapon.areaDamage) {
+ for (var k = 0; k < enemies.length; k++) {
+ if (k !== j) {
+ var e2 = enemies[k];
+ var d2 = Math.sqrt((proj.x - e2.x) * (proj.x - e2.x) + (proj.y - e2.y) * (proj.y - e2.y));
+ if (d2 < 180) {
+ e2.takeDamage(creatureWeapon.areaDamage);
+ }
+ }
+ }
+ }
+ // Piercing
+ if (creatureWeapon.pierce && proj.pierced === undefined) {
+ proj.pierced = 1;
+ }
+ if (creatureWeapon.pierce && proj.pierced < creatureWeapon.pierce) {
+ proj.pierced++;
+ // Do not destroy, allow to hit more enemies
+ } else {
+ proj.destroy();
+ projectiles.splice(i, 1);
+ }
if (killed) {
enemies.splice(j, 1);
}
break;
@@ -739,8 +806,12 @@
var angle = Math.atan2(dy, dx);
enemy.x += Math.cos(angle) * 120;
enemy.y += Math.sin(angle) * 120;
}
+ // Prevent creatures from causing damage while level up popup is open
+ if (!killedByProjectile && levelUpPopup) {
+ // Do not damage player or apply knockback
+ }
}
}
// Update exp gems
for (var i = expGems.length - 1; i >= 0; i--) {
police pixel art. In-Game asset. 2d. High contrast. No shadows
black person pixel art. In-Game asset. High contrast. No shadows
glock pixel art. In-Game asset. High contrast. No shadows
pixel art bullet. In-Game asset. High contrast. No shadows
money pixel art. In-Game asset. High contrast. No shadows
a police themed level up screen pixel art. In-Game asset. High contrast. No shadows