User prompt
Npc ler bizden uzakda kendi halerinde dusmanlarla savasin ve en guclu olani da mini map de gozuksun tipki io. Oyunlarindaki sistem gibi
User prompt
Npc ler bizden uzakda kendi halerinde dusmanlarla savasin ve en guclu olani da mini map de gozuksun tipki yilan oyunlarindaki sistem gibi
User prompt
Npc lerde dusmanlar gibi uzaklasinca kaybolmasin vede bizim gibi oynayip guclensinler bizimle savasinlar tipki bir oyuncu gibi dusmanlar onlarinda etrafinta dosun
User prompt
Dusman npc ler haritada rasgele dosunlar ve birbirleriyle de savasinlar ve guclensinler
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'enemy.x')' in or related to this line: 'var dx = hero.x - enemy.x;' Line Number: 3757
User prompt
Npc ler oyun baslayinca 12 tane dosun ve makismum 14 tane npc olsun mini map yap ve tum npc leri goster
User prompt
Dusman guruplari olmeden sedece 2gurup dosun
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'enemy.x')' in or related to this line: 'var dx = hero.x - enemy.x;' Line Number: 3716
User prompt
Npc lerde bizim gibi silah kulansin insan gibi haraket etsin ve dusmanlar karakter gibi onlarin yaninda dosunlar
User prompt
Dusmanlarin doma hizini azalt
User prompt
Dusmanlardan uzaklasinca yok olmasin
User prompt
Dusmanlar gurup halinde maksimum 10 kisi olsunlar 30 sansla maksimum gurup halinde gelsinler
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded.' in or related to this line: 'LK.effects.flashScreen(0xFF8C00, 150); // Brief orange screen flash' Line Number: 711
User prompt
Dusmanlar kendi hitbox larinin icine giremesib karakter dusmanlarin hitboxuna giremesin
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded.' in or related to this line: 'LK.effects.flashScreen(0xFF8C00, 150); // Brief orange screen flash' Line Number: 682
User prompt
Dusmanlar tur bitene kadar random gurup halinde spawnlansin
User prompt
Dusmanlar 10 kisik gurup halinde gelsin
User prompt
Dekorasyon tum chunklarda spawlansin
User prompt
Please fix the bug: 'undefined is not a constructor (evaluating 'new Set()')' in or related to this line: 'var spawnedChunks = new Set(); // Track spawned decoration chunks' Line Number: 1911
User prompt
1chunk dekorasyon 1defa spawnpasin
User prompt
Slime Npc ler hem bize hemde düşmanlara saldırsın düşmanlar bittikten sonra bize saldırsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Slime Npc ler hem bize hemde düşmanlara saldırsın düşmanlar bittikten sonra bize saldırsın
User prompt
Parayi modelle
User prompt
Npc ler kodla bizim gibi slime olsun ayni ozeliklerde onlarda level atlasin skor tablosu ekle ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Fastenemy patlayinda yanindaki dusmanlara ve karakterede hasar versin
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
totalKills: 0
});
/****
* Classes
****/
var BasicEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('basicEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 25;
self.maxHealth = 25;
self.damage = 15;
self.speed = 3;
self.scoreValue = 10;
// Enemy hitbox properties
self.width = 240; // Enemy visual width
self.height = 240; // Enemy visual height
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// 50% chance to drop coin
if (Math.random() < 0.5) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 60;
coin.y = self.y + (Math.random() - 0.5) * 60;
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('wikingboss', {
anchorX: 0.5,
anchorY: 0.5
});
bossGraphics.tint = 0x8B4513; // Brown viking color
bossGraphics.scaleX = 4.0; // Much larger viking boss model
bossGraphics.scaleY = 4.0; // Much larger viking boss model
// Add viking boss aura effect
var auraGraphics = self.attachAsset('wikingboss', {
anchorX: 0.5,
anchorY: 0.5
});
auraGraphics.tint = 0xDAA520; // Golden viking aura
auraGraphics.alpha = 0.4;
auraGraphics.scaleX = 4.5; // Larger aura to match viking boss size
auraGraphics.scaleY = 4.5; // Larger aura to match viking boss size
// Add pulsing viking aura animation
tween(auraGraphics, {
scaleX: 5.0,
scaleY: 5.0,
alpha: 0.2
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(auraGraphics, {
scaleX: 4.5,
scaleY: 4.5,
alpha: 0.4
}, {
duration: 1500,
easing: tween.easeInOut
});
}
});
self.health = 400 + (currentWave - 3) * 85; // Much higher health for viking boss
self.maxHealth = self.health;
self.damage = 70; // Higher damage for intimidating viking boss
self.speed = 1.1; // Slightly slower due to massive viking size
self.scoreValue = 250; // Higher reward for defeating viking boss
// Boss hitbox properties for accurate collision
self.width = 760; // Boss visual width (190 * 4 scale)
self.height = 760; // Boss visual height (190 * 4 scale)
self.lastLightningTime = 0;
self.lightningCooldown = 60; // 1 second at 60fps - much shorter for primary attack
self.lastChargeTime = 0;
self.chargeCooldown = 360; // 6 seconds at 60fps - less frequent
self.isCharging = false;
self.chargeSpeed = 8;
self.chargeTargetX = 0;
self.chargeTargetY = 0;
self.lastJumpTime = 0;
self.jumpCooldown = 300; // 5 seconds at 60fps - less frequent
self.isJumping = false;
self.jumpMarker = null;
self.lastAerialTime = 0;
self.aerialCooldown = 240; // 4 seconds at 60fps
self.isAerial = false;
self.aerialMarkers = [];
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Drop multiple XP orbs
for (var orbCount = 0; orbCount < 5; orbCount++) {
var xpOrb = new XPOrb();
xpOrb.x = self.x + (Math.random() - 0.5) * 100;
xpOrb.y = self.y + (Math.random() - 0.5) * 100;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
}
// Boss always drops coins
for (var coinCount = 0; coinCount < 10; coinCount++) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 150;
coin.y = self.y + (Math.random() - 0.5) * 150;
coin.coinValue = 10; // Boss coins are worth more
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
self.shootBigBullets = function () {
// Create multiple big bullets - increased from 5 to 7 for more coverage
for (var bulletCount = 0; bulletCount < 7; bulletCount++) {
var bigBullet = new BossBullet();
bigBullet.x = self.x;
bigBullet.y = self.y;
// Spread bullets in a wider arc for better coverage
var angleOffset = (bulletCount - 3) * Math.PI / 10;
var targetX = hero.x + Math.cos(angleOffset) * 200;
var targetY = hero.y + Math.sin(angleOffset) * 200;
bigBullet.setTarget(targetX, targetY);
bossBullets.push(bigBullet);
game.addChild(bigBullet);
}
// More dramatic visual effect for primary attack
LK.effects.flashObject(self, 0xFF4500, 600);
LK.effects.flashScreen(0xFF4500, 100);
};
self.startCharge = function () {
self.isCharging = true;
self.chargeTargetX = hero.x;
self.chargeTargetY = hero.y;
LK.effects.flashObject(self, 0xFF4500, 500);
// Viking boss grows larger during charge
tween(bossGraphics, {
scaleX: 4.5,
scaleY: 4.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Charge for 1 second then return to normal
LK.setTimeout(function () {
self.isCharging = false;
tween(bossGraphics, {
scaleX: 4.0,
scaleY: 4.0
}, {
duration: 200,
easing: tween.easeIn
});
}, 1000);
}
});
};
self.startJumpAttack = function () {
self.isJumping = true;
// Create red marker at hero's position
self.jumpMarker = LK.getAsset('jumpMarker', {
anchorX: 0.5,
anchorY: 0.5
});
self.jumpMarker.x = hero.x;
self.jumpMarker.y = hero.y;
self.jumpMarker.alpha = 0.6;
game.addChild(self.jumpMarker);
// Pulse the marker
tween(self.jumpMarker, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self.jumpMarker, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
// Boss prepares to jump - crouch animation
tween(bossGraphics, {
scaleY: 3.5
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
// Jump to marker position
var jumpX = self.jumpMarker.x;
var jumpY = self.jumpMarker.y;
// Jump animation
tween(self, {
x: jumpX,
y: jumpY
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Landing impact
LK.effects.flashScreen(0xFF0000, 200);
tween(bossGraphics, {
scaleY: 4.0
}, {
duration: 200,
easing: tween.easeOut
});
// Deal area damage at landing position
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (enemy !== self) {
var impactDx = enemy.x - self.x;
var impactDy = enemy.y - self.y;
var impactDistance = Math.sqrt(impactDx * impactDx + impactDy * impactDy);
if (impactDistance < 250) {
enemy.takeDamage(40);
}
}
}
// Check if hero is in impact area
var heroDx = hero.x - self.x;
var heroDy = hero.y - self.y;
var heroDistance = Math.sqrt(heroDx * heroDx + heroDy * heroDy);
if (heroDistance < 250) {
hero.takeDamage(60);
}
// Remove marker
if (self.jumpMarker) {
self.jumpMarker.destroy();
self.jumpMarker = null;
}
self.isJumping = false;
}
});
}
});
};
self.startAerialAttack = function () {
self.isAerial = true;
// Create multiple red markers in a pattern around hero
var markerCount = 5;
for (var i = 0; i < markerCount; i++) {
var angle = Math.PI * 2 / markerCount * i;
var markerDistance = 150;
var marker = LK.getAsset('jumpMarker', {
anchorX: 0.5,
anchorY: 0.5
});
marker.x = hero.x + Math.cos(angle) * markerDistance;
marker.y = hero.y + Math.sin(angle) * markerDistance;
marker.alpha = 0.8;
marker.tint = 0xFF0000;
game.addChild(marker);
self.aerialMarkers.push(marker);
// Pulse animation for markers
tween(marker, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0.4
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(marker, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.8
}, {
duration: 400,
easing: tween.easeInOut
});
}
});
}
// Boss rises up animation
tween(bossGraphics, {
scaleX: 3.5,
scaleY: 3.5,
alpha: 0.5
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// After delay, rain bullets from sky
LK.setTimeout(function () {
// Create bullets at each marker position
for (var j = 0; j < self.aerialMarkers.length; j++) {
var targetMarker = self.aerialMarkers[j];
// Create bullet high above
var skyBullet = new BossBullet();
skyBullet.x = targetMarker.x;
skyBullet.y = targetMarker.y - 800; // Start high above
skyBullet.setTarget(targetMarker.x, targetMarker.y);
bossBullets.push(skyBullet);
game.addChild(skyBullet);
}
// Boss returns to normal
tween(bossGraphics, {
scaleX: 4.0,
scaleY: 4.0,
alpha: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
// Remove markers after bullets are fired
for (var k = 0; k < self.aerialMarkers.length; k++) {
self.aerialMarkers[k].destroy();
}
self.aerialMarkers = [];
self.isAerial = false;
}, 800);
}
});
};
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var currentTime = LK.ticks;
// Big bullet attack - primary attack with extended range
if (distance < 900 && currentTime - self.lastLightningTime > self.lightningCooldown) {
self.shootBigBullets();
self.lastLightningTime = currentTime;
}
// Charge attack - secondary attack, less frequent
if (distance > 250 && distance < 600 && currentTime - self.lastChargeTime > self.chargeCooldown && !self.isCharging && !self.isJumping) {
self.startCharge();
self.lastChargeTime = currentTime;
}
// Jump attack - tertiary attack, least frequent
if (distance < 700 && currentTime - self.lastJumpTime > self.jumpCooldown && !self.isJumping && !self.isCharging && !self.isAerial) {
self.startJumpAttack();
self.lastJumpTime = currentTime;
}
// Aerial attack - quaternary attack
if (distance < 600 && currentTime - self.lastAerialTime > self.aerialCooldown && !self.isJumping && !self.isCharging && !self.isAerial) {
self.startAerialAttack();
self.lastAerialTime = currentTime;
}
// Movement behavior
if (self.isCharging) {
// Charge towards target position
var chargeDx = self.chargeTargetX - self.x;
var chargeDy = self.chargeTargetY - self.y;
var chargeDistance = Math.sqrt(chargeDx * chargeDx + chargeDy * chargeDy);
if (chargeDistance > 0) {
self.x += chargeDx / chargeDistance * self.chargeSpeed;
self.y += chargeDy / chargeDistance * self.chargeSpeed;
}
} else if (self.isJumping || self.isAerial) {
// Don't move while jumping or aerial attack
} else {
// Normal movement - maintain distance from hero
if (distance > 300) {
// Move closer
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else if (distance < 150) {
// Move away
if (distance > 0) {
self.x -= dx / distance * self.speed;
self.y -= dy / distance * self.speed;
}
}
}
};
return self;
});
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
bulletGraphics.scaleX = 1.5; // Scale for appropriate size
bulletGraphics.scaleY = 1.5; // Scale for appropriate size
// Add glowing effect to boss bullets
var glowGraphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
glowGraphics.tint = 0xFF6600; // Orange glow
glowGraphics.alpha = 0.4;
glowGraphics.scaleX = 2;
glowGraphics.scaleY = 2;
// Pulsing glow animation
tween(glowGraphics, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(glowGraphics, {
scaleX: 2,
scaleY: 2,
alpha: 0.4
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
self.speed = 6;
self.damage = 50;
// Boss bullet hitbox properties
self.width = 150; // Boss bullet visual width (100 * 1.5 scale)
self.height = 150; // Boss bullet visual height (100 * 1.5 scale)
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
var dx = x - self.x;
var dy = y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
}
// Rotate bullet to face direction
bulletGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
};
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
// Rotate the boss bullet for visual effect
self.rotation += 0.1;
// Remove bullet if it goes off screen
if (self.x < -50 || self.x > 8242 || self.y < -50 || self.y > 10978) {
self.destroy();
for (var i = bossBullets.length - 1; i >= 0; i--) {
if (bossBullets[i] === self) {
bossBullets.splice(i, 1);
break;
}
}
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Bullet.prototype.baseSpeed || 8;
self.damage = 25;
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
var dx = x - self.x;
var dy = y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
}
// Rotate bullet to face direction
bulletGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
};
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
// Remove bullet if it goes off screen
if (self.x < -50 || self.x > 8242 || self.y < -50 || self.y > 10978) {
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
}
};
return self;
});
var CoinPickup = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinGraphics.scaleX = 0.8;
coinGraphics.scaleY = 0.8;
// Add glowing effect
var glowGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
glowGraphics.tint = 0xFFF700; // Bright yellow glow
glowGraphics.alpha = 0.3;
glowGraphics.scaleX = 1.1;
glowGraphics.scaleY = 1.1;
// Add pulsing animation
tween(coinGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(coinGraphics, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 600,
easing: tween.easeInOut
});
}
});
// Add continuous rotation animation
tween(coinGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
coinGraphics.rotation = 0;
// Restart rotation
tween(coinGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear
});
}
});
self.coinValue = 5;
self.moveSpeed = 3;
self.attractRange = 120;
self.update = function () {
// Move toward hero if within attract range
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.attractRange) {
if (distance > 0) {
self.x += dx / distance * self.moveSpeed;
self.y += dy / distance * self.moveSpeed;
}
}
// Check if collected by hero
if (distance < 30) {
// Give coins to player
var currentCoins = storage.coins || 0;
storage.coins = currentCoins + self.coinValue;
updateCoinsDisplay();
LK.getSound('xpCollect').play();
LK.effects.flashObject(hero, 0xFFD700, 300); // Gold flash
// Remove from coins array
for (var i = coinPickups.length - 1; i >= 0; i--) {
if (coinPickups[i] === self) {
coinPickups.splice(i, 1);
break;
}
}
self.destroy();
}
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('fastEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 15;
self.maxHealth = 15;
self.damage = 10;
self.speed = 4.5;
self.scoreValue = 15;
// Enemy hitbox properties
self.width = 150; // Enemy visual width
self.height = 150; // Enemy visual height
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Create multiple explosion visual effects with different colors and timings
LK.effects.flashObject(self, 0xFF4500, 400); // Red-orange flash
LK.effects.flashScreen(0xFF8C00, 150); // Brief orange screen flash
// Add scaling explosion effect
tween(self, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
// Deal explosion damage to nearby enemies
for (var j = 0; j < enemies.length; j++) {
var otherEnemy = enemies[j];
if (otherEnemy !== self) {
var explodeDx = otherEnemy.x - self.x;
var explodeDy = otherEnemy.y - self.y;
var explodeDistance = Math.sqrt(explodeDx * explodeDx + explodeDy * explodeDy);
// Damage enemies within 150 pixel explosion radius
if (explodeDistance < 150) {
otherEnemy.takeDamage(25); // Increased explosion damage to enemies
// Push enemies away from explosion center
if (explodeDistance > 0) {
otherEnemy.x += explodeDx / explodeDistance * 80;
otherEnemy.y += explodeDy / explodeDistance * 80;
}
// Add flash effect to affected enemies
LK.effects.flashObject(otherEnemy, 0xFF4500, 200);
}
}
}
// Deal explosion damage to hero if in blast radius
var heroDx = hero.x - self.x;
var heroDy = hero.y - self.y;
var heroDistance = Math.sqrt(heroDx * heroDx + heroDy * heroDy);
if (heroDistance < 150) {
hero.takeDamage(20); // Explosion damage to hero
// Add visual feedback for hero being hit by explosion
LK.effects.flashObject(hero, 0xFF4500, 300);
}
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// 50% chance to drop coin
if (Math.random() < 0.5) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 60;
coin.y = self.y + (Math.random() - 0.5) * 60;
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
return self;
});
var HealthCrate = Container.expand(function () {
var self = Container.call(this);
var crateGraphics = self.attachAsset('crate', {
anchorX: 0.5,
anchorY: 0.5
});
crateGraphics.scaleX = 0.8;
crateGraphics.scaleY = 0.8;
self.health = 1;
self.takeDamage = function (damage) {
self.health -= damage;
// Shake effect when hit
LK.effects.flashObject(self, 0xFFFFFF, 100);
tween(self, {
rotation: self.rotation + 0.1
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
rotation: self.rotation - 0.2
}, {
duration: 50,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
rotation: self.rotation + 0.1
}, {
duration: 50,
easing: tween.easeOut
});
}
});
}
});
if (self.health <= 0) {
var dropChance = Math.random();
if (dropChance < 0.1) {
// 10% chance to drop level up item
var levelPickup = new LevelPickup();
levelPickup.x = self.x;
levelPickup.y = self.y;
levelPickups.push(levelPickup);
game.addChild(levelPickup);
} else if (dropChance < 0.55) {
// 45% chance to drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
} else {
// 45% chance to drop health pickup
var healthPickup = new HealthPickup();
healthPickup.x = self.x;
healthPickup.y = self.y;
healthPickups.push(healthPickup);
game.addChild(healthPickup);
}
self.destroy();
LK.getSound('enemyDestroy').play();
for (var i = healthCrates.length - 1; i >= 0; i--) {
if (healthCrates[i] === self) {
healthCrates.splice(i, 1);
break;
}
}
}
};
return self;
});
var HealthPickup = Container.expand(function () {
var self = Container.call(this);
var pickupGraphics = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
pickupGraphics.scaleX = 0.3;
pickupGraphics.scaleY = 0.3;
pickupGraphics.tint = 0xFF0000; // Red color for health
// Add pulsing animation
tween(pickupGraphics, {
scaleX: 0.35,
scaleY: 0.35
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(pickupGraphics, {
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
self.healAmount = 15;
self.update = function () {
// Check if collected by hero
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 40) {
// Heal player
if (hero.health < hero.maxHealth) {
hero.health = Math.min(hero.health + self.healAmount, hero.maxHealth);
updateHealthBar();
LK.getSound('xpCollect').play();
LK.effects.flashObject(hero, 0x00FF00, 300); // Green flash
}
// Remove from healthPickups array
for (var i = healthPickups.length - 1; i >= 0; i--) {
if (healthPickups[i] === self) {
healthPickups.splice(i, 1);
break;
}
}
self.destroy();
}
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
var weaponGraphics = self.attachAsset('weapon', {
anchorX: 0.5,
anchorY: 0.9
});
weaponGraphics.x = 25;
weaponGraphics.y = -10;
self.maxHealth = 100;
self.health = self.maxHealth;
self.attackDamage = 25;
self.isInvulnerable = false;
// Custom hitbox properties
self.hitboxWidth = 80; // Smaller than visual size for better gameplay
self.hitboxHeight = 100; // Adjusted for character proportions
self.hitboxOffsetX = 0; // Center aligned
self.hitboxOffsetY = 0; // Center aligned
self.takeDamage = function (damage) {
if (self.isInvulnerable) return;
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
// Add death visual effects
LK.effects.flashObject(self, 0xFF0000, 1000); // Long red flash
LK.effects.flashScreen(0x8B0000, 800); // Dark red screen flash
// Make hero semi-transparent to show death
tween(self, {
alpha: 0.3,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeOut
});
// Change to death state and show death menu
gameState = 'dead';
// Add a small delay before showing death menu for better UX
LK.setTimeout(function () {
createDeathMenu();
}, 500);
return;
}
// Flash red when taking damage
LK.effects.flashObject(self, 0xFF0000, 300);
LK.getSound('playerHit').play();
// Brief invulnerability
self.isInvulnerable = true;
LK.setTimeout(function () {
self.isInvulnerable = false;
}, 500);
};
self.attack = function (enemy) {
enemy.takeDamage(self.attackDamage);
LK.getSound('enemyHit').play();
// Weapon swing animation
tween(weaponGraphics, {
rotation: weaponGraphics.rotation + Math.PI / 3
}, {
duration: 100
});
};
self.updateWeapon = function (targetX, targetY) {
// Calculate angle to target
var dx = targetX - self.x;
var dy = targetY - self.y;
var angle = Math.atan2(dy, dx);
weaponGraphics.rotation = angle + Math.PI / 2;
};
self.shoot = function (targetX, targetY) {
var weapon = weaponTypes[currentWeapon];
if (currentWeapon === 'shotgun') {
// Shotgun shoots 5 bullets in a spread
for (var i = 0; i < 5; i++) {
var bullet = new Bullet();
bullet.x = self.x + Math.cos(weaponGraphics.rotation - Math.PI / 2) * 40;
bullet.y = self.y + Math.sin(weaponGraphics.rotation - Math.PI / 2) * 40;
bullet.damage = weapon.damage;
bullet.speed = weapon.bulletSpeed;
// Add spread to bullets
var spreadAngle = (i - 2) * 0.15; // -0.3 to 0.3 radians spread
var adjustedTargetX = targetX + Math.cos(spreadAngle) * 100;
var adjustedTargetY = targetY + Math.sin(spreadAngle) * 100;
bullet.setTarget(adjustedTargetX, adjustedTargetY);
bullets.push(bullet);
game.addChild(bullet);
}
} else {
// Single bullet for other weapons
var bullet = new Bullet();
bullet.x = self.x + Math.cos(weaponGraphics.rotation - Math.PI / 2) * 40;
bullet.y = self.y + Math.sin(weaponGraphics.rotation - Math.PI / 2) * 40;
bullet.damage = weapon.damage;
bullet.speed = weapon.bulletSpeed;
bullet.setTarget(targetX, targetY);
bullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('weaponShoot').play();
// Weapon recoil animation - store original position
var originalWeaponY = weaponGraphics.y;
tween(weaponGraphics, {
y: originalWeaponY + 5
}, {
duration: 50,
onComplete: function onComplete() {
tween(weaponGraphics, {
y: originalWeaponY
}, {
duration: 50
});
}
});
};
self.isWalking = false;
self.moveSpeed = 4;
self.analogMove = function (deltaX, deltaY) {
// Analog movement without bounds for infinite world
self.x += deltaX * self.moveSpeed;
self.y += deltaY * self.moveSpeed;
};
self.walkTo = function (targetX, targetY) {
// Don't start new walk if already walking
if (self.isWalking) {
tween.stop(self, {
x: true,
y: true
});
}
self.isWalking = true;
// No bounds checking for infinite world
// Calculate distance for duration
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var duration = distance * 2; // Adjust speed by changing multiplier
// Walking animation with slight bounce
tween(heroGraphics, {
scaleY: 0.9
}, {
duration: duration / 4,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(heroGraphics, {
scaleY: 1.1
}, {
duration: duration / 4,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(heroGraphics, {
scaleY: 1.0
}, {
duration: duration / 2,
easing: tween.easeOut
});
}
});
}
});
// Move to target position
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isWalking = false;
}
});
};
// Custom collision check method using hitbox
self.checkCollision = function (other) {
// Calculate hitbox bounds for hero
var heroLeft = self.x - self.hitboxWidth / 2 + self.hitboxOffsetX;
var heroRight = self.x + self.hitboxWidth / 2 + self.hitboxOffsetX;
var heroTop = self.y - self.hitboxHeight / 2 + self.hitboxOffsetY;
var heroBottom = self.y + self.hitboxHeight / 2 + self.hitboxOffsetY;
// Get other object bounds (assuming standard bounds)
var otherLeft = other.x - other.width / 2;
var otherRight = other.x + other.width / 2;
var otherTop = other.y - other.height / 2;
var otherBottom = other.y + other.height / 2;
// Check for overlap
return heroLeft < otherRight && heroRight > otherLeft && heroTop < otherBottom && heroBottom > otherTop;
};
// Debug method to visualize hitbox (can be called for testing)
self.showHitbox = function () {
if (!self.hitboxVisual) {
self.hitboxVisual = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5
});
self.hitboxVisual.width = self.hitboxWidth;
self.hitboxVisual.height = self.hitboxHeight;
self.hitboxVisual.x = self.hitboxOffsetX;
self.hitboxVisual.y = self.hitboxOffsetY;
self.hitboxVisual.alpha = 0.3;
self.hitboxVisual.tint = 0x00FF00;
self.addChild(self.hitboxVisual);
}
};
return self;
});
var LevelPickup = Container.expand(function () {
var self = Container.call(this);
var pickupGraphics = self.attachAsset('levelBar', {
anchorX: 0.5,
anchorY: 0.5
});
pickupGraphics.scaleX = 0.4;
pickupGraphics.scaleY = 0.4;
pickupGraphics.tint = 0xFFD700; // Gold color for level up
// Add glowing effect
var glowGraphics = self.attachAsset('levelBar', {
anchorX: 0.5,
anchorY: 0.5
});
glowGraphics.tint = 0xFFFF00; // Yellow glow
glowGraphics.alpha = 0.3;
glowGraphics.scaleX = 0.5;
glowGraphics.scaleY = 0.5;
// Add pulsing animation
tween(pickupGraphics, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(pickupGraphics, {
scaleX: 0.4,
scaleY: 0.4
}, {
duration: 600,
easing: tween.easeInOut
});
}
});
// Rotating glow effect
tween(glowGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
tween(glowGraphics, {
rotation: 0
}, {
duration: 2000,
easing: tween.linear
});
}
});
self.update = function () {
// Check if collected by hero
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 40) {
// Level up player
playerLevel++;
currentXP = 0;
xpToNextLevel = playerLevel * 30;
levelText.setText('Level ' + playerLevel);
// Level up effects
LK.effects.flashScreen(0xFFD700, 500);
hero.maxHealth += 3;
hero.health = hero.maxHealth; // Full heal on level up
updateHealthBar();
updateLevelBar();
LK.getSound('xpCollect').play();
LK.effects.flashObject(hero, 0xFFD700, 500); // Gold flash
// Show upgrade selection
showUpgradeSelection();
// Remove from levelPickups array
for (var i = levelPickups.length - 1; i >= 0; i--) {
if (levelPickups[i] === self) {
levelPickups.splice(i, 1);
break;
}
}
self.destroy();
}
};
return self;
});
var Lightning = Container.expand(function () {
var self = Container.call(this);
var lightningGraphics = self.attachAsset('lightningBolt', {
anchorX: 0.5,
anchorY: 0.5
});
// Add glowing effect to lightning bolt
var glowGraphics = self.attachAsset('lightningBolt', {
anchorX: 0.5,
anchorY: 0.5
});
glowGraphics.tint = 0xFFFF00; // Yellow glow
glowGraphics.alpha = 0.5;
glowGraphics.scaleX = 1.3;
glowGraphics.scaleY = 1.3;
self.speed = 7;
self.damage = 30;
// Lightning bolt hitbox properties
self.width = 80; // Lightning visual width
self.height = 200; // Lightning visual height
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.lifetime = 0;
self.maxLifetime = 90; // 1.5 seconds at 60fps
// Lightning crackling effect
tween(lightningGraphics, {
alpha: 0.3
}, {
duration: 100,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(lightningGraphics, {
alpha: 1.0
}, {
duration: 100,
easing: tween.easeInOut
});
}
});
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
var dx = x - self.x;
var dy = y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
}
// Rotate lightning to face direction
lightningGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
glowGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
};
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
self.lifetime++;
// Random flickering effect
if (Math.random() < 0.3) {
lightningGraphics.alpha = Math.random() * 0.5 + 0.5;
}
// Remove lightning after lifetime expires or goes off screen
if (self.lifetime > self.maxLifetime || self.x < -50 || self.x > 8242 || self.y < -50 || self.y > 10978) {
self.destroy();
for (var i = lightningBolts.length - 1; i >= 0; i--) {
if (lightningBolts[i] === self) {
lightningBolts.splice(i, 1);
break;
}
}
}
};
return self;
});
var MapDecoration = Container.expand(function () {
var self = Container.call(this);
self.decorationType = '';
self.setDecoration = function (type) {
self.decorationType = type;
var decorationGraphics;
switch (type) {
case 'tree':
decorationGraphics = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 1.0
});
decorationGraphics.tint = 0x228B22;
// Add slight random rotation for variety
decorationGraphics.rotation = (Math.random() - 0.5) * 0.3;
break;
case 'grass':
decorationGraphics = self.attachAsset('grass', {
anchorX: 0.5,
anchorY: 0.5
});
decorationGraphics.tint = 0x32CD32;
decorationGraphics.scaleX = 0.8 + Math.random() * 0.4;
decorationGraphics.scaleY = 0.8 + Math.random() * 0.4;
break;
case 'campfire':
decorationGraphics = self.attachAsset('campfire', {
anchorX: 0.5,
anchorY: 0.5
});
decorationGraphics.tint = 0xFF4500;
// Add flickering animation to campfire
tween(decorationGraphics, {
scaleX: 1.1,
scaleY: 1.1,
alpha: 0.8
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(decorationGraphics, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
break;
}
// Make decorations non-interactive and lower layer
self.alpha = 0.7;
};
return self;
});
var NPC = Container.expand(function () {
var self = Container.call(this);
var npcGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
// Random tint colors for variety
var tintColors = [0x00ff00, 0xff00ff, 0x00ffff, 0xffff00, 0xff8000, 0x8000ff];
npcGraphics.tint = tintColors[Math.floor(Math.random() * tintColors.length)];
self.maxHealth = 80;
self.health = self.maxHealth;
self.attackDamage = 20;
self.speed = 2.5;
self.level = 1;
self.xp = 0;
self.xpToNextLevel = 30;
self.scoreValue = 50;
// NPC hitbox properties
self.width = 130;
self.height = 130;
// AI behavior variables
self.target = null;
self.lastAttackTime = 0;
self.attackCooldown = 120; // 2 seconds at 60fps
self.searchRadius = 300;
self.attackRange = 60;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrb.xpValue = 10; // NPCs give more XP
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// 70% chance to drop coin
if (Math.random() < 0.7) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 60;
coin.y = self.y + (Math.random() - 0.5) * 60;
coin.coinValue = 15; // NPCs drop more valuable coins
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
// Update kill count
storage.totalKills = (storage.totalKills || 0) + 1;
for (var i = npcs.length - 1; i >= 0; i--) {
if (npcs[i] === self) {
npcs.splice(i, 1);
break;
}
}
}
};
self.gainXP = function (xpAmount) {
self.xp += xpAmount;
if (self.xp >= self.xpToNextLevel) {
self.levelUp();
}
};
self.levelUp = function () {
self.level++;
self.xp = 0;
self.xpToNextLevel = self.level * 30;
// Level up bonuses
self.maxHealth += 5;
self.health = self.maxHealth; // Full heal on level up
self.attackDamage += 3;
self.speed += 0.2;
// Visual effect for level up
LK.effects.flashObject(self, 0xFFD700, 500);
npcGraphics.scaleX = 1.2;
npcGraphics.scaleY = 1.2;
tween(npcGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
};
self.findTarget = function () {
// Look for enemies first
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.searchRadius && distance < nearestDistance) {
nearestEnemy = enemy;
nearestDistance = distance;
}
}
if (nearestEnemy) {
self.target = nearestEnemy;
return;
}
// If no enemies, look for other NPCs to compete with
for (var j = 0; j < npcs.length; j++) {
var otherNPC = npcs[j];
if (otherNPC !== self) {
var npcDx = otherNPC.x - self.x;
var npcDy = otherNPC.y - self.y;
var npcDistance = Math.sqrt(npcDx * npcDx + npcDy * npcDy);
if (npcDistance < self.searchRadius && npcDistance < nearestDistance) {
// Only target weaker NPCs
if (otherNPC.level <= self.level) {
self.target = otherNPC;
nearestDistance = npcDistance;
}
}
}
}
};
self.update = function () {
// Find target if we don't have one
if (!self.target || self.target.destroyed) {
self.findTarget();
}
if (self.target) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move towards target
if (distance > self.attackRange) {
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Attack target
var currentTime = LK.ticks;
if (currentTime - self.lastAttackTime > self.attackCooldown) {
if (self.target.takeDamage) {
self.target.takeDamage(self.attackDamage);
self.gainXP(5); // Gain XP for attacking
LK.getSound('enemyHit').play();
}
self.lastAttackTime = currentTime;
}
}
// If target is too far, lose it
if (distance > self.searchRadius * 1.5) {
self.target = null;
}
} else {
// Wander around hero's area
var heroDistance = Math.sqrt((hero.x - self.x) * (hero.x - self.x) + (hero.y - self.y) * (hero.y - self.y));
if (heroDistance > 400) {
// Move towards hero area
var heroDx = hero.x - self.x;
var heroDy = hero.y - self.y;
var heroDir = Math.sqrt(heroDx * heroDx + heroDy * heroDy);
if (heroDir > 0) {
self.x += heroDx / heroDir * self.speed * 0.5;
self.y += heroDy / heroDir * self.speed * 0.5;
}
}
}
};
return self;
});
var StrongEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('strongEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 50;
self.maxHealth = 50;
self.damage = 25;
self.speed = 2.8;
self.scoreValue = 25;
// Enemy hitbox properties
self.width = 300; // Enemy visual width
self.height = 300; // Enemy visual height
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// 50% chance to drop coin
if (Math.random() < 0.5) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 60;
coin.y = self.y + (Math.random() - 0.5) * 60;
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
return self;
});
var UpgradeOption = Container.expand(function () {
var self = Container.call(this);
// Background for upgrade option - made larger
var bgGraphics = self.attachAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
bgGraphics.scaleX = 3.5;
bgGraphics.scaleY = 4;
bgGraphics.tint = 0x2c3e50;
// Title text - made larger
self.titleText = new Text2('', {
size: 80,
fill: 0xFFD700
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -100;
self.addChild(self.titleText);
// Description text - made larger
self.descText = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
self.descText.anchor.set(0.5, 0.5);
self.descText.y = 0;
self.addChild(self.descText);
// Upgrade type
self.upgradeType = '';
self.setUpgrade = function (type, title, description) {
self.upgradeType = type;
self.titleText.setText(title);
self.descText.setText(description);
};
// Hover effect
self.down = function (x, y, obj) {
tween(bgGraphics, {
scaleX: 3.8,
scaleY: 4.3
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
tween(bgGraphics, {
scaleX: 3.5,
scaleY: 4
}, {
duration: 100,
easing: tween.easeIn
});
// Apply the upgrade
applyUpgrade(self.upgradeType);
};
return self;
});
var Wizard = Container.expand(function () {
var self = Container.call(this);
var wizardGraphics = self.attachAsset('Wizard', {
anchorX: 0.5,
anchorY: 0.5
});
// Add magical aura effect using the wizard asset
var auraGraphics = self.attachAsset('Wizard', {
anchorX: 0.5,
anchorY: 0.5
});
auraGraphics.tint = 0x9370DB; // Purple aura
auraGraphics.alpha = 0.3;
auraGraphics.scaleX = 1.3;
auraGraphics.scaleY = 1.3;
// Add pulsing magical aura animation
tween(auraGraphics, {
scaleX: 1.8,
scaleY: 1.8,
alpha: 0.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(auraGraphics, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
self.health = 60;
self.maxHealth = 60;
self.damage = 20;
self.speed = 2.5;
self.scoreValue = 30;
// Wizard hitbox properties
self.width = 310; // Wizard visual width
self.height = 310; // Wizard visual height
self.lastLightningTime = 0;
self.lightningCooldown = 60; // 1 second at 60fps - much faster attack speed
self.lightningRange = 600;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// 50% chance to drop coin
if (Math.random() < 0.5) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 60;
coin.y = self.y + (Math.random() - 0.5) * 60;
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
self.shootLightning = function () {
// Create lightning bolt
var lightning = new Lightning();
lightning.x = self.x;
lightning.y = self.y;
lightning.setTarget(hero.x, hero.y);
lightningBolts.push(lightning);
game.addChild(lightning);
// Enhanced lightning casting effects
LK.effects.flashObject(self, 0xFFFF00, 300);
LK.effects.flashObject(auraGraphics, 0xFFFFFF, 400);
// Dramatic casting animation - wizard grows larger then returns
tween(wizardGraphics, {
scaleX: 1.5,
scaleY: 1.5,
rotation: wizardGraphics.rotation + Math.PI / 6
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(wizardGraphics, {
scaleX: 1.2,
scaleY: 1.2,
rotation: wizardGraphics.rotation - Math.PI / 6
}, {
duration: 250,
easing: tween.easeIn
});
}
});
// Aura intensifies during casting
tween(auraGraphics, {
scaleX: 2.2,
scaleY: 2.2,
alpha: 0.6
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(auraGraphics, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}, {
duration: 300,
easing: tween.easeIn
});
}
});
};
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Keep distance and shoot lightning
if (distance < self.lightningRange && distance > 150) {
// Stop moving and prepare to shoot
var currentTime = LK.ticks;
if (currentTime - self.lastLightningTime > self.lightningCooldown) {
self.shootLightning();
self.lastLightningTime = currentTime;
}
} else if (distance > self.lightningRange) {
// Move closer to hero
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else if (distance < 150) {
// Move away from hero
if (distance > 0) {
self.x -= dx / distance * self.speed;
self.y -= dy / distance * self.speed;
}
}
};
return self;
});
var XPOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('xpOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.xpValue = 5;
self.moveSpeed = 2;
self.attractRange = 150;
// Add pulsing animation to make XP orbs more attractive
tween(orbGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(orbGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart the pulsing animation
tween(orbGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
}
});
self.update = function () {
// XP orb magnetic attraction to other nearby orbs
for (var o = 0; o < xpOrbs.length; o++) {
var otherOrb = xpOrbs[o];
if (otherOrb !== self) {
var orbDx = otherOrb.x - self.x;
var orbDy = otherOrb.y - self.y;
var orbDistance = Math.sqrt(orbDx * orbDx + orbDy * orbDy);
// Attract to nearby orbs within 80 pixels
if (orbDistance < 80 && orbDistance > 0) {
var attractForce = 0.5;
self.x += orbDx / orbDistance * attractForce;
self.y += orbDy / orbDistance * attractForce;
}
}
}
// Move toward hero if within attract range
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.attractRange) {
if (distance > 0) {
self.x += dx / distance * self.moveSpeed;
self.y += dy / distance * self.moveSpeed;
}
}
// Check if collected by hero
if (distance < 30) {
// Give XP to player
currentXP += self.xpValue;
LK.setScore(LK.getScore() + self.xpValue);
scoreTxt.setText(LK.getScore());
LK.getSound('xpCollect').play();
// Remove from xpOrbs array
for (var i = xpOrbs.length - 1; i >= 0; i--) {
if (xpOrbs[i] === self) {
xpOrbs.splice(i, 1);
break;
}
}
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
// Menu system variables
var gameState = 'menu'; // 'menu', 'playing', 'paused', 'dead', 'weaponSelect'
var menuContainer;
var gameContainer;
var deathMenuContainer;
var weaponSelectContainer;
var hero;
var enemies = [];
var bullets = [];
var xpOrbs = [];
var lightningBolts = [];
var bossBullets = [];
var healthCrates = [];
var healthPickups = [];
var levelPickups = [];
var coinPickups = [];
var npcs = [];
var coinsText;
var shopContainer;
var scoreboardContainer;
var spawnTimer = 0;
var difficultyLevel = 1;
var scoreTxt;
var healthBar;
var healthBarBg;
var attackIndicator;
var lastShootTime = 0;
var joystickBase;
var joystickKnob;
var isJoystickActive = false;
var joystickStartX = 0;
var joystickStartY = 0;
var joystickRadius = 80;
var movementX = 0;
var movementY = 0;
var healthText;
var levelBar;
var levelBarBg;
var levelText;
var playerLevel = 1;
var currentXP = 0;
var xpToNextLevel = 30;
var currentWave = 1;
var waveStartTime = 0;
var waveDuration = 60000; // 1 minute in milliseconds
var waveEnemyCount = 0;
var baseEnemiesPerWave = 20;
var waveText;
var waveTimer;
var bossSpawned = false;
var bossHealthBarBg;
var bossHealthBar;
var bossHealthText;
var upgradeSelectionContainer;
var isSelectingUpgrade = false;
var availableUpgrades = [{
type: 'health',
title: 'Health Boost',
description: '+20 Max Health'
}, {
type: 'damage',
title: 'Damage Up',
description: '+10 Attack Damage'
}, {
type: 'speed',
title: 'Speed Boost',
description: '+1 Movement Speed'
}, {
type: 'attackSpeed',
title: 'Attack Speed',
description: 'Faster Shooting'
}, {
type: 'bulletSpeed',
title: 'Bullet Speed',
description: 'Faster Bullets'
}, {
type: 'regen',
title: 'Regeneration',
description: 'Heal 1 HP/sec'
}];
// Weapon types
var weaponTypes = {
pistol: {
name: 'Tabanca',
damage: 25,
shootCooldown: 80,
bulletSpeed: 8,
description: 'Standart silah'
},
rifle: {
name: 'Tüfek',
damage: 40,
shootCooldown: 120,
bulletSpeed: 12,
description: 'Yüksek hasar, yavaş atış'
},
shotgun: {
name: 'Pompalı',
damage: 15,
shootCooldown: 100,
bulletSpeed: 6,
description: '5 mermi, yakın mesafe'
},
machinegun: {
name: 'Makineli',
damage: 8,
shootCooldown: 20,
bulletSpeed: 10,
description: 'Çok hızlı atış',
cost: 200
},
sniper: {
name: 'Keskin Nişancı',
damage: 80,
shootCooldown: 180,
bulletSpeed: 15,
description: 'Yüksek hasar, çok yavaş',
cost: 300
},
laser: {
name: 'Lazer Silahı',
damage: 35,
shootCooldown: 40,
bulletSpeed: 20,
description: 'Hızlı ve hassas',
cost: 250
},
explosive: {
name: 'Patlayıcı',
damage: 50,
shootCooldown: 150,
bulletSpeed: 5,
description: 'Alan hasarı verir',
cost: 350
}
};
var currentWeapon = 'pistol';
var lastRegenTime = 0;
var hasRegen = false;
var mapDecorations = [];
function createEntryMenu() {
// Create menu container
menuContainer = new Container();
game.addChild(menuContainer);
// Create menu background
var menuBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
menuBg.x = 2048 / 2;
menuBg.y = 2732 / 2;
menuBg.scaleX = 8;
menuBg.scaleY = 8;
menuBg.tint = 0x1a1a2e;
menuBg.alpha = 0.9;
menuContainer.addChild(menuBg);
// Create game title
var gameTitle = new Text2('SAVAŞ ALANINDA', {
size: 120,
fill: 0xFFD700
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.x = 2048 / 2;
gameTitle.y = 2732 / 2 - 200;
menuContainer.addChild(gameTitle);
// Create subtitle
var gameSubtitle = new Text2('Hayatta Kal!', {
size: 80,
fill: 0xFFFFFF
});
gameSubtitle.anchor.set(0.5, 0.5);
gameSubtitle.x = 2048 / 2;
gameSubtitle.y = 2732 / 2 - 100;
menuContainer.addChild(gameSubtitle);
// Create play button background
var playButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
playButtonBg.x = 2048 / 2;
playButtonBg.y = 2732 / 2 + 100;
playButtonBg.scaleX = 4;
playButtonBg.scaleY = 3;
playButtonBg.tint = 0x27ae60;
menuContainer.addChild(playButtonBg);
// Create play button text
var playButtonText = new Text2('OYNA', {
size: 90,
fill: 0xFFFFFF
});
playButtonText.anchor.set(0.5, 0.5);
playButtonText.x = 2048 / 2;
playButtonText.y = 2732 / 2 + 100;
menuContainer.addChild(playButtonText);
// Add button interaction
playButtonBg.down = function (x, y, obj) {
// Button press animation
tween(playButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
playButtonBg.up = function (x, y, obj) {
// Button release animation and start game
tween(playButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
startGame();
}
});
};
// Create weapon select button background
var weaponButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
weaponButtonBg.x = 2048 / 2;
weaponButtonBg.y = 2732 / 2 + 200;
weaponButtonBg.scaleX = 4;
weaponButtonBg.scaleY = 3;
weaponButtonBg.tint = 0xe67e22;
menuContainer.addChild(weaponButtonBg);
// Create weapon select button text
var weaponButtonText = new Text2('SİLAH SEÇ', {
size: 70,
fill: 0xFFFFFF
});
weaponButtonText.anchor.set(0.5, 0.5);
weaponButtonText.x = 2048 / 2;
weaponButtonText.y = 2732 / 2 + 200;
menuContainer.addChild(weaponButtonText);
// Create shop button background
var shopButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
shopButtonBg.x = 2048 / 2;
shopButtonBg.y = 2732 / 2 + 300;
shopButtonBg.scaleX = 4;
shopButtonBg.scaleY = 3;
shopButtonBg.tint = 0x9b59b6;
menuContainer.addChild(shopButtonBg);
// Create shop button text
var shopButtonText = new Text2('DÜKKAN', {
size: 70,
fill: 0xFFFFFF
});
shopButtonText.anchor.set(0.5, 0.5);
shopButtonText.x = 2048 / 2;
shopButtonText.y = 2732 / 2 + 300;
menuContainer.addChild(shopButtonText);
// Create scoreboard button background
var scoreboardButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
scoreboardButtonBg.x = 2048 / 2;
scoreboardButtonBg.y = 2732 / 2 + 400;
scoreboardButtonBg.scaleX = 4;
scoreboardButtonBg.scaleY = 3;
scoreboardButtonBg.tint = 0x34495e;
menuContainer.addChild(scoreboardButtonBg);
// Create scoreboard button text
var scoreboardButtonText = new Text2('SKOR TABLOSU', {
size: 60,
fill: 0xFFFFFF
});
scoreboardButtonText.anchor.set(0.5, 0.5);
scoreboardButtonText.x = 2048 / 2;
scoreboardButtonText.y = 2732 / 2 + 400;
menuContainer.addChild(scoreboardButtonText);
// Add weapon button interaction
weaponButtonBg.down = function (x, y, obj) {
tween(weaponButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
weaponButtonBg.up = function (x, y, obj) {
tween(weaponButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
showWeaponSelect();
}
});
};
// Add shop button interaction
shopButtonBg.down = function (x, y, obj) {
tween(shopButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
shopButtonBg.up = function (x, y, obj) {
tween(shopButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
showShop();
}
});
};
// Add scoreboard button interaction
scoreboardButtonBg.down = function (x, y, obj) {
tween(scoreboardButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
scoreboardButtonBg.up = function (x, y, obj) {
tween(scoreboardButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
showScoreboard();
}
});
};
// Create decorative elements around menu
for (var i = 0; i < 6; i++) {
var decorElement = LK.getAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
var angle = Math.PI * 2 / 6 * i;
var radius = 300;
decorElement.x = 2048 / 2 + Math.cos(angle) * radius;
decorElement.y = 2732 / 2 + Math.sin(angle) * radius;
decorElement.alpha = 0.3;
decorElement.scaleX = 0.8;
decorElement.scaleY = 0.8;
decorElement.tint = 0x3498db;
menuContainer.addChild(decorElement);
// Add rotation animation
tween(decorElement, {
rotation: Math.PI * 2
}, {
duration: 3000 + i * 500,
easing: tween.linear,
onFinish: function onFinish() {
this.rotation = 0;
}
});
}
}
function showWeaponSelect() {
// Hide menu
menuContainer.visible = false;
gameState = 'weaponSelect';
// Create weapon select container
weaponSelectContainer = new Container();
game.addChild(weaponSelectContainer);
// Create background
var selectBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
selectBg.x = 2048 / 2;
selectBg.y = 2732 / 2;
selectBg.scaleX = 10;
selectBg.scaleY = 10;
selectBg.tint = 0x2c3e50;
selectBg.alpha = 0.9;
weaponSelectContainer.addChild(selectBg);
// Create title
var selectTitle = new Text2('SİLAH SEÇİMİ', {
size: 120,
fill: 0xFFD700
});
selectTitle.anchor.set(0.5, 0.5);
selectTitle.x = 2048 / 2;
selectTitle.y = 300;
weaponSelectContainer.addChild(selectTitle);
// Create weapon options - only show owned weapons
var ownedWeapons = storage.ownedWeapons || ['pistol', 'rifle', 'shotgun'];
var weaponIndex = 0;
for (var w = 0; w < ownedWeapons.length; w++) {
var weaponType = ownedWeapons[w];
var weapon = weaponTypes[weaponType];
var weaponY = 600 + weaponIndex * 200;
// Weapon background
var weaponBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
weaponBg.x = 2048 / 2;
weaponBg.y = weaponY;
weaponBg.scaleX = 5;
weaponBg.scaleY = 2;
weaponBg.tint = currentWeapon === weaponType ? 0x27ae60 : 0x34495e;
weaponSelectContainer.addChild(weaponBg);
// Weapon name
var weaponName = new Text2(weapon.name, {
size: 60,
fill: 0xFFFFFF
});
weaponName.anchor.set(0, 0.5);
weaponName.x = 2048 / 2 - 400;
weaponName.y = weaponY;
weaponSelectContainer.addChild(weaponName);
// Weapon description
var weaponDesc = new Text2(weapon.description, {
size: 40,
fill: 0xBDC3C7
});
weaponDesc.anchor.set(0, 0.5);
weaponDesc.x = 2048 / 2 - 100;
weaponDesc.y = weaponY;
weaponSelectContainer.addChild(weaponDesc);
// Create closure to capture weapon type
(function (type, bg) {
bg.down = function (x, y, obj) {
tween(bg, {
scaleX: 5.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
bg.up = function (x, y, obj) {
tween(bg, {
scaleX: 5,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
currentWeapon = type;
hideWeaponSelect();
}
});
};
})(weaponType, weaponBg);
weaponIndex++;
}
// Create back button
var backButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
backButtonBg.x = 2048 / 2;
backButtonBg.y = 2732 - 200;
backButtonBg.scaleX = 3;
backButtonBg.scaleY = 2;
backButtonBg.tint = 0x95a5a6;
weaponSelectContainer.addChild(backButtonBg);
var backButtonText = new Text2('GERİ', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 2048 / 2;
backButtonText.y = 2732 - 200;
weaponSelectContainer.addChild(backButtonText);
backButtonBg.down = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
backButtonBg.up = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
hideWeaponSelect();
}
});
};
}
function hideWeaponSelect() {
weaponSelectContainer.destroy();
weaponSelectContainer = null;
menuContainer.visible = true;
gameState = 'menu';
}
function startGame() {
// Hide menu
menuContainer.visible = false;
// Change game state
gameState = 'playing';
// Initialize game elements
initializeGame();
}
function createDeathMenu() {
// Create death menu container
deathMenuContainer = new Container();
game.addChild(deathMenuContainer);
// Create death menu background
var deathMenuBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
deathMenuBg.x = 2048 / 2;
deathMenuBg.y = 2732 / 2;
deathMenuBg.scaleX = 8;
deathMenuBg.scaleY = 8;
deathMenuBg.tint = 0x8B0000; // Dark red background
deathMenuBg.alpha = 0.9;
deathMenuContainer.addChild(deathMenuBg);
// Create death message
var deathTitle = new Text2('ÖLDÜN!', {
size: 150,
fill: 0xFF0000
});
deathTitle.anchor.set(0.5, 0.5);
deathTitle.x = 2048 / 2;
deathTitle.y = 2732 / 2 - 250;
deathMenuContainer.addChild(deathTitle);
// Create final score display
var finalScoreText = new Text2('Final Skor: ' + LK.getScore(), {
size: 80,
fill: 0xFFFFFF
});
finalScoreText.anchor.set(0.5, 0.5);
finalScoreText.x = 2048 / 2;
finalScoreText.y = 2732 / 2 - 150;
deathMenuContainer.addChild(finalScoreText);
// Create wave reached display
var waveReachedText = new Text2('Ulaşılan Dalga: ' + currentWave, {
size: 60,
fill: 0xFFD700
});
waveReachedText.anchor.set(0.5, 0.5);
waveReachedText.x = 2048 / 2;
waveReachedText.y = 2732 / 2 - 80;
deathMenuContainer.addChild(waveReachedText);
// Create restart button background
var restartButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
restartButtonBg.x = 2048 / 2;
restartButtonBg.y = 2732 / 2 + 50;
restartButtonBg.scaleX = 4;
restartButtonBg.scaleY = 3;
restartButtonBg.tint = 0x27ae60;
deathMenuContainer.addChild(restartButtonBg);
// Create restart button text
var restartButtonText = new Text2('TEKRAR OYNA', {
size: 70,
fill: 0xFFFFFF
});
restartButtonText.anchor.set(0.5, 0.5);
restartButtonText.x = 2048 / 2;
restartButtonText.y = 2732 / 2 + 50;
deathMenuContainer.addChild(restartButtonText);
// Create menu button background
var menuButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
menuButtonBg.x = 2048 / 2;
menuButtonBg.y = 2732 / 2 + 150;
menuButtonBg.scaleX = 4;
menuButtonBg.scaleY = 3;
menuButtonBg.tint = 0x3498db;
deathMenuContainer.addChild(menuButtonBg);
// Create menu button text
var menuButtonText = new Text2('ANA MENÜ', {
size: 70,
fill: 0xFFFFFF
});
menuButtonText.anchor.set(0.5, 0.5);
menuButtonText.x = 2048 / 2;
menuButtonText.y = 2732 / 2 + 150;
deathMenuContainer.addChild(menuButtonText);
// Add restart button interaction
restartButtonBg.down = function (x, y, obj) {
// Button press animation
tween(restartButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
restartButtonBg.up = function (x, y, obj) {
// Button release animation and restart game
tween(restartButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
restartGame();
}
});
};
// Add menu button interaction
menuButtonBg.down = function (x, y, obj) {
// Button press animation
tween(menuButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
menuButtonBg.up = function (x, y, obj) {
// Button release animation and go to main menu
tween(menuButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
returnToMainMenu();
}
});
};
}
function initializeGame() {
// Create game container for all game elements
gameContainer = new Container();
game.addChild(gameContainer);
// Initialize all game UI and elements here
initializeGameUI();
initializeHero();
createMapBoundaries();
generateMapDecorations();
}
function createMapBoundaries() {
// Define map boundaries - large but bounded world
var mapWidth = 8192; // 4x screen width
var mapHeight = 10928; // 4x screen height
var wallThickness = 100;
// Create top wall
var topWall = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
topWall.x = mapWidth / 2;
topWall.y = 0;
topWall.scaleX = 2;
topWall.scaleY = 2.5;
topWall.tint = 0x404040;
gameContainer.addChild(topWall);
// Create bottom wall
var bottomWall = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
bottomWall.x = mapWidth / 2;
bottomWall.y = mapHeight;
bottomWall.scaleX = 2;
bottomWall.scaleY = 2.5;
bottomWall.tint = 0x404040;
gameContainer.addChild(bottomWall);
// Create left wall
var leftWall = LK.getAsset('wallVertical', {
anchorX: 0.5,
anchorY: 0.5
});
leftWall.x = 0;
leftWall.y = mapHeight / 2;
leftWall.scaleX = 2.5;
leftWall.scaleY = 1;
leftWall.tint = 0x404040;
gameContainer.addChild(leftWall);
// Create right wall
var rightWall = LK.getAsset('wallVertical', {
anchorX: 0.5,
anchorY: 0.5
});
rightWall.x = mapWidth;
rightWall.y = mapHeight / 2;
rightWall.scaleX = 2.5;
rightWall.scaleY = 1;
rightWall.tint = 0x404040;
gameContainer.addChild(rightWall);
// Place coins at map corners and edges
var coinPositions = [{
x: 200,
y: 200
},
// Top left corner
{
x: mapWidth - 200,
y: 200
},
// Top right corner
{
x: 200,
y: mapHeight - 200
},
// Bottom left corner
{
x: mapWidth - 200,
y: mapHeight - 200
},
// Bottom right corner
{
x: mapWidth / 2,
y: 200
},
// Top center
{
x: mapWidth / 2,
y: mapHeight - 200
},
// Bottom center
{
x: 200,
y: mapHeight / 2
},
// Left center
{
x: mapWidth - 200,
y: mapHeight / 2
} // Right center
];
for (var i = 0; i < coinPositions.length; i++) {
var coin = new CoinPickup();
coin.x = coinPositions[i].x;
coin.y = coinPositions[i].y;
coin.coinValue = 25; // Higher value coins at map edges
coinPickups.push(coin);
gameContainer.addChild(coin);
}
}
function initializeGameUI() {
// Create score display
scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create health bar background
healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
healthBarBg.x = 150;
healthBarBg.y = 50;
LK.gui.topLeft.addChild(healthBarBg);
// Create health bar
healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
healthBar.x = 150;
healthBar.y = 50;
LK.gui.topLeft.addChild(healthBar);
// Create health text
healthText = new Text2('100/100', {
size: 40,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0.5);
healthText.x = 370;
healthText.y = 60;
LK.gui.topLeft.addChild(healthText);
// Create level bar background at bottom
levelBarBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
levelBarBg.x = 2048 / 2;
levelBarBg.y = 2732 - 60;
gameContainer.addChild(levelBarBg);
// Create level bar fill
levelBar = LK.getAsset('levelBar', {
anchorX: 0,
anchorY: 0.5
});
levelBar.x = levelBarBg.x - levelBarBg.width / 2;
levelBar.y = levelBarBg.y;
gameContainer.addChild(levelBar);
// Create level text
levelText = new Text2('Level 1', {
size: 50,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.x = levelBarBg.x;
levelText.y = levelBarBg.y - 50;
gameContainer.addChild(levelText);
// Create wave display
waveText = new Text2('Wave 1', {
size: 60,
fill: 0xFFD700
});
waveText.anchor.set(1, 0);
waveText.x = 2048 - 20;
waveText.y = 20;
LK.gui.topRight.addChild(waveText);
// Create wave timer display
waveTimer = new Text2('2:00', {
size: 50,
fill: 0xFFFFFF
});
waveTimer.anchor.set(0.5, 0);
waveTimer.x = 0;
waveTimer.y = 80;
LK.gui.top.addChild(waveTimer);
// Create coins display
coinsText = new Text2('Coins: 0', {
size: 50,
fill: 0xFFD700
});
coinsText.anchor.set(0, 0);
coinsText.x = 20;
coinsText.y = 100;
LK.gui.topLeft.addChild(coinsText);
updateCoinsDisplay();
// Create upgrade selection container
upgradeSelectionContainer = new Container();
upgradeSelectionContainer.visible = false;
LK.gui.center.addChild(upgradeSelectionContainer);
// Create semi-transparent background
var upgradeBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
upgradeBg.scaleX = 8;
upgradeBg.scaleY = 8;
upgradeBg.tint = 0x000000;
upgradeBg.alpha = 0.8;
upgradeSelectionContainer.addChild(upgradeBg);
// Create "Choose Upgrade" title
var upgradeTitle = new Text2('Choose Your Upgrade!', {
size: 80,
fill: 0xFFD700
});
upgradeTitle.anchor.set(0.5, 0.5);
upgradeTitle.y = -200;
upgradeSelectionContainer.addChild(upgradeTitle);
// Create boss health bar background
bossHealthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0
});
bossHealthBarBg.x = 0;
bossHealthBarBg.y = 140;
bossHealthBarBg.visible = false;
bossHealthBarBg.scaleX = 2;
LK.gui.top.addChild(bossHealthBarBg);
// Create boss health bar
bossHealthBar = LK.getAsset('healthBar', {
anchorX: 0.5,
anchorY: 0
});
bossHealthBar.x = 0;
bossHealthBar.y = 140;
bossHealthBar.visible = false;
bossHealthBar.scaleX = 2;
bossHealthBar.tint = 0xFF4444; // Red color for boss health
LK.gui.top.addChild(bossHealthBar);
// Create boss health text
bossHealthText = new Text2('', {
size: 40,
fill: 0xFFFFFF
});
bossHealthText.anchor.set(0.5, 0);
bossHealthText.x = 0;
bossHealthText.y = 180;
bossHealthText.visible = false;
LK.gui.top.addChild(bossHealthText);
}
function initializeHero() {
// Create hero
hero = gameContainer.addChild(new Hero());
hero.x = 4096;
hero.y = 5464;
// Apply purchased upgrades from storage
if (storage.maxHealth) {
hero.maxHealth = storage.maxHealth;
hero.health = hero.maxHealth;
}
if (storage.attackDamage) {
hero.attackDamage = storage.attackDamage;
}
if (storage.moveSpeed) {
hero.moveSpeed = storage.moveSpeed;
}
// Camera following variables
cameraX = 0;
cameraY = 0;
cameraFollowSpeed = 0.1;
cameraSmoothing = true;
// Create attack range indicator (initially hidden)
attackIndicator = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5
});
attackIndicator.alpha = 0.3;
attackIndicator.visible = false;
gameContainer.addChild(attackIndicator);
// Create analog joystick base
joystickBase = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5
});
joystickBase.alpha = 0.2;
joystickBase.visible = false;
joystickBase.scaleX = 1.5;
joystickBase.scaleY = 1.5;
gameContainer.addChild(joystickBase);
// Create analog joystick knob
joystickKnob = LK.getAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
joystickKnob.alpha = 0.7;
joystickKnob.visible = false;
joystickKnob.scaleX = 0.6;
joystickKnob.scaleY = 0.6;
gameContainer.addChild(joystickKnob);
}
function generateMapDecorations() {
var decorationTypes = ['tree', 'grass', 'campfire'];
// Different distribution strategies for each decoration type
var decorationStrategies = {
tree: {
count: 8,
minDistance: 300,
maxDistance: 2000,
spacing: 250,
heroAvoidDistance: 150
},
// Trees appear less frequently across map
grass: {
count: 200,
minDistance: 30,
maxDistance: 2500,
spacing: 25,
heroAvoidDistance: 60
},
// Grass everywhere across entire map with high density
campfire: {
count: 3,
minDistance: 400,
maxDistance: 1500,
spacing: 400,
heroAvoidDistance: 120
}
// Campfires appear less frequently
};
// Generate decorations across the entire infinite map area
for (var type in decorationStrategies) {
var strategy = decorationStrategies[type];
var count = strategy.count;
for (var i = 0; i < count; i++) {
var decoration = new MapDecoration();
decoration.setDecoration(type);
var validPosition = false;
var attempts = 0;
var maxAttempts = 50;
// Try to find a valid position that doesn't conflict with hero or existing decorations
while (!validPosition && attempts < maxAttempts) {
// Generate completely random positions across very large area
var randomAngle = Math.random() * Math.PI * 2;
var randomDistance = strategy.minDistance + Math.random() * (strategy.maxDistance - strategy.minDistance);
// Generate positions in all directions from hero across entire map
decoration.x = hero.x + Math.cos(randomAngle) * randomDistance;
decoration.y = hero.y + Math.sin(randomAngle) * randomDistance;
// For grass, add extra scatter to make it truly everywhere
if (type === 'grass') {
decoration.x += (Math.random() - 0.5) * 800;
decoration.y += (Math.random() - 0.5) * 800;
}
// Check distance from hero - avoid spawning too close to hero's current position
var heroDistance = Math.sqrt((decoration.x - hero.x) * (decoration.x - hero.x) + (decoration.y - hero.y) * (decoration.y - hero.y));
if (heroDistance < strategy.heroAvoidDistance) {
attempts++;
continue; // Try again if too close to hero
}
// Check for minimum spacing between decorations of same type to avoid clustering
var tooClose = false;
for (var j = 0; j < mapDecorations.length; j++) {
var existingDecoration = mapDecorations[j];
if (existingDecoration.decorationType === type) {
var spacingDx = decoration.x - existingDecoration.x;
var spacingDy = decoration.y - existingDecoration.y;
var spacingDistance = Math.sqrt(spacingDx * spacingDx + spacingDy * spacingDy);
if (spacingDistance < strategy.spacing) {
tooClose = true;
break;
}
}
}
if (!tooClose) {
validPosition = true;
}
attempts++;
}
// Only add decoration if we found a valid position
if (validPosition) {
mapDecorations.push(decoration);
game.addChild(decoration);
}
}
}
}
// Initialize entry menu on game start
createEntryMenu();
function spawnEnemy() {
var enemyType = Math.random();
var enemy;
if (enemyType < 0.5) {
enemy = new BasicEnemy();
} else if (enemyType < 0.75) {
enemy = new FastEnemy();
} else if (enemyType < 0.95) {
enemy = new StrongEnemy();
} else {
enemy = new Wizard();
}
// Spawn enemies near hero's current position for infinite world
var spawnDistance = 400 + Math.random() * 200; // 400-600 pixels from hero
var angle = Math.random() * Math.PI * 2; // Random angle around hero
enemy.x = hero.x + Math.cos(angle) * spawnDistance;
enemy.y = hero.y + Math.sin(angle) * spawnDistance;
enemies.push(enemy);
game.addChild(enemy);
}
function spawnHealthCrate() {
var crate = new HealthCrate();
// Spawn near hero in infinite world
var crateDistance = 200 + Math.random() * 300; // 200-500 pixels from hero
var crateAngle = Math.random() * Math.PI * 2; // Random angle around hero
crate.x = hero.x + Math.cos(crateAngle) * crateDistance;
crate.y = hero.y + Math.sin(crateAngle) * crateDistance;
healthCrates.push(crate);
game.addChild(crate);
}
function spawnNPC() {
var npc = new NPC();
// Spawn near hero in infinite world
var npcDistance = 300 + Math.random() * 200; // 300-500 pixels from hero
var npcAngle = Math.random() * Math.PI * 2; // Random angle around hero
npc.x = hero.x + Math.cos(npcAngle) * npcDistance;
npc.y = hero.y + Math.sin(npcAngle) * npcDistance;
npcs.push(npc);
gameContainer.addChild(npc);
}
function updateHealthBar() {
var healthPercent = hero.health / hero.maxHealth;
healthBar.scaleX = healthPercent;
if (healthPercent > 0.5) {
healthBar.tint = 0x4CAF50; // Green
} else if (healthPercent > 0.25) {
healthBar.tint = 0xFFC107; // Yellow
} else {
healthBar.tint = 0xF44336; // Red
}
// Update health text
healthText.setText(Math.ceil(hero.health) + '/' + hero.maxHealth);
}
function updateLevelBar() {
var xpPercent = currentXP / xpToNextLevel;
levelBar.scaleX = xpPercent;
// Check for level up
if (currentXP >= xpToNextLevel) {
playerLevel++;
currentXP = 0;
xpToNextLevel = playerLevel * 30; // Increase XP requirement
levelText.setText('Level ' + playerLevel);
// Level up effects
LK.effects.flashScreen(0xFFD700, 500);
hero.maxHealth += 3;
hero.health = hero.maxHealth; // Full heal on level up
// Show upgrade selection
showUpgradeSelection();
}
}
function showUpgradeSelection() {
isSelectingUpgrade = true;
upgradeSelectionContainer.visible = true;
// Remove any existing upgrade options
for (var i = upgradeSelectionContainer.children.length - 1; i >= 0; i--) {
var child = upgradeSelectionContainer.children[i];
if (child instanceof UpgradeOption) {
child.destroy();
}
}
// Randomly select 3 different upgrades
var selectedUpgrades = [];
var tempUpgrades = availableUpgrades.slice(); // Copy array
for (var j = 0; j < 3 && tempUpgrades.length > 0; j++) {
var randomIndex = Math.floor(Math.random() * tempUpgrades.length);
selectedUpgrades.push(tempUpgrades[randomIndex]);
tempUpgrades.splice(randomIndex, 1);
}
// Create upgrade option buttons - vertical layout
for (var k = 0; k < selectedUpgrades.length; k++) {
var option = new UpgradeOption();
var upgrade = selectedUpgrades[k];
option.setUpgrade(upgrade.type, upgrade.title, upgrade.description);
option.x = 0; // Center horizontally
option.y = (k - 1) * 300; // Position vertically: -300, 0, 300
upgradeSelectionContainer.addChild(option);
}
}
function applyUpgrade(upgradeType) {
// Mark upgrade as applied
for (var i = 0; i < availableUpgrades.length; i++) {
if (availableUpgrades[i].type === upgradeType) {
availableUpgrades[i].applied = true;
break;
}
}
switch (upgradeType) {
case 'health':
hero.maxHealth += 20;
hero.health += 20;
updateHealthBar();
break;
case 'damage':
hero.attackDamage += 10;
break;
case 'speed':
hero.moveSpeed += 1;
break;
case 'attackSpeed':
// Handled in auto-shoot logic
break;
case 'bulletSpeed':
// Increase all future bullet speeds
Bullet.prototype.baseSpeed = 12; // Default is 8
break;
case 'regen':
hasRegen = true;
break;
}
// Hide upgrade selection
isSelectingUpgrade = false;
upgradeSelectionContainer.visible = false;
}
function updateBossHealthBar() {
// Find if there's a boss enemy alive
var currentBoss = null;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] instanceof Boss) {
currentBoss = enemies[i];
break;
}
}
// Show/hide boss health bar based on boss presence
if (currentBoss) {
bossHealthBarBg.visible = true;
bossHealthBar.visible = true;
bossHealthText.visible = true;
// Update boss health bar
var bossHealthPercent = currentBoss.health / currentBoss.maxHealth;
bossHealthBar.scaleX = bossHealthPercent * 2; // Scale to match background
// Update boss health text
bossHealthText.setText('Boss: ' + Math.ceil(currentBoss.health) + '/' + currentBoss.maxHealth);
} else {
bossHealthBarBg.visible = false;
bossHealthBar.visible = false;
bossHealthText.visible = false;
}
}
function startNewWave() {
// Show shop before starting new wave (except for wave 1)
if (currentWave > 1) {
showWaveEndShop();
return;
}
currentWave++;
waveStartTime = Date.now();
waveEnemyCount = 0;
bossSpawned = false;
waveText.setText('Wave ' + currentWave);
// Wave start effects
LK.effects.flashScreen(0x00FF00, 800);
// Increase difficulty each wave
difficultyLevel = currentWave;
}
function restartGame() {
// Hide death menu
deathMenuContainer.visible = false;
// Reset all game variables
resetGameVariables();
// Change game state
gameState = 'playing';
// Clean up existing game elements
cleanupGameElements();
// Initialize game again
initializeGame();
}
function returnToMainMenu() {
// Hide death menu
deathMenuContainer.visible = false;
// Clean up existing game elements
cleanupGameElements();
// Reset game variables
resetGameVariables();
// Show main menu
menuContainer.visible = true;
gameState = 'menu';
}
function resetGameVariables() {
// Reset player stats
playerLevel = 1;
currentXP = 0;
xpToNextLevel = 30;
currentWave = 1;
waveStartTime = 0;
waveEnemyCount = 0;
bossSpawned = false;
lastRegenTime = 0;
hasRegen = false;
spawnTimer = 0;
difficultyLevel = 1;
lastShootTime = 0;
isJoystickActive = false;
movementX = 0;
movementY = 0;
isSelectingUpgrade = false;
// Reset score
LK.setScore(0);
// Reset upgrade availability
for (var i = 0; i < availableUpgrades.length; i++) {
availableUpgrades[i].applied = false;
}
// Reset bullet speed
Bullet.prototype.baseSpeed = 8;
// Reset weapon to default
currentWeapon = 'pistol';
}
function cleanupGameElements() {
// Destroy all existing game elements
if (gameContainer) {
gameContainer.destroy();
gameContainer = null;
}
// Destroy death menu if it exists
if (deathMenuContainer) {
deathMenuContainer.destroy();
deathMenuContainer = null;
}
// Clear all arrays
enemies = [];
bullets = [];
xpOrbs = [];
lightningBolts = [];
bossBullets = [];
healthCrates = [];
healthPickups = [];
levelPickups = [];
coinPickups = [];
npcs = [];
mapDecorations = [];
}
function updateWaveTimer() {
var currentTime = Date.now();
var timeElapsed = currentTime - waveStartTime;
var timeRemaining = Math.max(0, waveDuration - timeElapsed);
var minutes = Math.floor(timeRemaining / 60000);
var seconds = Math.floor(timeRemaining % 60000 / 1000);
var timeText = minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
waveTimer.setText(timeText);
// Check if wave time is up
if (timeRemaining <= 0) {
startNewWave();
}
}
function updateCamera() {
// Calculate target camera position (center hero on screen)
var targetCameraX = -(hero.x - 2048 / 2);
var targetCameraY = -(hero.y - 2732 / 2);
// No camera bounds for infinite world
if (cameraSmoothing) {
// Smooth camera following using interpolation
cameraX += (targetCameraX - cameraX) * cameraFollowSpeed;
cameraY += (targetCameraY - cameraY) * cameraFollowSpeed;
} else {
// Direct camera following
cameraX = targetCameraX;
cameraY = targetCameraY;
}
// Apply camera position to game container
game.x = cameraX;
game.y = cameraY;
// Update level bar position to follow hero
levelBarBg.x = hero.x;
levelBarBg.y = hero.y + 300; // Position below hero
levelBar.x = levelBarBg.x - levelBarBg.width / 2;
levelBar.y = levelBarBg.y;
levelText.x = levelBarBg.x;
levelText.y = levelBarBg.y - 50;
}
function handleMove(x, y, obj) {
// Handle analog joystick movement
if (isJoystickActive) {
var deltaX = x - joystickStartX;
var deltaY = y - joystickStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Limit joystick range
if (distance > joystickRadius) {
deltaX = deltaX / distance * joystickRadius;
deltaY = deltaY / distance * joystickRadius;
}
// Update joystick knob position
joystickKnob.x = joystickStartX + deltaX;
joystickKnob.y = joystickStartY + deltaY;
// Calculate movement values (-1 to 1)
movementX = deltaX / joystickRadius;
movementY = deltaY / joystickRadius;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only process game input when in playing state
if (gameState === 'playing') {
// Make hero walk to touch position
hero.walkTo(x, y);
}
};
game.up = function (x, y, obj) {
// Only process game input when in playing state
if (gameState === 'playing') {
// Deactivate analog joystick
if (isJoystickActive) {
isJoystickActive = false;
joystickBase.visible = false;
joystickKnob.visible = false;
movementX = 0;
movementY = 0;
}
attackIndicator.visible = false;
}
// Allow death menu interactions when dead
else if (gameState === 'dead') {
// Death menu interactions are handled by the menu buttons themselves
// No additional processing needed here
}
};
game.update = function () {
// Only run game logic when in playing state
if (gameState !== 'playing') {
return;
}
// Initialize wave system on first update
if (waveStartTime === 0) {
waveStartTime = Date.now();
}
// Pause game logic during upgrade selection
if (isSelectingUpgrade) {
return;
}
// Update wave timer
updateWaveTimer();
// Apply regeneration if unlocked
if (hasRegen && hero.health < hero.maxHealth) {
var currentTime = LK.ticks;
if (currentTime - lastRegenTime > 60) {
// 60 ticks = 1 second
hero.health = Math.min(hero.health + 1, hero.maxHealth);
lastRegenTime = currentTime;
updateHealthBar();
}
}
// Process analog movement
if (isJoystickActive && (Math.abs(movementX) > 0.1 || Math.abs(movementY) > 0.1)) {
hero.analogMove(movementX, movementY);
}
spawnTimer++;
// Check if this is a boss wave (every 3rd wave: 3, 6, 9, etc.)
var isBossWave = currentWave % 3 === 0;
// Boss spawning for every 3rd wave
if (isBossWave && !bossSpawned) {
var boss = new Boss();
// Spawn boss near hero in infinite world
var bossDistance = 600 + Math.random() * 200; // 600-800 pixels from hero
var bossAngle = Math.random() * Math.PI * 2; // Random angle around hero
boss.x = hero.x + Math.cos(bossAngle) * bossDistance;
boss.y = hero.y + Math.sin(bossAngle) * bossDistance;
enemies.push(boss);
game.addChild(boss);
bossSpawned = true;
// Boss spawn effects
LK.effects.flashScreen(0xFF0000, 1000);
} else if (!isBossWave) {
// Regular enemy spawning only on non-boss waves
var maxEnemiesThisWave = baseEnemiesPerWave + (currentWave - 1) * 5;
var spawnRate = Math.max(60 - currentWave * 3, 15);
// Only spawn if we haven't reached the wave enemy limit
if (spawnTimer >= spawnRate && waveEnemyCount < maxEnemiesThisWave) {
spawnEnemy();
waveEnemyCount++;
spawnTimer = 0;
}
}
// Update weapon to point towards nearest enemy
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var j = 0; j < enemies.length; j++) {
var tempEnemy = enemies[j];
var tempDx = hero.x - tempEnemy.x;
var tempDy = hero.y - tempEnemy.y;
var tempDistance = Math.sqrt(tempDx * tempDx + tempDy * tempDy);
if (tempDistance < nearestDistance) {
nearestEnemy = tempEnemy;
nearestDistance = tempDistance;
}
}
if (nearestEnemy) {
hero.updateWeapon(nearestEnemy.x, nearestEnemy.y);
// Auto-shoot while moving - shoot at nearest enemy
var currentTime = LK.ticks;
var weapon = weaponTypes[currentWeapon];
var shootCooldown = weapon.shootCooldown;
// Check if attack speed upgrade was selected
for (var u = 0; u < availableUpgrades.length; u++) {
if (availableUpgrades[u].type === 'attackSpeed' && availableUpgrades[u].applied) {
shootCooldown = Math.floor(shootCooldown * 0.5); // 50% faster shooting
break;
}
}
if (currentTime - lastShootTime > shootCooldown && nearestDistance < 800) {
hero.shoot(nearestEnemy.x, nearestEnemy.y);
lastShootTime = currentTime;
}
}
// Check bullet collisions with enemies
for (var b = bullets.length - 1; b >= 0; b--) {
var bullet = bullets[b];
var bulletHit = false;
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
if (bullet.intersects(enemy)) {
// Bullet hits enemy
enemy.takeDamage(bullet.damage);
bullet.destroy();
bullets.splice(b, 1);
bulletHit = true;
break;
}
}
}
// Check bullet collisions with NPCs
for (var bn = bullets.length - 1; bn >= 0; bn--) {
var bulletNpc = bullets[bn];
var npcHit = false;
for (var n = npcs.length - 1; n >= 0; n--) {
var npc = npcs[n];
if (bulletNpc.intersects(npc)) {
// Bullet hits NPC
npc.takeDamage(bulletNpc.damage);
bulletNpc.destroy();
bullets.splice(bn, 1);
npcHit = true;
break;
}
}
}
// Check lightning bolt collisions with hero
for (var l = lightningBolts.length - 1; l >= 0; l--) {
var lightning = lightningBolts[l];
if (hero.checkCollision(lightning)) {
// Lightning hits hero
hero.takeDamage(lightning.damage);
LK.effects.flashObject(hero, 0xFFFF00, 300);
lightning.destroy();
lightningBolts.splice(l, 1);
}
}
// Check boss bullet collisions with hero
for (var bb = bossBullets.length - 1; bb >= 0; bb--) {
var bossBullet = bossBullets[bb];
if (hero.checkCollision(bossBullet)) {
// Boss bullet hits hero
hero.takeDamage(bossBullet.damage);
LK.effects.flashObject(hero, 0xFF4500, 300);
bossBullet.destroy();
bossBullets.splice(bb, 1);
}
}
// Check collisions and close combat between hero and enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var dx = hero.x - enemy.x;
var dy = hero.y - enemy.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Auto-attack when very close (melee range)
if (distance < 60 && !enemy.justAttacked) {
hero.attack(enemy);
enemy.justAttacked = true;
// Reset attack flag after short delay
LK.setTimeout(function () {
if (enemy && !enemy.destroyed) {
enemy.justAttacked = false;
}
}, 300);
} else if (hero.checkCollision(enemy) && !enemy.justHitHero) {
// Take damage from collision but don't destroy enemy
hero.takeDamage(enemy.damage);
enemy.justHitHero = true;
// Reset hit flag after short delay to prevent rapid damage
LK.setTimeout(function () {
if (enemy && !enemy.destroyed) {
enemy.justHitHero = false;
}
}, 1000); // 1 second cooldown between hits
}
// Remove enemies that are too far from hero in infinite world (but not bosses)
var enemyDistanceFromHero = Math.sqrt((enemy.x - hero.x) * (enemy.x - hero.x) + (enemy.y - hero.y) * (enemy.y - hero.y));
if (enemyDistanceFromHero > 1200 && !(enemy instanceof Boss)) {
// Remove enemies more than 1200 pixels from hero (except bosses)
enemy.destroy();
enemies.splice(i, 1);
}
}
// Remove NPCs that are too far from hero
for (var np = npcs.length - 1; np >= 0; np--) {
var npcObj = npcs[np];
var npcDistanceFromHero = Math.sqrt((npcObj.x - hero.x) * (npcObj.x - hero.x) + (npcObj.y - hero.y) * (npcObj.y - hero.y));
if (npcDistanceFromHero > 1000) {
// Remove NPCs more than 1000 pixels from hero
npcObj.destroy();
npcs.splice(np, 1);
}
}
// Update high score
var currentScore = LK.getScore();
if (currentScore > (storage.highScore || 0)) {
storage.highScore = currentScore;
}
// Update health bar
updateHealthBar();
// Update level bar
updateLevelBar();
// Update boss health bar
updateBossHealthBar();
// Spawn health crates occasionally
if (LK.ticks % 600 === 0) {
// Every 10 seconds
spawnHealthCrate();
}
// Spawn NPCs occasionally
if (LK.ticks % 900 === 0 && npcs.length < 5) {
// Every 15 seconds, max 5 NPCs
spawnNPC();
}
// Check bullet collisions with health crates
for (var bc = bullets.length - 1; bc >= 0; bc--) {
var bulletCrate = bullets[bc];
var crateHit = false;
for (var hc = healthCrates.length - 1; hc >= 0; hc--) {
var healthCrate = healthCrates[hc];
if (bulletCrate.intersects(healthCrate)) {
// Bullet hits crate
healthCrate.takeDamage(bulletCrate.damage);
bulletCrate.destroy();
bullets.splice(bc, 1);
crateHit = true;
break;
}
}
}
// Check hero melee attacks on crates
for (var cr = healthCrates.length - 1; cr >= 0; cr--) {
var crate = healthCrates[cr];
var crateDx = hero.x - crate.x;
var crateDy = hero.y - crate.y;
var crateDistance = Math.sqrt(crateDx * crateDx + crateDy * crateDy);
// Auto-attack crates when very close
if (crateDistance < 60 && !crate.justAttacked) {
crate.takeDamage(hero.attackDamage);
crate.justAttacked = true;
// Reset attack flag after short delay
LK.setTimeout(function () {
if (crate && !crate.destroyed) {
crate.justAttacked = false;
}
}, 300);
}
}
// Clean up decorations that are too far from hero
for (var d = mapDecorations.length - 1; d >= 0; d--) {
var decoration = mapDecorations[d];
var decorationDistance = Math.sqrt((decoration.x - hero.x) * (decoration.x - hero.x) + (decoration.y - hero.y) * (decoration.y - hero.y));
if (decorationDistance > 1500) {
// Remove decorations more than 1500 pixels from hero
decoration.destroy();
mapDecorations.splice(d, 1);
}
}
// Dynamically generate new decorations as hero moves
if (LK.ticks % 300 === 0) {
// Every 5 seconds
generateMapDecorations();
}
// Update camera to follow hero
updateCamera();
scoreTxt.setText(LK.getScore());
updateCoinsDisplay();
};
function updateCoinsDisplay() {
var currentCoins = storage.coins || 0;
coinsText.setText('Coins: ' + currentCoins);
}
function showShop() {
// Hide menu
menuContainer.visible = false;
gameState = 'shop';
// Create shop container
shopContainer = new Container();
game.addChild(shopContainer);
// Create background
var shopBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
shopBg.x = 2048 / 2;
shopBg.y = 2732 / 2;
shopBg.scaleX = 10;
shopBg.scaleY = 10;
shopBg.tint = 0x2c3e50;
shopBg.alpha = 0.9;
shopContainer.addChild(shopBg);
// Create title
var shopTitle = new Text2('DÜKKAN', {
size: 120,
fill: 0xFFD700
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 2048 / 2;
shopTitle.y = 300;
shopContainer.addChild(shopTitle);
// Create coins display
var shopCoinsText = new Text2('Coins: ' + (storage.coins || 0), {
size: 80,
fill: 0xFFD700
});
shopCoinsText.anchor.set(0.5, 0.5);
shopCoinsText.x = 2048 / 2;
shopCoinsText.y = 400;
shopContainer.addChild(shopCoinsText);
// Shop items
var shopItems = [{
name: 'Max Health +20',
cost: 50,
type: 'health'
}, {
name: 'Attack +10',
cost: 75,
type: 'damage'
}, {
name: 'Speed +1',
cost: 100,
type: 'speed'
}, {
name: 'Makineli Tüfek',
cost: 200,
type: 'weapon',
weaponType: 'machinegun'
}, {
name: 'Keskin Nişancı',
cost: 300,
type: 'weapon',
weaponType: 'sniper'
}, {
name: 'Lazer Silahı',
cost: 250,
type: 'weapon',
weaponType: 'laser'
}, {
name: 'Patlayıcı',
cost: 350,
type: 'weapon',
weaponType: 'explosive'
}];
// Create shop item buttons
for (var i = 0; i < shopItems.length; i++) {
var item = shopItems[i];
var itemY = 600 + i * 150;
// Item background
var itemBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
itemBg.x = 2048 / 2;
itemBg.y = itemY;
itemBg.scaleX = 6;
itemBg.scaleY = 2;
var currentCoins = storage.coins || 0;
itemBg.tint = currentCoins >= item.cost ? 0x27ae60 : 0x7f8c8d;
shopContainer.addChild(itemBg);
// Item name
var itemName = new Text2(item.name, {
size: 60,
fill: 0xFFFFFF
});
itemName.anchor.set(0, 0.5);
itemName.x = 2048 / 2 - 300;
itemName.y = itemY;
shopContainer.addChild(itemName);
// Item cost
var itemCost = new Text2(item.cost + ' Coins', {
size: 50,
fill: 0xFFD700
});
itemCost.anchor.set(1, 0.5);
itemCost.x = 2048 / 2 + 300;
itemCost.y = itemY;
shopContainer.addChild(itemCost);
// Create closure for button interaction
(function (shopItem, bg, nameText, costText) {
bg.down = function (x, y, obj) {
tween(bg, {
scaleX: 6.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
bg.up = function (x, y, obj) {
tween(bg, {
scaleX: 6,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
buyItem(shopItem, shopCoinsText, bg, nameText, costText);
}
});
};
})(item, itemBg, itemName, itemCost);
}
// Create back button
var backButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
backButtonBg.x = 2048 / 2;
backButtonBg.y = 2732 - 200;
backButtonBg.scaleX = 3;
backButtonBg.scaleY = 2;
backButtonBg.tint = 0x95a5a6;
shopContainer.addChild(backButtonBg);
var backButtonText = new Text2('GERİ', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 2048 / 2;
backButtonText.y = 2732 - 200;
shopContainer.addChild(backButtonText);
backButtonBg.down = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
backButtonBg.up = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
hideShop();
}
});
};
}
function buyItem(item, coinsText, bg, nameText, costText) {
var currentCoins = storage.coins || 0;
if (currentCoins >= item.cost) {
storage.coins = currentCoins - item.cost;
// Apply upgrade based on type
switch (item.type) {
case 'health':
var currentMaxHealth = storage.maxHealth || 100;
storage.maxHealth = currentMaxHealth + 20;
break;
case 'damage':
var currentDamage = storage.attackDamage || 25;
storage.attackDamage = currentDamage + 10;
break;
case 'speed':
var currentSpeed = storage.moveSpeed || 4;
storage.moveSpeed = currentSpeed + 1;
break;
case 'weapon':
if (!storage.ownedWeapons) {
storage.ownedWeapons = ['pistol', 'rifle', 'shotgun'];
}
if (storage.ownedWeapons.indexOf(item.weaponType) === -1) {
storage.ownedWeapons.push(item.weaponType);
}
break;
}
// Update display
coinsText.setText('Coins: ' + storage.coins);
// Update button color
bg.tint = storage.coins >= item.cost ? 0x27ae60 : 0x7f8c8d;
// Success effect
LK.effects.flashScreen(0x00FF00, 300);
LK.getSound('xpCollect').play();
} else {
// Not enough coins effect
LK.effects.flashScreen(0xFF0000, 200);
}
}
function hideShop() {
shopContainer.destroy();
shopContainer = null;
menuContainer.visible = true;
gameState = 'menu';
}
function showScoreboard() {
// Hide menu
menuContainer.visible = false;
gameState = 'scoreboard';
// Create scoreboard container
scoreboardContainer = new Container();
game.addChild(scoreboardContainer);
// Create background
var scoreboardBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
scoreboardBg.x = 2048 / 2;
scoreboardBg.y = 2732 / 2;
scoreboardBg.scaleX = 10;
scoreboardBg.scaleY = 10;
scoreboardBg.tint = 0x2c3e50;
scoreboardBg.alpha = 0.9;
scoreboardContainer.addChild(scoreboardBg);
// Create title
var scoreboardTitle = new Text2('SKOR TABLOSU', {
size: 120,
fill: 0xFFD700
});
scoreboardTitle.anchor.set(0.5, 0.5);
scoreboardTitle.x = 2048 / 2;
scoreboardTitle.y = 400;
scoreboardContainer.addChild(scoreboardTitle);
// Create high score display
var highScoreText = new Text2('En Yüksek Skor: ' + (storage.highScore || 0), {
size: 80,
fill: 0x00FF00
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 2048 / 2;
highScoreText.y = 600;
scoreboardContainer.addChild(highScoreText);
// Create total kills display
var totalKillsText = new Text2('Toplam Öldürme: ' + (storage.totalKills || 0), {
size: 70,
fill: 0xFF6B6B
});
totalKillsText.anchor.set(0.5, 0.5);
totalKillsText.x = 2048 / 2;
totalKillsText.y = 750;
scoreboardContainer.addChild(totalKillsText);
// Create current score display
var currentScoreText = new Text2('Şu Anki Skor: ' + LK.getScore(), {
size: 70,
fill: 0xFFFFFF
});
currentScoreText.anchor.set(0.5, 0.5);
currentScoreText.x = 2048 / 2;
currentScoreText.y = 900;
scoreboardContainer.addChild(currentScoreText);
// Create statistics
var coinsEarned = storage.coins || 0;
var statsText = new Text2('Toplam Para: ' + coinsEarned, {
size: 60,
fill: 0xFFD700
});
statsText.anchor.set(0.5, 0.5);
statsText.x = 2048 / 2;
statsText.y = 1050;
scoreboardContainer.addChild(statsText);
// Create back button
var backButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
backButtonBg.x = 2048 / 2;
backButtonBg.y = 2732 - 200;
backButtonBg.scaleX = 3;
backButtonBg.scaleY = 2;
backButtonBg.tint = 0x95a5a6;
scoreboardContainer.addChild(backButtonBg);
var backButtonText = new Text2('GERİ', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 2048 / 2;
backButtonText.y = 2732 - 200;
scoreboardContainer.addChild(backButtonText);
backButtonBg.down = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
backButtonBg.up = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
hideScoreboard();
}
});
};
}
function hideScoreboard() {
scoreboardContainer.destroy();
scoreboardContainer = null;
menuContainer.visible = true;
gameState = 'menu';
}
function showWaveEndShop() {
// Pause game logic during shop
gameState = 'waveShop';
// Create wave shop container
var waveShopContainer = new Container();
game.addChild(waveShopContainer);
// Create background
var shopBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
shopBg.x = 2048 / 2;
shopBg.y = 2732 / 2;
shopBg.scaleX = 10;
shopBg.scaleY = 10;
shopBg.tint = 0x1a1a2e;
shopBg.alpha = 0.95;
waveShopContainer.addChild(shopBg);
// Create title
var shopTitle = new Text2('TUR TAMAMLANDI!', {
size: 100,
fill: 0xFFD700
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 2048 / 2;
shopTitle.y = 250;
waveShopContainer.addChild(shopTitle);
// Create wave info
var waveInfo = new Text2('Dalga ' + currentWave + ' Bitti', {
size: 70,
fill: 0xFFFFFF
});
waveInfo.anchor.set(0.5, 0.5);
waveInfo.x = 2048 / 2;
waveInfo.y = 350;
waveShopContainer.addChild(waveInfo);
// Create coins display
var shopCoinsText = new Text2('Paralar: ' + (storage.coins || 0), {
size: 60,
fill: 0xFFD700
});
shopCoinsText.anchor.set(0.5, 0.5);
shopCoinsText.x = 2048 / 2;
shopCoinsText.y = 450;
waveShopContainer.addChild(shopCoinsText);
// Shop items for wave end
var waveShopItems = [{
name: 'Maksimum Can +20',
cost: 50,
type: 'health'
}, {
name: 'Saldırı Gücü +10',
cost: 75,
type: 'damage'
}, {
name: 'Hareket Hızı +1',
cost: 100,
type: 'speed'
}, {
name: 'Can Yenileme',
cost: 150,
type: 'regen'
}];
// Create shop item buttons
for (var i = 0; i < waveShopItems.length; i++) {
var item = waveShopItems[i];
var itemY = 600 + i * 120;
// Item background
var itemBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
itemBg.x = 2048 / 2;
itemBg.y = itemY;
itemBg.scaleX = 5;
itemBg.scaleY = 1.8;
var currentCoins = storage.coins || 0;
itemBg.tint = currentCoins >= item.cost ? 0x27ae60 : 0x7f8c8d;
waveShopContainer.addChild(itemBg);
// Item name
var itemName = new Text2(item.name, {
size: 50,
fill: 0xFFFFFF
});
itemName.anchor.set(0, 0.5);
itemName.x = 2048 / 2 - 250;
itemName.y = itemY;
waveShopContainer.addChild(itemName);
// Item cost
var itemCost = new Text2(item.cost + ' Para', {
size: 45,
fill: 0xFFD700
});
itemCost.anchor.set(1, 0.5);
itemCost.x = 2048 / 2 + 250;
itemCost.y = itemY;
waveShopContainer.addChild(itemCost);
// Create closure for button interaction
(function (shopItem, bg, coinsDisplay) {
bg.down = function (x, y, obj) {
tween(bg, {
scaleX: 5.2,
scaleY: 2.0
}, {
duration: 100,
easing: tween.easeOut
});
};
bg.up = function (x, y, obj) {
tween(bg, {
scaleX: 5,
scaleY: 1.8
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
buyWaveItem(shopItem, coinsDisplay, bg);
}
});
};
})(item, itemBg, shopCoinsText);
}
// Create market button
var marketButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
marketButtonBg.x = 2048 / 2 - 200;
marketButtonBg.y = 2732 - 150;
marketButtonBg.scaleX = 3.5;
marketButtonBg.scaleY = 2.5;
marketButtonBg.tint = 0x9b59b6;
waveShopContainer.addChild(marketButtonBg);
var marketButtonText = new Text2('MARKET', {
size: 60,
fill: 0xFFFFFF
});
marketButtonText.anchor.set(0.5, 0.5);
marketButtonText.x = 2048 / 2 - 200;
marketButtonText.y = 2732 - 150;
waveShopContainer.addChild(marketButtonText);
marketButtonBg.down = function (x, y, obj) {
tween(marketButtonBg, {
scaleX: 3.7,
scaleY: 2.7
}, {
duration: 100,
easing: tween.easeOut
});
};
marketButtonBg.up = function (x, y, obj) {
tween(marketButtonBg, {
scaleX: 3.5,
scaleY: 2.5
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
waveShopContainer.destroy();
showShop();
}
});
};
// Create continue button
var continueButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
continueButtonBg.x = 2048 / 2 + 200;
continueButtonBg.y = 2732 - 150;
continueButtonBg.scaleX = 3.5;
continueButtonBg.scaleY = 2.5;
continueButtonBg.tint = 0x3498db;
waveShopContainer.addChild(continueButtonBg);
var continueButtonText = new Text2('DEVAM ET', {
size: 60,
fill: 0xFFFFFF
});
continueButtonText.anchor.set(0.5, 0.5);
continueButtonText.x = 2048 / 2 + 200;
continueButtonText.y = 2732 - 150;
waveShopContainer.addChild(continueButtonText);
continueButtonBg.down = function (x, y, obj) {
tween(continueButtonBg, {
scaleX: 3.7,
scaleY: 2.7
}, {
duration: 100,
easing: tween.easeOut
});
};
continueButtonBg.up = function (x, y, obj) {
tween(continueButtonBg, {
scaleX: 3.5,
scaleY: 2.5
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
// Close shop and continue to next wave
waveShopContainer.destroy();
continueToNextWave();
}
});
};
}
function buyWaveItem(item, coinsText, bg) {
var currentCoins = storage.coins || 0;
if (currentCoins >= item.cost) {
storage.coins = currentCoins - item.cost;
// Apply upgrade based on type
switch (item.type) {
case 'health':
var currentMaxHealth = storage.maxHealth || 100;
storage.maxHealth = currentMaxHealth + 20;
// Also heal current hero if in game
if (hero) {
hero.maxHealth = storage.maxHealth;
hero.health = Math.min(hero.health + 20, hero.maxHealth);
updateHealthBar();
}
break;
case 'damage':
var currentDamage = storage.attackDamage || 25;
storage.attackDamage = currentDamage + 10;
// Also update current hero if in game
if (hero) {
hero.attackDamage = storage.attackDamage;
}
break;
case 'speed':
var currentSpeed = storage.moveSpeed || 4;
storage.moveSpeed = currentSpeed + 1;
// Also update current hero if in game
if (hero) {
hero.moveSpeed = storage.moveSpeed;
}
break;
case 'regen':
hasRegen = true;
break;
}
// Update display
coinsText.setText('Paralar: ' + storage.coins);
updateCoinsDisplay();
// Update button color
bg.tint = storage.coins >= item.cost ? 0x27ae60 : 0x7f8c8d;
// Success effect
LK.effects.flashScreen(0x00FF00, 300);
LK.getSound('xpCollect').play();
} else {
// Not enough coins effect
LK.effects.flashScreen(0xFF0000, 200);
}
}
function continueToNextWave() {
currentWave++;
waveStartTime = Date.now();
waveEnemyCount = 0;
bossSpawned = false;
waveText.setText('Wave ' + currentWave);
// Wave start effects
LK.effects.flashScreen(0x00FF00, 800);
// Increase difficulty each wave
difficultyLevel = currentWave;
// Resume game
gameState = 'playing';
} ===================================================================
--- original.js
+++ change.js
@@ -542,24 +542,23 @@
return self;
});
var CoinPickup = Container.expand(function () {
var self = Container.call(this);
- var coinGraphics = self.attachAsset('xpOrb', {
+ var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinGraphics.scaleX = 0.8;
coinGraphics.scaleY = 0.8;
- coinGraphics.tint = 0xFFD700; // Gold color for coins
// Add glowing effect
- var glowGraphics = self.attachAsset('xpOrb', {
+ var glowGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
glowGraphics.tint = 0xFFF700; // Bright yellow glow
- glowGraphics.alpha = 0.4;
- glowGraphics.scaleX = 1.2;
- glowGraphics.scaleY = 1.2;
+ glowGraphics.alpha = 0.3;
+ glowGraphics.scaleX = 1.1;
+ glowGraphics.scaleY = 1.1;
// Add pulsing animation
tween(coinGraphics, {
scaleX: 1.0,
scaleY: 1.0
@@ -575,8 +574,25 @@
easing: tween.easeInOut
});
}
});
+ // Add continuous rotation animation
+ tween(coinGraphics, {
+ rotation: Math.PI * 2
+ }, {
+ duration: 2000,
+ easing: tween.linear,
+ onFinish: function onFinish() {
+ coinGraphics.rotation = 0;
+ // Restart rotation
+ tween(coinGraphics, {
+ rotation: Math.PI * 2
+ }, {
+ duration: 2000,
+ easing: tween.linear
+ });
+ }
+ });
self.coinValue = 5;
self.moveSpeed = 3;
self.attractRange = 120;
self.update = function () {
Ucan bomba. In-Game asset. 2d. High contrast. No shadows
Qanli iskelet. In-Game asset. 2d. High contrast. No shadows
Beyaz zirhli sovalye. In-Game asset. 2d. High contrast. No shadows
Iskeleten Elektirik buycusu. In-Game asset. 2d. High contrast. No shadows
Wiking boss. In-Game asset. 2d. High contrast. No shadows
Mavi tatli kucuk slime gozleri parildasin. In-Game asset. 2d. High contrast. No shadows
Yesil top halinde tukuruk. In-Game asset. 2d. High contrast. No shadows
Simsek topu. In-Game asset. 2d. High contrast. No shadows
Sandik. In-Game asset. 2d. High contrast. No shadows
Ağac. In-Game asset. 2d. High contrast. No shadows
Cim yesilik. In-Game asset. 2d. High contrast. No shadows
Kamp atesi. In-Game asset. 2d. High contrast. No shadows
Madeni para. In-Game asset. 2d. High contrast. No shadows
Bullet. In-Game asset. 2d. High contrast. No shadows
Lasergun. In-Game asset. 2d. High contrast. No shadows