User prompt
LİNE 25 FİX İT
User prompt
Fix the line 25
User prompt
Fix the line 25
User prompt
Error is not fixed
User prompt
the error is not fixed
User prompt
fix the error on the line 25
User prompt
fix the error
User prompt
fix the error
User prompt
theres a error on the code line
User prompt
I want more items
User prompt
rotate the hero s photo only right and left
User prompt
special photos according to the character's movements, for example walking up, walking down, walking right, walking left
User prompt
make monsters shoot their bullets a little bit slower
User prompt
rotate the character's photo according to the direction they are walking
User prompt
rotate your photo according to the side from which the spit is thrown
User prompt
make characters meele range more big
User prompt
there's a bit of a problem with the ware panel
User prompt
the item panel has a bit of a problem, the click area has shifted a bit to the right
User prompt
the hitboxes of the item panel have shifted a little to the right, fix them
User prompt
Most of the stuff doesn't work,
User prompt
monsters turn left or right depending on the direction they walk
User prompt
the max hp item is not working
User prompt
the speed boost is not working
User prompt
instead of taking the character directly to the places where I click or hold it, take it slowly
User prompt
give things a special value, depending on which items are more likely to appear in the store
/**** * 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 = 2.2; 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 = 1.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 }); // Add sword asset var swordGfx = self.attachAsset('herosword', { anchorX: 0.1, anchorY: 0.5, x: heroGfx.width * 0.5 + 30, y: 0, rotation: 0 }); swordGfx.rotation = 0; swordGfx.visible = true; self.addChild(swordGfx); self.radius = heroGfx.width / 2; self.speed = 22; self.shootCooldown = 0; self.shootInterval = 18; // frames self.invuln = 0; self.hp = 3; // Sword swing state self.swordSwing = 0; // 0 = idle, >0 = animating self.swordSwingDir = 1; // 1 = right, -1 = left self.update = function () { if (self.shootCooldown > 0) self.shootCooldown--; if (self.invuln > 0) self.invuln--; // Always point sword at nearest monster, animate a subtle swing var nearest = null; var minDist = 999999; for (var i = 0; i < monsters.length; ++i) { var m = monsters[i]; if (m.type === 'burrower' && m.burrowed) continue; var dx = m.x - self.x; var dy = m.y - self.y; var d = Math.sqrt(dx * dx + dy * dy); if (d < minDist) { minDist = d; nearest = m; } } if (nearest) { var dx = nearest.x - self.x; var dy = nearest.y - self.y; var angle = Math.atan2(dy, dx); // Animate a subtle swing: oscillate +/- 0.18 radians var swing = Math.sin(LK.ticks / 10) * 0.18; // Sword hit animation: if recently hit, flash sword if (self.swordHitAnim && self.swordHitAnim > 0) { // Animate sword: scale up and flash color swordGfx.scaleX = 1.3 + 0.3 * Math.sin(self.swordHitAnim * Math.PI / 6); swordGfx.scaleY = 1.3 + 0.3 * Math.sin(self.swordHitAnim * Math.PI / 6); swordGfx.tint = 0xffe066; self.swordHitAnim--; if (self.swordHitAnim === 0) { swordGfx.scaleX = 1; swordGfx.scaleY = 1; swordGfx.tint = 0xf5e663; } } else { swordGfx.scaleX = 1; swordGfx.scaleY = 1; swordGfx.tint = 0xf5e663; } swordGfx.rotation = angle + swing; // Position sword at edge of hero var dist = heroGfx.width * 0.5 + 30; swordGfx.x = Math.cos(angle) * dist; swordGfx.y = Math.sin(angle) * dist; } else { // No monsters: point up, subtle swing var angle = -Math.PI / 2; var swing = Math.sin(LK.ticks / 10) * 0.18; swordGfx.rotation = angle + swing; var dist = heroGfx.width * 0.5 + 30; swordGfx.x = Math.cos(angle) * dist; swordGfx.y = Math.sin(angle) * dist; } }; // Flash when hit self.flash = function () { tween(heroGfx, { alpha: 0.3 }, { duration: 80, onFinish: function onFinish() { tween(heroGfx, { alpha: 1 }, { duration: 80 }); } }); }; // Sword swing trigger self.swingSword = function (dir) { self.swordSwing = self.swordSwingMax = 10; self.swordSwingDir = dir || 1; swordGfx.rotation = 0; }; 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 = 7; 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 = 1.1; self.hp = 2; self.type = 'spitter'; self.shootCooldown = 0; self.shootInterval = 110 + Math.floor(Math.random() * 40); // fire much slower 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 = 3.2; // even slower bullet speed 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 monsters = []; var monsterBullets = []; var golds = []; var gold = 0; var storeBtns = []; var passives = []; var availablePassives = [{ id: 'lifesteal', name: 'Lifesteal', desc: 'Gain 1 HP every 8 gold picked up.', weight: 2, // More likely to appear apply: function apply() { passives.push({ id: 'lifesteal', stacks: 1, counter: 0 }); } }, { id: 'reflect', name: 'Reflect Shield', desc: 'Occasionally reflects a monster bullet.', weight: 1, // Less likely apply: function apply() { passives.push({ id: 'reflect', stacks: 1, timer: 0 }); } }, { id: 'regen', name: 'Regeneration', desc: 'Regenerate 1 HP every 12 seconds.', weight: 1, // Less likely apply: function apply() { passives.push({ id: 'regen', stacks: 1, timer: 0 }); } }, { id: 'speed', name: 'Speed Boost', desc: 'Move much faster.', weight: 2, // More likely apply: function apply() { hero.speed += 7; } }, { id: 'goldboost', name: 'Gold Magnet', desc: 'Gold is attracted to you.', weight: 3, // Most likely to appear apply: function apply() { passives.push({ id: 'goldboost', stacks: 1 }); } }, { id: 'maxhp', name: 'Max HP Up', desc: 'Increase max HP by 1.', weight: 2, // More likely apply: function apply() { hero.hp++; } }]; // Store state var storeChoices = []; function getRandomPassive(excludeIds) { var pool = []; // Build weighted 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) { var weight = availablePassives[i].weight || 1; for (var w = 0; w < weight; ++w) { pool.push(availablePassives[i]); } } } if (pool.length === 0) { // fallback: all passives, weighted for (var i = 0; i < availablePassives.length; ++i) { var weight = availablePassives[i].weight || 1; for (var w = 0; w < weight; ++w) { pool.push(availablePassives[i]); } } } 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; // Add a little sparkle/emoji to the name for beauty var prettyName = "★ " + p.name + " ★"; btn.txt.setText(prettyName); btn.shadow.setText(prettyName); 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 center, beautified) for (var i = 0; i < 3; ++i) { var btn = new Container(); var bg = btn.attachAsset('storebtn', { anchorX: 0.5, anchorY: 0 }); // Center horizontally, stack vertically with spacing btn.x = 2048 / 2; btn.y = 160 + i * 160; // Add a subtle drop shadow effect by layering a slightly offset, darker text btn.shadow = new Text2('', { size: 64, fill: 0x222222 }); btn.shadow.anchor.set(0.5, 0); btn.shadow.x = 0 + 3; btn.shadow.y = 10 + 3; btn.addChild(btn.shadow); // Beautified item name: larger, bold, gold color, centered btn.txt = new Text2('', { size: 64, fill: 0xFFE066, font: "Impact, 'Arial Black', Tahoma" }); btn.txt.anchor.set(0.5, 0); btn.txt.x = 0; btn.txt.y = 10; btn.addChild(btn.txt); // Description: slightly larger, italic, silver color, centered btn.desc = new Text2('', { size: 40, fill: 0xCCCCCC, font: "italic 36px Tahoma" }); btn.desc.anchor.set(0.5, 0); btn.desc.x = 0; btn.desc.y = 80; btn.addChild(btn.desc); // Price: gold coin color, bold, left side btn.price = new Text2('5', { size: 54, fill: 0xFFD700, font: "bold 48px Tahoma" }); btn.price.anchor.set(0, 0); btn.price.x = -180; btn.price.y = 40; 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; // Make Spitter and Burrower much more rare: Chaser 80%, Spitter 7%, Burrower 13% if (t < 0.8) { m = new Chaser(); } else if (t < 0.87) { 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; }; // 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; } } } // Monster bullets for (var i = monsterBullets.length - 1; i >= 0; --i) { var b = monsterBullets[i]; b.update(); // Reflect Shield passive: reflect a bullet every 7 seconds for (var j = 0; j < passives.length; ++j) { if (passives[j].id === 'reflect') { passives[j].timer++; if (passives[j].timer >= 60 * 7) { if (circlesIntersect(b, hero)) { b.dirX *= -1; b.dirY *= -1; b.x += b.dirX * 30; b.y += b.dirY * 30; passives[j].timer = 0; break; } } } } 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; } } // --- Sword hit detection in update --- if (m.type !== 'burrower' || !m.burrowed) { // Sword hitbox: check monsters in a 180px arc in front of hero var swordRange = 180; var swordArc = Math.PI / 2; // 90 deg arc // Find sword angle (same as in Hero.update) var nearest = null; var minDist = 999999; for (var mi = 0; mi < monsters.length; ++mi) { var mm = monsters[mi]; if (mm.type === 'burrower' && mm.burrowed) continue; var dx = mm.x - hero.x; var dy = mm.y - hero.y; var d = Math.sqrt(dx * dx + dy * dy); if (d < minDist) { minDist = d; nearest = mm; } } var swordAngle = -Math.PI / 2; if (nearest) { swordAngle = Math.atan2(nearest.y - hero.x, nearest.x - hero.x); // Correction: should be (nearest.y - hero.y, nearest.x - hero.x) swordAngle = Math.atan2(nearest.y - hero.y, nearest.x - hero.x); } var mx = m.x - hero.x, my = m.y - hero.y; var mdist = Math.sqrt(mx * mx + my * my); if (mdist < swordRange) { var mangle = Math.atan2(my, mx); var diff = Math.abs((mangle - swordAngle + Math.PI * 3) % (Math.PI * 2) - Math.PI); if (diff < swordArc / 2) { m.hp -= 1; m.flash(); LK.getSound('hit').play(); // --- Sword hit animation trigger --- if (typeof hero.swordHitAnim === "undefined" || hero.swordHitAnim === 0) { hero.swordHitAnim = 8; // frames of animation } else { hero.swordHitAnim = 8; } 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(i, 1); continue; } } } } } // 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; // Only show highlight if pointer is over the button 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 }); // Always ensure highlight is above the background but below text btn.setChildIndex(btn.hl, 1); } } else { if (btn.hl) { btn.hl.destroy(); btn.hl = null; } } } // Spawn monsters if (LK.ticks % 120 === 0 && monsters.length < 7) { 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; });
/****
* 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 = 2.2;
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 = 1.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
});
// Add sword asset
var swordGfx = self.attachAsset('herosword', {
anchorX: 0.1,
anchorY: 0.5,
x: heroGfx.width * 0.5 + 30,
y: 0,
rotation: 0
});
swordGfx.rotation = 0;
swordGfx.visible = true;
self.addChild(swordGfx);
self.radius = heroGfx.width / 2;
self.speed = 22;
self.shootCooldown = 0;
self.shootInterval = 18; // frames
self.invuln = 0;
self.hp = 3;
// Sword swing state
self.swordSwing = 0; // 0 = idle, >0 = animating
self.swordSwingDir = 1; // 1 = right, -1 = left
self.update = function () {
if (self.shootCooldown > 0) self.shootCooldown--;
if (self.invuln > 0) self.invuln--;
// Always point sword at nearest monster, animate a subtle swing
var nearest = null;
var minDist = 999999;
for (var i = 0; i < monsters.length; ++i) {
var m = monsters[i];
if (m.type === 'burrower' && m.burrowed) continue;
var dx = m.x - self.x;
var dy = m.y - self.y;
var d = Math.sqrt(dx * dx + dy * dy);
if (d < minDist) {
minDist = d;
nearest = m;
}
}
if (nearest) {
var dx = nearest.x - self.x;
var dy = nearest.y - self.y;
var angle = Math.atan2(dy, dx);
// Animate a subtle swing: oscillate +/- 0.18 radians
var swing = Math.sin(LK.ticks / 10) * 0.18;
// Sword hit animation: if recently hit, flash sword
if (self.swordHitAnim && self.swordHitAnim > 0) {
// Animate sword: scale up and flash color
swordGfx.scaleX = 1.3 + 0.3 * Math.sin(self.swordHitAnim * Math.PI / 6);
swordGfx.scaleY = 1.3 + 0.3 * Math.sin(self.swordHitAnim * Math.PI / 6);
swordGfx.tint = 0xffe066;
self.swordHitAnim--;
if (self.swordHitAnim === 0) {
swordGfx.scaleX = 1;
swordGfx.scaleY = 1;
swordGfx.tint = 0xf5e663;
}
} else {
swordGfx.scaleX = 1;
swordGfx.scaleY = 1;
swordGfx.tint = 0xf5e663;
}
swordGfx.rotation = angle + swing;
// Position sword at edge of hero
var dist = heroGfx.width * 0.5 + 30;
swordGfx.x = Math.cos(angle) * dist;
swordGfx.y = Math.sin(angle) * dist;
} else {
// No monsters: point up, subtle swing
var angle = -Math.PI / 2;
var swing = Math.sin(LK.ticks / 10) * 0.18;
swordGfx.rotation = angle + swing;
var dist = heroGfx.width * 0.5 + 30;
swordGfx.x = Math.cos(angle) * dist;
swordGfx.y = Math.sin(angle) * dist;
}
};
// Flash when hit
self.flash = function () {
tween(heroGfx, {
alpha: 0.3
}, {
duration: 80,
onFinish: function onFinish() {
tween(heroGfx, {
alpha: 1
}, {
duration: 80
});
}
});
};
// Sword swing trigger
self.swingSword = function (dir) {
self.swordSwing = self.swordSwingMax = 10;
self.swordSwingDir = dir || 1;
swordGfx.rotation = 0;
};
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 = 7;
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 = 1.1;
self.hp = 2;
self.type = 'spitter';
self.shootCooldown = 0;
self.shootInterval = 110 + Math.floor(Math.random() * 40); // fire much slower
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 = 3.2; // even slower bullet speed
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 monsters = [];
var monsterBullets = [];
var golds = [];
var gold = 0;
var storeBtns = [];
var passives = [];
var availablePassives = [{
id: 'lifesteal',
name: 'Lifesteal',
desc: 'Gain 1 HP every 8 gold picked up.',
weight: 2,
// More likely to appear
apply: function apply() {
passives.push({
id: 'lifesteal',
stacks: 1,
counter: 0
});
}
}, {
id: 'reflect',
name: 'Reflect Shield',
desc: 'Occasionally reflects a monster bullet.',
weight: 1,
// Less likely
apply: function apply() {
passives.push({
id: 'reflect',
stacks: 1,
timer: 0
});
}
}, {
id: 'regen',
name: 'Regeneration',
desc: 'Regenerate 1 HP every 12 seconds.',
weight: 1,
// Less likely
apply: function apply() {
passives.push({
id: 'regen',
stacks: 1,
timer: 0
});
}
}, {
id: 'speed',
name: 'Speed Boost',
desc: 'Move much faster.',
weight: 2,
// More likely
apply: function apply() {
hero.speed += 7;
}
}, {
id: 'goldboost',
name: 'Gold Magnet',
desc: 'Gold is attracted to you.',
weight: 3,
// Most likely to appear
apply: function apply() {
passives.push({
id: 'goldboost',
stacks: 1
});
}
}, {
id: 'maxhp',
name: 'Max HP Up',
desc: 'Increase max HP by 1.',
weight: 2,
// More likely
apply: function apply() {
hero.hp++;
}
}];
// Store state
var storeChoices = [];
function getRandomPassive(excludeIds) {
var pool = [];
// Build weighted 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) {
var weight = availablePassives[i].weight || 1;
for (var w = 0; w < weight; ++w) {
pool.push(availablePassives[i]);
}
}
}
if (pool.length === 0) {
// fallback: all passives, weighted
for (var i = 0; i < availablePassives.length; ++i) {
var weight = availablePassives[i].weight || 1;
for (var w = 0; w < weight; ++w) {
pool.push(availablePassives[i]);
}
}
}
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;
// Add a little sparkle/emoji to the name for beauty
var prettyName = "★ " + p.name + " ★";
btn.txt.setText(prettyName);
btn.shadow.setText(prettyName);
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 center, beautified)
for (var i = 0; i < 3; ++i) {
var btn = new Container();
var bg = btn.attachAsset('storebtn', {
anchorX: 0.5,
anchorY: 0
});
// Center horizontally, stack vertically with spacing
btn.x = 2048 / 2;
btn.y = 160 + i * 160;
// Add a subtle drop shadow effect by layering a slightly offset, darker text
btn.shadow = new Text2('', {
size: 64,
fill: 0x222222
});
btn.shadow.anchor.set(0.5, 0);
btn.shadow.x = 0 + 3;
btn.shadow.y = 10 + 3;
btn.addChild(btn.shadow);
// Beautified item name: larger, bold, gold color, centered
btn.txt = new Text2('', {
size: 64,
fill: 0xFFE066,
font: "Impact, 'Arial Black', Tahoma"
});
btn.txt.anchor.set(0.5, 0);
btn.txt.x = 0;
btn.txt.y = 10;
btn.addChild(btn.txt);
// Description: slightly larger, italic, silver color, centered
btn.desc = new Text2('', {
size: 40,
fill: 0xCCCCCC,
font: "italic 36px Tahoma"
});
btn.desc.anchor.set(0.5, 0);
btn.desc.x = 0;
btn.desc.y = 80;
btn.addChild(btn.desc);
// Price: gold coin color, bold, left side
btn.price = new Text2('5', {
size: 54,
fill: 0xFFD700,
font: "bold 48px Tahoma"
});
btn.price.anchor.set(0, 0);
btn.price.x = -180;
btn.price.y = 40;
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;
// Make Spitter and Burrower much more rare: Chaser 80%, Spitter 7%, Burrower 13%
if (t < 0.8) {
m = new Chaser();
} else if (t < 0.87) {
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;
};
// 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;
}
}
}
// Monster bullets
for (var i = monsterBullets.length - 1; i >= 0; --i) {
var b = monsterBullets[i];
b.update();
// Reflect Shield passive: reflect a bullet every 7 seconds
for (var j = 0; j < passives.length; ++j) {
if (passives[j].id === 'reflect') {
passives[j].timer++;
if (passives[j].timer >= 60 * 7) {
if (circlesIntersect(b, hero)) {
b.dirX *= -1;
b.dirY *= -1;
b.x += b.dirX * 30;
b.y += b.dirY * 30;
passives[j].timer = 0;
break;
}
}
}
}
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;
}
}
// --- Sword hit detection in update ---
if (m.type !== 'burrower' || !m.burrowed) {
// Sword hitbox: check monsters in a 180px arc in front of hero
var swordRange = 180;
var swordArc = Math.PI / 2; // 90 deg arc
// Find sword angle (same as in Hero.update)
var nearest = null;
var minDist = 999999;
for (var mi = 0; mi < monsters.length; ++mi) {
var mm = monsters[mi];
if (mm.type === 'burrower' && mm.burrowed) continue;
var dx = mm.x - hero.x;
var dy = mm.y - hero.y;
var d = Math.sqrt(dx * dx + dy * dy);
if (d < minDist) {
minDist = d;
nearest = mm;
}
}
var swordAngle = -Math.PI / 2;
if (nearest) {
swordAngle = Math.atan2(nearest.y - hero.x, nearest.x - hero.x);
// Correction: should be (nearest.y - hero.y, nearest.x - hero.x)
swordAngle = Math.atan2(nearest.y - hero.y, nearest.x - hero.x);
}
var mx = m.x - hero.x,
my = m.y - hero.y;
var mdist = Math.sqrt(mx * mx + my * my);
if (mdist < swordRange) {
var mangle = Math.atan2(my, mx);
var diff = Math.abs((mangle - swordAngle + Math.PI * 3) % (Math.PI * 2) - Math.PI);
if (diff < swordArc / 2) {
m.hp -= 1;
m.flash();
LK.getSound('hit').play();
// --- Sword hit animation trigger ---
if (typeof hero.swordHitAnim === "undefined" || hero.swordHitAnim === 0) {
hero.swordHitAnim = 8; // frames of animation
} else {
hero.swordHitAnim = 8;
}
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(i, 1);
continue;
}
}
}
}
}
// 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;
// Only show highlight if pointer is over the button
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
});
// Always ensure highlight is above the background but below text
btn.setChildIndex(btn.hl, 1);
}
} else {
if (btn.hl) {
btn.hl.destroy();
btn.hl = null;
}
}
}
// Spawn monsters
if (LK.ticks % 120 === 0 && monsters.length < 7) {
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;
});
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