/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// --- Enemy Class ---
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Enemy asset: red ellipse
var enemyAsset = self.attachAsset('enemy', {
width: 100,
height: 100,
color: 0xd83318,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 50;
self.speed = 4 + Math.random() * 2; // randomize speed a bit
self.state = 'idle'; // 'idle' or 'chase'
self.radarRadius = 400; // detection radius
self.target = null; // player
// For hit flash
self.flashTicks = 0;
self.update = function () {
if (!self.target) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// Radar detection
if (self.state === 'idle' && dist < self.radarRadius) {
self.state = 'chase';
}
// Move if chasing
if (self.state === 'chase') {
if (dist > 5) {
var moveX = dx / dist * self.speed;
var moveY = dy / dist * self.speed;
self.x += moveX;
self.y += moveY;
}
}
// Flash on hit
if (self.flashTicks > 0) {
self.flashTicks--;
enemyAsset.tint = 0xffff00;
} else {
enemyAsset.tint = 0xd83318;
}
};
// Called when hit by sword
self.hit = function () {
self.flashTicks = 6;
};
return self;
});
// --- Player Class ---
var Player = Container.expand(function () {
var self = Container.call(this);
// Player asset: a colored ellipse (body)
var body = self.attachAsset('player', {
width: 120,
height: 120,
color: 0x2e86de,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
// Sword child
self.sword = new Sword();
self.addChild(self.sword);
self.sword.x = 0;
self.sword.y = 0;
self.radius = 60; // for collision
// For dragging
self.isDragging = false;
// For invulnerability after hit
self.invulnTicks = 0;
// Called every tick
self.update = function () {
if (self.invulnTicks > 0) {
self.invulnTicks--;
body.alpha = LK.ticks % 10 < 5 ? 0.5 : 1;
} else {
body.alpha = 1;
}
// Make sword(s) rotate much faster and support multiple swords
if (!self.sword.swinging) {
// Sword speed multiplier (default 0.18, can be upgraded)
if (typeof self.swordSpeed === "undefined") self.swordSpeed = 0.18;
// Number of swords (default 1, can be upgraded)
if (typeof self.swordCount === "undefined") self.swordCount = 1;
for (var i = 0; i < self.swordCount; i++) {
var angle = (LK.ticks * self.swordSpeed + Math.PI * 2 * i / self.swordCount) % (Math.PI * 2);
if (i === 0) {
self.sword.rotation = angle;
} else {
// Add extra swords if not already present
if (!self.extraSwords) self.extraSwords = [];
if (!self.extraSwords[i - 1]) {
var newSword = new Sword();
self.addChild(newSword);
newSword.x = 0;
newSword.y = 0;
self.extraSwords[i - 1] = newSword;
}
self.extraSwords[i - 1].rotation = angle;
}
}
// Remove extra swords if swordCount decreased
if (self.extraSwords && self.extraSwords.length > self.swordCount - 1) {
for (var j = self.swordCount - 1; j < self.extraSwords.length; j++) {
self.extraSwords[j].destroy();
}
self.extraSwords.length = self.swordCount - 1;
}
}
};
// Start sword swing
self.attack = function (onFinish) {
self.sword.swing(onFinish);
};
return self;
});
// --- Sword Class ---
var Sword = Container.expand(function () {
var self = Container.call(this);
// Sword asset: a long, thin rectangle (box)
var swordAsset = self.attachAsset('sword', {
width: 40,
height: 220,
color: 0xffffff,
shape: 'box',
anchorX: 0.5,
anchorY: 0.9 // handle is at bottom
});
self.swinging = false;
self.swingAngle = 0; // in radians
// Called every tick
self.update = function () {
// If swinging, animate the sword
if (self.swinging) {
self.rotation = self.swingAngle;
}
};
// Start a sword swing animation
self.swing = function (_onFinish) {
// Sword is always rotating, so swing does nothing
if (_onFinish) _onFinish();
};
return self;
});
// --- Upgrader Class ---
var Upgrader = Container.expand(function () {
var self = Container.call(this);
// Randomly choose upgrade type
var types = [{
type: "speed",
color: 0x00ffcc
}, {
type: "multi",
color: 0xffcc00
}];
var chosen = types[Math.floor(Math.random() * types.length)];
self.upgradeType = chosen.type;
// Visual: colored ellipse
var asset = self.attachAsset('centerCircle', {
width: 90,
height: 90,
color: chosen.color,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
// Animate (pulse)
tween(asset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.linear,
onFinish: function onFinish() {
// Reverse pulse for yoyo effect
tween(asset, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.linear,
onFinish: function onFinish() {
// Repeat indefinitely
if (asset && asset.parent) {
// Only repeat if still in scene
// Use setTimeout to avoid call stack overflow
LK.setTimeout(function () {
if (asset && asset.parent) {
// Restart pulse
tween(asset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.linear,
onFinish: arguments.callee
});
}
}, 0);
}
}
});
}
});
asset.scaleX = 1.0;
asset.scaleY = 1.0;
// For collision
self.radius = 45;
// Lifetime (10s default)
self.lifetime = 600 + Math.floor(Math.random() * 600); // 10-20s
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.destroy();
if (typeof upgraders !== "undefined") {
var idx = upgraders.indexOf(self);
if (idx !== -1) upgraders.splice(idx, 1);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// --- Game Variables ---
var player;
var enemies = [];
var upgraders = [];
var maxEnemies = 6;
var spawnAreaMargin = 200;
var score = 0;
var lives = 3;
var scoreTxt, livesTxt;
var dragNode = null;
var lastTouch = {
x: 0,
y: 0
};
var swordHitCooldown = 0;
// Upgrader spawn timer
var nextUpgraderTick = LK.ticks + 60 * (2 + Math.random() * 28); // 2-30s
// --- UI Setup ---
scoreTxt = new Text2('Skor: 0', {
size: 100,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
livesTxt = new Text2('Can: 3', {
size: 80,
fill: "#fff"
});
livesTxt.anchor.set(1, 0);
livesTxt.x = -40; // right margin
LK.gui.topRight.addChild(livesTxt);
// --- Player Setup ---
player = new Player();
player.x = 2048 / 2;
player.y = 2732 * 0.7;
game.addChild(player);
// --- Enemy Spawning ---
function spawnEnemy() {
var enemy = new Enemy();
enemy.target = player;
// Spawn at random edge
var edge = Math.floor(Math.random() * 4);
var x, y;
if (edge === 0) {
// top
x = spawnAreaMargin + Math.random() * (2048 - 2 * spawnAreaMargin);
y = spawnAreaMargin;
} else if (edge === 1) {
// bottom
x = spawnAreaMargin + Math.random() * (2048 - 2 * spawnAreaMargin);
y = 2732 - spawnAreaMargin;
} else if (edge === 2) {
// left
x = spawnAreaMargin;
y = spawnAreaMargin + Math.random() * (2732 - 2 * spawnAreaMargin);
} else {
// right
x = 2048 - spawnAreaMargin;
y = spawnAreaMargin + Math.random() * (2732 - 2 * spawnAreaMargin);
}
enemy.x = x;
enemy.y = y;
enemies.push(enemy);
game.addChild(enemy);
}
// Initial enemies
for (var i = 0; i < maxEnemies; i++) {
spawnEnemy();
}
// --- Touch/Drag Controls ---
game.down = function (x, y, obj) {
// Only drag if touch is on player
var dx = x - player.x;
var dy = y - player.y;
if (dx * dx + dy * dy < player.radius * player.radius) {
dragNode = player;
lastTouch.x = x;
lastTouch.y = y;
}
};
game.move = function (x, y, obj) {
if (dragNode === player) {
// Clamp to game area
var nx = Math.max(player.radius, Math.min(2048 - player.radius, x));
var ny = Math.max(player.radius, Math.min(2732 - player.radius, y));
player.x = nx;
player.y = ny;
lastTouch.x = x;
lastTouch.y = y;
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// --- Sword Attack (Tap anywhere except player) ---
game.tapCooldown = 0;
game.downSword = function (x, y, obj) {
// If not dragging player, swing sword
var dx = x - player.x;
var dy = y - player.y;
// Sword now rotates automatically; manual swing disabled
};
// Listen for down events for sword attack
game.on('down', function (x, y, obj) {
game.downSword(x, y, obj);
});
// --- Game Update Loop ---
game.update = function () {
player.update();
// --- Upgrader spawn logic ---
if (LK.ticks >= nextUpgraderTick) {
// Spawn upgrader at random position (not too close to player)
var tries = 0;
var ux, uy;
do {
ux = 200 + Math.random() * (2048 - 400);
uy = 200 + Math.random() * (2732 - 400);
tries++;
} while (tries < 10 && Math.sqrt((ux - player.x) * (ux - player.x) + (uy - player.y) * (uy - player.y)) < 300);
var upgrader = new Upgrader();
upgrader.x = ux;
upgrader.y = uy;
upgraders.push(upgrader);
game.addChild(upgrader);
// Next spawn in 2-30s
nextUpgraderTick = LK.ticks + 60 * (2 + Math.random() * 28);
}
// --- Upgrader update and collision ---
for (var u = upgraders.length - 1; u >= 0; u--) {
var upgrader = upgraders[u];
if (upgrader.update) upgrader.update();
// Check collision with player
var dxu = upgrader.x - player.x;
var dyu = upgrader.y - player.y;
var distu = Math.sqrt(dxu * dxu + dyu * dyu);
if (distu < player.radius + upgrader.radius) {
// Apply upgrade
if (upgrader.upgradeType === "speed") {
if (typeof player.swordSpeed === "undefined") player.swordSpeed = 0.18;
player.swordSpeed *= 1.4;
LK.effects.flashObject(player.sword, 0x00ffcc, 400);
} else if (upgrader.upgradeType === "multi") {
if (typeof player.swordCount === "undefined") player.swordCount = 1;
player.swordCount = Math.min(player.swordCount + 1, 5);
LK.effects.flashObject(player.sword, 0xffcc00, 400);
}
// Remove upgrader
upgrader.destroy();
upgraders.splice(u, 1);
}
}
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Check collision: enemy with player
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < enemy.radius + player.radius - 10) {
// Only if not invulnerable
if (player.invulnTicks === 0) {
lives--;
livesTxt.setText('Can: ' + lives);
player.invulnTicks = 60;
LK.effects.flashObject(player, 0xff0000, 600);
if (lives <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
// Check collision: enemy with sword(s)
var swordLen = player.sword.height * 0.9;
var hit = false;
// Check all swords
var swordAngles = [player.sword.rotation];
if (player.extraSwords) {
for (var si = 0; si < player.extraSwords.length; si++) {
swordAngles.push(player.extraSwords[si].rotation);
}
}
for (var sa = 0; sa < swordAngles.length; sa++) {
var angle = swordAngles[sa];
var tipX = player.x + Math.sin(angle) * swordLen;
var tipY = player.y - Math.cos(angle) * swordLen;
var sdx = enemy.x - tipX;
var sdy = enemy.y - tipY;
var sdist = Math.sqrt(sdx * sdx + sdy * sdy);
if (sdist < enemy.radius + 30) {
hit = true;
break;
}
}
if (hit) {
// Enemy hit!
score++;
scoreTxt.setText('Skor: ' + score);
enemy.hit();
LK.effects.flashObject(enemy, 0xffff00, 200);
// --- Upgrader spawn on every 2 kills ---
if (typeof killsSinceLastUpgrader === "undefined") killsSinceLastUpgrader = 0;
killsSinceLastUpgrader++;
if (killsSinceLastUpgrader >= 2) {
killsSinceLastUpgrader = 0;
// Spawn upgrader at enemy's death position
var upgrader = new Upgrader();
upgrader.x = enemy.x;
upgrader.y = enemy.y;
upgraders.push(upgrader);
game.addChild(upgrader);
}
enemy.destroy();
enemies.splice(i, 1);
// Spawn new enemy
LK.setTimeout(function () {
if (enemies.length < maxEnemies) spawnEnemy();
}, 400);
// Win condition
if (score >= 30) {
LK.showYouWin();
return;
}
}
}
// Sword cooldown removed; sword rotates automatically
// Keep enemy count
if (enemies.length < maxEnemies && LK.ticks % 90 === 0) {
spawnEnemy();
}
};
// --- Prevent UI Overlap (top left 100x100) ---
player.x = Math.max(player.x, 160);
player.y = Math.max(player.y, 160); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// --- Enemy Class ---
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Enemy asset: red ellipse
var enemyAsset = self.attachAsset('enemy', {
width: 100,
height: 100,
color: 0xd83318,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 50;
self.speed = 4 + Math.random() * 2; // randomize speed a bit
self.state = 'idle'; // 'idle' or 'chase'
self.radarRadius = 400; // detection radius
self.target = null; // player
// For hit flash
self.flashTicks = 0;
self.update = function () {
if (!self.target) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// Radar detection
if (self.state === 'idle' && dist < self.radarRadius) {
self.state = 'chase';
}
// Move if chasing
if (self.state === 'chase') {
if (dist > 5) {
var moveX = dx / dist * self.speed;
var moveY = dy / dist * self.speed;
self.x += moveX;
self.y += moveY;
}
}
// Flash on hit
if (self.flashTicks > 0) {
self.flashTicks--;
enemyAsset.tint = 0xffff00;
} else {
enemyAsset.tint = 0xd83318;
}
};
// Called when hit by sword
self.hit = function () {
self.flashTicks = 6;
};
return self;
});
// --- Player Class ---
var Player = Container.expand(function () {
var self = Container.call(this);
// Player asset: a colored ellipse (body)
var body = self.attachAsset('player', {
width: 120,
height: 120,
color: 0x2e86de,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
// Sword child
self.sword = new Sword();
self.addChild(self.sword);
self.sword.x = 0;
self.sword.y = 0;
self.radius = 60; // for collision
// For dragging
self.isDragging = false;
// For invulnerability after hit
self.invulnTicks = 0;
// Called every tick
self.update = function () {
if (self.invulnTicks > 0) {
self.invulnTicks--;
body.alpha = LK.ticks % 10 < 5 ? 0.5 : 1;
} else {
body.alpha = 1;
}
// Make sword(s) rotate much faster and support multiple swords
if (!self.sword.swinging) {
// Sword speed multiplier (default 0.18, can be upgraded)
if (typeof self.swordSpeed === "undefined") self.swordSpeed = 0.18;
// Number of swords (default 1, can be upgraded)
if (typeof self.swordCount === "undefined") self.swordCount = 1;
for (var i = 0; i < self.swordCount; i++) {
var angle = (LK.ticks * self.swordSpeed + Math.PI * 2 * i / self.swordCount) % (Math.PI * 2);
if (i === 0) {
self.sword.rotation = angle;
} else {
// Add extra swords if not already present
if (!self.extraSwords) self.extraSwords = [];
if (!self.extraSwords[i - 1]) {
var newSword = new Sword();
self.addChild(newSword);
newSword.x = 0;
newSword.y = 0;
self.extraSwords[i - 1] = newSword;
}
self.extraSwords[i - 1].rotation = angle;
}
}
// Remove extra swords if swordCount decreased
if (self.extraSwords && self.extraSwords.length > self.swordCount - 1) {
for (var j = self.swordCount - 1; j < self.extraSwords.length; j++) {
self.extraSwords[j].destroy();
}
self.extraSwords.length = self.swordCount - 1;
}
}
};
// Start sword swing
self.attack = function (onFinish) {
self.sword.swing(onFinish);
};
return self;
});
// --- Sword Class ---
var Sword = Container.expand(function () {
var self = Container.call(this);
// Sword asset: a long, thin rectangle (box)
var swordAsset = self.attachAsset('sword', {
width: 40,
height: 220,
color: 0xffffff,
shape: 'box',
anchorX: 0.5,
anchorY: 0.9 // handle is at bottom
});
self.swinging = false;
self.swingAngle = 0; // in radians
// Called every tick
self.update = function () {
// If swinging, animate the sword
if (self.swinging) {
self.rotation = self.swingAngle;
}
};
// Start a sword swing animation
self.swing = function (_onFinish) {
// Sword is always rotating, so swing does nothing
if (_onFinish) _onFinish();
};
return self;
});
// --- Upgrader Class ---
var Upgrader = Container.expand(function () {
var self = Container.call(this);
// Randomly choose upgrade type
var types = [{
type: "speed",
color: 0x00ffcc
}, {
type: "multi",
color: 0xffcc00
}];
var chosen = types[Math.floor(Math.random() * types.length)];
self.upgradeType = chosen.type;
// Visual: colored ellipse
var asset = self.attachAsset('centerCircle', {
width: 90,
height: 90,
color: chosen.color,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
// Animate (pulse)
tween(asset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.linear,
onFinish: function onFinish() {
// Reverse pulse for yoyo effect
tween(asset, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.linear,
onFinish: function onFinish() {
// Repeat indefinitely
if (asset && asset.parent) {
// Only repeat if still in scene
// Use setTimeout to avoid call stack overflow
LK.setTimeout(function () {
if (asset && asset.parent) {
// Restart pulse
tween(asset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.linear,
onFinish: arguments.callee
});
}
}, 0);
}
}
});
}
});
asset.scaleX = 1.0;
asset.scaleY = 1.0;
// For collision
self.radius = 45;
// Lifetime (10s default)
self.lifetime = 600 + Math.floor(Math.random() * 600); // 10-20s
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.destroy();
if (typeof upgraders !== "undefined") {
var idx = upgraders.indexOf(self);
if (idx !== -1) upgraders.splice(idx, 1);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// --- Game Variables ---
var player;
var enemies = [];
var upgraders = [];
var maxEnemies = 6;
var spawnAreaMargin = 200;
var score = 0;
var lives = 3;
var scoreTxt, livesTxt;
var dragNode = null;
var lastTouch = {
x: 0,
y: 0
};
var swordHitCooldown = 0;
// Upgrader spawn timer
var nextUpgraderTick = LK.ticks + 60 * (2 + Math.random() * 28); // 2-30s
// --- UI Setup ---
scoreTxt = new Text2('Skor: 0', {
size: 100,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
livesTxt = new Text2('Can: 3', {
size: 80,
fill: "#fff"
});
livesTxt.anchor.set(1, 0);
livesTxt.x = -40; // right margin
LK.gui.topRight.addChild(livesTxt);
// --- Player Setup ---
player = new Player();
player.x = 2048 / 2;
player.y = 2732 * 0.7;
game.addChild(player);
// --- Enemy Spawning ---
function spawnEnemy() {
var enemy = new Enemy();
enemy.target = player;
// Spawn at random edge
var edge = Math.floor(Math.random() * 4);
var x, y;
if (edge === 0) {
// top
x = spawnAreaMargin + Math.random() * (2048 - 2 * spawnAreaMargin);
y = spawnAreaMargin;
} else if (edge === 1) {
// bottom
x = spawnAreaMargin + Math.random() * (2048 - 2 * spawnAreaMargin);
y = 2732 - spawnAreaMargin;
} else if (edge === 2) {
// left
x = spawnAreaMargin;
y = spawnAreaMargin + Math.random() * (2732 - 2 * spawnAreaMargin);
} else {
// right
x = 2048 - spawnAreaMargin;
y = spawnAreaMargin + Math.random() * (2732 - 2 * spawnAreaMargin);
}
enemy.x = x;
enemy.y = y;
enemies.push(enemy);
game.addChild(enemy);
}
// Initial enemies
for (var i = 0; i < maxEnemies; i++) {
spawnEnemy();
}
// --- Touch/Drag Controls ---
game.down = function (x, y, obj) {
// Only drag if touch is on player
var dx = x - player.x;
var dy = y - player.y;
if (dx * dx + dy * dy < player.radius * player.radius) {
dragNode = player;
lastTouch.x = x;
lastTouch.y = y;
}
};
game.move = function (x, y, obj) {
if (dragNode === player) {
// Clamp to game area
var nx = Math.max(player.radius, Math.min(2048 - player.radius, x));
var ny = Math.max(player.radius, Math.min(2732 - player.radius, y));
player.x = nx;
player.y = ny;
lastTouch.x = x;
lastTouch.y = y;
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// --- Sword Attack (Tap anywhere except player) ---
game.tapCooldown = 0;
game.downSword = function (x, y, obj) {
// If not dragging player, swing sword
var dx = x - player.x;
var dy = y - player.y;
// Sword now rotates automatically; manual swing disabled
};
// Listen for down events for sword attack
game.on('down', function (x, y, obj) {
game.downSword(x, y, obj);
});
// --- Game Update Loop ---
game.update = function () {
player.update();
// --- Upgrader spawn logic ---
if (LK.ticks >= nextUpgraderTick) {
// Spawn upgrader at random position (not too close to player)
var tries = 0;
var ux, uy;
do {
ux = 200 + Math.random() * (2048 - 400);
uy = 200 + Math.random() * (2732 - 400);
tries++;
} while (tries < 10 && Math.sqrt((ux - player.x) * (ux - player.x) + (uy - player.y) * (uy - player.y)) < 300);
var upgrader = new Upgrader();
upgrader.x = ux;
upgrader.y = uy;
upgraders.push(upgrader);
game.addChild(upgrader);
// Next spawn in 2-30s
nextUpgraderTick = LK.ticks + 60 * (2 + Math.random() * 28);
}
// --- Upgrader update and collision ---
for (var u = upgraders.length - 1; u >= 0; u--) {
var upgrader = upgraders[u];
if (upgrader.update) upgrader.update();
// Check collision with player
var dxu = upgrader.x - player.x;
var dyu = upgrader.y - player.y;
var distu = Math.sqrt(dxu * dxu + dyu * dyu);
if (distu < player.radius + upgrader.radius) {
// Apply upgrade
if (upgrader.upgradeType === "speed") {
if (typeof player.swordSpeed === "undefined") player.swordSpeed = 0.18;
player.swordSpeed *= 1.4;
LK.effects.flashObject(player.sword, 0x00ffcc, 400);
} else if (upgrader.upgradeType === "multi") {
if (typeof player.swordCount === "undefined") player.swordCount = 1;
player.swordCount = Math.min(player.swordCount + 1, 5);
LK.effects.flashObject(player.sword, 0xffcc00, 400);
}
// Remove upgrader
upgrader.destroy();
upgraders.splice(u, 1);
}
}
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Check collision: enemy with player
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < enemy.radius + player.radius - 10) {
// Only if not invulnerable
if (player.invulnTicks === 0) {
lives--;
livesTxt.setText('Can: ' + lives);
player.invulnTicks = 60;
LK.effects.flashObject(player, 0xff0000, 600);
if (lives <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
// Check collision: enemy with sword(s)
var swordLen = player.sword.height * 0.9;
var hit = false;
// Check all swords
var swordAngles = [player.sword.rotation];
if (player.extraSwords) {
for (var si = 0; si < player.extraSwords.length; si++) {
swordAngles.push(player.extraSwords[si].rotation);
}
}
for (var sa = 0; sa < swordAngles.length; sa++) {
var angle = swordAngles[sa];
var tipX = player.x + Math.sin(angle) * swordLen;
var tipY = player.y - Math.cos(angle) * swordLen;
var sdx = enemy.x - tipX;
var sdy = enemy.y - tipY;
var sdist = Math.sqrt(sdx * sdx + sdy * sdy);
if (sdist < enemy.radius + 30) {
hit = true;
break;
}
}
if (hit) {
// Enemy hit!
score++;
scoreTxt.setText('Skor: ' + score);
enemy.hit();
LK.effects.flashObject(enemy, 0xffff00, 200);
// --- Upgrader spawn on every 2 kills ---
if (typeof killsSinceLastUpgrader === "undefined") killsSinceLastUpgrader = 0;
killsSinceLastUpgrader++;
if (killsSinceLastUpgrader >= 2) {
killsSinceLastUpgrader = 0;
// Spawn upgrader at enemy's death position
var upgrader = new Upgrader();
upgrader.x = enemy.x;
upgrader.y = enemy.y;
upgraders.push(upgrader);
game.addChild(upgrader);
}
enemy.destroy();
enemies.splice(i, 1);
// Spawn new enemy
LK.setTimeout(function () {
if (enemies.length < maxEnemies) spawnEnemy();
}, 400);
// Win condition
if (score >= 30) {
LK.showYouWin();
return;
}
}
}
// Sword cooldown removed; sword rotates automatically
// Keep enemy count
if (enemies.length < maxEnemies && LK.ticks % 90 === 0) {
spawnEnemy();
}
};
// --- Prevent UI Overlap (top left 100x100) ---
player.x = Math.max(player.x, 160);
player.y = Math.max(player.y, 160);