User prompt
başlangıç ve bitiş noktaları tam köşede olamaz
User prompt
düşman yolu düzgün çalışmıyor. köşeden köşeye çizgi şeklinde.
User prompt
düşman güzergahı duvarlardan 1 kare boşluğa sahip olmalı. Başlangıç ve bitiş noktaları ise duvara bitişik olmalı
User prompt
kırmızı sarı yeşil gibi diğer kuleleri koyamıyorum. Aynı zamanda kuleleri sürükleyip bırakırken saldırı alanı kulenin kendisi ile hizalı değil onu da düzelt
User prompt
şimdi alttaki mavi kırmızı yeşil sarı ve mor için kule satın almaya imkan sağla. sürükleyip bırakarak grid üzerinde herhangi bir kareye konulabilsin. Düşman güzergahına ait yol üzerine konulamaz
User prompt
normal kulesini kaldırabilirsin
User prompt
grid alanını 10x12 olarak güncelle. En altta 1 grid alanlık boşluk bırak, ardından 5 tane kare daha ekle. Bu 5 kare, bizim satın alabileceğimiz kuleleri koyacağız. Her kule ayrı renkte olsun.
User prompt
düşman güzergahı her seferinde rastgele olsun, kuleleri koyabileceğim alanları da kaldır şimdilik.
User prompt
grid arkaplan kenarlardan margin'e sahip olmalı. 10x15 bir grid alan olsun
User prompt
şimdi, haritayı biraz daha şekillendirelim. karelerden oluşan bir düzlem olsun. düşman güzergahı ve kuleler bu kare ızgarada bir konuma yerleştirilebilsin
User prompt
next wave için auto seçeneği ekle, seçili olduğunda otomatik olarak sonraki dalga gelsin
User prompt
kuleleri yerleştirebileceğim yerler, düşman güzergahının etrafında olsun
User prompt
şu anki dalga bittikten sonra sonraki dalga için next wave butonu points altında belirsin.
User prompt
dalga, can ve puan için daha düzgün bir yerleşim yap. aynı zamanda boyutlarını biraz daha küçült. Wave bilgisi sol altta olsun. Can değeri uygun yerde. KP bilgisini Points diye değiştir ve ekranın orta üst kısmında olsun
User prompt
puan, can ve aşama bilgisi çok büyük. aynı zamanda aşama ve puan bilgisi üst üste geliyor. onları düzeltir misin?
User prompt
sadece 1 tane bırakabiliyorum
User prompt
halen bırakamıyorum
User prompt
normal kuleyi tutup sürükleyebiliyorum ama gerekli alana bırakamıyorum. en yakın noktaya otomatik yerleşmesi lazım
User prompt
normal kuleyi herhangi bir yere yerleştiremiyorum. mouse ile sürükleyip bırakabilmem gerekiyor
User prompt
normal kulesini aşağıda görüyorum ama tıklayıp bir yere koyamıyorum. Normal yazısı ekranın çok aşağısında kalıyor
User prompt
oyun başladığında düşmanlar ilerliyor ama savunma kuleleri koyulamıyor. Savunma kulesi için alt tarafa kule çeşitlerini listelemen lazım. bu kulelerden biri seçildiğinde boş alanlara yerleştirilebiliyor olmalı ve düşmana ateş ediyor olmaları lazım
User prompt
lets update the text wave, health and kp (knowledge point)
User prompt
there is nothing happens when press the play button. only the overlay goes away
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'visible')' in or related to this line: 'if (typeof nextWaveBtn !== "undefined" && nextWaveBtn) {' Line Number: 428
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'visible')' in or related to this line: 'nextWaveBtn.visible = visible;' Line Number: 428
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // BuildTile class (for tower placement) var BuildTile = Container.expand(function () { var self = Container.call(this); // Attach tile asset (box, light gray) var tileAsset = self.attachAsset('buildTile', { anchorX: 0.5, anchorY: 0.5 }); self.occupied = false; self.tower = null; // For highlighting self.highlight = function (on) { tileAsset.tint = on ? 0x2ecc40 : 0xbdc3c7; }; return self; }); // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); // Attach bullet asset (small yellow box) var bulletAsset = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.target = null; self.damage = 5; self.speed = 24; self.update = function () { if (!self.target || self.target.health <= 0 || self.target.reachedBase) { self.destroyed = true; return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 32) { // Hit self.target.takeDamage(self.damage); self.destroyed = true; return; } var moveDist = Math.min(self.speed, dist); self.x += dx / dist * moveDist; self.y += dy / dist * moveDist; }; return self; }); // Enemy (Creep) class var Enemy = Container.expand(function () { var self = Container.call(this); // Attach enemy asset (ellipse, purple) var enemyAsset = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Enemy stats self.maxHealth = 10 + (currentWave - 1) * 5; self.health = self.maxHealth; self.speed = 2 + (currentWave - 1) * 0.2; // Slightly faster each wave self.reward = 5 + (currentWave - 1) * 2; // Path progress self.pathIndex = 0; self.pathProgress = 0; // For hit flash self.isFlashing = false; // Move along path self.update = function () { 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) { self.pathIndex++; self.pathProgress = 0; return; } var moveDist = self.speed; self.pathProgress += moveDist; if (self.pathProgress >= dist) { self.pathIndex++; self.pathProgress = 0; if (self.pathIndex >= path.length - 1) { // Reached end self.x = to.x; self.y = to.y; self.reachedBase = true; return; } } var t = self.pathProgress / dist; self.x = from.x + dx * t; self.y = from.y + dy * t; }; // Take damage self.takeDamage = function (dmg) { self.health -= dmg; if (!self.isFlashing) { self.isFlashing = true; tween(enemyAsset, { tint: 0xffffff }, { duration: 80, onFinish: function onFinish() { tween(enemyAsset, { tint: 0x8e44ad }, { duration: 120, onFinish: function onFinish() { self.isFlashing = false; } }); } }); } }; return self; }); // Tower class var Tower = Container.expand(function () { var self = Container.call(this); // Attach tower asset (box, blue) var towerAsset = self.attachAsset('tower', { anchorX: 0.5, anchorY: 0.5 }); // Tower stats self.level = 1; self.range = 320; self.damage = 5; self.fireRate = 60; // frames per shot self.cooldown = 0; // For upgrade flash self.isFlashing = false; // Show range circle (for placement) self.rangeCircle = self.attachAsset('rangeCircle', { anchorX: 0.5, anchorY: 0.5, alpha: 0.15 }); self.rangeCircle.width = self.range * 2; self.rangeCircle.height = self.range * 2; self.rangeCircle.visible = false; // Upgrade tower self.upgrade = function () { if (self.level >= 3) return false; self.level++; self.damage += 5; self.range += 40; self.fireRate = Math.max(30, self.fireRate - 10); self.rangeCircle.width = self.range * 2; self.rangeCircle.height = self.range * 2; // Flash for upgrade if (!self.isFlashing) { self.isFlashing = true; tween(towerAsset, { tint: 0xffff00 }, { duration: 120, onFinish: function onFinish() { tween(towerAsset, { tint: 0x3498db }, { duration: 180, onFinish: function onFinish() { self.isFlashing = false; } }); } }); } return true; }; // Tower attack logic self.update = function () { if (self.cooldown > 0) { self.cooldown--; return; } // Find nearest enemy in range var nearest = null; var minDist = 99999; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; var dx = e.x - self.x; var dy = e.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist <= self.range && dist < minDist) { nearest = e; minDist = dist; } } if (nearest) { // Shoot var b = new Bullet(); b.x = self.x; b.y = self.y; b.target = nearest; b.damage = self.damage; b.speed = 24; b.lastX = b.x; b.lastY = b.y; bullets.push(b); game.addChild(b); self.cooldown = self.fireRate; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // --- Grid system --- // Set grid to 10x12 with margins, leave 1 row margin at bottom, and add 5 tower selection squares below grid var GRID_COLS = 10; var GRID_ROWS = 12; var GRID_SIZE = 160; // Calculate margins to center grid in 2048x2732, leaving 1 row margin at bottom for spacing var GRID_TOTAL_WIDTH = GRID_COLS * GRID_SIZE; var GRID_TOTAL_HEIGHT = GRID_ROWS * GRID_SIZE; var GRID_MARGIN_X = Math.floor((2048 - GRID_TOTAL_WIDTH) / 2); var GRID_MARGIN_Y = Math.floor((2732 - (GRID_TOTAL_HEIGHT + GRID_SIZE)) / 2); // +GRID_SIZE for 1 row margin at bottom // Helper to snap to grid (with margin) function snapToGrid(x, y) { return { x: GRID_MARGIN_X + Math.round((x - GRID_MARGIN_X) / GRID_SIZE) * GRID_SIZE, y: GRID_MARGIN_Y + Math.round((y - GRID_MARGIN_Y) / GRID_SIZE) * GRID_SIZE }; } // Path definition (array of {x, y}), snapped to grid // Generate a path from top row to bottom row, always moving to adjacent grid cells (no diagonals) // The path always has a 1-cell margin from the grid edges except at start and end (which are wall-adjacent, but never at the exact corners) function generateProperPath() { var pathArr = []; // Start at random wall-adjacent column on top row, but not at the exact corners (not 0 or GRID_COLS-1) var startCols = []; for (var c = 1; c < GRID_COLS - 1; c++) { startCols.push(c); } var startCol = startCols[Math.floor(Math.random() * startCols.length)]; var col = startCol; var row = 0; pathArr.push(snapToGrid(GRID_MARGIN_X + col * GRID_SIZE, GRID_MARGIN_Y + row * GRID_SIZE)); // For rows 1 to GRID_ROWS-2, stay within [1, GRID_COLS-2] // We'll alternate between moving down and left/right, but never diagonally var visited = {}; visited[col + "," + row] = true; while (row < GRID_ROWS - 2) { // For the next row, pick a column in [1, GRID_COLS-2] (margin 1 from wall) var nextRow = row + 1; var minCol = 1; var maxCol = GRID_COLS - 2; // If next row is the last before end, allow wall-adjacent columns (but not corners) if (nextRow === GRID_ROWS - 1) { minCol = 1; maxCol = GRID_COLS - 2; } // Try to move horizontally a bit before going down, to make the path less straight var horizMoves = []; // Only allow horizontal moves if not at wall if (col > minCol) horizMoves.push(col - 1); if (col < maxCol) horizMoves.push(col + 1); // Randomly decide to move horizontally 0-2 times before going down var horizSteps = Math.floor(Math.random() * 3); for (var h = 0; h < horizSteps && horizMoves.length > 0; h++) { var nextCol = horizMoves[Math.floor(Math.random() * horizMoves.length)]; if (!visited[nextCol + "," + row]) { col = nextCol; pathArr.push(snapToGrid(GRID_MARGIN_X + col * GRID_SIZE, GRID_MARGIN_Y + row * GRID_SIZE)); visited[col + "," + row] = true; } } // Now move down row = nextRow; // Clamp col to minCol/maxCol for intermediate rows if (row < GRID_ROWS - 1) { if (col < minCol) col = minCol; if (col > maxCol) col = maxCol; } pathArr.push(snapToGrid(GRID_MARGIN_X + col * GRID_SIZE, GRID_MARGIN_Y + row * GRID_SIZE)); visited[col + "," + row] = true; } // End at random wall-adjacent column on bottom row, but not at the exact corners (not 0 or GRID_COLS-1) var endCols = []; for (var c = 1; c < GRID_COLS - 1; c++) { endCols.push(c); } var endCol = endCols[Math.floor(Math.random() * endCols.length)]; pathArr.push(snapToGrid(GRID_MARGIN_X + endCol * GRID_SIZE, GRID_MARGIN_Y + (GRID_ROWS - 1) * GRID_SIZE)); return pathArr; } var path = generateProperPath(); // --- Start Game Button Logic --- var gameStarted = false; var startBtn = new Text2('▶ Start Game', { size: 120, fill: 0x27AE60 }); startBtn.anchor.set(0.5, 0.5); LK.gui.center.addChild(startBtn); function setStartBtnVisible(visible) { startBtn.visible = visible; } setStartBtnVisible(true); startBtn.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; setStartBtnVisible(false); setNextWaveBtnVisible(true); startWave(); // Start the first wave immediately } }; // Hide all gameplay UI until game starts setNextWaveBtnVisible(false); if (typeof kpTxt !== "undefined") kpTxt.visible = false; if (typeof healthTxt !== "undefined") healthTxt.visible = false; if (typeof waveTxt !== "undefined") waveTxt.visible = false; if (typeof nextWaveBtn !== "undefined") nextWaveBtn.visible = false; if (typeof autoNextWaveBtn !== "undefined") autoNextWaveBtn.visible = false; // Show gameplay UI when game starts function showGameplayUI() { kpTxt.visible = true; healthTxt.visible = true; waveTxt.visible = true; nextWaveBtn.visible = false; nextWaveBtn.x = 0; nextWaveBtn.y = kpTxt.y + kpTxt.height + 20; autoNextWaveBtn.x = 0; autoNextWaveBtn.y = nextWaveBtn.y + nextWaveBtn.height + 10; autoNextWaveBtn.visible = true; kpTxt.setText('Points: ' + knowledgePoints); healthTxt.setText('Base: ' + baseHealth); waveTxt.setText('Wave: ' + currentWave + '/' + maxWaves); } var _origStartWave = startWave; startWave = function startWave() { if (!gameStarted) return; showGameplayUI(); _origStartWave(); }; // Buildable tile logic removed for now var buildTilePositions = []; // Global game state var enemies = []; var towers = []; var bullets = []; // buildTiles removed for now var baseHealth = 10; var knowledgePoints = 30; var currentWave = 1; var maxWaves = 10; var waveInProgress = false; var waveTimer = null; var spawnIndex = 0; var spawnDelay = 40; // frames between spawns var enemiesToSpawn = 0; var selectedTile = null; // Asset initialization // Draw grid background (light gray squares) with margins and 10x12 grid area for (var row = 0; row < GRID_ROWS; row++) { for (var col = 0; col < GRID_COLS; col++) { var gridNode = LK.getAsset('buildTile', { anchorX: 0.5, anchorY: 0.5, width: GRID_SIZE - 4, height: GRID_SIZE - 4, color: 0xf4f4f4, shape: 'box', alpha: 0.18 }); gridNode.x = GRID_MARGIN_X + col * GRID_SIZE; gridNode.y = GRID_MARGIN_Y + row * GRID_SIZE; game.addChild(gridNode); } } // Draw 5 colored tower selection squares below the grid, centered horizontally var TOWER_SELECT_COUNT = 5; var TOWER_SELECT_SIZE = 140; var TOWER_SELECT_SPACING = 60; var TOWER_SELECT_COLORS = [0x3498db, 0xe74c3c, 0x2ecc40, 0xf1c40f, 0x8e44ad]; var TOWER_SELECT_LABELS = ['Mavi', 'Kırmızı', 'Yeşil', 'Sarı', 'Mor']; var towerSelectSquares = []; var totalWidth = TOWER_SELECT_COUNT * TOWER_SELECT_SIZE + (TOWER_SELECT_COUNT - 1) * TOWER_SELECT_SPACING; var startX = Math.floor((2048 - totalWidth) / 2) + TOWER_SELECT_SIZE / 2; var selectY = GRID_MARGIN_Y + GRID_ROWS * GRID_SIZE + GRID_SIZE / 2; for (var i = 0; i < TOWER_SELECT_COUNT; i++) { var square = LK.getAsset('buildTile', { anchorX: 0.5, anchorY: 0.5, width: TOWER_SELECT_SIZE, height: TOWER_SELECT_SIZE, color: TOWER_SELECT_COLORS[i], shape: 'box', alpha: 0.95 }); square.x = startX + i * (TOWER_SELECT_SIZE + TOWER_SELECT_SPACING); square.y = selectY; game.addChild(square); // Add label for each tower color var label = new Text2(TOWER_SELECT_LABELS[i], { size: 48, fill: "#fff" }); label.anchor.set(0.5, 0); label.x = square.x; label.y = square.y + TOWER_SELECT_SIZE / 2 + 8; game.addChild(label); towerSelectSquares.push(square); } // Draw path (for visual reference) for (var i = 0; i < path.length - 1; i++) { var from = path[i]; var to = path[i + 1]; var dx = to.x - from.x; var dy = to.y - from.y; var dist = Math.sqrt(dx * dx + dy * dy); var steps = Math.floor(dist / 40); for (var s = 0; s <= steps; s++) { var t = s / steps; var px = from.x + dx * t; var py = from.y + dy * t; var node = LK.getAsset('pathDot', { anchorX: 0.5, anchorY: 0.5, width: 32, height: 32, color: 0x7f8c8d, shape: 'ellipse' }); node.x = px; node.y = py; game.addChild(node); } } // Buildable tile objects removed for now // --- Tower Selection Bar --- var towerTypes = []; var selectedTowerType = null; var towerButtons = []; var towerBtnY = 2400; var towerBtnSpacing = 260; var towerBtnStartX = 400; var draggingTowerType = null; var draggingTowerGhost = null; // No tower selection buttons since normal tower is removed // --- Drag-and-drop tower placement from colored squares --- for (var i = 0; i < towerSelectSquares.length; i++) { (function (colorIdx) { var square = towerSelectSquares[colorIdx]; square.down = function (x, y, obj) { // Clean up any previous ghost if (draggingTowerGhost) { if (draggingTowerGhost.rangeCircle) draggingTowerGhost.rangeCircle.destroy(); draggingTowerGhost.destroy(); draggingTowerGhost = null; draggingTowerType = null; } draggingTowerType = colorIdx; draggingTowerGhost = new Tower(); // Snap to grid for initial drag position var gridX = Math.round((x - GRID_MARGIN_X) / GRID_SIZE); var gridY = Math.round((y - GRID_MARGIN_Y) / GRID_SIZE); var snapX = GRID_MARGIN_X + gridX * GRID_SIZE; var snapY = GRID_MARGIN_Y + gridY * GRID_SIZE; draggingTowerGhost.x = snapX; draggingTowerGhost.y = snapY; // Set color of ghost tower if (draggingTowerGhost.children && draggingTowerGhost.children.length > 0) { draggingTowerGhost.children[0].tint = TOWER_SELECT_COLORS[colorIdx]; } // Show range circle while dragging, and center it on the ghost if (draggingTowerGhost.rangeCircle) { draggingTowerGhost.rangeCircle.visible = true; draggingTowerGhost.rangeCircle.x = 0; draggingTowerGhost.rangeCircle.y = 0; } draggingTowerGhost.alpha = 0.7; game.addChild(draggingTowerGhost); }; })(i); } // Helper: check if a grid cell is on the path function isCellOnPath(gridX, gridY) { for (var i = 0; i < path.length; i++) { var px = path[i].x; var py = path[i].y; var cellX = Math.round((px - GRID_MARGIN_X) / GRID_SIZE); var cellY = Math.round((py - GRID_MARGIN_Y) / GRID_SIZE); if (cellX === gridX && cellY === gridY) return true; } return false; } // Helper: check if a tower already exists at grid cell function isTowerAtCell(gridX, gridY) { for (var i = 0; i < towers.length; i++) { var t = towers[i]; var tx = Math.round((t.x - GRID_MARGIN_X) / GRID_SIZE); var ty = Math.round((t.y - GRID_MARGIN_Y) / GRID_SIZE); if (tx === gridX && ty === gridY) return true; } return false; } // Dragging ghost tower with finger/mouse game.move = function (x, y, obj) { if (draggingTowerGhost) { // Snap ghost to grid for feedback var gridX = Math.round((x - GRID_MARGIN_X) / GRID_SIZE); var gridY = Math.round((y - GRID_MARGIN_Y) / GRID_SIZE); var snapX = GRID_MARGIN_X + gridX * GRID_SIZE; var snapY = GRID_MARGIN_Y + gridY * GRID_SIZE; draggingTowerGhost.x = snapX; draggingTowerGhost.y = snapY; // Always center rangeCircle on the ghost (0,0 in local coordinates) if (draggingTowerGhost.rangeCircle) { draggingTowerGhost.rangeCircle.x = 0; draggingTowerGhost.rangeCircle.y = 0; } // Visual feedback: tint red if invalid, normal if valid var valid = true; // Only allow inside grid if (gridX < 0 || gridX >= GRID_COLS || gridY < 0 || gridY >= GRID_ROWS || isCellOnPath(gridX, gridY) || isTowerAtCell(gridX, gridY)) { valid = false; } if (draggingTowerGhost.children && draggingTowerGhost.children.length > 0) { draggingTowerGhost.children[0].tint = valid ? TOWER_SELECT_COLORS[draggingTowerType] : 0x888888; } draggingTowerGhost.alpha = valid ? 0.7 : 0.35; } }; // Place tower on grid on up game.up = function (x, y, obj) { if (draggingTowerGhost && draggingTowerType !== null) { var gridX = Math.round((draggingTowerGhost.x - GRID_MARGIN_X) / GRID_SIZE); var gridY = Math.round((draggingTowerGhost.y - GRID_MARGIN_Y) / GRID_SIZE); var valid = true; if (gridX < 0 || gridX >= GRID_COLS || gridY < 0 || gridY >= GRID_ROWS || isCellOnPath(gridX, gridY) || isTowerAtCell(gridX, gridY)) { valid = false; } if (valid) { // Place tower if enough points var buildCost = 20; if (knowledgePoints >= buildCost) { knowledgePoints -= buildCost; var tower = new Tower(); tower.x = GRID_MARGIN_X + gridX * GRID_SIZE; tower.y = GRID_MARGIN_Y + gridY * GRID_SIZE; // Set color if (tower.children && tower.children.length > 0) { tower.children[0].tint = TOWER_SELECT_COLORS[draggingTowerType]; } towers.push(tower); game.addChild(tower); kpTxt.setText('Points: ' + knowledgePoints); } } // Clean up ghost if (draggingTowerGhost.rangeCircle) draggingTowerGhost.rangeCircle.destroy(); draggingTowerGhost.destroy(); draggingTowerGhost = null; draggingTowerType = null; return; } // If not placing, just clear ghost if (draggingTowerGhost) { if (draggingTowerGhost.rangeCircle) draggingTowerGhost.rangeCircle.destroy(); draggingTowerGhost.destroy(); draggingTowerGhost = null; draggingTowerType = null; } }; // Base indicator (ellipse, red) var baseNode = LK.getAsset('base', { anchorX: 0.5, anchorY: 0.5, width: 160, height: 160, color: 0xe74c3c, shape: 'ellipse' }); baseNode.x = path[path.length - 1].x; baseNode.y = path[path.length - 1].y; game.addChild(baseNode); // GUI: Points (KP) - Center top, smaller size, renamed to Points var kpTxt = new Text2('Points: ' + knowledgePoints, { size: 48, fill: 0x222222 }); kpTxt.anchor.set(0.5, 0); // center aligned, top kpTxt.x = 0; kpTxt.y = 10; LK.gui.top.addChild(kpTxt); // GUI: Base Health - Top right, smaller size var healthTxt = new Text2('Base: ' + baseHealth, { size: 48, fill: 0xE74C3C }); healthTxt.anchor.set(1, 0); // right aligned, top healthTxt.x = -40; // right margin healthTxt.y = 10; LK.gui.topRight.addChild(healthTxt); // GUI: Wave - Bottom left, smaller size var waveTxt = new Text2('Wave: ' + currentWave + '/' + maxWaves, { size: 48, fill: 0x2980B9 }); waveTxt.anchor.set(0, 1); // left aligned, bottom waveTxt.x = 40; waveTxt.y = -40; LK.gui.bottomLeft.addChild(waveTxt); // GUI: Next Wave Button var nextWaveBtn = new Text2('▶ Next Wave', { size: 90, fill: 0x27AE60 }); nextWaveBtn.anchor.set(0.5, 0); // Place nextWaveBtn under Points (kpTxt) in gui.top, centered horizontally nextWaveBtn.x = 0; nextWaveBtn.y = kpTxt.y + kpTxt.height + 20; LK.gui.top.addChild(nextWaveBtn); // Auto-next wave toggle var autoNextWave = false; var autoNextWaveBtn = new Text2('Auto: OFF', { size: 54, fill: 0x2980B9 }); autoNextWaveBtn.anchor.set(0.5, 0); autoNextWaveBtn.x = 0; autoNextWaveBtn.y = nextWaveBtn.y + nextWaveBtn.height + 10; LK.gui.top.addChild(autoNextWaveBtn); autoNextWaveBtn.visible = false; autoNextWaveBtn.down = function (x, y, obj) { autoNextWave = !autoNextWave; autoNextWaveBtn.setText('Auto: ' + (autoNextWave ? 'ON' : 'OFF')); }; // Show/hide next wave button function setNextWaveBtnVisible(visible) { // Defensive: Only set visible if nextWaveBtn is defined and has a visible property if (typeof nextWaveBtn !== "undefined" && nextWaveBtn && typeof nextWaveBtn.visible !== "undefined") { nextWaveBtn.visible = visible; } } setNextWaveBtnVisible(false); // Start next wave function startWave() { if (waveInProgress || currentWave > maxWaves) return; waveInProgress = true; setNextWaveBtnVisible(false); enemiesToSpawn = 6 + currentWave * 2; spawnIndex = 0; } // Next wave button event nextWaveBtn.down = function (x, y, obj) { if (!waveInProgress && currentWave <= maxWaves) { startWave(); } }; // Build/upgrade tower on tile function tryBuildOrUpgrade(tile) { if (tile.occupied) { // Try upgrade if (tile.tower.level < 3) { var upgradeCost = 20 + tile.tower.level * 15; if (knowledgePoints >= upgradeCost) { knowledgePoints -= upgradeCost; tile.tower.upgrade(); kpTxt.setText('Points: ' + knowledgePoints); } } } else { // Build new tower var buildCost = 20; if (knowledgePoints >= buildCost) { knowledgePoints -= buildCost; var tower = new Tower(); tower.x = tile.x; tower.y = tile.y; towers.push(tower); game.addChild(tower); tile.occupied = true; tile.tower = tower; kpTxt.setText('Points: ' + knowledgePoints); } } } // Highlight build tiles on touch game.down = function (x, y, obj) { // No tap-to-place logic; only drag-and-drop is supported for tower placement }; // Remove highlight/range on up // (handled by drag-and-drop up logic above) // Main game update game.update = function () { // Spawn enemies for wave if (waveInProgress && enemiesToSpawn > 0 && LK.ticks % spawnDelay === 0) { var enemy = new Enemy(); enemy.x = path[0].x; enemy.y = path[0].y; enemy.pathIndex = 0; enemy.pathProgress = 0; enemies.push(enemy); game.addChild(enemy); enemiesToSpawn--; } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; e.update(); if (e.health <= 0) { // Enemy defeated knowledgePoints += e.reward; kpTxt.setText('Points: ' + knowledgePoints); e.destroy(); enemies.splice(i, 1); kpTxt.setText('Points: ' + knowledgePoints); } else if (e.reachedBase) { // Enemy reached base baseHealth--; healthTxt.setText('Base: ' + baseHealth); e.destroy(); enemies.splice(i, 1); healthTxt.setText('Base: ' + baseHealth); LK.effects.flashScreen(0xe74c3c, 400); if (baseHealth <= 0) { LK.showGameOver(); return; } } } // Update towers for (var i = 0; i < towers.length; i++) { towers[i].update(); } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); if (b.destroyed) { b.destroy(); bullets.splice(i, 1); } } // End wave if all enemies defeated and none left to spawn if (waveInProgress && enemies.length === 0 && enemiesToSpawn === 0) { waveInProgress = false; currentWave++; if (currentWave > maxWaves) { LK.showYouWin(); return; } waveTxt.setText('Wave: ' + currentWave + '/' + maxWaves); // Reposition nextWaveBtn and autoNextWaveBtn under Points (kpTxt) in case Points text size changes nextWaveBtn.x = 0; nextWaveBtn.y = kpTxt.y + kpTxt.height + 20; autoNextWaveBtn.x = 0; autoNextWaveBtn.y = nextWaveBtn.y + nextWaveBtn.height + 10; if (autoNextWave) { setNextWaveBtnVisible(false); // Start next wave automatically after a short delay for feedback LK.setTimeout(function () { if (!waveInProgress && currentWave <= maxWaves) { startWave(); } }, 700); } else { setNextWaveBtnVisible(true); } } };
===================================================================
--- original.js
+++ change.js
@@ -245,13 +245,16 @@
};
}
// Path definition (array of {x, y}), snapped to grid
// Generate a path from top row to bottom row, always moving to adjacent grid cells (no diagonals)
-// The path always has a 1-cell margin from the grid edges except at start and end (which are wall-adjacent)
+// The path always has a 1-cell margin from the grid edges except at start and end (which are wall-adjacent, but never at the exact corners)
function generateProperPath() {
var pathArr = [];
- // Start at random wall-adjacent column on top row (col 0 or col GRID_COLS-1)
- var startCols = [0, GRID_COLS - 1];
+ // Start at random wall-adjacent column on top row, but not at the exact corners (not 0 or GRID_COLS-1)
+ var startCols = [];
+ for (var c = 1; c < GRID_COLS - 1; c++) {
+ startCols.push(c);
+ }
var startCol = startCols[Math.floor(Math.random() * startCols.length)];
var col = startCol;
var row = 0;
pathArr.push(snapToGrid(GRID_MARGIN_X + col * GRID_SIZE, GRID_MARGIN_Y + row * GRID_SIZE));
@@ -263,12 +266,12 @@
// For the next row, pick a column in [1, GRID_COLS-2] (margin 1 from wall)
var nextRow = row + 1;
var minCol = 1;
var maxCol = GRID_COLS - 2;
- // If next row is the last before end, allow wall-adjacent columns
+ // If next row is the last before end, allow wall-adjacent columns (but not corners)
if (nextRow === GRID_ROWS - 1) {
- minCol = 0;
- maxCol = GRID_COLS - 1;
+ minCol = 1;
+ maxCol = GRID_COLS - 2;
}
// Try to move horizontally a bit before going down, to make the path less straight
var horizMoves = [];
// Only allow horizontal moves if not at wall
@@ -293,10 +296,13 @@
}
pathArr.push(snapToGrid(GRID_MARGIN_X + col * GRID_SIZE, GRID_MARGIN_Y + row * GRID_SIZE));
visited[col + "," + row] = true;
}
- // End at random wall-adjacent column on bottom row
- var endCols = [0, GRID_COLS - 1];
+ // End at random wall-adjacent column on bottom row, but not at the exact corners (not 0 or GRID_COLS-1)
+ var endCols = [];
+ for (var c = 1; c < GRID_COLS - 1; c++) {
+ endCols.push(c);
+ }
var endCol = endCols[Math.floor(Math.random() * endCols.length)];
pathArr.push(snapToGrid(GRID_MARGIN_X + endCol * GRID_SIZE, GRID_MARGIN_Y + (GRID_ROWS - 1) * GRID_SIZE));
return pathArr;
}