User prompt
Make the zombies and the bullet more slow
Code edit (1 edits merged)
Please save this source code
User prompt
Monster Gold Rush
Initial prompt
Make a game, let there be 3 types of monsters, let them follow me, each of them has different features, ranged, rangeless, attacking from underground, and so on, so that I can kill them and collect gold from them, I can buy something from the store at the top right with the gold that comes out, and the store mechanics are like this, if I buy one of those three items, the other items will go randomly, make the passives of the items yourself, but be unique.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Burrower monster var Burrower = Container.expand(function () { var self = Container.call(this); var burrowerGfx = self.attachAsset('burrower', { anchorX: 0.5, anchorY: 0.5 }); self.radius = burrowerGfx.width / 2; self.speed = 10; self.hp = 1; self.type = 'burrower'; self.burrowTimer = 0; self.burrowInterval = 90 + Math.floor(Math.random() * 60); self.burrowed = false; self.update = function () { if (self.burrowed) { self.burrowTimer--; if (self.burrowTimer <= 0) { // Unburrow self.burrowed = false; burrowerGfx.alpha = 1; self.burrowTimer = self.burrowInterval; } // Move fast toward hero var dx = hero.x - self.x; var dy = hero.y - self.y; var d = Math.sqrt(dx * dx + dy * dy); if (d > 0.1) { self.x += dx / d * (self.speed * 2.2); self.y += dy / d * (self.speed * 2.2); } } else { self.burrowTimer--; if (self.burrowTimer <= 0) { // Burrow self.burrowed = true; burrowerGfx.alpha = 0.3; self.burrowTimer = 36 + Math.floor(Math.random() * 24); } // Move toward hero var dx = hero.x - self.x; var dy = hero.y - self.y; var d = Math.sqrt(dx * dx + dy * dy); if (d > 0.1) { self.x += dx / d * self.speed; self.y += dy / d * self.speed; } } }; self.flash = function () { tween(burrowerGfx, { alpha: 0.1 }, { duration: 40, onFinish: function onFinish() { tween(burrowerGfx, { alpha: self.burrowed ? 0.3 : 1 }, { duration: 40 }); } }); }; return self; }); // Chaser monster var Chaser = Container.expand(function () { var self = Container.call(this); var chaserGfx = self.attachAsset('chaser', { anchorX: 0.5, anchorY: 0.5 }); self.radius = chaserGfx.width / 2; self.speed = 7.5; self.hp = 2; self.type = 'chaser'; self.update = function () { // Move toward hero var dx = hero.x - self.x; var dy = hero.y - self.y; var d = Math.sqrt(dx * dx + dy * dy); if (d > 0.1) { self.x += dx / d * self.speed; self.y += dy / d * self.speed; } }; self.flash = function () { tween(chaserGfx, { alpha: 0.3 }, { duration: 60, onFinish: function onFinish() { tween(chaserGfx, { alpha: 1 }, { duration: 60 }); } }); }; return self; }); // Gold coin var Gold = Container.expand(function () { var self = Container.call(this); var goldGfx = self.attachAsset('gold', { anchorX: 0.5, anchorY: 0.5 }); self.radius = goldGfx.width / 2; self.vx = 0; self.vy = 0; self.update = function () { self.x += self.vx; self.y += self.vy; // Slow down self.vx *= 0.92; self.vy *= 0.92; }; return self; }); // Hero class var Hero = Container.expand(function () { var self = Container.call(this); var heroGfx = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); self.radius = heroGfx.width / 2; self.speed = 22; self.shootCooldown = 0; self.shootInterval = 18; // frames self.invuln = 0; self.hp = 3; self.update = function () { if (self.shootCooldown > 0) self.shootCooldown--; if (self.invuln > 0) self.invuln--; }; // Flash when hit self.flash = function () { tween(heroGfx, { alpha: 0.3 }, { duration: 80, onFinish: function onFinish() { tween(heroGfx, { alpha: 1 }, { duration: 80 }); } }); }; return self; }); // Hero bullet var HeroBullet = Container.expand(function () { var self = Container.call(this); var bulletGfx = self.attachAsset('herobullet', { anchorX: 0.5, anchorY: 0.5 }); self.radius = bulletGfx.width / 2; self.speed = 38; self.dirX = 0; self.dirY = -1; self.damage = 1; self.update = function () { self.x += self.dirX * self.speed; self.y += self.dirY * self.speed; }; return self; }); // Monster bullet (spit) var MonsterBullet = Container.expand(function () { var self = Container.call(this); var bulletGfx = self.attachAsset('herobullet', { anchorX: 0.5, anchorY: 0.5 }); bulletGfx.tint = 0x7cfd3a; self.radius = bulletGfx.width / 2; self.speed = 16; self.dirX = 0; self.dirY = 1; self.damage = 1; self.update = function () { self.x += self.dirX * self.speed; self.y += self.dirY * self.speed; }; return self; }); // Spitter monster var Spitter = Container.expand(function () { var self = Container.call(this); var spitterGfx = self.attachAsset('spitter', { anchorX: 0.5, anchorY: 0.5 }); self.radius = spitterGfx.width / 2; self.speed = 4.5; self.hp = 2; self.type = 'spitter'; self.shootCooldown = 0; self.shootInterval = 60 + Math.floor(Math.random() * 30); self.update = function () { // Keep distance from hero, shoot var dx = hero.x - self.x; var dy = hero.y - self.y; var d = Math.sqrt(dx * dx + dy * dy); if (d > 400) { self.x += dx / d * self.speed; self.y += dy / d * self.speed; } else if (d < 320) { self.x -= dx / d * self.speed; self.y -= dy / d * self.speed; } if (self.shootCooldown > 0) self.shootCooldown--;else { // Spit at hero var spit = new MonsterBullet(); spit.x = self.x; spit.y = self.y; var tx = hero.x - self.x; var ty = hero.y - self.y; var td = Math.sqrt(tx * tx + ty * ty); spit.dirX = td > 0.1 ? tx / td : 0; spit.dirY = td > 0.1 ? ty / td : 0; spit.speed = 16; spit.radius = 32; monsterBullets.push(spit); game.addChild(spit); self.shootCooldown = self.shootInterval; } }; self.flash = function () { tween(spitterGfx, { alpha: 0.3 }, { duration: 60, onFinish: function onFinish() { tween(spitterGfx, { alpha: 1 }, { duration: 60 }); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Sound effects // Store button highlight // Store button background // Gold coin // Hero bullet // Burrower monster // Spitter monster // Chaser monster // Hero // Global variables var hero = new Hero(); var heroBullets = []; var monsters = []; var monsterBullets = []; var golds = []; var gold = 0; var storeBtns = []; var passives = []; var availablePassives = [{ id: 'firerate', name: 'Rapid Fire', desc: 'Shoot much faster.', apply: function apply() { hero.shootInterval = Math.max(6, hero.shootInterval - 8); } }, { id: 'pierce', name: 'Piercing Shots', desc: 'Bullets pierce through 1 extra enemy.', apply: function apply() { passives.push({ id: 'pierce', stacks: 1 }); } }, { id: 'lifesteal', name: 'Lifesteal', desc: 'Gain 1 HP every 8 gold picked up.', apply: function apply() { passives.push({ id: 'lifesteal', stacks: 1, counter: 0 }); } }, { id: 'spread', name: 'Spread Shot', desc: 'Shoot 3 bullets in a spread.', apply: function apply() { passives.push({ id: 'spread', stacks: 1 }); } }, { id: 'regen', name: 'Regeneration', desc: 'Regenerate 1 HP every 12 seconds.', apply: function apply() { passives.push({ id: 'regen', stacks: 1, timer: 0 }); } }, { id: 'speed', name: 'Speed Boost', desc: 'Move much faster.', apply: function apply() { hero.speed += 7; } }, { id: 'bigshot', name: 'Big Bullets', desc: 'Bullets are much larger.', apply: function apply() { passives.push({ id: 'bigshot', stacks: 1 }); } }, { id: 'goldboost', name: 'Gold Magnet', desc: 'Gold is attracted to you.', apply: function apply() { passives.push({ id: 'goldboost', stacks: 1 }); } }, { id: 'maxhp', name: 'Max HP Up', desc: 'Increase max HP by 1.', apply: function apply() { hero.hp++; } }]; // Store state var storeChoices = []; function getRandomPassive(excludeIds) { var pool = []; for (var i = 0; i < availablePassives.length; ++i) { var id = availablePassives[i].id; var already = false; for (var j = 0; j < excludeIds.length; ++j) { if (excludeIds[j] === id) { already = true; break; } } if (!already) pool.push(availablePassives[i]); } if (pool.length === 0) pool = availablePassives; return pool[Math.floor(Math.random() * pool.length)]; } function rerollStore() { storeChoices = []; var exclude = []; for (var i = 0; i < 3; ++i) { var p = getRandomPassive(exclude); storeChoices.push(p); exclude.push(p.id); } updateStoreBtns(); } function updateStoreBtns() { for (var i = 0; i < storeBtns.length; ++i) { var btn = storeBtns[i]; var p = storeChoices[i]; btn.passive = p; btn.txt.setText(p.name); btn.desc.setText(p.desc); btn.price.setText("5"); } } // GUI var goldTxt = new Text2('0', { size: 90, fill: 0xFFE066 }); goldTxt.anchor.set(1, 0); LK.gui.topRight.addChild(goldTxt); var hpTxt = new Text2('❤❤❤', { size: 90, fill: 0xFF3A3A }); hpTxt.anchor.set(0, 0); LK.gui.top.addChild(hpTxt); // Store buttons (top right, below gold) for (var i = 0; i < 3; ++i) { var btn = new Container(); var bg = btn.attachAsset('storebtn', { anchorX: 1, anchorY: 0 }); btn.x = 2048 - 40; btn.y = 160 + i * 140; btn.txt = new Text2('', { size: 54, fill: 0xFFE066 }); btn.txt.anchor.set(1, 0); btn.txt.x = 380; btn.txt.y = 12; btn.addChild(btn.txt); btn.desc = new Text2('', { size: 36, fill: 0xCCCCCC }); btn.desc.anchor.set(1, 0); btn.desc.x = 380; btn.desc.y = 62; btn.addChild(btn.desc); btn.price = new Text2('5', { size: 48, fill: 0xFFD700 }); btn.price.anchor.set(0, 0); btn.price.x = 20; btn.price.y = 30; btn.addChild(btn.price); btn.index = i; storeBtns.push(btn); game.addChild(btn); } // Place hero in center hero.x = 2048 / 2; hero.y = 2732 / 2; game.addChild(hero); // Initial monsters function spawnMonster() { var edge = Math.floor(Math.random() * 4); var x, y; if (edge === 0) { // top x = 200 + Math.random() * (2048 - 400); y = -80; } else if (edge === 1) { // bottom x = 200 + Math.random() * (2048 - 400); y = 2732 + 80; } else if (edge === 2) { // left x = -80; y = 200 + Math.random() * (2732 - 400); } else { // right x = 2048 + 80; y = 200 + Math.random() * (2732 - 400); } var t = Math.random(); var m; if (t < 0.4) m = new Chaser();else if (t < 0.7) m = new Spitter();else m = new Burrower(); m.x = x; m.y = y; monsters.push(m); game.addChild(m); } for (var i = 0; i < 5; ++i) spawnMonster(); // Store logic rerollStore(); // Dragging var dragNode = null; function handleMove(x, y, obj) { if (dragNode) { // Clamp to screen var r = hero.radius; dragNode.x = Math.max(r, Math.min(2048 - r, x)); dragNode.y = Math.max(r, Math.min(2732 - r, y)); } } game.move = handleMove; game.down = function (x, y, obj) { // Check store buttons first for (var i = 0; i < storeBtns.length; ++i) { var btn = storeBtns[i]; var bx = btn.x - 420, by = btn.y, bw = 420, bh = 120; if (x >= bx && x <= bx + bw && y >= by && y <= by + bh) { // Buy if (gold >= 5) { gold -= 5; goldTxt.setText(gold); btn.passive.apply(); LK.getSound('buy').play(); rerollStore(); } return; } } // Drag hero dragNode = hero; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; // Shoot logic function shootAt(tx, ty) { if (hero.shootCooldown > 0) return; hero.shootCooldown = hero.shootInterval; var dx = tx - hero.x; var dy = ty - hero.y; var d = Math.sqrt(dx * dx + dy * dy); if (d < 0.1) { dx = 0; dy = -1; d = 1; } var spread = 0; var n = 1; var big = false; for (var i = 0; i < passives.length; ++i) { if (passives[i].id === 'spread') n = 3; if (passives[i].id === 'bigshot') big = true; } for (var i = 0; i < n; ++i) { var b = new HeroBullet(); b.x = hero.x; b.y = hero.y; var angle = Math.atan2(dy, dx); if (n > 1) angle += (i - 1) * 0.18; b.dirX = Math.cos(angle); b.dirY = Math.sin(angle); if (big) { b.scaleX = b.scaleY = 1.7; b.radius *= 1.7; } heroBullets.push(b); game.addChild(b); } LK.getSound('shoot').play(); } // Touch anywhere to shoot game.on('down', function (x, y, obj) { // Don't shoot if clicking store for (var i = 0; i < storeBtns.length; ++i) { var btn = storeBtns[i]; var bx = btn.x - 420, by = btn.y, bw = 420, bh = 120; if (x >= bx && x <= bx + bw && y >= by && y <= by + bh) return; } shootAt(x, y); }); // Helper: collision function circlesIntersect(a, b) { var dx = a.x - b.x, dy = a.y - b.y; var r = (a.radius || 40) + (b.radius || 40); return dx * dx + dy * dy < r * r; } // Update GUI function updateHP() { var s = ''; for (var i = 0; i < hero.hp; ++i) s += '❤'; hpTxt.setText(s); } // Main update game.update = function () { // Hero update hero.update(); // Regen passive for (var i = 0; i < passives.length; ++i) { if (passives[i].id === 'regen') { passives[i].timer++; if (passives[i].timer >= 60 * 12) { hero.hp++; updateHP(); passives[i].timer = 0; } } } // Hero bullets for (var i = heroBullets.length - 1; i >= 0; --i) { var b = heroBullets[i]; b.update(); // Offscreen if (b.x < -60 || b.x > 2048 + 60 || b.y < -60 || b.y > 2732 + 60) { b.destroy(); heroBullets.splice(i, 1); continue; } // Hit monster var pierced = false; for (var j = monsters.length - 1; j >= 0; --j) { var m = monsters[j]; if (m.type === 'burrower' && m.burrowed) continue; if (circlesIntersect(b, m)) { m.hp -= b.damage; m.flash(); LK.getSound('hit').play(); if (m.hp <= 0) { // Drop gold var g = new Gold(); g.x = m.x; g.y = m.y; g.vx = (Math.random() - 0.5) * 8; g.vy = (Math.random() - 0.5) * 8; golds.push(g); game.addChild(g); LK.getSound('monsterdie').play(); m.destroy(); monsters.splice(j, 1); } // Pierce? var pierce = 0; for (var k = 0; k < passives.length; ++k) if (passives[k].id === 'pierce') pierce++; if (pierce > 0 && !pierced) { b.damage--; pierced = true; if (b.damage <= 0) { b.destroy(); heroBullets.splice(i, 1); } } else { b.destroy(); heroBullets.splice(i, 1); } break; } } } // Monster bullets for (var i = monsterBullets.length - 1; i >= 0; --i) { var b = monsterBullets[i]; b.update(); if (b.x < -60 || b.x > 2048 + 60 || b.y < -60 || b.y > 2732 + 60) { b.destroy(); monsterBullets.splice(i, 1); continue; } // Hit hero if (hero.invuln === 0 && circlesIntersect(b, hero)) { hero.hp--; updateHP(); hero.invuln = 40; hero.flash(); b.destroy(); monsterBullets.splice(i, 1); if (hero.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } } // Monsters for (var i = monsters.length - 1; i >= 0; --i) { var m = monsters[i]; m.update(); // Hit hero if (hero.invuln === 0 && circlesIntersect(m, hero)) { hero.hp--; updateHP(); hero.invuln = 40; hero.flash(); if (hero.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } } // Gold for (var i = golds.length - 1; i >= 0; --i) { var g = golds[i]; g.update(); // Magnet passive for (var j = 0; j < passives.length; ++j) { if (passives[j].id === 'goldboost') { var dx = hero.x - g.x, dy = hero.y - g.y; var d = Math.sqrt(dx * dx + dy * dy); if (d < 600) { g.vx += dx / d * 2.5; g.vy += dy / d * 2.5; } } } // Pick up if (circlesIntersect(g, hero)) { gold++; goldTxt.setText(gold); LK.getSound('pickup').play(); // Lifesteal for (var j = 0; j < passives.length; ++j) { if (passives[j].id === 'lifesteal') { passives[j].counter++; if (passives[j].counter >= 8) { hero.hp++; updateHP(); passives[j].counter = 0; } } } g.destroy(); golds.splice(i, 1); } } // Store button highlight for (var i = 0; i < storeBtns.length; ++i) { var btn = storeBtns[i]; var bx = btn.x - 420, by = btn.y, bw = 420, bh = 120; if (game.lastDown && game.lastDown.x >= bx && game.lastDown.x <= bx + bw && game.lastDown.y >= by && game.lastDown.y <= by + bh) { if (!btn.hl) { btn.hl = btn.attachAsset('storebtnhl', { anchorX: 1, anchorY: 0 }); btn.setChildIndex(btn.hl, 0); } } else { if (btn.hl) { btn.hl.destroy(); btn.hl = null; } } } // Spawn monsters if (LK.ticks % 60 === 0 && monsters.length < 12) { spawnMonster(); } }; // Track last down for store highlight game.lastDown = null; game.on('down', function (x, y, obj) { game.lastDown = { x: x, y: y }; }); game.on('up', function (x, y, obj) { game.lastDown = null; });
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,775 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Burrower monster
+var Burrower = Container.expand(function () {
+ var self = Container.call(this);
+ var burrowerGfx = self.attachAsset('burrower', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = burrowerGfx.width / 2;
+ self.speed = 10;
+ self.hp = 1;
+ self.type = 'burrower';
+ self.burrowTimer = 0;
+ self.burrowInterval = 90 + Math.floor(Math.random() * 60);
+ self.burrowed = false;
+ self.update = function () {
+ if (self.burrowed) {
+ self.burrowTimer--;
+ if (self.burrowTimer <= 0) {
+ // Unburrow
+ self.burrowed = false;
+ burrowerGfx.alpha = 1;
+ self.burrowTimer = self.burrowInterval;
+ }
+ // Move fast toward hero
+ var dx = hero.x - self.x;
+ var dy = hero.y - self.y;
+ var d = Math.sqrt(dx * dx + dy * dy);
+ if (d > 0.1) {
+ self.x += dx / d * (self.speed * 2.2);
+ self.y += dy / d * (self.speed * 2.2);
+ }
+ } else {
+ self.burrowTimer--;
+ if (self.burrowTimer <= 0) {
+ // Burrow
+ self.burrowed = true;
+ burrowerGfx.alpha = 0.3;
+ self.burrowTimer = 36 + Math.floor(Math.random() * 24);
+ }
+ // Move toward hero
+ var dx = hero.x - self.x;
+ var dy = hero.y - self.y;
+ var d = Math.sqrt(dx * dx + dy * dy);
+ if (d > 0.1) {
+ self.x += dx / d * self.speed;
+ self.y += dy / d * self.speed;
+ }
+ }
+ };
+ self.flash = function () {
+ tween(burrowerGfx, {
+ alpha: 0.1
+ }, {
+ duration: 40,
+ onFinish: function onFinish() {
+ tween(burrowerGfx, {
+ alpha: self.burrowed ? 0.3 : 1
+ }, {
+ duration: 40
+ });
+ }
+ });
+ };
+ return self;
+});
+// Chaser monster
+var Chaser = Container.expand(function () {
+ var self = Container.call(this);
+ var chaserGfx = self.attachAsset('chaser', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = chaserGfx.width / 2;
+ self.speed = 7.5;
+ self.hp = 2;
+ self.type = 'chaser';
+ self.update = function () {
+ // Move toward hero
+ var dx = hero.x - self.x;
+ var dy = hero.y - self.y;
+ var d = Math.sqrt(dx * dx + dy * dy);
+ if (d > 0.1) {
+ self.x += dx / d * self.speed;
+ self.y += dy / d * self.speed;
+ }
+ };
+ self.flash = function () {
+ tween(chaserGfx, {
+ alpha: 0.3
+ }, {
+ duration: 60,
+ onFinish: function onFinish() {
+ tween(chaserGfx, {
+ alpha: 1
+ }, {
+ duration: 60
+ });
+ }
+ });
+ };
+ return self;
+});
+// Gold coin
+var Gold = Container.expand(function () {
+ var self = Container.call(this);
+ var goldGfx = self.attachAsset('gold', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = goldGfx.width / 2;
+ self.vx = 0;
+ self.vy = 0;
+ self.update = function () {
+ self.x += self.vx;
+ self.y += self.vy;
+ // Slow down
+ self.vx *= 0.92;
+ self.vy *= 0.92;
+ };
+ return self;
+});
+// Hero class
+var Hero = Container.expand(function () {
+ var self = Container.call(this);
+ var heroGfx = self.attachAsset('hero', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = heroGfx.width / 2;
+ self.speed = 22;
+ self.shootCooldown = 0;
+ self.shootInterval = 18; // frames
+ self.invuln = 0;
+ self.hp = 3;
+ self.update = function () {
+ if (self.shootCooldown > 0) self.shootCooldown--;
+ if (self.invuln > 0) self.invuln--;
+ };
+ // Flash when hit
+ self.flash = function () {
+ tween(heroGfx, {
+ alpha: 0.3
+ }, {
+ duration: 80,
+ onFinish: function onFinish() {
+ tween(heroGfx, {
+ alpha: 1
+ }, {
+ duration: 80
+ });
+ }
+ });
+ };
+ return self;
+});
+// Hero bullet
+var HeroBullet = Container.expand(function () {
+ var self = Container.call(this);
+ var bulletGfx = self.attachAsset('herobullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = bulletGfx.width / 2;
+ self.speed = 38;
+ self.dirX = 0;
+ self.dirY = -1;
+ self.damage = 1;
+ self.update = function () {
+ self.x += self.dirX * self.speed;
+ self.y += self.dirY * self.speed;
+ };
+ return self;
+});
+// Monster bullet (spit)
+var MonsterBullet = Container.expand(function () {
+ var self = Container.call(this);
+ var bulletGfx = self.attachAsset('herobullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ bulletGfx.tint = 0x7cfd3a;
+ self.radius = bulletGfx.width / 2;
+ self.speed = 16;
+ self.dirX = 0;
+ self.dirY = 1;
+ self.damage = 1;
+ self.update = function () {
+ self.x += self.dirX * self.speed;
+ self.y += self.dirY * self.speed;
+ };
+ return self;
+});
+// Spitter monster
+var Spitter = Container.expand(function () {
+ var self = Container.call(this);
+ var spitterGfx = self.attachAsset('spitter', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = spitterGfx.width / 2;
+ self.speed = 4.5;
+ self.hp = 2;
+ self.type = 'spitter';
+ self.shootCooldown = 0;
+ self.shootInterval = 60 + Math.floor(Math.random() * 30);
+ self.update = function () {
+ // Keep distance from hero, shoot
+ var dx = hero.x - self.x;
+ var dy = hero.y - self.y;
+ var d = Math.sqrt(dx * dx + dy * dy);
+ if (d > 400) {
+ self.x += dx / d * self.speed;
+ self.y += dy / d * self.speed;
+ } else if (d < 320) {
+ self.x -= dx / d * self.speed;
+ self.y -= dy / d * self.speed;
+ }
+ if (self.shootCooldown > 0) self.shootCooldown--;else {
+ // Spit at hero
+ var spit = new MonsterBullet();
+ spit.x = self.x;
+ spit.y = self.y;
+ var tx = hero.x - self.x;
+ var ty = hero.y - self.y;
+ var td = Math.sqrt(tx * tx + ty * ty);
+ spit.dirX = td > 0.1 ? tx / td : 0;
+ spit.dirY = td > 0.1 ? ty / td : 0;
+ spit.speed = 16;
+ spit.radius = 32;
+ monsterBullets.push(spit);
+ game.addChild(spit);
+ self.shootCooldown = self.shootInterval;
+ }
+ };
+ self.flash = function () {
+ tween(spitterGfx, {
+ alpha: 0.3
+ }, {
+ duration: 60,
+ onFinish: function onFinish() {
+ tween(spitterGfx, {
+ alpha: 1
+ }, {
+ duration: 60
+ });
+ }
+ });
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
+ backgroundColor: 0x181818
+});
+
+/****
+* Game Code
+****/
+// Sound effects
+// Store button highlight
+// Store button background
+// Gold coin
+// Hero bullet
+// Burrower monster
+// Spitter monster
+// Chaser monster
+// Hero
+// Global variables
+var hero = new Hero();
+var heroBullets = [];
+var monsters = [];
+var monsterBullets = [];
+var golds = [];
+var gold = 0;
+var storeBtns = [];
+var passives = [];
+var availablePassives = [{
+ id: 'firerate',
+ name: 'Rapid Fire',
+ desc: 'Shoot much faster.',
+ apply: function apply() {
+ hero.shootInterval = Math.max(6, hero.shootInterval - 8);
+ }
+}, {
+ id: 'pierce',
+ name: 'Piercing Shots',
+ desc: 'Bullets pierce through 1 extra enemy.',
+ apply: function apply() {
+ passives.push({
+ id: 'pierce',
+ stacks: 1
+ });
+ }
+}, {
+ id: 'lifesteal',
+ name: 'Lifesteal',
+ desc: 'Gain 1 HP every 8 gold picked up.',
+ apply: function apply() {
+ passives.push({
+ id: 'lifesteal',
+ stacks: 1,
+ counter: 0
+ });
+ }
+}, {
+ id: 'spread',
+ name: 'Spread Shot',
+ desc: 'Shoot 3 bullets in a spread.',
+ apply: function apply() {
+ passives.push({
+ id: 'spread',
+ stacks: 1
+ });
+ }
+}, {
+ id: 'regen',
+ name: 'Regeneration',
+ desc: 'Regenerate 1 HP every 12 seconds.',
+ apply: function apply() {
+ passives.push({
+ id: 'regen',
+ stacks: 1,
+ timer: 0
+ });
+ }
+}, {
+ id: 'speed',
+ name: 'Speed Boost',
+ desc: 'Move much faster.',
+ apply: function apply() {
+ hero.speed += 7;
+ }
+}, {
+ id: 'bigshot',
+ name: 'Big Bullets',
+ desc: 'Bullets are much larger.',
+ apply: function apply() {
+ passives.push({
+ id: 'bigshot',
+ stacks: 1
+ });
+ }
+}, {
+ id: 'goldboost',
+ name: 'Gold Magnet',
+ desc: 'Gold is attracted to you.',
+ apply: function apply() {
+ passives.push({
+ id: 'goldboost',
+ stacks: 1
+ });
+ }
+}, {
+ id: 'maxhp',
+ name: 'Max HP Up',
+ desc: 'Increase max HP by 1.',
+ apply: function apply() {
+ hero.hp++;
+ }
+}];
+// Store state
+var storeChoices = [];
+function getRandomPassive(excludeIds) {
+ var pool = [];
+ for (var i = 0; i < availablePassives.length; ++i) {
+ var id = availablePassives[i].id;
+ var already = false;
+ for (var j = 0; j < excludeIds.length; ++j) {
+ if (excludeIds[j] === id) {
+ already = true;
+ break;
+ }
+ }
+ if (!already) pool.push(availablePassives[i]);
+ }
+ if (pool.length === 0) pool = availablePassives;
+ return pool[Math.floor(Math.random() * pool.length)];
+}
+function rerollStore() {
+ storeChoices = [];
+ var exclude = [];
+ for (var i = 0; i < 3; ++i) {
+ var p = getRandomPassive(exclude);
+ storeChoices.push(p);
+ exclude.push(p.id);
+ }
+ updateStoreBtns();
+}
+function updateStoreBtns() {
+ for (var i = 0; i < storeBtns.length; ++i) {
+ var btn = storeBtns[i];
+ var p = storeChoices[i];
+ btn.passive = p;
+ btn.txt.setText(p.name);
+ btn.desc.setText(p.desc);
+ btn.price.setText("5");
+ }
+}
+// GUI
+var goldTxt = new Text2('0', {
+ size: 90,
+ fill: 0xFFE066
+});
+goldTxt.anchor.set(1, 0);
+LK.gui.topRight.addChild(goldTxt);
+var hpTxt = new Text2('❤❤❤', {
+ size: 90,
+ fill: 0xFF3A3A
+});
+hpTxt.anchor.set(0, 0);
+LK.gui.top.addChild(hpTxt);
+// Store buttons (top right, below gold)
+for (var i = 0; i < 3; ++i) {
+ var btn = new Container();
+ var bg = btn.attachAsset('storebtn', {
+ anchorX: 1,
+ anchorY: 0
+ });
+ btn.x = 2048 - 40;
+ btn.y = 160 + i * 140;
+ btn.txt = new Text2('', {
+ size: 54,
+ fill: 0xFFE066
+ });
+ btn.txt.anchor.set(1, 0);
+ btn.txt.x = 380;
+ btn.txt.y = 12;
+ btn.addChild(btn.txt);
+ btn.desc = new Text2('', {
+ size: 36,
+ fill: 0xCCCCCC
+ });
+ btn.desc.anchor.set(1, 0);
+ btn.desc.x = 380;
+ btn.desc.y = 62;
+ btn.addChild(btn.desc);
+ btn.price = new Text2('5', {
+ size: 48,
+ fill: 0xFFD700
+ });
+ btn.price.anchor.set(0, 0);
+ btn.price.x = 20;
+ btn.price.y = 30;
+ btn.addChild(btn.price);
+ btn.index = i;
+ storeBtns.push(btn);
+ game.addChild(btn);
+}
+// Place hero in center
+hero.x = 2048 / 2;
+hero.y = 2732 / 2;
+game.addChild(hero);
+// Initial monsters
+function spawnMonster() {
+ var edge = Math.floor(Math.random() * 4);
+ var x, y;
+ if (edge === 0) {
+ // top
+ x = 200 + Math.random() * (2048 - 400);
+ y = -80;
+ } else if (edge === 1) {
+ // bottom
+ x = 200 + Math.random() * (2048 - 400);
+ y = 2732 + 80;
+ } else if (edge === 2) {
+ // left
+ x = -80;
+ y = 200 + Math.random() * (2732 - 400);
+ } else {
+ // right
+ x = 2048 + 80;
+ y = 200 + Math.random() * (2732 - 400);
+ }
+ var t = Math.random();
+ var m;
+ if (t < 0.4) m = new Chaser();else if (t < 0.7) m = new Spitter();else m = new Burrower();
+ m.x = x;
+ m.y = y;
+ monsters.push(m);
+ game.addChild(m);
+}
+for (var i = 0; i < 5; ++i) spawnMonster();
+// Store logic
+rerollStore();
+// Dragging
+var dragNode = null;
+function handleMove(x, y, obj) {
+ if (dragNode) {
+ // Clamp to screen
+ var r = hero.radius;
+ dragNode.x = Math.max(r, Math.min(2048 - r, x));
+ dragNode.y = Math.max(r, Math.min(2732 - r, y));
+ }
+}
+game.move = handleMove;
+game.down = function (x, y, obj) {
+ // Check store buttons first
+ for (var i = 0; i < storeBtns.length; ++i) {
+ var btn = storeBtns[i];
+ var bx = btn.x - 420,
+ by = btn.y,
+ bw = 420,
+ bh = 120;
+ if (x >= bx && x <= bx + bw && y >= by && y <= by + bh) {
+ // Buy
+ if (gold >= 5) {
+ gold -= 5;
+ goldTxt.setText(gold);
+ btn.passive.apply();
+ LK.getSound('buy').play();
+ rerollStore();
+ }
+ return;
+ }
+ }
+ // Drag hero
+ dragNode = hero;
+ handleMove(x, y, obj);
+};
+game.up = function (x, y, obj) {
+ dragNode = null;
+};
+// Shoot logic
+function shootAt(tx, ty) {
+ if (hero.shootCooldown > 0) return;
+ hero.shootCooldown = hero.shootInterval;
+ var dx = tx - hero.x;
+ var dy = ty - hero.y;
+ var d = Math.sqrt(dx * dx + dy * dy);
+ if (d < 0.1) {
+ dx = 0;
+ dy = -1;
+ d = 1;
+ }
+ var spread = 0;
+ var n = 1;
+ var big = false;
+ for (var i = 0; i < passives.length; ++i) {
+ if (passives[i].id === 'spread') n = 3;
+ if (passives[i].id === 'bigshot') big = true;
+ }
+ for (var i = 0; i < n; ++i) {
+ var b = new HeroBullet();
+ b.x = hero.x;
+ b.y = hero.y;
+ var angle = Math.atan2(dy, dx);
+ if (n > 1) angle += (i - 1) * 0.18;
+ b.dirX = Math.cos(angle);
+ b.dirY = Math.sin(angle);
+ if (big) {
+ b.scaleX = b.scaleY = 1.7;
+ b.radius *= 1.7;
+ }
+ heroBullets.push(b);
+ game.addChild(b);
+ }
+ LK.getSound('shoot').play();
+}
+// Touch anywhere to shoot
+game.on('down', function (x, y, obj) {
+ // Don't shoot if clicking store
+ for (var i = 0; i < storeBtns.length; ++i) {
+ var btn = storeBtns[i];
+ var bx = btn.x - 420,
+ by = btn.y,
+ bw = 420,
+ bh = 120;
+ if (x >= bx && x <= bx + bw && y >= by && y <= by + bh) return;
+ }
+ shootAt(x, y);
+});
+// Helper: collision
+function circlesIntersect(a, b) {
+ var dx = a.x - b.x,
+ dy = a.y - b.y;
+ var r = (a.radius || 40) + (b.radius || 40);
+ return dx * dx + dy * dy < r * r;
+}
+// Update GUI
+function updateHP() {
+ var s = '';
+ for (var i = 0; i < hero.hp; ++i) s += '❤';
+ hpTxt.setText(s);
+}
+// Main update
+game.update = function () {
+ // Hero update
+ hero.update();
+ // Regen passive
+ for (var i = 0; i < passives.length; ++i) {
+ if (passives[i].id === 'regen') {
+ passives[i].timer++;
+ if (passives[i].timer >= 60 * 12) {
+ hero.hp++;
+ updateHP();
+ passives[i].timer = 0;
+ }
+ }
+ }
+ // Hero bullets
+ for (var i = heroBullets.length - 1; i >= 0; --i) {
+ var b = heroBullets[i];
+ b.update();
+ // Offscreen
+ if (b.x < -60 || b.x > 2048 + 60 || b.y < -60 || b.y > 2732 + 60) {
+ b.destroy();
+ heroBullets.splice(i, 1);
+ continue;
+ }
+ // Hit monster
+ var pierced = false;
+ for (var j = monsters.length - 1; j >= 0; --j) {
+ var m = monsters[j];
+ if (m.type === 'burrower' && m.burrowed) continue;
+ if (circlesIntersect(b, m)) {
+ m.hp -= b.damage;
+ m.flash();
+ LK.getSound('hit').play();
+ if (m.hp <= 0) {
+ // Drop gold
+ var g = new Gold();
+ g.x = m.x;
+ g.y = m.y;
+ g.vx = (Math.random() - 0.5) * 8;
+ g.vy = (Math.random() - 0.5) * 8;
+ golds.push(g);
+ game.addChild(g);
+ LK.getSound('monsterdie').play();
+ m.destroy();
+ monsters.splice(j, 1);
+ }
+ // Pierce?
+ var pierce = 0;
+ for (var k = 0; k < passives.length; ++k) if (passives[k].id === 'pierce') pierce++;
+ if (pierce > 0 && !pierced) {
+ b.damage--;
+ pierced = true;
+ if (b.damage <= 0) {
+ b.destroy();
+ heroBullets.splice(i, 1);
+ }
+ } else {
+ b.destroy();
+ heroBullets.splice(i, 1);
+ }
+ break;
+ }
+ }
+ }
+ // Monster bullets
+ for (var i = monsterBullets.length - 1; i >= 0; --i) {
+ var b = monsterBullets[i];
+ b.update();
+ if (b.x < -60 || b.x > 2048 + 60 || b.y < -60 || b.y > 2732 + 60) {
+ b.destroy();
+ monsterBullets.splice(i, 1);
+ continue;
+ }
+ // Hit hero
+ if (hero.invuln === 0 && circlesIntersect(b, hero)) {
+ hero.hp--;
+ updateHP();
+ hero.invuln = 40;
+ hero.flash();
+ b.destroy();
+ monsterBullets.splice(i, 1);
+ if (hero.hp <= 0) {
+ LK.effects.flashScreen(0xff0000, 1000);
+ LK.showGameOver();
+ return;
+ }
+ }
+ }
+ // Monsters
+ for (var i = monsters.length - 1; i >= 0; --i) {
+ var m = monsters[i];
+ m.update();
+ // Hit hero
+ if (hero.invuln === 0 && circlesIntersect(m, hero)) {
+ hero.hp--;
+ updateHP();
+ hero.invuln = 40;
+ hero.flash();
+ if (hero.hp <= 0) {
+ LK.effects.flashScreen(0xff0000, 1000);
+ LK.showGameOver();
+ return;
+ }
+ }
+ }
+ // Gold
+ for (var i = golds.length - 1; i >= 0; --i) {
+ var g = golds[i];
+ g.update();
+ // Magnet passive
+ for (var j = 0; j < passives.length; ++j) {
+ if (passives[j].id === 'goldboost') {
+ var dx = hero.x - g.x,
+ dy = hero.y - g.y;
+ var d = Math.sqrt(dx * dx + dy * dy);
+ if (d < 600) {
+ g.vx += dx / d * 2.5;
+ g.vy += dy / d * 2.5;
+ }
+ }
+ }
+ // Pick up
+ if (circlesIntersect(g, hero)) {
+ gold++;
+ goldTxt.setText(gold);
+ LK.getSound('pickup').play();
+ // Lifesteal
+ for (var j = 0; j < passives.length; ++j) {
+ if (passives[j].id === 'lifesteal') {
+ passives[j].counter++;
+ if (passives[j].counter >= 8) {
+ hero.hp++;
+ updateHP();
+ passives[j].counter = 0;
+ }
+ }
+ }
+ g.destroy();
+ golds.splice(i, 1);
+ }
+ }
+ // Store button highlight
+ for (var i = 0; i < storeBtns.length; ++i) {
+ var btn = storeBtns[i];
+ var bx = btn.x - 420,
+ by = btn.y,
+ bw = 420,
+ bh = 120;
+ if (game.lastDown && game.lastDown.x >= bx && game.lastDown.x <= bx + bw && game.lastDown.y >= by && game.lastDown.y <= by + bh) {
+ if (!btn.hl) {
+ btn.hl = btn.attachAsset('storebtnhl', {
+ anchorX: 1,
+ anchorY: 0
+ });
+ btn.setChildIndex(btn.hl, 0);
+ }
+ } else {
+ if (btn.hl) {
+ btn.hl.destroy();
+ btn.hl = null;
+ }
+ }
+ }
+ // Spawn monsters
+ if (LK.ticks % 60 === 0 && monsters.length < 12) {
+ spawnMonster();
+ }
+};
+// Track last down for store highlight
+game.lastDown = null;
+game.on('down', function (x, y, obj) {
+ game.lastDown = {
+ x: x,
+ y: y
+ };
+});
+game.on('up', function (x, y, obj) {
+ game.lastDown = null;
});
\ No newline at end of file
a zombie but its half phantom. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a zombie. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a gold. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a spitter zombie. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a green zombi spitt. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a man with green tshirt and blue pant. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a man with green tshirt and blue pant walking up. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a sword . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat