User prompt
oyun ilk açıldığında oluşturulan ilk dalganın yol uzunluğu 300 pixel olsun. ve bu her seferinde aynı olsun
User prompt
oyun ilk açıldığında ilk dalga için oluşturulan yol uzunluğu 300 pixel olsun
User prompt
oyunda düzeltme yapmak istiyorum. oyun ilk açıldığında oluşturulan ilk dalganın yol uzunluğu 300 pixel olsun.
User prompt
oyun ilk açıldığında oluşturulan ilk dalganın yol uzunluğu 300 pixel olsun
User prompt
oyun ilk açıldığında oluşturulan ilk dalganın yol uzunluğu ekranın yüksekliği kadar olsun
User prompt
oyun ilk açıldığında oluşturulan ilk dalganın yol uzunluğu 50 yaratık sığcak kadar uzun olsun
User prompt
oyun ilk açıldığında oluşturulan ilk dalganın yol uzunluğu 30 yaratık sığcak kadar uzun olsun
User prompt
oyun ilk açıldığında oluşturulan ilk dalganın yol uzunluğu 30 kareden oluşsun
User prompt
yol oluşturulurken yol kendi üzerinden geçmesin
User prompt
hala düz oluyor lütfen her yolu oluştururken 3n az 3 yerde dönüş yaparmısın
User prompt
yeni yol oluşturulurken en az 3 yerde dönüş olsun
User prompt
yol oluşturulurken yola değmeden oluştursun
User prompt
oyunun ilk başında oluşturulan yol dışında her oluşturulan yeni yol bir önceki yolun %10 u kadar daha uzun olsun
User prompt
yol oluşturulurken en az 3 dönüş olsun
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'x')' in or related to this line: 'base.x = gamePath[gamePath.length - 1].x;' Line Number: 1109
User prompt
yol oluşturma oyun ilk başında da gerçekleşsin
User prompt
yol karelerden oluşmasın daha düz gerçek bir yolmuş gibi gözüksün
User prompt
yol oluşturulurken yol kendine değmesin ve üzerinden geçmesin
User prompt
yeni yol uluşturulurken öncekinden %5 daha uzun olsun ve mutlaka en az 2 dönüş olsun
User prompt
yollar oluşturulurken birbirine değmesin ve kesişmesin
User prompt
yollar oluşturulurken birbirinin üzerinden geçmesin
User prompt
sadece özelliklerini alsın aynı yolu yapıyor bunu düzeltirmisin
User prompt
oyun ilk başladığındaki yolun özelliklerine benzer olarak yol değişsin ve yüzde 3 kadar uzasın
User prompt
her yol oluşumunda lütfen dönüşler olsun ve yol kısalmasın önceki yolun uzunluğunun yüzde 3 civarı kadar uzunluğu artsın
User prompt
yollar oluşturulurken çapraz yamuk oluşmasın lütfen hep düz olsun sadece dönüşler 90 derece olsun. ayrıca her yoldeğişiminde yol yüzde 3 oranında uzasın
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (tower, target, towerType) {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.tower = tower;
self.target = target;
self.towerType = towerType;
self.speed = 8;
// Calculate direction from tower to target
var dx = target.x - tower.x;
var dy = target.y - tower.y;
var distance = Math.sqrt(dx * dx + dy * dy);
self.vx = dx / distance * self.speed;
self.vy = dy / distance * self.speed;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Check collision with intended target only
if (self.target && self.target.parent && self.intersects(self.target)) {
self.hit();
return;
}
// Remove bullet if target is destroyed
if (!self.target || !self.target.parent) {
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
return;
}
// Remove if off screen
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
}
};
self.hit = function () {
LK.getSound('hit').play();
if (self.towerType === 'splash') {
// Splash damage
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy && enemy.parent) {
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.tower.splashRadius) {
var killed = enemy.takeDamage(self.tower.damage);
if (killed) {
coins += enemy.reward;
enemy.destroy();
enemies.splice(i, 1);
}
}
}
}
// Create explosion effect
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
explosion.x = self.x;
explosion.y = self.y;
explosion.alpha = 0.7;
game.addChild(explosion);
tween(explosion, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
explosion.destroy();
}
});
} else {
// Regular damage
if (self.target && self.target.parent) {
var killed = self.target.takeDamage(self.tower.damage);
if (killed) {
coins += self.target.reward;
self.target.destroy();
var targetIndex = enemies.indexOf(self.target);
if (targetIndex !== -1) {
enemies.splice(targetIndex, 1);
}
}
// Apply slow effect if slow tower
if (self.towerType === 'slow' && !killed) {
self.target.applySlow(self.tower.slowFactor, self.tower.slowDuration);
}
}
}
// Remove bullet
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
};
return self;
});
// Game variables
var Enemy = Container.expand(function (type, pathIndex) {
var self = Container.call(this);
// Enemy properties based on type
var enemyConfig = {
basic: {
asset: 'basicEnemy',
health: 100,
speed: 2,
reward: 10
},
fast: {
asset: 'fastEnemy',
health: 60,
speed: 4,
reward: 15
},
tank: {
asset: 'tankEnemy',
health: 300,
speed: 1,
reward: 25
},
boss: {
asset: 'tankEnemy',
health: 1000,
speed: 1.5,
reward: 100
}
};
var config = enemyConfig[type] || enemyConfig.basic;
var enemyGraphics = self.attachAsset(config.asset, {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = config.health;
self.health = config.health;
self.speed = config.speed;
self.reward = config.reward;
self.pathIndex = pathIndex || 0;
self.slowEffect = 1;
self.slowDuration = 0;
// Health bar
var healthBarBg = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.1,
y: -40
});
healthBarBg.tint = 0x333333;
self.addChild(healthBarBg);
var healthBar = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.1,
y: -40
});
healthBar.tint = 0x00FF00;
self.addChild(healthBar);
self.healthBar = healthBar;
self.takeDamage = function (damage) {
self.health -= damage;
var healthPercent = Math.max(0, self.health / self.maxHealth);
self.healthBar.scaleX = 0.6 * healthPercent;
// Health bar color changes
if (healthPercent > 0.6) {
self.healthBar.tint = 0x00FF00;
} else if (healthPercent > 0.3) {
self.healthBar.tint = 0xFFFF00;
} else {
self.healthBar.tint = 0xFF0000;
}
// Flash effect
tween(enemyGraphics, {
tint: 0xFF0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
return self.health <= 0;
};
self.applySlow = function (factor, duration) {
self.slowEffect = Math.min(self.slowEffect, factor);
self.slowDuration = Math.max(self.slowDuration, duration);
};
self.update = function () {
// Update slow effect
if (self.slowDuration > 0) {
self.slowDuration--;
if (self.slowDuration <= 0) {
self.slowEffect = 1;
}
}
// Move along path
if (self.pathIndex < gamePath.length - 1 && gamePath[self.pathIndex + 1]) {
var currentTarget = gamePath[self.pathIndex + 1];
var dx = currentTarget.x - self.x;
var dy = currentTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20) {
self.pathIndex++;
if (self.pathIndex >= gamePath.length - 1) {
// Reached base
baseHealth--;
return;
}
} else {
var moveSpeed = self.speed * self.slowEffect;
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
} else if (self.pathIndex >= gamePath.length - 1) {
// Reached base
baseHealth--;
return;
}
};
return self;
});
var Tower = Container.expand(function (type) {
var self = Container.call(this);
// Tower configurations
var towerConfig = {
basic: {
asset: 'basicTower',
damage: 25,
range: 180,
fireRate: 60,
cost: 100,
upgradeCost: 75
},
splash: {
asset: 'splashTower',
damage: 40,
range: 150,
fireRate: 90,
cost: 200,
upgradeCost: 150,
splashRadius: 80
},
slow: {
asset: 'slowTower',
damage: 15,
range: 200,
fireRate: 45,
cost: 150,
upgradeCost: 100,
slowFactor: 0.5,
slowDuration: 120
}
};
var config = towerConfig[type] || towerConfig.basic;
var towerGraphics = self.attachAsset(config.asset, {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type;
self.damage = config.damage;
self.range = config.range;
self.fireRate = config.fireRate;
self.cost = config.cost;
self.upgradeCost = config.upgradeCost;
self.splashRadius = config.splashRadius;
self.slowFactor = config.slowFactor;
self.slowDuration = config.slowDuration;
self.lastShot = 0;
self.level = 1;
// Range indicator (hidden by default)
var rangeIndicator = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.range / 50,
scaleY: self.range / 50
});
rangeIndicator.tint = 0x00FF00;
rangeIndicator.alpha = 0.2;
rangeIndicator.visible = false;
self.addChild(rangeIndicator);
self.rangeIndicator = rangeIndicator;
self.showRange = function () {
self.rangeIndicator.visible = true;
};
self.hideRange = function () {
self.rangeIndicator.visible = false;
};
self.canShoot = function () {
return LK.ticks - self.lastShot >= self.fireRate;
};
self.findTarget = function () {
var closestEnemy = null;
var closestDistance = self.range;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (enemy && enemy.parent) {
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.range && distance < closestDistance) {
closestEnemy = enemy;
closestDistance = distance;
}
}
}
return closestEnemy;
};
self.shoot = function (target) {
if (!self.canShoot()) return;
self.lastShot = LK.ticks;
// Create bullet
var bullet = new Bullet(self, target, self.type);
bullet.x = self.x;
bullet.y = self.y;
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.upgrade = function () {
if (coins >= self.upgradeCost) {
coins -= self.upgradeCost;
self.level++;
self.damage = Math.floor(self.damage * 1.5);
self.range = Math.floor(self.range * 1.1);
self.upgradeCost = Math.floor(self.upgradeCost * 1.8);
// Update global tower info stats
towerInfoStats[self.type].level = Math.max(towerInfoStats[self.type].level, self.level);
towerInfoStats[self.type].damage = Math.max(towerInfoStats[self.type].damage, self.damage);
towerInfoStats[self.type].upgradeCost = Math.max(towerInfoStats[self.type].upgradeCost, self.upgradeCost);
// Visual upgrade effect
tween(towerGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(towerGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
// Update range indicator
self.rangeIndicator.scaleX = self.range / 50;
self.rangeIndicator.scaleY = self.range / 50;
return true;
}
return false;
};
self.down = function (x, y, obj) {
selectedTower = self;
self.showRange();
};
self.update = function () {
// Find target in range
var target = self.findTarget();
if (target) {
// Rotate tower towards target
var angle = Math.atan2(target.y - self.y, target.x - self.x);
towerGraphics.rotation = angle;
// Shoot if ready
if (self.canShoot()) {
self.shoot(target);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x4a6b3a
});
/****
* Game Code
****/
// Sounds
// Game elements
// Enemy assets
// Tower assets
// Game variables
var gamePath = [{
x: 100,
y: 400
}, {
x: 500,
y: 400
}, {
x: 500,
y: 800
}, {
x: 900,
y: 800
}, {
x: 900,
y: 1200
}, {
x: 1400,
y: 1200
}, {
x: 1400,
y: 1600
}, {
x: 1800,
y: 1600
}];
var enemies = [];
var towers = [];
var bullets = [];
var coins = 300;
var baseHealth = 20;
var currentWave = 1;
var enemiesSpawned = 0;
var enemiesPerWave = 5;
var waveDelay = 0;
var selectedTower = null;
var towerInfoPanel = null;
var bossWave = false;
var bossSpawned = false;
var pathExtensionFactor = 1.0;
// Draw path with visible tiles
for (var i = 0; i < gamePath.length; i++) {
var pathTile = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5
});
pathTile.x = gamePath[i].x;
pathTile.y = gamePath[i].y;
pathTile.alpha = 0.8;
pathTile.tint = 0x8B4513;
game.addChild(pathTile);
}
// Draw connecting path segments
for (var i = 0; i < gamePath.length - 1; i++) {
var startPoint = gamePath[i];
var endPoint = gamePath[i + 1];
var dx = endPoint.x - startPoint.x;
var dy = endPoint.y - startPoint.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var segments = Math.ceil(distance / 50);
for (var j = 1; j < segments; j++) {
var t = j / segments;
var segmentX = startPoint.x + dx * t;
var segmentY = startPoint.y + dy * t;
var segmentTile = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
segmentTile.x = segmentX;
segmentTile.y = segmentY;
segmentTile.alpha = 0.6;
segmentTile.tint = 0x8B4513;
game.addChild(segmentTile);
}
}
// Create base
var base = LK.getAsset('base', {
anchorX: 0.5,
anchorY: 0.5
});
base.x = gamePath[gamePath.length - 1].x;
base.y = gamePath[gamePath.length - 1].y;
game.addChild(base);
// Create baslangic image at spawn point
var baslangicImage = LK.getAsset('baslangic', {
anchorX: 0.5,
anchorY: 0.5
});
baslangicImage.x = gamePath[0].x;
baslangicImage.y = gamePath[0].y;
game.addChild(baslangicImage);
// UI Elements
var coinsText = new Text2('Coins: ' + coins, {
size: 50,
fill: 0xFFD700
});
coinsText.anchor.set(0, 0);
coinsText.x = 150;
coinsText.y = 20;
LK.gui.topLeft.addChild(coinsText);
var healthText = new Text2('Base Health: ' + baseHealth, {
size: 50,
fill: 0xFF0000
});
healthText.anchor.set(1, 0);
healthText.y = 20;
LK.gui.topRight.addChild(healthText);
var waveText = new Text2('Wave: ' + currentWave, {
size: 50,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
waveText.y = 20;
LK.gui.top.addChild(waveText);
// Tower selection buttons
var basicTowerImage = LK.getAsset('basicTower', {
anchorX: 0.5,
anchorY: 1,
scaleX: 0.8,
scaleY: 0.8
});
basicTowerImage.x = 60;
basicTowerImage.y = -20;
LK.gui.bottomLeft.addChild(basicTowerImage);
var basicTowerBtn = new Text2('Basic (100)', {
size: 40,
fill: 0x4444FF
});
basicTowerBtn.anchor.set(0, 1);
basicTowerBtn.x = 100;
basicTowerBtn.y = -20;
LK.gui.bottomLeft.addChild(basicTowerBtn);
var basicTowerInfo = new Text2('Level: 1 | DMG: 25 | Upgrade: 75', {
size: 25,
fill: 0xFFFFFF
});
basicTowerInfo.anchor.set(0, 1);
basicTowerInfo.x = 350;
basicTowerInfo.y = -20;
LK.gui.bottomLeft.addChild(basicTowerInfo);
var splashTowerImage = LK.getAsset('splashTower', {
anchorX: 0.5,
anchorY: 1,
scaleX: 0.8,
scaleY: 0.8
});
splashTowerImage.x = 60;
splashTowerImage.y = -80;
LK.gui.bottomLeft.addChild(splashTowerImage);
var splashTowerBtn = new Text2('Splash (200)', {
size: 40,
fill: 0xFF4444
});
splashTowerBtn.anchor.set(0, 1);
splashTowerBtn.x = 100;
splashTowerBtn.y = -80;
LK.gui.bottomLeft.addChild(splashTowerBtn);
var splashTowerInfo = new Text2('Level: 1 | DMG: 40 | Upgrade: 150', {
size: 25,
fill: 0xFFFFFF
});
splashTowerInfo.anchor.set(0, 1);
splashTowerInfo.x = 350;
splashTowerInfo.y = -80;
LK.gui.bottomLeft.addChild(splashTowerInfo);
var slowTowerImage = LK.getAsset('slowTower', {
anchorX: 0.5,
anchorY: 1,
scaleX: 0.8,
scaleY: 0.8
});
slowTowerImage.x = 60;
slowTowerImage.y = -140;
LK.gui.bottomLeft.addChild(slowTowerImage);
var slowTowerBtn = new Text2('Slow (150)', {
size: 40,
fill: 0x44FF44
});
slowTowerBtn.anchor.set(0, 1);
slowTowerBtn.x = 100;
slowTowerBtn.y = -140;
LK.gui.bottomLeft.addChild(slowTowerBtn);
var slowTowerInfo = new Text2('Level: 1 | DMG: 15 | Upgrade: 100', {
size: 25,
fill: 0xFFFFFF
});
slowTowerInfo.anchor.set(0, 1);
slowTowerInfo.x = 350;
slowTowerInfo.y = -140;
LK.gui.bottomLeft.addChild(slowTowerInfo);
// Add levelatla upgrade buttons
var basicLevelatlaBtn = LK.getAsset('levelatla', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
basicLevelatlaBtn.x = 770;
basicLevelatlaBtn.y = -40;
LK.gui.bottomLeft.addChild(basicLevelatlaBtn);
var splashLevelatlaBtn = LK.getAsset('levelatla', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
splashLevelatlaBtn.x = 770;
splashLevelatlaBtn.y = -100;
LK.gui.bottomLeft.addChild(splashLevelatlaBtn);
var slowLevelatlaBtn = LK.getAsset('levelatla', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
slowLevelatlaBtn.x = 770;
slowLevelatlaBtn.y = -160;
LK.gui.bottomLeft.addChild(slowLevelatlaBtn);
// Selected tower type
var selectedTowerType = 'basic';
// Tower info tracking
var towerInfoStats = {
basic: {
level: 1,
damage: 25,
upgradeCost: 75
},
splash: {
level: 1,
damage: 40,
upgradeCost: 150
},
slow: {
level: 1,
damage: 15,
upgradeCost: 100
}
};
// Add background highlights for tower selection
var basicTowerBg = LK.getAsset('pathTile', {
anchorX: 0,
anchorY: 0.5,
scaleX: 8.0,
scaleY: 0.8
});
basicTowerBg.tint = 0x00FF00;
basicTowerBg.alpha = 0.3;
basicTowerBg.x = 10;
basicTowerBg.y = -40;
LK.gui.bottomLeft.addChild(basicTowerBg);
var splashTowerBg = LK.getAsset('pathTile', {
anchorX: 0,
anchorY: 0.5,
scaleX: 8.0,
scaleY: 0.8
});
splashTowerBg.tint = 0x00FF00;
splashTowerBg.alpha = 0;
splashTowerBg.x = 10;
splashTowerBg.y = -100;
LK.gui.bottomLeft.addChild(splashTowerBg);
var slowTowerBg = LK.getAsset('pathTile', {
anchorX: 0,
anchorY: 0.5,
scaleX: 8.0,
scaleY: 0.8
});
slowTowerBg.tint = 0x00FF00;
slowTowerBg.alpha = 0;
slowTowerBg.x = 10;
slowTowerBg.y = -160;
LK.gui.bottomLeft.addChild(slowTowerBg);
// Helper functions
function updateUI() {
coinsText.setText('Coins: ' + coins);
healthText.setText('Base Health: ' + baseHealth);
waveText.setText('Wave: ' + currentWave + (bossWave ? ' (BOSS)' : ''));
// Update button colors based on affordability
basicTowerBtn.tint = coins >= 100 ? 0x4444FF : 0x666666;
splashTowerBtn.tint = coins >= 200 ? 0xFF4444 : 0x666666;
slowTowerBtn.tint = coins >= 150 ? 0x44FF44 : 0x666666;
// Update tower info displays
basicTowerInfo.setText('Level: ' + towerInfoStats.basic.level + ' | DMG: ' + towerInfoStats.basic.damage + ' | Upgrade: ' + towerInfoStats.basic.upgradeCost);
splashTowerInfo.setText('Level: ' + towerInfoStats.splash.level + ' | DMG: ' + towerInfoStats.splash.damage + ' | Upgrade: ' + towerInfoStats.splash.upgradeCost);
slowTowerInfo.setText('Level: ' + towerInfoStats.slow.level + ' | DMG: ' + towerInfoStats.slow.damage + ' | Upgrade: ' + towerInfoStats.slow.upgradeCost);
// Update tower selection highlighting
basicTowerBg.alpha = selectedTowerType === 'basic' ? 0.3 : 0;
splashTowerBg.alpha = selectedTowerType === 'splash' ? 0.3 : 0;
slowTowerBg.alpha = selectedTowerType === 'slow' ? 0.3 : 0;
// Add pulsing animation to selected tower
var selectedBg = selectedTowerType === 'basic' ? basicTowerBg : selectedTowerType === 'splash' ? splashTowerBg : slowTowerBg;
if (selectedBg.alpha > 0) {
var pulseAlpha = 0.3 + Math.sin(LK.ticks * 0.1) * 0.1;
selectedBg.alpha = pulseAlpha;
}
// Show/hide levelatla buttons based on available coins
basicLevelatlaBtn.visible = coins >= towerInfoStats.basic.upgradeCost;
splashLevelatlaBtn.visible = coins >= towerInfoStats.splash.upgradeCost;
slowLevelatlaBtn.visible = coins >= towerInfoStats.slow.upgradeCost;
}
function canPlaceTower(x, y) {
// Check if position is not on path points
for (var i = 0; i < gamePath.length; i++) {
var pathPoint = gamePath[i];
var distance = Math.sqrt((x - pathPoint.x) * (x - pathPoint.x) + (y - pathPoint.y) * (y - pathPoint.y));
if (distance < 80) {
return false;
}
}
// Check if position is not on path segments
for (var i = 0; i < gamePath.length - 1; i++) {
var startPoint = gamePath[i];
var endPoint = gamePath[i + 1];
// Calculate distance from point to line segment
var A = x - startPoint.x;
var B = y - startPoint.y;
var C = endPoint.x - startPoint.x;
var D = endPoint.y - startPoint.y;
var dot = A * C + B * D;
var lenSq = C * C + D * D;
var param = lenSq != 0 ? dot / lenSq : -1;
var xx, yy;
if (param < 0) {
xx = startPoint.x;
yy = startPoint.y;
} else if (param > 1) {
xx = endPoint.x;
yy = endPoint.y;
} else {
xx = startPoint.x + param * C;
yy = startPoint.y + param * D;
}
var dx = x - xx;
var dy = y - yy;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
return false;
}
}
// Check if position is not too close to other towers
for (var i = 0; i < towers.length; i++) {
var tower = towers[i];
var distance = Math.sqrt((x - tower.x) * (x - tower.x) + (y - tower.y) * (y - tower.y));
if (distance < 100) {
return false;
}
}
return true;
}
function spawnEnemy() {
var enemyTypes = ['basic', 'fast', 'tank'];
var waveMultiplier = Math.floor((currentWave - 1) / 3);
// Choose enemy type based on wave
var enemyType = 'basic';
if (currentWave > 3) {
enemyType = enemyTypes[Math.floor(Math.random() * 2)]; // basic or fast
}
if (currentWave > 6) {
enemyType = enemyTypes[Math.floor(Math.random() * 3)]; // all types
}
var enemy = new Enemy(enemyType, 0);
enemy.x = gamePath[0].x;
enemy.y = gamePath[0].y;
// Scale health for later waves
enemy.maxHealth *= 1 + waveMultiplier * 0.5;
enemy.health = enemy.maxHealth;
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
function generateNewPath() {
// Clear existing path tiles
for (var i = 0; i < game.children.length; i++) {
var child = game.children[i];
if (child.tint === 0x8B4513) {
child.destroy();
i--;
}
}
// Calculate middle 80% vertical bounds (10% margin top and bottom)
var screenHeight = 2732;
var topMargin = screenHeight * 0.1; // 10% from top
var bottomMargin = screenHeight * 0.9; // 90% from top (10% margin at bottom)
var minY = topMargin;
var maxY = bottomMargin;
// Increase path length by 5% each wave
pathExtensionFactor += 0.05; // 5% increase per wave
// Function to calculate distance from point to line segment
function distanceToLineSegment(point, lineStart, lineEnd) {
var A = point.x - lineStart.x;
var B = point.y - lineStart.y;
var C = lineEnd.x - lineStart.x;
var D = lineEnd.y - lineStart.y;
var dot = A * C + B * D;
var lenSq = C * C + D * D;
if (lenSq === 0) return Math.sqrt(A * A + B * B);
var param = dot / lenSq;
var xx, yy;
if (param < 0) {
xx = lineStart.x;
yy = lineStart.y;
} else if (param > 1) {
xx = lineEnd.x;
yy = lineEnd.y;
} else {
xx = lineStart.x + param * C;
yy = lineStart.y + param * D;
}
var dx = point.x - xx;
var dy = point.y - yy;
return Math.sqrt(dx * dx + dy * dy);
}
// Function to check if two line segments intersect
function doLinesIntersect(p1, q1, p2, q2) {
function orientation(p, q, r) {
var val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
if (val === 0) return 0; // collinear
return val > 0 ? 1 : 2; // clockwise or counterclockwise
}
function onSegment(p, q, r) {
return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
}
var o1 = orientation(p1, q1, p2);
var o2 = orientation(p1, q1, q2);
var o3 = orientation(p2, q2, p1);
var o4 = orientation(p2, q2, q1);
// General case
if (o1 !== o2 && o3 !== o4) return true;
// Special cases
if (o1 === 0 && onSegment(p1, p2, q1)) return true;
if (o2 === 0 && onSegment(p1, q2, q1)) return true;
if (o3 === 0 && onSegment(p2, p1, q2)) return true;
if (o4 === 0 && onSegment(p2, q1, q2)) return true;
return false;
}
// Function to check if proposed segment would intersect or get too close to existing path
function wouldIntersectPath(newStart, newEnd, existingPath) {
var minDistance = 150; // Increased minimum distance to prevent touching
// Check intersection with ALL existing segments (not just non-adjacent ones)
for (var i = 0; i < existingPath.length - 1; i++) {
var segStart = existingPath[i];
var segEnd = existingPath[i + 1];
// Only skip the immediate previous segment that connects to newStart
if (i === existingPath.length - 2) continue;
// Check for direct intersection
if (doLinesIntersect(newStart, newEnd, segStart, segEnd)) {
return true;
}
// Check minimum distance between segments - more comprehensive checking
var dist1 = distanceToLineSegment(newStart, segStart, segEnd);
var dist2 = distanceToLineSegment(newEnd, segStart, segEnd);
var dist3 = distanceToLineSegment(segStart, newStart, newEnd);
var dist4 = distanceToLineSegment(segEnd, newStart, newEnd);
// Additional check: distance between segment midpoints
var newMidX = (newStart.x + newEnd.x) / 2;
var newMidY = (newStart.y + newEnd.y) / 2;
var existingMidX = (segStart.x + segEnd.x) / 2;
var existingMidY = (segStart.y + segEnd.y) / 2;
var midDistance = Math.sqrt((newMidX - existingMidX) * (newMidX - existingMidX) + (newMidY - existingMidY) * (newMidY - existingMidY));
if (dist1 < minDistance || dist2 < minDistance || dist3 < minDistance || dist4 < minDistance || midDistance < minDistance) {
return true;
}
}
// Check distance to ALL existing path points (not just non-adjacent ones)
for (var i = 0; i < existingPath.length; i++) {
var pathPoint = existingPath[i];
// Only skip the immediate previous point that connects to newStart
if (i === existingPath.length - 1) continue;
var distToStart = Math.sqrt((newStart.x - pathPoint.x) * (newStart.x - pathPoint.x) + (newStart.y - pathPoint.y) * (newStart.y - pathPoint.y));
var distToEnd = Math.sqrt((newEnd.x - pathPoint.x) * (newEnd.x - pathPoint.x) + (newEnd.y - pathPoint.y) * (newEnd.y - pathPoint.y));
// Additional check: distance from path point to the new segment
var distFromPointToNewSeg = distanceToLineSegment(pathPoint, newStart, newEnd);
if (distToStart < minDistance || distToEnd < minDistance || distFromPointToNewSeg < minDistance) {
return true;
}
}
// Additional comprehensive check: ensure the new segment doesn't create any loops or near-loops
// Check if newEnd gets too close to any earlier parts of the path (beyond immediate predecessor)
for (var i = 0; i < existingPath.length - 2; i++) {
var earlyPoint = existingPath[i];
var distToEarlyPoint = Math.sqrt((newEnd.x - earlyPoint.x) * (newEnd.x - earlyPoint.x) + (newEnd.y - earlyPoint.y) * (newEnd.y - earlyPoint.y));
if (distToEarlyPoint < minDistance * 1.2) {
// Slightly larger distance for loop prevention
return true;
}
}
return false;
}
// Create varied path shapes while maintaining characteristics
gamePath = [];
var baseSegmentLength = Math.floor(300 * pathExtensionFactor); // Apply 5% extension
var numSegments = Math.max(6, Math.floor(5 + currentWave * 0.5)); // More segments in later waves
var turnCount = 0; // Track number of turns
// Starting position - randomize within left area
var startX = 100 + Math.random() * 200;
var startY = minY + 100 + Math.random() * (maxY - minY - 200);
gamePath.push({
x: startX,
y: startY
});
var currentX = startX;
var currentY = startY;
var direction = 0; // 0=right, 1=down, 2=left, 3=up
// Generate varied path with only 90-degree turns
for (var seg = 0; seg < numSegments; seg++) {
var segmentLength = Math.max(250, baseSegmentLength + Math.random() * 200 - 100); // Increased minimum segment length
var attempts = 0;
var validSegmentFound = false;
while (!validSegmentFound && attempts < 50) {
// Increased max attempts
var shouldTurn = false;
// Force turn if we need more turns to reach minimum of 2
if (turnCount < 2 && seg >= numSegments - (2 - turnCount)) {
shouldTurn = true;
} else if (seg > 0 && Math.random() < 0.7) {
shouldTurn = true;
}
if (shouldTurn) {
// Change direction (90-degree turn)
var oldDirection = direction;
var possibleDirections = [];
if (direction !== 2 && currentX + segmentLength < 1900) possibleDirections.push(0); // right
if (direction !== 3 && currentY + segmentLength < maxY) possibleDirections.push(1); // down
if (direction !== 0 && currentX - segmentLength > 100) possibleDirections.push(2); // left
if (direction !== 1 && currentY - segmentLength > minY) possibleDirections.push(3); // up
if (possibleDirections.length > 0) {
direction = possibleDirections[Math.floor(Math.random() * possibleDirections.length)];
if (direction !== oldDirection) {
turnCount++;
}
}
}
// Calculate next position based on direction
var nextX = currentX;
var nextY = currentY;
if (direction === 0) {
// right
nextX = Math.min(1900, currentX + segmentLength);
} else if (direction === 1) {
// down
nextY = Math.min(maxY, currentY + segmentLength);
} else if (direction === 2) {
// left
nextX = Math.max(100, currentX - segmentLength);
} else if (direction === 3) {
// up
nextY = Math.max(minY, currentY - segmentLength);
}
// Ensure we're moving towards the general end area in later segments
if (seg > numSegments * 0.6) {
if (nextX < 1500 && direction !== 2) {
nextX = Math.min(1900, currentX + segmentLength);
direction = 0;
}
}
// Check if this segment would intersect existing path
var proposedStart = {
x: currentX,
y: currentY
};
var proposedEnd = {
x: nextX,
y: nextY
};
// Only check intersection if we have at least 2 segments (to avoid checking the immediate previous segment)
if (gamePath.length < 2 || !wouldIntersectPath(proposedStart, proposedEnd, gamePath)) {
gamePath.push({
x: nextX,
y: nextY
});
currentX = nextX;
currentY = nextY;
validSegmentFound = true;
} else {
// Try different direction or shorter segment
segmentLength = Math.max(200, segmentLength * 0.7);
attempts++;
// If we've tried many times, try a completely different direction
if (attempts > 10) {
direction = (direction + 1) % 4;
segmentLength = baseSegmentLength;
}
}
}
if (!validSegmentFound) {
// Force a valid segment if we can't find one - try multiple directions
var fallbackFound = false;
var fallbackDirections = [0, 1, 2, 3]; // right, down, left, up
for (var fd = 0; fd < fallbackDirections.length && !fallbackFound; fd++) {
var fallbackDir = fallbackDirections[fd];
var fallbackLength = 200;
var fallbackX = currentX;
var fallbackY = currentY;
if (fallbackDir === 0 && currentX + fallbackLength < 1900) {
// right
fallbackX = currentX + fallbackLength;
} else if (fallbackDir === 1 && currentY + fallbackLength < maxY) {
// down
fallbackY = currentY + fallbackLength;
} else if (fallbackDir === 2 && currentX - fallbackLength > 100) {
// left
fallbackX = currentX - fallbackLength;
} else if (fallbackDir === 3 && currentY - fallbackLength > minY) {
// up
fallbackY = currentY - fallbackLength;
} else {
continue; // Try next direction
}
var fallbackStart = {
x: currentX,
y: currentY
};
var fallbackEnd = {
x: fallbackX,
y: fallbackY
};
// Check if this fallback direction works
if (gamePath.length < 2 || !wouldIntersectPath(fallbackStart, fallbackEnd, gamePath)) {
gamePath.push({
x: fallbackX,
y: fallbackY
});
currentX = fallbackX;
currentY = fallbackY;
direction = fallbackDir;
fallbackFound = true;
}
}
// If still no valid segment found, break the loop to prevent infinite generation
if (!fallbackFound) {
break;
}
}
}
// Ensure final path reaches right side of screen
if (currentX < 1600) {
gamePath.push({
x: Math.min(1900, currentX + 300),
y: currentY
});
}
// Redraw path tiles
for (var i = 0; i < gamePath.length; i++) {
var pathTile = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5
});
pathTile.x = gamePath[i].x;
pathTile.y = gamePath[i].y;
pathTile.alpha = 0.8;
pathTile.tint = 0x8B4513;
game.addChild(pathTile);
}
// Draw connecting segments
for (var i = 0; i < gamePath.length - 1; i++) {
var startPoint = gamePath[i];
var endPoint = gamePath[i + 1];
var dx = endPoint.x - startPoint.x;
var dy = endPoint.y - startPoint.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var segments = Math.ceil(distance / 50);
for (var j = 1; j < segments; j++) {
var t = j / segments;
var segmentX = startPoint.x + dx * t;
var segmentY = startPoint.y + dy * t;
var segmentTile = LK.getAsset('pathTile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
segmentTile.x = segmentX;
segmentTile.y = segmentY;
segmentTile.alpha = 0.6;
segmentTile.tint = 0x8B4513;
game.addChild(segmentTile);
}
}
// Update base position to new end position
base.x = gamePath[gamePath.length - 1].x;
base.y = gamePath[gamePath.length - 1].y;
// Update baslangic position to new start position
baslangicImage.x = gamePath[0].x;
baslangicImage.y = gamePath[0].y;
// Ensure base and baslangic stay in foreground
game.addChild(base);
game.addChild(baslangicImage);
}
function clearAllTowers() {
for (var i = towers.length - 1; i >= 0; i--) {
towers[i].destroy();
}
towers = [];
}
function spawnBossEnemy() {
var waveMultiplier = Math.floor((currentWave - 1) / 3);
var totalEnemyHealth = 0;
var enemyCount = enemiesPerWave * currentWave;
// Calculate total health of all enemies that would spawn in wave 5
for (var i = 0; i < enemyCount; i++) {
var baseHealth = 100; // Basic enemy health
if (currentWave > 3) baseHealth = 80; // Mix of basic and fast
if (currentWave > 6) baseHealth = 120; // Mix of all types
totalEnemyHealth += baseHealth * (1 + waveMultiplier * 0.5);
}
var boss = new Enemy('boss', 0);
boss.x = gamePath[0].x;
boss.y = gamePath[0].y;
boss.maxHealth = totalEnemyHealth;
boss.health = totalEnemyHealth;
boss.reward = 200;
enemies.push(boss);
game.addChild(boss);
bossSpawned = true;
}
function showTowerInfo(tower) {
if (!tower) return;
if (towerInfoPanel) {
towerInfoPanel.destroy();
}
var panel = LK.getAsset('base', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1.5
});
panel.tint = 0x333333;
panel.alpha = 0.8;
panel.x = tower.x;
panel.y = Math.max(150, tower.y - 150);
game.addChild(panel);
towerInfoPanel = panel;
var infoText = new Text2('Level: ' + tower.level + '\nDamage: ' + tower.damage + '\nUpgrade: ' + tower.upgradeCost, {
size: 25,
fill: 0xFFFFFF
});
infoText.anchor.set(0.5, 0.5);
infoText.x = 0;
infoText.y = -25;
panel.addChild(infoText);
if (coins >= tower.upgradeCost) {
var upgradeBtn = new Text2('UPGRADE', {
size: 30,
fill: 0x00FF00
});
upgradeBtn.anchor.set(0.5, 0.5);
upgradeBtn.y = 35;
panel.addChild(upgradeBtn);
}
}
// Event handlers
basicTowerBtn.down = function () {
selectedTowerType = 'basic';
if (selectedTower) {
selectedTower.hideRange();
selectedTower = null;
}
};
splashTowerBtn.down = function () {
selectedTowerType = 'splash';
if (selectedTower) {
selectedTower.hideRange();
selectedTower = null;
}
};
slowTowerBtn.down = function () {
selectedTowerType = 'slow';
if (selectedTower) {
selectedTower.hideRange();
selectedTower = null;
}
};
// Add click handlers for levelatla upgrade buttons
basicLevelatlaBtn.down = function () {
if (coins >= towerInfoStats.basic.upgradeCost) {
coins -= towerInfoStats.basic.upgradeCost;
towerInfoStats.basic.level++;
towerInfoStats.basic.damage = Math.floor(towerInfoStats.basic.damage * 1.5);
towerInfoStats.basic.upgradeCost = Math.floor(towerInfoStats.basic.upgradeCost * 1.8);
}
};
splashLevelatlaBtn.down = function () {
if (coins >= towerInfoStats.splash.upgradeCost) {
coins -= towerInfoStats.splash.upgradeCost;
towerInfoStats.splash.level++;
towerInfoStats.splash.damage = Math.floor(towerInfoStats.splash.damage * 1.5);
towerInfoStats.splash.upgradeCost = Math.floor(towerInfoStats.splash.upgradeCost * 1.8);
}
};
slowLevelatlaBtn.down = function () {
if (coins >= towerInfoStats.slow.upgradeCost) {
coins -= towerInfoStats.slow.upgradeCost;
towerInfoStats.slow.level++;
towerInfoStats.slow.damage = Math.floor(towerInfoStats.slow.damage * 1.5);
towerInfoStats.slow.upgradeCost = Math.floor(towerInfoStats.slow.upgradeCost * 1.8);
}
};
game.down = function (x, y, obj) {
// Hide tower range if clicking elsewhere
if (selectedTower) {
selectedTower.hideRange();
selectedTower = null;
}
// Try to place tower
var towerCost = selectedTowerType === 'basic' ? 100 : selectedTowerType === 'splash' ? 200 : 150;
if (coins >= towerCost && canPlaceTower(x, y)) {
var tower = new Tower(selectedTowerType);
tower.x = x;
tower.y = y;
towers.push(tower);
game.addChild(tower);
coins -= towerCost;
// Update tower info stats
towerInfoStats[selectedTowerType].level = Math.max(towerInfoStats[selectedTowerType].level, tower.level);
towerInfoStats[selectedTowerType].damage = Math.max(towerInfoStats[selectedTowerType].damage, tower.damage);
towerInfoStats[selectedTowerType].upgradeCost = Math.max(towerInfoStats[selectedTowerType].upgradeCost, tower.upgradeCost);
LK.getSound('place').play();
}
};
// Main game loop
game.update = function () {
// Spawn enemies
if (bossWave) {
// Boss wave spawning
if (waveDelay <= 0 && !bossSpawned) {
spawnBossEnemy();
waveDelay = 0;
} else {
waveDelay--;
}
} else {
// Normal wave spawning
if (waveDelay <= 0 && enemiesSpawned < enemiesPerWave * currentWave) {
spawnEnemy();
waveDelay = 60; // 1 second between spawns
} else {
waveDelay--;
}
}
// Check wave completion
if (bossWave) {
// Boss wave completion
if (bossSpawned && enemies.length === 0) {
// Clear all towers at wave completion
clearAllTowers();
// Generate new path with different shape and increased length
generateNewPath();
currentWave++;
enemiesSpawned = 0;
coins += 100 * currentWave; // Bonus coins for completing boss wave
waveDelay = 300; // 5 second break after boss
bossWave = false;
bossSpawned = false;
}
} else {
// Normal wave completion
if (enemiesSpawned >= enemiesPerWave * currentWave && enemies.length === 0) {
// Clear all towers at wave completion
clearAllTowers();
// Generate new path with different shape and increased length
generateNewPath();
// Check if this completes a set of 5 waves
if (currentWave % 5 === 0) {
// Start boss wave
bossWave = true;
bossSpawned = false;
waveDelay = 180; // 3 second break before boss
} else {
// Normal wave progression
currentWave++;
enemiesSpawned = 0;
coins += 25 * currentWave; // Bonus coins for completing wave
waveDelay = 180; // 3 second break between waves
}
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.pathIndex >= gamePath.length - 1) {
// Enemy reached base
baseHealth--;
enemy.destroy();
enemies.splice(i, 1);
}
}
// Update towers
for (var i = 0; i < towers.length; i++) {
towers[i].update();
}
// Update bullets
for (var i = 0; i < bullets.length; i++) {
bullets[i].update();
}
// Check game over
if (baseHealth <= 0) {
LK.setScore(currentWave - 1);
LK.showGameOver();
}
// Update UI
updateUI();
}; ===================================================================
--- original.js
+++ change.js
@@ -849,39 +849,57 @@
return false;
}
// Function to check if proposed segment would intersect or get too close to existing path
function wouldIntersectPath(newStart, newEnd, existingPath) {
- var minDistance = 120; // Minimum distance to prevent touching
- // Check intersection with existing segments
+ var minDistance = 150; // Increased minimum distance to prevent touching
+ // Check intersection with ALL existing segments (not just non-adjacent ones)
for (var i = 0; i < existingPath.length - 1; i++) {
var segStart = existingPath[i];
var segEnd = existingPath[i + 1];
- // Skip checking against the immediate previous segment
+ // Only skip the immediate previous segment that connects to newStart
if (i === existingPath.length - 2) continue;
// Check for direct intersection
if (doLinesIntersect(newStart, newEnd, segStart, segEnd)) {
return true;
}
- // Check minimum distance between segments
+ // Check minimum distance between segments - more comprehensive checking
var dist1 = distanceToLineSegment(newStart, segStart, segEnd);
var dist2 = distanceToLineSegment(newEnd, segStart, segEnd);
var dist3 = distanceToLineSegment(segStart, newStart, newEnd);
var dist4 = distanceToLineSegment(segEnd, newStart, newEnd);
- if (dist1 < minDistance || dist2 < minDistance || dist3 < minDistance || dist4 < minDistance) {
+ // Additional check: distance between segment midpoints
+ var newMidX = (newStart.x + newEnd.x) / 2;
+ var newMidY = (newStart.y + newEnd.y) / 2;
+ var existingMidX = (segStart.x + segEnd.x) / 2;
+ var existingMidY = (segStart.y + segEnd.y) / 2;
+ var midDistance = Math.sqrt((newMidX - existingMidX) * (newMidX - existingMidX) + (newMidY - existingMidY) * (newMidY - existingMidY));
+ if (dist1 < minDistance || dist2 < minDistance || dist3 < minDistance || dist4 < minDistance || midDistance < minDistance) {
return true;
}
}
- // Check distance to existing path points
+ // Check distance to ALL existing path points (not just non-adjacent ones)
for (var i = 0; i < existingPath.length; i++) {
var pathPoint = existingPath[i];
- // Skip checking against the immediate previous point
+ // Only skip the immediate previous point that connects to newStart
if (i === existingPath.length - 1) continue;
var distToStart = Math.sqrt((newStart.x - pathPoint.x) * (newStart.x - pathPoint.x) + (newStart.y - pathPoint.y) * (newStart.y - pathPoint.y));
var distToEnd = Math.sqrt((newEnd.x - pathPoint.x) * (newEnd.x - pathPoint.x) + (newEnd.y - pathPoint.y) * (newEnd.y - pathPoint.y));
- if (distToStart < minDistance || distToEnd < minDistance) {
+ // Additional check: distance from path point to the new segment
+ var distFromPointToNewSeg = distanceToLineSegment(pathPoint, newStart, newEnd);
+ if (distToStart < minDistance || distToEnd < minDistance || distFromPointToNewSeg < minDistance) {
return true;
}
}
+ // Additional comprehensive check: ensure the new segment doesn't create any loops or near-loops
+ // Check if newEnd gets too close to any earlier parts of the path (beyond immediate predecessor)
+ for (var i = 0; i < existingPath.length - 2; i++) {
+ var earlyPoint = existingPath[i];
+ var distToEarlyPoint = Math.sqrt((newEnd.x - earlyPoint.x) * (newEnd.x - earlyPoint.x) + (newEnd.y - earlyPoint.y) * (newEnd.y - earlyPoint.y));
+ if (distToEarlyPoint < minDistance * 1.2) {
+ // Slightly larger distance for loop prevention
+ return true;
+ }
+ }
return false;
}
// Create varied path shapes while maintaining characteristics
gamePath = [];
@@ -899,12 +917,13 @@
var currentY = startY;
var direction = 0; // 0=right, 1=down, 2=left, 3=up
// Generate varied path with only 90-degree turns
for (var seg = 0; seg < numSegments; seg++) {
- var segmentLength = Math.max(200, baseSegmentLength + Math.random() * 200 - 100); // Ensure minimum segment length
+ var segmentLength = Math.max(250, baseSegmentLength + Math.random() * 200 - 100); // Increased minimum segment length
var attempts = 0;
var validSegmentFound = false;
- while (!validSegmentFound && attempts < 20) {
+ while (!validSegmentFound && attempts < 50) {
+ // Increased max attempts
var shouldTurn = false;
// Force turn if we need more turns to reach minimum of 2
if (turnCount < 2 && seg >= numSegments - (2 - turnCount)) {
shouldTurn = true;
@@ -978,14 +997,55 @@
}
}
}
if (!validSegmentFound) {
- // Force a valid segment if we can't find one
- gamePath.push({
- x: currentX + 100,
- y: currentY
- });
- currentX += 100;
+ // Force a valid segment if we can't find one - try multiple directions
+ var fallbackFound = false;
+ var fallbackDirections = [0, 1, 2, 3]; // right, down, left, up
+ for (var fd = 0; fd < fallbackDirections.length && !fallbackFound; fd++) {
+ var fallbackDir = fallbackDirections[fd];
+ var fallbackLength = 200;
+ var fallbackX = currentX;
+ var fallbackY = currentY;
+ if (fallbackDir === 0 && currentX + fallbackLength < 1900) {
+ // right
+ fallbackX = currentX + fallbackLength;
+ } else if (fallbackDir === 1 && currentY + fallbackLength < maxY) {
+ // down
+ fallbackY = currentY + fallbackLength;
+ } else if (fallbackDir === 2 && currentX - fallbackLength > 100) {
+ // left
+ fallbackX = currentX - fallbackLength;
+ } else if (fallbackDir === 3 && currentY - fallbackLength > minY) {
+ // up
+ fallbackY = currentY - fallbackLength;
+ } else {
+ continue; // Try next direction
+ }
+ var fallbackStart = {
+ x: currentX,
+ y: currentY
+ };
+ var fallbackEnd = {
+ x: fallbackX,
+ y: fallbackY
+ };
+ // Check if this fallback direction works
+ if (gamePath.length < 2 || !wouldIntersectPath(fallbackStart, fallbackEnd, gamePath)) {
+ gamePath.push({
+ x: fallbackX,
+ y: fallbackY
+ });
+ currentX = fallbackX;
+ currentY = fallbackY;
+ direction = fallbackDir;
+ fallbackFound = true;
+ }
+ }
+ // If still no valid segment found, break the loop to prevent infinite generation
+ if (!fallbackFound) {
+ break;
+ }
}
}
// Ensure final path reaches right side of screen
if (currentX < 1600) {