User prompt
6 tane unit koyma yeri olsun
User prompt
Oyunun yolunu ilk haline getir
User prompt
Reset
User prompt
Yol sağ üste bitsin
User prompt
Oyunun ilk haline çevir yolu
User prompt
Yolu virajlarda yap 4 tane biris sağa biris sol biridaha sağ biridaha sol
User prompt
Yolu değiştir 3 tane kıvrım olsun
User prompt
Toplamda 12 tane unit koyalım ve yolları daha çok kıvrımlı yap
User prompt
15 wawe 20 wawe arası sadece kırmızı zombş gelsin
User prompt
Yeşil zombi oldurdunde 1 para kırmızı zombş oldurdunde 2 para gelsin
User prompt
4. Upraded değiştir 1 rer 1 rer vursun hasarı 8 olsun 5. Upgraded 2 tane aynanda atsın her birisi 7.25şar 7.25 şar vursun toplam hasar 15 4. Upgraded fiyatı 50 5. Upgraded fiyatı 100
User prompt
add 3rd upgraded to units, red unit should be added to right and left arm and should hit with its arm and hit 2 times in a row, its damage should be 10, its money should be 30, the price of 2nd upgraded should be 20, the price of 1st upgraded should be 10
User prompt
10 waves, 1 red zombie comes. 11 waves, 2 red zombies come. 1 red zombie comes every round until 20 waves.
User prompt
After the 5th wave, both green and red zombies will come mixed. From wave 10 to wave 20, only red will come.
User prompt
Red zombş heatlh 10
User prompt
Green zombşe health 5
User prompt
Upgraded ettiniz zaman unitlerin tipi değişsin görselleri değişsin
User prompt
Wawe 5 getir zaman 1 kırmızı zombi gelsin sonra wawe 6 2 tane sonra 3 tane sen kafam random ama ilk 5 ile 8 tur arasında en fazla 4 kırmızı zombi gelsin
User prompt
Wawe 5 ten sonra kırmızı zombiler gelsin normal yeşil zombilerin 2x canı olsun
User prompt
Üstlerinde can barı olsun
User prompt
Upgraded 1 fiyat 5 upgraded 2 fiyatı 10
User prompt
Asker koydunuz zaman bidaha ustune tınladımız zaman upgraded cıksın upgraded edince daha çok hasar versin
Code edit (1 edits merged)
Please save this source code
User prompt
Curvy Path Defense
Initial prompt
Towet defense Birtane yol olsun kıvrımlı her tur daha güçlü daha cok canı olan zom iler gelsin yolu takip etsinler yolu en sonunda base olsun eyeri base canı 100 0 ulaşırsa defeay diye bir yazı cıksın bizimde duvarların üstünde asker koyalım sol alta askerler olsun 4 tane 1. Si para 10 olsun oyuna 10 parayla basliyalım her zombi ayrı puan versin daha güçlüler daha çok puan versin 1. 10 para hasarı 20 2. Para 25 hasarı 50 3. Para 50 hasarı 100 4. Son olarak para 250 hasarı 125
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
self.target = null;
self.speed = 18;
self.damage = 1;
self.type = 1;
self.active = true;
self.shooter = null;
self.setType = function (type) {
self.type = type;
var assetId = 'bullet' + type;
self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
if (!self.active || !self.target || self.target.dead) {
self.destroy();
return;
}
// Move toward target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 30) {
// Hit
self.target.takeDamage(self.damage);
self.destroy();
return;
}
var step = self.speed / (dist || 1);
self.x += dx * step;
self.y += dy * step;
};
return self;
});
// Soldier class
var Soldier = Container.expand(function () {
var self = Container.call(this);
self.type = 1;
self.fireRate = 60; // ticks between shots
self.damage = 1;
self.range = 350;
self.cooldown = 0;
self.level = 1;
self.wallSpot = null;
self.setType = function (type) {
self.type = type;
// Remove all previous children (visuals)
while (self.children && self.children.length > 0) {
self.removeChild(self.children[0]);
}
var assetId = 'soldier' + type;
self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Set stats
if (type === 1) {
self.fireRate = 60;
self.damage = 1;
self.range = 350;
self.dualHit = false;
self.money = 3;
}
if (type === 2) {
self.fireRate = 40;
self.damage = 1;
self.range = 300;
self.dualHit = false;
self.money = 10;
}
if (type === 3) {
self.fireRate = 90;
self.damage = 3;
self.range = 320;
self.dualHit = false;
self.money = 20;
}
if (type === 4) {
self.fireRate = 60;
self.damage = 8;
self.range = 400;
self.dualHit = false; // 4th upgrade: single hit
self.money = 50;
}
if (type === 5) {
self.fireRate = 60;
self.damage = 7.25;
self.range = 400;
self.dualHit = true; // 5th upgrade: dual shot
self.money = 100;
}
};
self.update = function () {
if (self.cooldown > 0) {
self.cooldown--;
return;
}
// Find nearest zombie in range
var nearest = null;
var minDist = 99999;
for (var i = 0; i < zombies.length; ++i) {
var z = zombies[i];
if (z.dead) continue;
var dx = z.x - self.x;
var dy = z.y - self.y;
var d = Math.sqrt(dx * dx + dy * dy);
if (d < self.range && d < minDist) {
minDist = d;
nearest = z;
}
}
if (nearest) {
// Shoot
if (self.type === 5 && self.dualHit) {
// 5th upgrade: dual shot, each 7.25 dmg, total 15
for (var i = 0; i < 2; ++i) {
var bullet = new Bullet();
bullet.setType(self.type);
// Offset for left/right arm
bullet.x = self.x + (i === 0 ? -30 : 30);
bullet.y = self.y;
bullet.target = nearest;
bullet.damage = self.damage;
bullet.shooter = self;
bullets.push(bullet);
game.addChild(bullet);
}
self.cooldown = self.fireRate;
} else if (self.type === 4 && !self.dualHit) {
// 4th upgrade: single hit, 8 dmg
var bullet = new Bullet();
bullet.setType(self.type);
bullet.x = self.x;
bullet.y = self.y;
bullet.target = nearest;
bullet.damage = self.damage;
bullet.shooter = self;
bullets.push(bullet);
game.addChild(bullet);
self.cooldown = self.fireRate;
} else if (self.type === 4 && self.dualHit) {
// (legacy, should not occur, but keep for safety)
for (var i = 0; i < 2; ++i) {
var bullet = new Bullet();
bullet.setType(self.type);
bullet.x = self.x + (i === 0 ? -30 : 30);
bullet.y = self.y;
bullet.target = nearest;
bullet.damage = self.damage;
bullet.shooter = self;
bullets.push(bullet);
game.addChild(bullet);
}
self.cooldown = self.fireRate;
} else {
var bullet = new Bullet();
bullet.setType(self.type);
bullet.x = self.x;
bullet.y = self.y;
bullet.target = nearest;
bullet.damage = self.damage;
bullet.shooter = self;
bullets.push(bullet);
game.addChild(bullet);
self.cooldown = self.fireRate;
}
}
};
return self;
});
// Zombie class
var Zombie = Container.expand(function () {
var self = Container.call(this);
self.isRed = false; // Will be set after construction if needed
var sprite = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
// Health bar background
var hpBarBg = LK.getAsset('pathnode', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 14,
y: -60,
alpha: 0.25,
color: 0x000000
});
self.setRed = function () {
if (!self.isRed) {
self.isRed = true;
// Remove old sprite
if (sprite && sprite.parent === self) self.removeChild(sprite);
// Attach red zombie asset
var redSprite = self.attachAsset('zombieRed', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
self.addChild(hpBarBg);
// Health bar foreground
var hpBar = LK.getAsset('pathnode', {
anchorX: 0.5,
anchorY: 0.5,
width: 56,
height: 10,
y: -60,
color: 0xff2222,
alpha: 0.85
});
self.addChild(hpBar);
self.speed = 1.2;
self.maxHp = 5;
self.hp = 5;
self.reward = 1;
self.pathIndex = 0;
self.progress = 0; // 0-1 between path[pathIndex] and path[pathIndex+1]
self.targetX = 0;
self.targetY = 0;
self.dead = false;
self.setStats = function (hp, speed, reward) {
self.maxHp = hp;
self.hp = hp;
self.speed = speed;
self.reward = reward;
// Update health bar on spawn
if (hpBar) {
hpBar.width = 56;
}
};
self.setPathIndex = function (idx) {
self.pathIndex = idx;
self.progress = 0;
};
self.update = function () {
if (self.dead) return;
// Move along path
if (self.pathIndex >= path.length - 1) return;
var from = path[self.pathIndex];
var to = path[self.pathIndex + 1];
var dx = to.x - from.x;
var dy = to.y - from.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) dist = 1;
var step = self.speed / dist;
self.progress += step;
if (self.progress >= 1) {
self.pathIndex++;
self.progress = 0;
if (self.pathIndex >= path.length - 1) {
// At base
self.x = to.x;
self.y = to.y;
self.reachedBase = true;
return;
}
}
var from = path[self.pathIndex];
var to = path[self.pathIndex + 1];
self.x = from.x + (to.x - from.x) * self.progress;
self.y = from.y + (to.y - from.y) * self.progress;
// Update health bar position and width
if (hpBar && hpBarBg) {
hpBarBg.x = 0;
hpBarBg.y = -60;
hpBar.x = 0;
hpBar.y = -60;
var ratio = Math.max(0, Math.min(1, self.hp / self.maxHp));
hpBar.width = 56 * ratio;
if (ratio > 0.6) {
hpBar.color = 0x44ff44;
} else if (ratio > 0.3) {
hpBar.color = 0xffe680;
} else {
hpBar.color = 0xff2222;
}
}
};
self.takeDamage = function (dmg) {
self.hp -= dmg;
if (self.hp <= 0 && !self.dead) {
self.dead = true;
// Animate fade out
tween(self, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Path and wall spot colors
// Path definition (original, straight/less-curvy path for the first version of the game)
var path = [{
x: 200,
y: 400
},
// Start
{
x: 200,
y: 1000
}, {
x: 200,
y: 1800
}, {
x: 600,
y: 2200
}, {
x: 1200,
y: 2200
}, {
x: 1800,
y: 1800
}, {
x: 1800,
y: 1000
}, {
x: 1800,
y: 400
} // Base (top right)
];
// Wall spot positions (now 6 unit placement positions)
var wallSpots = [{
x: 400,
y: 800
}, {
x: 400,
y: 1600
}, {
x: 800,
y: 2000
}, {
x: 1200,
y: 1800
}, {
x: 1600,
y: 1200
}, {
x: 1600,
y: 800
}];
// Wall spot state
var wallSpotStates = [];
for (var i = 0; i < wallSpots.length; ++i) wallSpotStates[i] = null;
// Game state
var zombies = [];
var bullets = [];
var soldiers = [];
var coins = 10;
var baseHp = 10;
var wave = 1;
var spawnTimer = 0;
var spawnIdx = 0;
var zombiesToSpawn = 0;
var waveInProgress = false;
var baseNode = null;
var selectedSoldierType = 1;
var placingSoldier = false;
var placingSoldierIdx = -1;
var gameOver = false;
// GUI
var coinTxt = new Text2('Coins: 10', {
size: 80,
fill: 0xFFE680
});
coinTxt.anchor.set(0, 0);
LK.gui.top.addChild(coinTxt);
var baseHpTxt = new Text2('Base: 10', {
size: 80,
fill: 0xFFAAAA
});
baseHpTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(baseHpTxt);
var waveTxt = new Text2('Wave: 1', {
size: 80,
fill: 0xAAFFAA
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
var soldierBtns = [];
var soldierCosts = [3, 10, 20, 50, 100];
var soldierNames = ['Basic', 'Rapid', 'Heavy', 'Red Arm', 'Dual Arm'];
var soldierBtnY = 0;
for (var i = 0; i < 4; ++i) {
var btn = new Text2(soldierNames[i] + "\n" + soldierCosts[i] + "c", {
size: 60,
fill: "#fff"
});
btn.anchor.set(0.5, 0);
btn.x = 300 + i * 300;
btn.y = 0;
LK.gui.bottom.addChild(btn);
soldierBtns.push(btn);
}
// Note: Only 4 buttons shown, but 5 upgrades available via upgrade
// Draw path (as faint nodes)
for (var i = 0; i < path.length; ++i) {
var node = LK.getAsset('pathnode', {
anchorX: 0.5,
anchorY: 0.5,
x: path[i].x,
y: path[i].y,
alpha: 0.18
});
game.addChild(node);
// Connect lines (not possible, so just nodes)
}
// Draw wall spots
var wallSpotNodes = [];
for (var i = 0; i < wallSpots.length; ++i) {
var ws = LK.getAsset('wallspot', {
anchorX: 0.5,
anchorY: 0.5,
x: wallSpots[i].x,
y: wallSpots[i].y,
alpha: 0.5
});
ws.idx = i;
wallSpotNodes.push(ws);
game.addChild(ws);
}
// Draw base
baseNode = LK.getAsset('base', {
anchorX: 0.5,
anchorY: 0.5,
x: path[path.length - 1].x,
y: path[path.length - 1].y
});
game.addChild(baseNode);
// Handle soldier button selection
for (var i = 0; i < soldierBtns.length; ++i) {
(function (idx) {
soldierBtns[idx].down = function (x, y, obj) {
selectedSoldierType = idx + 1;
for (var j = 0; j < soldierBtns.length; ++j) {
soldierBtns[j].setStyle({
fill: j === idx ? "#ffff00" : "#fff"
});
}
};
})(i);
}
soldierBtns[0].setStyle({
fill: 0xFFFF00
});
// Place soldier on wall spot
for (var i = 0; i < wallSpotNodes.length; ++i) {
(function (idx) {
wallSpotNodes[idx].down = function (x, y, obj) {
if (gameOver) return;
if (wallSpotStates[idx] === null) {
// Place soldier if empty
var cost = soldierCosts[selectedSoldierType - 1];
if (coins < cost) {
// Flash red
tween(wallSpotNodes[idx], {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(wallSpotNodes[idx], {
tint: 0x888888
}, {
duration: 200
});
}
});
return;
}
coins -= cost;
coinTxt.setText('Coins: ' + coins);
// Place soldier
var s = new Soldier();
s.setType(selectedSoldierType);
s.x = wallSpots[idx].x;
s.y = wallSpots[idx].y;
s.wallSpot = idx;
wallSpotStates[idx] = s;
soldiers.push(s);
game.addChild(s);
// Add upgrade text overlay
var upgradeTxt = new Text2('Upgrade', {
size: 40,
fill: 0x00FF00
});
upgradeTxt.anchor.set(0.5, 1);
upgradeTxt.x = s.x;
upgradeTxt.y = s.y - 60;
upgradeTxt.visible = false;
s.upgradeTxt = upgradeTxt;
game.addChild(upgradeTxt);
// Add tap handler for upgrade
s.down = function (x, y, obj) {
if (gameOver) return;
// Show upgrade text if not max level
if (s.level < 5) {
s.upgradeTxt.visible = true;
// Hide after 1s
LK.setTimeout(function () {
if (s.upgradeTxt) s.upgradeTxt.visible = false;
}, 1000);
}
// If already at max, do nothing
};
// Add tap handler for upgrade text
upgradeTxt.down = function (x, y, obj) {
if (gameOver) return;
if (s.level >= 5) return;
// Upgrade cost: Level 2 = 10, Level 3 = 20, Level 4 = 50, Level 5 = 100
var upgradeCost = 0;
if (s.level === 1) upgradeCost = 10;else if (s.level === 2) upgradeCost = 20;else if (s.level === 3) upgradeCost = 50;else if (s.level === 4) upgradeCost = 100;
if (coins < upgradeCost) {
// Flash red
tween(upgradeTxt, {
fill: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(upgradeTxt, {
fill: 0x00ff00
}, {
duration: 200
});
}
});
return;
}
coins -= upgradeCost;
coinTxt.setText('Coins: ' + coins);
s.level += 1;
// Change type and visuals on upgrade
if (s.level === 2) {
s.setType(2);
}
if (s.level === 3) {
s.setType(3);
}
if (s.level === 4) {
s.setType(4);
}
if (s.level === 5) {
s.setType(5);
}
// Show upgraded text
upgradeTxt.setText('Upgraded!');
upgradeTxt.fill = "#ffff00";
LK.setTimeout(function () {
if (upgradeTxt) {
upgradeTxt.setText('Upgrade');
upgradeTxt.fill = "#00ff00";
upgradeTxt.visible = false;
}
}, 1000);
};
} else {
// If already a soldier, tap to show upgrade
var s = wallSpotStates[idx];
if (s && s.upgradeTxt && s.level < 5) {
s.upgradeTxt.visible = true;
LK.setTimeout(function () {
if (s.upgradeTxt) s.upgradeTxt.visible = false;
}, 1000);
}
}
};
})(i);
}
// Start first wave
// Red zombie spawn plan: wave 10-20, 1 red per wave; wave 11, 2 reds; otherwise, 1 red per wave 1-10
var redZombiePlan = {}; // wave number -> array of 0/1 (1=red)
function setupRedZombiePlan() {
// For waves 1-9: 1 red per wave
for (var w = 1; w <= 9; ++w) {
var arr = [];
var totalZ = 5 + w * 2;
for (var i = 0; i < totalZ; ++i) arr.push(0);
arr[0] = 1; // Always first zombie is red (could randomize if desired)
// Shuffle so red is not always first
for (var i = arr.length - 1; i > 0; --i) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
redZombiePlan[w] = arr;
}
// Wave 10: 1 red
var arr10 = [];
var totalZ10 = 5 + 10 * 2;
for (var i = 0; i < totalZ10; ++i) arr10.push(0);
arr10[0] = 1;
for (var i = arr10.length - 1; i > 0; --i) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = arr10[i];
arr10[i] = arr10[j];
arr10[j] = tmp;
}
redZombiePlan[10] = arr10;
// Wave 11: 2 reds
var arr11 = [];
var totalZ11 = 5 + 11 * 2;
for (var i = 0; i < totalZ11; ++i) arr11.push(0);
arr11[0] = 1;
arr11[1] = 1;
for (var i = arr11.length - 1; i > 0; --i) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = arr11[i];
arr11[i] = arr11[j];
arr11[j] = tmp;
}
redZombiePlan[11] = arr11;
// Waves 12-20: 1 red per wave
for (var w = 12; w <= 20; ++w) {
var arr = [];
var totalZ = 5 + w * 2;
for (var i = 0; i < totalZ; ++i) arr.push(0);
arr[0] = 1;
for (var i = arr.length - 1; i > 0; --i) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
redZombiePlan[w] = arr;
}
}
setupRedZombiePlan();
function startWave() {
waveInProgress = true;
spawnIdx = 0;
zombiesToSpawn = 5 + wave * 2;
spawnTimer = 0;
waveTxt.setText('Wave: ' + wave);
}
startWave();
// Spawn zombie
function spawnZombie() {
var z = new Zombie();
// Stats scale with wave
var hp = 5; // Green zombie health is always 5
var speed = 1.2 + 0.08 * wave;
var reward = 1 + Math.floor(wave / 2);
// Red zombie logic
var makeRed = false;
if (wave >= 15 && wave <= 20) {
// Only red zombies between wave 15 and 20
makeRed = true;
} else if (wave >= 1 && wave <= 20 && redZombiePlan[wave]) {
if (spawnIdx < redZombiePlan[wave].length && redZombiePlan[wave][spawnIdx] === 1) {
makeRed = true;
}
} else if (wave > 20) {
// After wave 20, only green zombies
makeRed = false;
}
if (makeRed) {
z.setRed();
hp = 10; // Red zombie health is always 10
reward = reward * 2;
}
z.setStats(hp, speed, reward);
z.setPathIndex(0);
z.x = path[0].x;
z.y = path[0].y;
zombies.push(z);
game.addChild(z);
}
// Main game update
game.update = function () {
if (gameOver) return;
// Spawn zombies for wave
if (waveInProgress && spawnIdx < zombiesToSpawn) {
if (spawnTimer <= 0) {
spawnZombie();
spawnIdx++;
spawnTimer = 40 - Math.min(wave * 2, 30); // Faster spawns later
} else {
spawnTimer--;
}
}
// Update zombies
for (var i = zombies.length - 1; i >= 0; --i) {
var z = zombies[i];
z.update();
if (z.dead) {
// Reward coins
if (z.isRed) {
coins += 2;
} else {
coins += 1;
}
coinTxt.setText('Coins: ' + coins);
zombies.splice(i, 1);
continue;
}
if (z.pathIndex >= path.length - 1 && !z.dead) {
// Reached base
baseHp--;
baseHpTxt.setText('Base: ' + baseHp);
LK.effects.flashObject(baseNode, 0xff0000, 400);
z.dead = true;
z.destroy();
zombies.splice(i, 1);
if (baseHp <= 0) {
gameOver = true;
LK.effects.flashScreen(0xff0000, 1200);
LK.showGameOver();
return;
}
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
b.update();
if (!b.parent) {
bullets.splice(i, 1);
}
}
// Update soldiers
for (var i = 0; i < soldiers.length; ++i) {
soldiers[i].update();
}
// Check if wave is over
if (waveInProgress && spawnIdx >= zombiesToSpawn && zombies.length === 0) {
waveInProgress = false;
// Next wave after short delay
LK.setTimeout(function () {
wave++;
startWave();
}, 1200);
}
};
// Allow dragging soldiers to swap positions (optional, MVP skips this)
// Prevent placing elements in top left 100x100 (already handled by GUI placement)
// No background, music, or sound per requirements
// No pause, leaderboard, or game over handling (LK does this) ===================================================================
--- original.js
+++ change.js
@@ -346,9 +346,9 @@
x: 1800,
y: 400
} // Base (top right)
];
-// Wall spot positions (original, fewer and simpler positions)
+// Wall spot positions (now 6 unit placement positions)
var wallSpots = [{
x: 400,
y: 800
}, {
Soilder. In-Game asset. 2d. High contrast. No shadows
one-gun soldier. In-Game asset. 2d. High contrast. No shadows
soldier with 2 kate ak47 in his hand. In-Game asset. 2d. High contrast. No shadows
soldier with rifle. In-Game asset. 2d. High contrast. No shadows
Zombie. In-Game asset. 2d. High contrast. No shadows
Zombie. In-Game asset. 2d. High contrast. No shadows