User prompt
ejderhalar güçlendirildiğinde renkleri koyulaşsın bütün ejderhalar 70 altın olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
elektrik ejderhasının saldırıları iskeletler arasında sekecekti sekme sırasında fırlattığı şimşek gözüksün ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ilk dalgada 20 tane sıradan iskelet olsun
User prompt
dalgalar sırasında ejderha alınıp konulabilsin ve ilk dalgada 20 tane iskelet sırayla gelsin
User prompt
ilk dalgada 20 tane sıradan iskelet olsun
User prompt
iskeletlerin hızı yüzde yüz artsın
User prompt
ejderhalar haritanın her yerine saldırabilsin iskeletlerin arasında boşluk olsun başlangıç parası 100 altın olsun
User prompt
ateş ejderhası 300 hasar vursun bütün iskeletlerin hızı yüzde iki yüz yavaşlatılsın
Code edit (1 edits merged)
Please save this source code
User prompt
Dragon Defense: Skeleton Siege
Initial prompt
oyun tower defense oyunu olacak. 3 tür ejderha 3 tür iskelet olacak. birinci ejderha ateş ejderhası olacak 100 hasar vuracak alev topu fırlatarak iskeletlere hasar verecek 30 altın değerinde olacak. ikinci ejderha buz ejderhası olacak 50 hasar vuracak vurduğu iskeletin arkasındaki iki iskeleti ve vurduğu iskeleti yüzde 60 yavaşlatacak. örneğin iskeletin hızı 1 metre/saniyeyese bu 0,4 metre/ saniye olacak. buz ejderhası buz kristalleri fırlatarak hasar vuracak ve yavaşlatacak. değeri 50 altın olacak. son ejderha elektrik ejderhası olacak. şimşek fırlatarak hasar vuracak. şimşeği isabet ettirdiği iskelet 200 hasar yiyecek. ejderin attığı şimşek iskeletler arasından sekebilecek. ilk isabet ettiği iskelete 200 ordan bi arkasındaki iskelete sekecek ve o iskelete 100 hasar vuracak. ordan da üçüncü iskelete sıçrayıp üçüncü iskelete 50 hasar vuracak ve şimşek daha sekmeyecek. yani elektrik ejderi tek şimşek atışında üç iskelete hasar verebilecek ve maksimum 350 hasara ulaşabilecek. elektrik ejderinin değeri 70 altın olacak. bütün ejderhalar 1,5 saniyede bir saldırı gerçekleştirecek. ejderhalar kendilerine en yakın olan iskelete saldırabilecek. ejderhalar haritanın her yerine saldırabilecek. ejderhalar altın karşılığında güçlendirilebilecek. ateş ejderi 30 altın karşılığında güçledirilebilir. güçlendirildiğinde 150 hasar vurabilecek. buz ejderi 50 altın karşılığında güçlendirilebilcek hasarı değişmeyecek fakat artık düşmanları yüzde seksen yavaşlatacak. yani hızı 1 m/saniye olan bir iskeletin hızı 0,2 metre/saniye olacak. elektrik ejderi 70 altın karşılığında güçlendirilcek. güçlendirildiğinde bir şimşek atışı beş iskelete hasar vurabilecek. 1. iskelete 200 2. iskelete 150 3. iskelete 100 4. iskelete 80 5. iskelete 50 hasar vuaracak. şimşeğin sekme yönü hep arkaya doğru olacak. oyun 3 dalgadan oluşacak. birinci dalgada sıradan iskeletler olacak. bir sıradan iskeletin normalde canı 300 hızı 1m/saniye olacak. 1. dalgada 20 tane sıradan iskelet 0,5 metre aralıklarla patikaya girecek. hasar almadıkları senaryoda bir sıradan iskeletin patikayı bitirme süresi 15 saniye olacak. yani patika 15 metre olacak. 2. iskelet türü kalkanlı iskelet olacak. bu iskeletlerin ellerinde tutacakları kalkanları olacak. canları 1000 olacak. hızları sıradan iskeletlerin yarısı yani 0,5 metre/saniye olacak. yani normal koşullardah patikayı 30 saniyede bitirecekler. 2 dalgada 20 tane kalkanlı iskelet sırayla patikaya girecek. aralarında 0,25 metre olacak. 3. dalga sonuncu dalga olacak. bu dalgada dev iskeletler ve bir adet cadı olacak. cadı boss olacak ve canı 15000 olacak. hızı 0,1 metre/saniye olacak yani normal şartlarda patikayı 150 saniyede bitirecek. cadının önünde ve arkasında birer tane dev iskelet olacak. dev iskeletler cadıylar aynı hızda olacak ve aralarında birer metre olacak yani 3. dalgada iki dev iskelet bir cadı boss olacak. dev iskeletin canı 5000 olacak hızı cadıyla eşit olacak. patikanın girişi sağdan çıkışı soldan olacak iskeletlerin yürüyebileceği tek bir patika olacak ve bu patika kıvrımlı toplam 15 metre olacak. ölen her sıradan iskelet için 10 altın. ölen her kalkanlı iskelet için 15 altın kazanılacak. başlangıçta 30 altın olacak. haritada ejderhaların yerleştirilebileceği toplamda 10 alan olacak yani haritada toplam on ejderha olabilir. başlangıçta hiç bir ejder olmaz oyuncu kazandığı altınlarla ejderhaları alıp yerleştirebilir. ejderhaları satın alabilceği bir market sekmesi hep açık olur. bu sekme ekranın altında olur ve ejderhaların kaç altına alınabileceği ejderhaların altında yazar. ejderhaları satın almak için markette üzerine tıklar. eğer parası yetiyorsa ejderhayı alır ve harita üzerinde belirlenmiş on bölgeden birisine tıklayarak ejderhayı yerleştirir.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (type, damage, target, isChain) {
var self = Container.call(this);
var bulletGraphics = self.attachAsset(type + 'Bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = damage;
self.target = target;
self.speed = 8;
self.isChain = isChain || false;
self.hasHit = false;
self.update = function () {
if (!self.target || self.hasHit) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 30) {
self.hitTarget();
} else {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
self.hitTarget = function () {
if (self.hasHit) return;
self.hasHit = true;
self.target.takeDamage(self.damage);
LK.getSound('enemyHit').play();
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
};
return self;
});
var Dragon = Container.expand(function (type, x, y) {
var self = Container.call(this);
var dragonGraphics = self.attachAsset(type + 'Dragon', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type;
self.isUpgraded = false;
self.lastShotTime = 0;
self.shootInterval = 1500;
if (type === 'fire') {
self.damage = 500;
self.range = 500;
self.cost = 100;
} else if (type === 'ice') {
self.damage = 500;
self.range = 500;
self.cost = 120;
} else if (type === 'lightning') {
self.damage = 400;
self.range = 500;
self.cost = 200;
} else if (type === 'beam') {
self.damage = 10;
self.range = 500;
self.cost = 750;
self.beamTarget = null;
self.beamDamageMultiplier = 1;
self.beamStartTime = 0;
self.shootInterval = 100; // Beam updates faster
}
self.x = x;
self.y = y;
self.update = function () {
var currentTime = Date.now();
if (self.type === 'beam') {
// Handle beam dragon logic
if (self.beamTarget && self.beamTarget.health > 0) {
var dx = self.beamTarget.x - self.x;
var dy = self.beamTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.range) {
// Create or update beam visual effect
if (!self.beamLaser) {
self.beamLaser = game.addChild(LK.getAsset('beamLaser', {
anchorX: 0,
anchorY: 0.5
}));
}
// Position and rotate the beam
self.beamLaser.x = self.x;
self.beamLaser.y = self.y;
var angle = Math.atan2(dy, dx);
self.beamLaser.rotation = angle;
self.beamLaser.width = distance;
// Calculate damage based on time
var timeElapsed = (currentTime - self.beamStartTime) / 1000;
var currentDamage;
if (timeElapsed < 1) {
currentDamage = self.isUpgraded ? 15 : 10;
} else if (timeElapsed < 2) {
currentDamage = self.isUpgraded ? 300 : 200;
} else if (timeElapsed < 3) {
currentDamage = self.isUpgraded ? 750 : 500;
} else if (timeElapsed < 4) {
currentDamage = self.isUpgraded ? 1200 : 800;
} else {
currentDamage = self.isUpgraded ? 1500 : 1000;
}
// Apply damage every 0.5 seconds after 3rd second, otherwise every second
var shouldDamage = false;
if (timeElapsed >= 3) {
shouldDamage = Math.floor(timeElapsed * 2) > Math.floor((timeElapsed - 0.017) * 2);
} else {
shouldDamage = Math.floor(timeElapsed) > Math.floor(timeElapsed - 0.017);
}
if (shouldDamage) {
self.beamTarget.takeDamage(currentDamage);
LK.getSound('enemyHit').play();
}
} else {
self.beamTarget = null;
if (self.beamLaser) {
self.beamLaser.destroy();
self.beamLaser = null;
}
}
} else {
self.beamTarget = null;
if (self.beamLaser) {
self.beamLaser.destroy();
self.beamLaser = null;
}
}
if (!self.beamTarget) {
var target = self.findTarget();
if (target) {
self.shoot(target);
}
}
} else {
if (currentTime - self.lastShotTime >= self.shootInterval) {
var target = self.findTarget();
if (target) {
self.shoot(target);
self.lastShotTime = currentTime;
}
}
}
};
self.findTarget = function () {
var closestEnemy = null;
var closestDistance = 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 < closestDistance && distance <= self.range) {
closestDistance = distance;
closestEnemy = enemy;
}
}
return closestEnemy;
};
self.shoot = function (target) {
if (self.type === 'beam') {
// Handle beam dragon shooting
if (!self.beamTarget || self.beamTarget.health <= 0) {
self.beamTarget = target;
self.beamStartTime = Date.now();
self.beamDamageMultiplier = 1;
}
return;
}
LK.getSound('shoot').play();
if (self.type === 'lightning') {
// Create visible lightning bullet
var bullet = new Bullet(self.type, 0, target, false);
bullet.x = self.x;
bullet.y = self.y;
bullets.push(bullet);
game.addChild(bullet);
// New lightning system: single target, double hit
var firstDamage = self.isUpgraded ? 750 : 500;
var secondDamage = self.isUpgraded ? 1250 : 1000;
// Apply first damage immediately
target.takeDamage(firstDamage);
LK.getSound('enemyHit').play();
LK.effects.flashObject(target, 0xffff00, 200);
// Schedule second damage after 1 second with freeze effect
LK.setTimeout(function () {
if (target && target.health > 0) {
target.takeDamage(secondDamage);
LK.getSound('enemyHit').play();
LK.effects.flashObject(target, 0xffff00, 200);
// Freeze target for 0.75 seconds
target.applySlowEffect(0);
target.slowDuration = 45; // 0.75 seconds at 60fps
}
}, 1000);
} else {
var bullet = new Bullet(self.type, self.damage, target, false);
bullet.x = self.x;
bullet.y = self.y;
bullets.push(bullet);
game.addChild(bullet);
}
if (self.type === 'ice') {
target.applySlowEffect(self.isUpgraded ? 0.50 : 0.85);
}
};
self.upgrade = function () {
if (self.isUpgraded) return false;
if (playerGold >= 150) {
playerGold -= 150;
self.isUpgraded = true;
if (self.type === 'fire') {
self.damage = 1000;
tween(dragonGraphics, {
tint: 0xcc0000
}, {
duration: 500
});
} else if (self.type === 'ice') {
self.damage = Math.floor(self.damage * 1.5);
tween(dragonGraphics, {
tint: 0x0000cc
}, {
duration: 500
});
} else if (self.type === 'lightning') {
self.damage = Math.floor(self.damage * 1.5);
tween(dragonGraphics, {
tint: 0xcccc00
}, {
duration: 500
});
} else if (self.type === 'beam') {
self.damage = Math.floor(self.damage * 1.5);
tween(dragonGraphics, {
tint: 0xcc00cc
}, {
duration: 500
});
}
updateGoldDisplay();
return true;
}
return false;
};
self.down = function (x, y, obj) {
if (gameState === 'playing') {
selectedDragon = self;
updateUpgradeButton();
}
};
return self;
});
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
var enemyGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type;
self.pathIndex = 0;
self.speed = 0.968; // Base speed increased by 10% (0.88 * 1.1)
self.slowEffect = 1;
self.slowDuration = 0;
if (type === 'regularSkeleton') {
self.maxHealth = 500;
self.goldValue = 20;
self.speed = 1.95; // Regular skeleton speed 1.50 * 1.30 = 1.95 meter/second
} else if (type === 'shieldedSkeleton') {
self.maxHealth = 3000; // Increased by 50%
self.goldValue = 25;
self.speed = 1.30; // Shielded skeleton speed 1.0 * 1.30 = 1.30 meter/second
} else if (type === 'fastSkeleton') {
self.maxHealth = 2250; // Increased by 50%
self.goldValue = 30;
self.speed = 3.90; // Fast skeleton speed 3.0 * 1.30 = 3.90 meter/second
} else if (type === 'giantSkeleton') {
self.maxHealth = 20000;
self.goldValue = 100;
self.speed = 1.30; // Giant skeleton speed 1.0 * 1.30 = 1.30 meter/second
} else if (type === 'witchBoss') {
self.maxHealth = 104000;
self.goldValue = 50;
self.speed = 1.30; // Witch boss speed 1.0 * 1.30 = 1.30 meter/second
}
self.health = self.maxHealth;
self.x = pathPoints[0].x;
self.y = pathPoints[0].y;
self.update = function () {
if (self.slowDuration > 0) {
self.slowDuration--;
} else {
self.slowEffect = 1;
}
if (self.pathIndex < pathPoints.length - 1) {
var currentPoint = pathPoints[self.pathIndex];
var nextPoint = pathPoints[self.pathIndex + 1];
var dx = nextPoint.x - self.x;
var dy = nextPoint.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
} else {
var moveSpeed = self.speed * self.slowEffect;
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
} else {
self.reachEnd();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.die();
}
};
self.applySlowEffect = function (slowAmount) {
self.slowEffect = slowAmount;
self.slowDuration = 180;
};
self.die = function () {
playerGold += self.goldValue;
updateGoldDisplay();
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
checkWaveComplete();
};
self.reachEnd = function () {
// Only giant skeletons and witch bosses cause immediate game over
if (self.type === 'giantSkeleton' || self.type === 'witchBoss') {
gameState = 'gameOver';
LK.showGameOver();
} else {
// Regular skeletons reduce lives by 1
playerLives--;
updateLivesDisplay();
if (playerLives <= 0) {
gameState = 'gameOver';
LK.showGameOver();
}
}
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
var gameState = 'playing';
var playerGold = 100;
var playerLives = 5;
var currentWave = 1;
var waveInProgress = false;
var selectedDragon = null;
var dragons = [];
var enemies = [];
var bullets = [];
var placementZones = [];
var pathPoints = [{
x: 2048,
y: 1500
}, {
x: 1400,
y: 1500
}, {
x: 1000,
y: 1200
}, {
x: 700,
y: 800
}, {
x: 1000,
y: 400
}, {
x: 1400,
y: 700
}, {
x: 1000,
y: 1000
}, {
x: 600,
y: 1300
}, {
x: 0,
y: 1500
}];
var placementPositions = [{
// Near entrance area
x: 1600,
y: 1450
}, {
// Upper right strategic position
x: 1550,
y: 1200
}, {
// Mid-path right side
x: 1250,
y: 1350
}, {
// Lower mid right
x: 950,
y: 1150
}, {
// Center strategic position
x: 750,
y: 950
}, {
// Left side mid
x: 550,
y: 750
}, {
// Upper left strategic
x: 850,
y: 500
}, {
// Far upper position
x: 1200,
y: 200
}, {
// Upper mid strategic
x: 1000,
y: 400
}, {
// Right upper curve
x: 1500,
y: 750
}, {
// Left strategic covering exit
x: 400,
y: 1300
}, {
// Final exit coverage
x: 300,
y: 1050
}];
// Create grass background tiles
for (var gx = 0; gx < 2048; gx += 150) {
for (var gy = 0; gy < 2732; gy += 150) {
var grassTile = game.addChild(LK.getAsset('grass', {
anchorX: 0,
anchorY: 0
}));
grassTile.x = gx;
grassTile.y = gy;
}
}
// Add decorative stones scattered around
var stonePositions = [{
x: 300,
y: 400
}, {
x: 800,
y: 300
}, {
x: 1200,
y: 600
}, {
x: 400,
y: 900
}, {
x: 1600,
y: 800
}, {
x: 900,
y: 1600
}, {
x: 1500,
y: 1800
}, {
x: 200,
y: 1200
}, {
x: 1800,
y: 400
}, {
x: 600,
y: 2000
}, {
x: 1400,
y: 2200
}, {
x: 500,
y: 600
}];
for (var s = 0; s < stonePositions.length; s++) {
var stone = game.addChild(LK.getAsset('stone', {
anchorX: 0.5,
anchorY: 0.5
}));
stone.x = stonePositions[s].x;
stone.y = stonePositions[s].y;
}
// Add decorative flowers
var flowerPositions = [{
x: 250,
y: 500
}, {
x: 750,
y: 200
}, {
x: 1100,
y: 700
}, {
x: 350,
y: 1000
}, {
x: 1550,
y: 900
}, {
x: 850,
y: 1700
}, {
x: 1450,
y: 1900
}, {
x: 150,
y: 1300
}, {
x: 1750,
y: 500
}, {
x: 550,
y: 2100
}, {
x: 1350,
y: 2300
}, {
x: 450,
y: 700
}, {
x: 1050,
y: 1400
}, {
x: 650,
y: 1100
}, {
x: 1250,
y: 300
}];
for (var f = 0; f < flowerPositions.length; f++) {
var flower = game.addChild(LK.getAsset('flower', {
anchorX: 0.5,
anchorY: 0.5
}));
flower.x = flowerPositions[f].x;
flower.y = flowerPositions[f].y;
}
// Create visible forest path following the actual route
for (var p = 0; p < pathPoints.length - 1; p++) {
var currentPoint = pathPoints[p];
var nextPoint = pathPoints[p + 1];
var dx = nextPoint.x - currentPoint.x;
var dy = nextPoint.y - currentPoint.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var angle = Math.atan2(dy, dx);
var pathSegment = game.addChild(LK.getAsset('forestPath', {
anchorX: 0,
anchorY: 0.5,
scaleX: distance / 100,
scaleY: 1.2
}));
pathSegment.x = currentPoint.x;
pathSegment.y = currentPoint.y;
pathSegment.rotation = angle;
}
// Placement zones removed - dragons can be placed anywhere valid
// Create shop panel
var shopPanel = LK.gui.bottom.addChild(LK.getAsset('shopPanel', {
anchorX: 0.5,
anchorY: 1
}));
// Create dragon buttons
var fireButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -450,
y: -150,
tint: 0xff4444,
scaleX: 1.3,
scaleY: 1.3
}));
var iceButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -250,
y: -150,
tint: 0x4444ff,
scaleX: 1.3,
scaleY: 1.3
}));
var lightningButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -50,
y: -150,
tint: 0xffff44,
scaleX: 1.3,
scaleY: 1.3
}));
var beamButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 150,
y: -150,
tint: 0xff44ff,
scaleX: 1.3,
scaleY: 1.3
}));
var upgradeButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 350,
y: -150,
tint: 0x00ff00,
scaleX: 1.3,
scaleY: 1.3
}));
var startWaveButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 550,
y: -150,
tint: 0xff8800,
scaleX: 1.3,
scaleY: 1.3
}));
// Create UI text
var goldText = LK.gui.topRight.addChild(new Text2('Gold: 100', {
size: 60,
fill: 0xFFFF00
}));
goldText.anchor.set(1, 0);
var livesText = LK.gui.topRight.addChild(new Text2('Lives: 5', {
size: 60,
fill: 0xFF0000
}));
livesText.anchor.set(1, 0);
livesText.y = 80;
var waveText = LK.gui.top.addChild(new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
}));
waveText.anchor.set(0.5, 0);
var fireButtonText = LK.gui.bottom.addChild(new Text2('Fire\n100g', {
size: 40,
fill: 0xFFFFFF
}));
fireButtonText.anchor.set(0.5, 0.5);
fireButtonText.x = -450;
fireButtonText.y = -150;
var iceButtonText = LK.gui.bottom.addChild(new Text2('Ice\n120g', {
size: 40,
fill: 0xFFFFFF
}));
iceButtonText.anchor.set(0.5, 0.5);
iceButtonText.x = -250;
iceButtonText.y = -150;
var lightningButtonText = LK.gui.bottom.addChild(new Text2('Lightning\n200g', {
size: 40,
fill: 0xFFFFFF
}));
lightningButtonText.anchor.set(0.5, 0.5);
lightningButtonText.x = -50;
lightningButtonText.y = -150;
var beamButtonText = LK.gui.bottom.addChild(new Text2('Beam\n750g', {
size: 40,
fill: 0xFFFFFF
}));
beamButtonText.anchor.set(0.5, 0.5);
beamButtonText.x = 150;
beamButtonText.y = -150;
var upgradeButtonText = LK.gui.bottom.addChild(new Text2('Upgrade\nSelect', {
size: 40,
fill: 0xFFFFFF
}));
upgradeButtonText.anchor.set(0.5, 0.5);
upgradeButtonText.x = 350;
upgradeButtonText.y = -150;
var startWaveButtonText = LK.gui.bottom.addChild(new Text2('Start\nWave', {
size: 40,
fill: 0xFFFFFF
}));
startWaveButtonText.anchor.set(0.5, 0.5);
startWaveButtonText.x = 550;
startWaveButtonText.y = -150;
var selectedDragonType = null;
var waveSpawnIndex = 0;
var waveSpawnTimer = 0;
function updateGoldDisplay() {
goldText.setText('Gold: ' + playerGold);
}
function updateLivesDisplay() {
livesText.setText('Lives: ' + playerLives);
}
function updateWaveDisplay() {
waveText.setText('Wave: ' + currentWave);
}
function updateUpgradeButton() {
if (selectedDragon && !selectedDragon.isUpgraded) {
upgradeButtonText.setText('Upgrade\n150g');
} else {
upgradeButtonText.setText('Upgrade\nSelect');
}
}
function placeDragon(type, x, y, zoneIndex) {
var cost;
if (type === 'fire') cost = 100;else if (type === 'ice') cost = 120;else if (type === 'lightning') cost = 200;else if (type === 'beam') cost = 750;
if (playerGold >= cost) {
playerGold -= cost;
updateGoldDisplay();
var dragon = game.addChild(new Dragon(type, x, y));
dragons.push(dragon);
selectedDragonType = null;
updateButtonHighlights();
}
}
function updateButtonHighlights() {
fireButton.tint = selectedDragonType === 'fire' ? 0xffaaaa : 0xff4444;
iceButton.tint = selectedDragonType === 'ice' ? 0xaaaaff : 0x4444ff;
lightningButton.tint = selectedDragonType === 'lightning' ? 0xffffaa : 0xffff44;
beamButton.tint = selectedDragonType === 'beam' ? 0xffaaff : 0xff44ff;
}
function startWave() {
if (waveInProgress) return;
waveInProgress = true;
waveSpawnIndex = 0;
waveSpawnTimer = 0;
selectedDragon = null;
updateUpgradeButton();
}
function spawnEnemy() {
var enemyType;
var waveSize;
if (currentWave === 1) {
enemyType = 'regularSkeleton';
waveSize = 15;
} else if (currentWave === 2) {
enemyType = 'shieldedSkeleton';
waveSize = 15;
} else if (currentWave === 3) {
enemyType = 'fastSkeleton';
waveSize = 15;
} else if (currentWave === 4) {
if (waveSpawnIndex < 10) {
enemyType = 'regularSkeleton';
} else if (waveSpawnIndex < 20) {
enemyType = 'shieldedSkeleton';
} else {
enemyType = 'fastSkeleton';
}
waveSize = 30;
} else if (currentWave === 5) {
if (waveSpawnIndex < 2) {
enemyType = 'giantSkeleton';
} else {
enemyType = 'witchBoss';
}
waveSize = 3;
}
if (waveSpawnIndex < waveSize) {
var enemy = game.addChild(new Enemy(enemyType));
enemies.push(enemy);
waveSpawnIndex++;
}
}
function checkWaveComplete() {
if (waveInProgress && enemies.length === 0) {
// Only complete wave if all enemies have been spawned
var expectedWaveSize;
if (currentWave === 1 || currentWave === 2 || currentWave === 3) {
expectedWaveSize = 15;
} else if (currentWave === 4) {
expectedWaveSize = 30;
} else if (currentWave === 5) {
expectedWaveSize = 3;
}
if (waveSpawnIndex >= expectedWaveSize) {
waveInProgress = false;
if (currentWave >= 5) {
gameState = 'victory';
LK.showYouWin();
} else {
currentWave++;
updateWaveDisplay();
}
}
}
}
// Helper function to check if position is on path
function isOnPath(x, y) {
for (var i = 0; i < pathPoints.length - 1; i++) {
var currentPoint = pathPoints[i];
var nextPoint = pathPoints[i + 1];
var dx = nextPoint.x - currentPoint.x;
var dy = nextPoint.y - currentPoint.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Calculate distance from point to line segment
var A = x - currentPoint.x;
var B = y - currentPoint.y;
var C = dx;
var D = dy;
var dot = A * C + B * D;
var lenSq = C * C + D * D;
var param = -1;
if (lenSq !== 0) {
param = dot / lenSq;
}
var xx, yy;
if (param < 0) {
xx = currentPoint.x;
yy = currentPoint.y;
} else if (param > 1) {
xx = nextPoint.x;
yy = nextPoint.y;
} else {
xx = currentPoint.x + param * C;
yy = currentPoint.y + param * D;
}
var distToPath = Math.sqrt((x - xx) * (x - xx) + (y - yy) * (y - yy));
if (distToPath < 80) {
// Path thickness consideration
return true;
}
}
return false;
}
// Game click handler for dragon placement
game.down = function (x, y, obj) {
if (gameState === 'playing' && selectedDragonType) {
// Check if position is valid (not on path and no existing dragon)
if (!isOnPath(x, y)) {
var hasExistingDragon = false;
for (var i = 0; i < dragons.length; i++) {
if (Math.abs(dragons[i].x - x) < 100 && Math.abs(dragons[i].y - y) < 100) {
hasExistingDragon = true;
break;
}
}
if (!hasExistingDragon) {
placeDragon(selectedDragonType, x, y, -1);
}
}
}
};
// Button event handlers
fireButton.down = function () {
if (gameState === 'playing' && playerGold >= 100) {
selectedDragonType = selectedDragonType === 'fire' ? null : 'fire';
updateButtonHighlights();
}
};
iceButton.down = function () {
if (gameState === 'playing' && playerGold >= 120) {
selectedDragonType = selectedDragonType === 'ice' ? null : 'ice';
updateButtonHighlights();
}
};
lightningButton.down = function () {
if (gameState === 'playing' && playerGold >= 200) {
selectedDragonType = selectedDragonType === 'lightning' ? null : 'lightning';
updateButtonHighlights();
}
};
beamButton.down = function () {
if (gameState === 'playing' && playerGold >= 750) {
selectedDragonType = selectedDragonType === 'beam' ? null : 'beam';
updateButtonHighlights();
}
};
upgradeButton.down = function () {
if (gameState === 'playing' && selectedDragon) {
selectedDragon.upgrade();
updateUpgradeButton();
}
};
startWaveButton.down = function () {
if (gameState === 'playing' && !waveInProgress) {
startWave();
}
};
game.update = function () {
if (gameState !== 'playing') return;
// Update dragons
for (var i = 0; i < dragons.length; i++) {
dragons[i].update();
}
// Update enemies
for (var i = 0; i < enemies.length; i++) {
enemies[i].update();
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].update();
}
// Spawn enemies during wave
if (waveInProgress) {
waveSpawnTimer++;
var spawnInterval = currentWave === 1 ? 24 : 60; // Half the spacing: 48/2 = 24, 120/2 = 60
if (waveSpawnTimer >= spawnInterval) {
spawnEnemy();
waveSpawnTimer = 0;
}
}
// Check if wave is complete - only after all enemies are spawned
var expectedWaveSize;
if (currentWave === 1 || currentWave === 2 || currentWave === 3) {
expectedWaveSize = 15;
} else if (currentWave === 4) {
expectedWaveSize = 30;
} else if (currentWave === 5) {
expectedWaveSize = 3;
}
if (waveInProgress && waveSpawnIndex >= expectedWaveSize) {
if (enemies.length === 0) {
checkWaveComplete();
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (type, damage, target, isChain) {
var self = Container.call(this);
var bulletGraphics = self.attachAsset(type + 'Bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = damage;
self.target = target;
self.speed = 8;
self.isChain = isChain || false;
self.hasHit = false;
self.update = function () {
if (!self.target || self.hasHit) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 30) {
self.hitTarget();
} else {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
self.hitTarget = function () {
if (self.hasHit) return;
self.hasHit = true;
self.target.takeDamage(self.damage);
LK.getSound('enemyHit').play();
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
};
return self;
});
var Dragon = Container.expand(function (type, x, y) {
var self = Container.call(this);
var dragonGraphics = self.attachAsset(type + 'Dragon', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type;
self.isUpgraded = false;
self.lastShotTime = 0;
self.shootInterval = 1500;
if (type === 'fire') {
self.damage = 500;
self.range = 500;
self.cost = 100;
} else if (type === 'ice') {
self.damage = 500;
self.range = 500;
self.cost = 120;
} else if (type === 'lightning') {
self.damage = 400;
self.range = 500;
self.cost = 200;
} else if (type === 'beam') {
self.damage = 10;
self.range = 500;
self.cost = 750;
self.beamTarget = null;
self.beamDamageMultiplier = 1;
self.beamStartTime = 0;
self.shootInterval = 100; // Beam updates faster
}
self.x = x;
self.y = y;
self.update = function () {
var currentTime = Date.now();
if (self.type === 'beam') {
// Handle beam dragon logic
if (self.beamTarget && self.beamTarget.health > 0) {
var dx = self.beamTarget.x - self.x;
var dy = self.beamTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.range) {
// Create or update beam visual effect
if (!self.beamLaser) {
self.beamLaser = game.addChild(LK.getAsset('beamLaser', {
anchorX: 0,
anchorY: 0.5
}));
}
// Position and rotate the beam
self.beamLaser.x = self.x;
self.beamLaser.y = self.y;
var angle = Math.atan2(dy, dx);
self.beamLaser.rotation = angle;
self.beamLaser.width = distance;
// Calculate damage based on time
var timeElapsed = (currentTime - self.beamStartTime) / 1000;
var currentDamage;
if (timeElapsed < 1) {
currentDamage = self.isUpgraded ? 15 : 10;
} else if (timeElapsed < 2) {
currentDamage = self.isUpgraded ? 300 : 200;
} else if (timeElapsed < 3) {
currentDamage = self.isUpgraded ? 750 : 500;
} else if (timeElapsed < 4) {
currentDamage = self.isUpgraded ? 1200 : 800;
} else {
currentDamage = self.isUpgraded ? 1500 : 1000;
}
// Apply damage every 0.5 seconds after 3rd second, otherwise every second
var shouldDamage = false;
if (timeElapsed >= 3) {
shouldDamage = Math.floor(timeElapsed * 2) > Math.floor((timeElapsed - 0.017) * 2);
} else {
shouldDamage = Math.floor(timeElapsed) > Math.floor(timeElapsed - 0.017);
}
if (shouldDamage) {
self.beamTarget.takeDamage(currentDamage);
LK.getSound('enemyHit').play();
}
} else {
self.beamTarget = null;
if (self.beamLaser) {
self.beamLaser.destroy();
self.beamLaser = null;
}
}
} else {
self.beamTarget = null;
if (self.beamLaser) {
self.beamLaser.destroy();
self.beamLaser = null;
}
}
if (!self.beamTarget) {
var target = self.findTarget();
if (target) {
self.shoot(target);
}
}
} else {
if (currentTime - self.lastShotTime >= self.shootInterval) {
var target = self.findTarget();
if (target) {
self.shoot(target);
self.lastShotTime = currentTime;
}
}
}
};
self.findTarget = function () {
var closestEnemy = null;
var closestDistance = 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 < closestDistance && distance <= self.range) {
closestDistance = distance;
closestEnemy = enemy;
}
}
return closestEnemy;
};
self.shoot = function (target) {
if (self.type === 'beam') {
// Handle beam dragon shooting
if (!self.beamTarget || self.beamTarget.health <= 0) {
self.beamTarget = target;
self.beamStartTime = Date.now();
self.beamDamageMultiplier = 1;
}
return;
}
LK.getSound('shoot').play();
if (self.type === 'lightning') {
// Create visible lightning bullet
var bullet = new Bullet(self.type, 0, target, false);
bullet.x = self.x;
bullet.y = self.y;
bullets.push(bullet);
game.addChild(bullet);
// New lightning system: single target, double hit
var firstDamage = self.isUpgraded ? 750 : 500;
var secondDamage = self.isUpgraded ? 1250 : 1000;
// Apply first damage immediately
target.takeDamage(firstDamage);
LK.getSound('enemyHit').play();
LK.effects.flashObject(target, 0xffff00, 200);
// Schedule second damage after 1 second with freeze effect
LK.setTimeout(function () {
if (target && target.health > 0) {
target.takeDamage(secondDamage);
LK.getSound('enemyHit').play();
LK.effects.flashObject(target, 0xffff00, 200);
// Freeze target for 0.75 seconds
target.applySlowEffect(0);
target.slowDuration = 45; // 0.75 seconds at 60fps
}
}, 1000);
} else {
var bullet = new Bullet(self.type, self.damage, target, false);
bullet.x = self.x;
bullet.y = self.y;
bullets.push(bullet);
game.addChild(bullet);
}
if (self.type === 'ice') {
target.applySlowEffect(self.isUpgraded ? 0.50 : 0.85);
}
};
self.upgrade = function () {
if (self.isUpgraded) return false;
if (playerGold >= 150) {
playerGold -= 150;
self.isUpgraded = true;
if (self.type === 'fire') {
self.damage = 1000;
tween(dragonGraphics, {
tint: 0xcc0000
}, {
duration: 500
});
} else if (self.type === 'ice') {
self.damage = Math.floor(self.damage * 1.5);
tween(dragonGraphics, {
tint: 0x0000cc
}, {
duration: 500
});
} else if (self.type === 'lightning') {
self.damage = Math.floor(self.damage * 1.5);
tween(dragonGraphics, {
tint: 0xcccc00
}, {
duration: 500
});
} else if (self.type === 'beam') {
self.damage = Math.floor(self.damage * 1.5);
tween(dragonGraphics, {
tint: 0xcc00cc
}, {
duration: 500
});
}
updateGoldDisplay();
return true;
}
return false;
};
self.down = function (x, y, obj) {
if (gameState === 'playing') {
selectedDragon = self;
updateUpgradeButton();
}
};
return self;
});
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
var enemyGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type;
self.pathIndex = 0;
self.speed = 0.968; // Base speed increased by 10% (0.88 * 1.1)
self.slowEffect = 1;
self.slowDuration = 0;
if (type === 'regularSkeleton') {
self.maxHealth = 500;
self.goldValue = 20;
self.speed = 1.95; // Regular skeleton speed 1.50 * 1.30 = 1.95 meter/second
} else if (type === 'shieldedSkeleton') {
self.maxHealth = 3000; // Increased by 50%
self.goldValue = 25;
self.speed = 1.30; // Shielded skeleton speed 1.0 * 1.30 = 1.30 meter/second
} else if (type === 'fastSkeleton') {
self.maxHealth = 2250; // Increased by 50%
self.goldValue = 30;
self.speed = 3.90; // Fast skeleton speed 3.0 * 1.30 = 3.90 meter/second
} else if (type === 'giantSkeleton') {
self.maxHealth = 20000;
self.goldValue = 100;
self.speed = 1.30; // Giant skeleton speed 1.0 * 1.30 = 1.30 meter/second
} else if (type === 'witchBoss') {
self.maxHealth = 104000;
self.goldValue = 50;
self.speed = 1.30; // Witch boss speed 1.0 * 1.30 = 1.30 meter/second
}
self.health = self.maxHealth;
self.x = pathPoints[0].x;
self.y = pathPoints[0].y;
self.update = function () {
if (self.slowDuration > 0) {
self.slowDuration--;
} else {
self.slowEffect = 1;
}
if (self.pathIndex < pathPoints.length - 1) {
var currentPoint = pathPoints[self.pathIndex];
var nextPoint = pathPoints[self.pathIndex + 1];
var dx = nextPoint.x - self.x;
var dy = nextPoint.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
self.pathIndex++;
} else {
var moveSpeed = self.speed * self.slowEffect;
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
} else {
self.reachEnd();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.die();
}
};
self.applySlowEffect = function (slowAmount) {
self.slowEffect = slowAmount;
self.slowDuration = 180;
};
self.die = function () {
playerGold += self.goldValue;
updateGoldDisplay();
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
checkWaveComplete();
};
self.reachEnd = function () {
// Only giant skeletons and witch bosses cause immediate game over
if (self.type === 'giantSkeleton' || self.type === 'witchBoss') {
gameState = 'gameOver';
LK.showGameOver();
} else {
// Regular skeletons reduce lives by 1
playerLives--;
updateLivesDisplay();
if (playerLives <= 0) {
gameState = 'gameOver';
LK.showGameOver();
}
}
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
var gameState = 'playing';
var playerGold = 100;
var playerLives = 5;
var currentWave = 1;
var waveInProgress = false;
var selectedDragon = null;
var dragons = [];
var enemies = [];
var bullets = [];
var placementZones = [];
var pathPoints = [{
x: 2048,
y: 1500
}, {
x: 1400,
y: 1500
}, {
x: 1000,
y: 1200
}, {
x: 700,
y: 800
}, {
x: 1000,
y: 400
}, {
x: 1400,
y: 700
}, {
x: 1000,
y: 1000
}, {
x: 600,
y: 1300
}, {
x: 0,
y: 1500
}];
var placementPositions = [{
// Near entrance area
x: 1600,
y: 1450
}, {
// Upper right strategic position
x: 1550,
y: 1200
}, {
// Mid-path right side
x: 1250,
y: 1350
}, {
// Lower mid right
x: 950,
y: 1150
}, {
// Center strategic position
x: 750,
y: 950
}, {
// Left side mid
x: 550,
y: 750
}, {
// Upper left strategic
x: 850,
y: 500
}, {
// Far upper position
x: 1200,
y: 200
}, {
// Upper mid strategic
x: 1000,
y: 400
}, {
// Right upper curve
x: 1500,
y: 750
}, {
// Left strategic covering exit
x: 400,
y: 1300
}, {
// Final exit coverage
x: 300,
y: 1050
}];
// Create grass background tiles
for (var gx = 0; gx < 2048; gx += 150) {
for (var gy = 0; gy < 2732; gy += 150) {
var grassTile = game.addChild(LK.getAsset('grass', {
anchorX: 0,
anchorY: 0
}));
grassTile.x = gx;
grassTile.y = gy;
}
}
// Add decorative stones scattered around
var stonePositions = [{
x: 300,
y: 400
}, {
x: 800,
y: 300
}, {
x: 1200,
y: 600
}, {
x: 400,
y: 900
}, {
x: 1600,
y: 800
}, {
x: 900,
y: 1600
}, {
x: 1500,
y: 1800
}, {
x: 200,
y: 1200
}, {
x: 1800,
y: 400
}, {
x: 600,
y: 2000
}, {
x: 1400,
y: 2200
}, {
x: 500,
y: 600
}];
for (var s = 0; s < stonePositions.length; s++) {
var stone = game.addChild(LK.getAsset('stone', {
anchorX: 0.5,
anchorY: 0.5
}));
stone.x = stonePositions[s].x;
stone.y = stonePositions[s].y;
}
// Add decorative flowers
var flowerPositions = [{
x: 250,
y: 500
}, {
x: 750,
y: 200
}, {
x: 1100,
y: 700
}, {
x: 350,
y: 1000
}, {
x: 1550,
y: 900
}, {
x: 850,
y: 1700
}, {
x: 1450,
y: 1900
}, {
x: 150,
y: 1300
}, {
x: 1750,
y: 500
}, {
x: 550,
y: 2100
}, {
x: 1350,
y: 2300
}, {
x: 450,
y: 700
}, {
x: 1050,
y: 1400
}, {
x: 650,
y: 1100
}, {
x: 1250,
y: 300
}];
for (var f = 0; f < flowerPositions.length; f++) {
var flower = game.addChild(LK.getAsset('flower', {
anchorX: 0.5,
anchorY: 0.5
}));
flower.x = flowerPositions[f].x;
flower.y = flowerPositions[f].y;
}
// Create visible forest path following the actual route
for (var p = 0; p < pathPoints.length - 1; p++) {
var currentPoint = pathPoints[p];
var nextPoint = pathPoints[p + 1];
var dx = nextPoint.x - currentPoint.x;
var dy = nextPoint.y - currentPoint.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var angle = Math.atan2(dy, dx);
var pathSegment = game.addChild(LK.getAsset('forestPath', {
anchorX: 0,
anchorY: 0.5,
scaleX: distance / 100,
scaleY: 1.2
}));
pathSegment.x = currentPoint.x;
pathSegment.y = currentPoint.y;
pathSegment.rotation = angle;
}
// Placement zones removed - dragons can be placed anywhere valid
// Create shop panel
var shopPanel = LK.gui.bottom.addChild(LK.getAsset('shopPanel', {
anchorX: 0.5,
anchorY: 1
}));
// Create dragon buttons
var fireButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -450,
y: -150,
tint: 0xff4444,
scaleX: 1.3,
scaleY: 1.3
}));
var iceButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -250,
y: -150,
tint: 0x4444ff,
scaleX: 1.3,
scaleY: 1.3
}));
var lightningButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -50,
y: -150,
tint: 0xffff44,
scaleX: 1.3,
scaleY: 1.3
}));
var beamButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 150,
y: -150,
tint: 0xff44ff,
scaleX: 1.3,
scaleY: 1.3
}));
var upgradeButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 350,
y: -150,
tint: 0x00ff00,
scaleX: 1.3,
scaleY: 1.3
}));
var startWaveButton = shopPanel.addChild(LK.getAsset('dragonButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 550,
y: -150,
tint: 0xff8800,
scaleX: 1.3,
scaleY: 1.3
}));
// Create UI text
var goldText = LK.gui.topRight.addChild(new Text2('Gold: 100', {
size: 60,
fill: 0xFFFF00
}));
goldText.anchor.set(1, 0);
var livesText = LK.gui.topRight.addChild(new Text2('Lives: 5', {
size: 60,
fill: 0xFF0000
}));
livesText.anchor.set(1, 0);
livesText.y = 80;
var waveText = LK.gui.top.addChild(new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
}));
waveText.anchor.set(0.5, 0);
var fireButtonText = LK.gui.bottom.addChild(new Text2('Fire\n100g', {
size: 40,
fill: 0xFFFFFF
}));
fireButtonText.anchor.set(0.5, 0.5);
fireButtonText.x = -450;
fireButtonText.y = -150;
var iceButtonText = LK.gui.bottom.addChild(new Text2('Ice\n120g', {
size: 40,
fill: 0xFFFFFF
}));
iceButtonText.anchor.set(0.5, 0.5);
iceButtonText.x = -250;
iceButtonText.y = -150;
var lightningButtonText = LK.gui.bottom.addChild(new Text2('Lightning\n200g', {
size: 40,
fill: 0xFFFFFF
}));
lightningButtonText.anchor.set(0.5, 0.5);
lightningButtonText.x = -50;
lightningButtonText.y = -150;
var beamButtonText = LK.gui.bottom.addChild(new Text2('Beam\n750g', {
size: 40,
fill: 0xFFFFFF
}));
beamButtonText.anchor.set(0.5, 0.5);
beamButtonText.x = 150;
beamButtonText.y = -150;
var upgradeButtonText = LK.gui.bottom.addChild(new Text2('Upgrade\nSelect', {
size: 40,
fill: 0xFFFFFF
}));
upgradeButtonText.anchor.set(0.5, 0.5);
upgradeButtonText.x = 350;
upgradeButtonText.y = -150;
var startWaveButtonText = LK.gui.bottom.addChild(new Text2('Start\nWave', {
size: 40,
fill: 0xFFFFFF
}));
startWaveButtonText.anchor.set(0.5, 0.5);
startWaveButtonText.x = 550;
startWaveButtonText.y = -150;
var selectedDragonType = null;
var waveSpawnIndex = 0;
var waveSpawnTimer = 0;
function updateGoldDisplay() {
goldText.setText('Gold: ' + playerGold);
}
function updateLivesDisplay() {
livesText.setText('Lives: ' + playerLives);
}
function updateWaveDisplay() {
waveText.setText('Wave: ' + currentWave);
}
function updateUpgradeButton() {
if (selectedDragon && !selectedDragon.isUpgraded) {
upgradeButtonText.setText('Upgrade\n150g');
} else {
upgradeButtonText.setText('Upgrade\nSelect');
}
}
function placeDragon(type, x, y, zoneIndex) {
var cost;
if (type === 'fire') cost = 100;else if (type === 'ice') cost = 120;else if (type === 'lightning') cost = 200;else if (type === 'beam') cost = 750;
if (playerGold >= cost) {
playerGold -= cost;
updateGoldDisplay();
var dragon = game.addChild(new Dragon(type, x, y));
dragons.push(dragon);
selectedDragonType = null;
updateButtonHighlights();
}
}
function updateButtonHighlights() {
fireButton.tint = selectedDragonType === 'fire' ? 0xffaaaa : 0xff4444;
iceButton.tint = selectedDragonType === 'ice' ? 0xaaaaff : 0x4444ff;
lightningButton.tint = selectedDragonType === 'lightning' ? 0xffffaa : 0xffff44;
beamButton.tint = selectedDragonType === 'beam' ? 0xffaaff : 0xff44ff;
}
function startWave() {
if (waveInProgress) return;
waveInProgress = true;
waveSpawnIndex = 0;
waveSpawnTimer = 0;
selectedDragon = null;
updateUpgradeButton();
}
function spawnEnemy() {
var enemyType;
var waveSize;
if (currentWave === 1) {
enemyType = 'regularSkeleton';
waveSize = 15;
} else if (currentWave === 2) {
enemyType = 'shieldedSkeleton';
waveSize = 15;
} else if (currentWave === 3) {
enemyType = 'fastSkeleton';
waveSize = 15;
} else if (currentWave === 4) {
if (waveSpawnIndex < 10) {
enemyType = 'regularSkeleton';
} else if (waveSpawnIndex < 20) {
enemyType = 'shieldedSkeleton';
} else {
enemyType = 'fastSkeleton';
}
waveSize = 30;
} else if (currentWave === 5) {
if (waveSpawnIndex < 2) {
enemyType = 'giantSkeleton';
} else {
enemyType = 'witchBoss';
}
waveSize = 3;
}
if (waveSpawnIndex < waveSize) {
var enemy = game.addChild(new Enemy(enemyType));
enemies.push(enemy);
waveSpawnIndex++;
}
}
function checkWaveComplete() {
if (waveInProgress && enemies.length === 0) {
// Only complete wave if all enemies have been spawned
var expectedWaveSize;
if (currentWave === 1 || currentWave === 2 || currentWave === 3) {
expectedWaveSize = 15;
} else if (currentWave === 4) {
expectedWaveSize = 30;
} else if (currentWave === 5) {
expectedWaveSize = 3;
}
if (waveSpawnIndex >= expectedWaveSize) {
waveInProgress = false;
if (currentWave >= 5) {
gameState = 'victory';
LK.showYouWin();
} else {
currentWave++;
updateWaveDisplay();
}
}
}
}
// Helper function to check if position is on path
function isOnPath(x, y) {
for (var i = 0; i < pathPoints.length - 1; i++) {
var currentPoint = pathPoints[i];
var nextPoint = pathPoints[i + 1];
var dx = nextPoint.x - currentPoint.x;
var dy = nextPoint.y - currentPoint.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Calculate distance from point to line segment
var A = x - currentPoint.x;
var B = y - currentPoint.y;
var C = dx;
var D = dy;
var dot = A * C + B * D;
var lenSq = C * C + D * D;
var param = -1;
if (lenSq !== 0) {
param = dot / lenSq;
}
var xx, yy;
if (param < 0) {
xx = currentPoint.x;
yy = currentPoint.y;
} else if (param > 1) {
xx = nextPoint.x;
yy = nextPoint.y;
} else {
xx = currentPoint.x + param * C;
yy = currentPoint.y + param * D;
}
var distToPath = Math.sqrt((x - xx) * (x - xx) + (y - yy) * (y - yy));
if (distToPath < 80) {
// Path thickness consideration
return true;
}
}
return false;
}
// Game click handler for dragon placement
game.down = function (x, y, obj) {
if (gameState === 'playing' && selectedDragonType) {
// Check if position is valid (not on path and no existing dragon)
if (!isOnPath(x, y)) {
var hasExistingDragon = false;
for (var i = 0; i < dragons.length; i++) {
if (Math.abs(dragons[i].x - x) < 100 && Math.abs(dragons[i].y - y) < 100) {
hasExistingDragon = true;
break;
}
}
if (!hasExistingDragon) {
placeDragon(selectedDragonType, x, y, -1);
}
}
}
};
// Button event handlers
fireButton.down = function () {
if (gameState === 'playing' && playerGold >= 100) {
selectedDragonType = selectedDragonType === 'fire' ? null : 'fire';
updateButtonHighlights();
}
};
iceButton.down = function () {
if (gameState === 'playing' && playerGold >= 120) {
selectedDragonType = selectedDragonType === 'ice' ? null : 'ice';
updateButtonHighlights();
}
};
lightningButton.down = function () {
if (gameState === 'playing' && playerGold >= 200) {
selectedDragonType = selectedDragonType === 'lightning' ? null : 'lightning';
updateButtonHighlights();
}
};
beamButton.down = function () {
if (gameState === 'playing' && playerGold >= 750) {
selectedDragonType = selectedDragonType === 'beam' ? null : 'beam';
updateButtonHighlights();
}
};
upgradeButton.down = function () {
if (gameState === 'playing' && selectedDragon) {
selectedDragon.upgrade();
updateUpgradeButton();
}
};
startWaveButton.down = function () {
if (gameState === 'playing' && !waveInProgress) {
startWave();
}
};
game.update = function () {
if (gameState !== 'playing') return;
// Update dragons
for (var i = 0; i < dragons.length; i++) {
dragons[i].update();
}
// Update enemies
for (var i = 0; i < enemies.length; i++) {
enemies[i].update();
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].update();
}
// Spawn enemies during wave
if (waveInProgress) {
waveSpawnTimer++;
var spawnInterval = currentWave === 1 ? 24 : 60; // Half the spacing: 48/2 = 24, 120/2 = 60
if (waveSpawnTimer >= spawnInterval) {
spawnEnemy();
waveSpawnTimer = 0;
}
}
// Check if wave is complete - only after all enemies are spawned
var expectedWaveSize;
if (currentWave === 1 || currentWave === 2 || currentWave === 3) {
expectedWaveSize = 15;
} else if (currentWave === 4) {
expectedWaveSize = 30;
} else if (currentWave === 5) {
expectedWaveSize = 3;
}
if (waveInProgress && waveSpawnIndex >= expectedWaveSize) {
if (enemies.length === 0) {
checkWaveComplete();
}
}
};
basic red fire dragon. 3d. In-Game asset. 2d. High contrast. No shadows
şimşek. In-Game asset. 2d. High contrast. No shadows
skeleton. In-Game asset. 2d. High contrast. No shadows
kalkanlı zırhlı iskelet. In-Game asset. 2d. High contrast. No shadows
cadı boss. In-Game asset. 2d. High contrast. No shadows
şimşek fırlatan bir elektrik ejderhası. In-Game asset. 2d. High contrast. No shadows şimşekleri sil
bu buz fırlatan bir buz ejderhası soğukları iliklerimize kadar hissetiriyor ejderha çizimi buz içermesin. In-Game asset. 2d. High contrast. No shadows bu çizimde ejderhanın ağzı açık olsun ama bir şey çıkmasın
bu bir buz parçası. uzun sivri bir koni gibi. In-Game asset. 2d. High contrast. No shadows
yuvarlak alev topu. In-Game asset. 2d. High contrast. No shadows
dümdüz toprak bir yol taş süslemeleri. In-Game asset. 2d. High contrast. No shadows
papatya. In-Game asset. 2d. High contrast. No shadows
üstten bakılan kaya parçaları. In-Game asset. 2d. High contrast. No shadows
çizimler iyi . ağzı açık olsun ama lazer olmasın. In-Game asset. 2d. High contrast. No shadows