User prompt
sana bırakıyorum bu oyunu geliştir hamle çeğiştitiği, arada spawnlanan özellik eşyaları, stabilite, bug fix, yapabildiğin ne varsa yap ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
rakip Ai güçlendir ve 3 oyuncusunu da taktiğine dahil edebilsin
User prompt
son eklediğimiz 4 konum şöyle olsun - (x+2, y+1) - (x-1, y+1) - (x-2, y-1) - (x+1, y-1)
User prompt
4 konum daha ekleyelim - (x+1, y+1) - (x-1, y+1) - (x-1, y-1) - (x+1, y-1) toplamda gidebileceği 12 kare olsun
User prompt
(x, y) konumunu - (x+1, y+3) - (x+3, y+1) - (x-1, y+3) - (x-3, y+1) - (x+1, y-3) - (x+3, y-1) - (x-1, y-3) - (x-3, y-1) yapabilir misin bizim ve Ai rakibin
User prompt
evet gösterge çok iyi çalışıyor şut atıldıktan sonra topun yol aldığı mesafeyi de 7 bloğa düşür
User prompt
şut mesafesini 7 bloğa düşür top 7 bloktan fazla gitmesin
User prompt
duvar çıkma şansını %5 e düşür
User prompt
Please fix the bug: 'TypeError: tween.create is not a function' in or related to this line: 'tween.create(ball).to({' Line Number: 941
User prompt
gol olduktan sonra topu ortaya koy oyunu öyle bitir
User prompt
Please fix the bug: 'TypeError: tween.to is not a function' in or related to this line: 'tween.to(ball, {' Line Number: 938
User prompt
Please fix the bug: 'TypeError: tween.create is not a function' in or related to this line: 'tween.create(ball).to({' Line Number: 938
User prompt
Please fix the bug: 'TypeError: tween.to is not a function' in or related to this line: 'tween.to(ball, {' Line Number: 938
User prompt
top usteki kale bloğuna geldiğinde bizim takıma sayı ver ve sahayı sıfırla duvarları sil. top alttaki kale bloğuna geldiğinde rakibe sayı ver ve aynen sahayı sifirla. skoru unutma sıfırlamada
User prompt
tamam eski haline getir
User prompt
bizim kalenin ve rakip kalenin yanındaki saha bloklarınına yeni texture ekle bakalım haklı mısın
User prompt
kale ekle takımlara ve güzel bi gol mekaniği yap topla
User prompt
add game elemets
User prompt
tüm sahayı %5 küçült
User prompt
top kaleye giremiyor
User prompt
top rakip kaleye girmiyor skor olmuyor hata var
User prompt
kalemizi 1 blok yukarı taşı oyuncunun kalesini
User prompt
tüm sahayı %5 küçült
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'indexOf')' in or related to this line: 'if (goalBotRows.indexOf(py) !== -1) {' Line Number: 205
User prompt
üst orta 3 kareye rakip kale. alt orta 3 kareye bizim kaleyi oluştur oyuncular kaleye giremez ve top kaleye girerse gol atan takım skor alır ve oyun baştan başlar
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // --- Ball --- var Ball = Container.expand(function () { var self = Container.call(this); self.gridX = 0; self.gridY = 0; self.ballAsset = self.attachAsset('ball', { width: cellSize * 0.6 * 1.75, height: cellSize * 0.6 * 1.75, color: 0xffffff, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); self.setGridPos = function (gx, gy) { self.gridX = gx; self.gridY = gy; self.x = gridOriginX + gx * cellSize + cellSize / 2; self.y = gridOriginY + gy * cellSize + cellSize / 2; }; self.flash = function () { LK.effects.flashObject(self, 0xffa500, 200); }; return self; }); // --- PlayerPawn: For both player and AI pawns --- var PlayerPawn = Container.expand(function () { var self = Container.call(this); // Use different colors for player and AI self.isAI = false; self.gridX = 0; self.gridY = 0; self.hasBall = false; self.pawnAsset = null; self.init = function (isAI) { self.isAI = isAI; var color = isAI ? 0x1e90ff : 0x32cd32; self.pawnAsset = self.attachAsset('pawn_' + (isAI ? 'ai' : 'player'), { width: (cellSize - 8) * 1.75, height: (cellSize - 8) * 1.75, color: color, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); }; self.setGridPos = function (gx, gy) { self.gridX = gx; self.gridY = gy; self.x = gridOriginX + gx * cellSize + cellSize / 2; self.y = gridOriginY + gy * cellSize + cellSize / 2; }; self.flash = function () { LK.effects.flashObject(self, 0xffff00, 300); }; return self; }); // --- PowerUp: Spawnable items with special effects --- var PowerUp = Container.expand(function () { var self = Container.call(this); self.gridX = 0; self.gridY = 0; self.type = 'speed'; // 'speed', 'shield', 'multishot' self.powerUpAsset = null; self.init = function (type) { self.type = type; var colors = { 'speed': 0x00ff00, 'shield': 0x0080ff, 'multishot': 0xff8000 }; self.powerUpAsset = self.attachAsset('target_indicator', { width: cellSize * 0.8, height: cellSize * 0.8, color: colors[type] || 0xffffff, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); // Pulsing animation self.startPulse(); }; self.startPulse = function () { tween(self.powerUpAsset, { scaleX: 1.2, scaleY: 1.2 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.powerUpAsset, { scaleX: 1, scaleY: 1 }, { duration: 800, easing: tween.easeInOut, onFinish: self.startPulse }); } }); }; self.setGridPos = function (gx, gy) { self.gridX = gx; self.gridY = gy; self.x = gridOriginX + gx * cellSize + cellSize / 2; self.y = gridOriginY + gy * cellSize + cellSize / 2; }; self.applyEffect = function (pawn) { switch (self.type) { case 'speed': pawn.speedBoost = 3; // Extra moves for 3 turns LK.effects.flashObject(pawn, 0x00ff00, 500); break; case 'shield': pawn.shield = 2; // Blocks shots for 2 turns LK.effects.flashObject(pawn, 0x0080ff, 500); break; case 'multishot': pawn.multiShot = 1; // Can shoot multiple times LK.effects.flashObject(pawn, 0xff8000, 500); break; } }; return self; }); // --- Wall: Tetris block wall, occupies multiple cells --- var Wall = Container.expand(function () { var self = Container.call(this); self.cells = []; // [{x, y}] self.wallId = null; self.blocks = []; self.init = function (cells, wallId) { self.cells = cells; self.wallId = wallId; for (var i = 0; i < cells.length; i++) { var block = self.attachAsset('wall', { width: cellSize - 6, height: cellSize - 6, color: 0x888888, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: (cells[i].x - cells[0].x) * cellSize, y: (cells[i].y - cells[0].y) * cellSize }); self.blocks.push(block); } // Position wall at first cell self.x = gridOriginX + cells[0].x * cellSize + cellSize / 2; self.y = gridOriginY + cells[0].y * cellSize + cellSize / 2; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ // --- Grid Setup --- // --- GridCell: For grid logic, not a display object --- var GridCell = function GridCell(x, y) { this.x = x; this.y = y; this.occupied = null; // null, 'player', 'ai', 'wall', 'ball' this.wallId = null; // If wall, which wall }; var gridCols = 21; var gridRows = 31; var cellSize = Math.floor(Math.min(2048 / gridCols, 2732 / gridRows) * 0.95); var gridWidth = gridCols * cellSize; var gridHeight = gridRows * cellSize; var gridOriginX = Math.floor((2048 - gridWidth) / 2); var gridOriginY = Math.floor((2732 - gridHeight) / 2); // --- Game State --- var grid = []; for (var y = 0; y < gridRows; y++) { var row = []; for (var x = 0; x < gridCols; x++) { row.push(new GridCell(x, y)); } grid.push(row); } var playerPawns = []; var aiPawns = []; var ball = null; var walls = []; var gameElements = []; // Track all game elements for management (future use) var wallIdCounter = 1; var turn = 'player'; // 'player' or 'ai' var selectedPawn = null; var validMoves = []; var validShots = []; var gameLocked = false; var playerScore = 0; var aiScore = 0; var goalToWin = 3; var scoreTxt = null; var infoTxt = null; var powerUps = []; var turnCounter = 0; var gameStats = storage.gameStats || { gamesPlayed: 0, wins: 0, losses: 0 }; // --- Draw grid cell backgrounds --- var goalCols = []; for (var i = Math.floor(gridCols / 2) - 2; i <= Math.floor(gridCols / 2) + 2; i++) { goalCols.push(i); } for (var gy = 0; gy < gridRows; gy++) { for (var gx = 0; gx < gridCols; gx++) { var cellBg = LK.getAsset('grid_cell', { width: cellSize, height: cellSize, anchorX: 0, anchorY: 0, x: gridOriginX + gx * cellSize, y: gridOriginY + gy * cellSize }); game.addChild(cellBg); } } // --- Draw grid lines (for visual aid) --- for (var gx = 0; gx <= gridCols; gx++) { var vline = LK.getAsset('wall_block', { width: 4, height: gridHeight, color: 0x222222, shape: 'box', anchorX: 0.5, anchorY: 0, x: gridOriginX + gx * cellSize - 2, y: gridOriginY }); game.addChild(vline); } for (var gy = 0; gy <= gridRows; gy++) { var hline = LK.getAsset('wall_block', { width: gridWidth, height: 4, color: 0x222222, shape: 'box', anchorX: 0, anchorY: 0.5, x: gridOriginX, y: gridOriginY + gy * cellSize - 2 }); game.addChild(hline); } // --- Place Pawns --- function placePawns() { // Player: 3 pawns, bottom center var pxs = [Math.floor(gridCols / 2) - 2, Math.floor(gridCols / 2), Math.floor(gridCols / 2) + 2]; for (var i = 0; i < 3; i++) { var pawn = new PlayerPawn(); pawn.init(false); pawn.setGridPos(pxs[i], gridRows - 3); playerPawns.push(pawn); gameElements.push(pawn); game.addChild(pawn); grid[gridRows - 3][pxs[i]].occupied = 'player'; } // AI: 3 pawns, top center var axs = [Math.floor(gridCols / 2) - 2, Math.floor(gridCols / 2), Math.floor(gridCols / 2) + 2]; for (var i = 0; i < 3; i++) { var pawn = new PlayerPawn(); pawn.init(true); pawn.setGridPos(axs[i], 2); aiPawns.push(pawn); gameElements.push(pawn); game.addChild(pawn); grid[2][axs[i]].occupied = 'ai'; } } placePawns(); // --- Place Ball --- function placeBall(center) { if (ball) { ball.destroy(); } ball = new Ball(); gameElements.push(ball); var bx = center ? Math.floor(gridCols / 2) : playerPawns[1].gridX; var by = center ? Math.floor(gridRows / 2) : playerPawns[1].gridY - 1; ball.setGridPos(bx, by); game.addChild(ball); grid[by][bx].occupied = 'ball'; } placeBall(true); // --- Draw Goals (visual only, with goal image asset) --- var goalWidth = 5; var goalImgW = cellSize * goalWidth * 1.05; var goalImgH = cellSize * 1.2; var goalColsStart = Math.floor(gridCols / 2) - 2; var goalColsEnd = Math.floor(gridCols / 2) + 2; // Top goal (AI's goal) var goalTopImg = LK.getAsset('goal', { width: goalImgW, height: goalImgH, anchorX: 0.5, anchorY: 1, x: gridOriginX + (goalColsStart + goalColsEnd) / 2 * cellSize + cellSize / 2, y: gridOriginY + 2 // slight offset for visual }); game.addChild(goalTopImg); // Bottom goal (Player's goal) var goalBotImg = LK.getAsset('goal', { width: goalImgW, height: goalImgH, anchorX: 0.5, anchorY: 0, x: gridOriginX + (goalColsStart + goalColsEnd) / 2 * cellSize + cellSize / 2, y: gridOriginY + gridHeight - 2 // slight offset for visual }); game.addChild(goalBotImg); // --- Score Display --- scoreTxt = new Text2('0 : 0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Info Text --- infoTxt = new Text2('', { size: 60, fill: "#fff" }); infoTxt.anchor.set(0.5, 0); LK.gui.bottom.addChild(infoTxt); // --- Utility Functions --- function updateScore() { scoreTxt.setText(playerScore + ' : ' + aiScore); } function setInfo(msg) { infoTxt.setText(msg); } function clearInfo() { infoTxt.setText(''); } function isInsideGrid(x, y) { return x >= 0 && x < gridCols && y >= 0 && y < gridRows; } function isGoal(x, y, forPlayer) { // Top row for player, bottom row for AI var goalCols = []; for (var i = Math.floor(gridCols / 2) - 2; i <= Math.floor(gridCols / 2) + 2; i++) { goalCols.push(i); } if (forPlayer && y === 0 && goalCols.indexOf(x) !== -1) return true; if (!forPlayer && y === gridRows - 1 && goalCols.indexOf(x) !== -1) return true; return false; } function getPawnAt(x, y) { for (var i = 0; i < playerPawns.length; i++) { if (playerPawns[i].gridX === x && playerPawns[i].gridY === y) return playerPawns[i]; } for (var i = 0; i < aiPawns.length; i++) { if (aiPawns[i].gridX === x && aiPawns[i].gridY === y) return aiPawns[i]; } return null; } function getWallAt(x, y) { for (var i = 0; i < walls.length; i++) { var wall = walls[i]; for (var j = 0; j < wall.cells.length; j++) { if (wall.cells[j].x === x && wall.cells[j].y === y) return wall; } } return null; } function cellBlocked(x, y) { if (!isInsideGrid(x, y)) return true; var occ = grid[y][x].occupied; return occ === 'player' || occ === 'ai' || occ === 'wall'; } function cellFree(x, y) { if (!isInsideGrid(x, y)) return false; var occ = grid[y][x].occupied; return occ === null || occ === 'ball' || occ === 'powerup'; } function knightMoves(x, y, pawn) { var moves = [{ dx: 1, dy: 3 }, { dx: 3, dy: 1 }, { dx: -1, dy: 3 }, { dx: -3, dy: 1 }, { dx: 1, dy: -3 }, { dx: 3, dy: -1 }, { dx: -1, dy: -3 }, { dx: -3, dy: -1 }, // Extra moves (as requested) { dx: 2, dy: 1 }, { dx: -1, dy: 1 }, { dx: -2, dy: -1 }, { dx: 1, dy: -1 }]; // Add speed boost moves if pawn has speed power-up if (pawn && pawn.speedBoost > 0) { moves = moves.concat([{ dx: 2, dy: 2 }, { dx: -2, dy: 2 }, { dx: 2, dy: -2 }, { dx: -2, dy: -2 }, { dx: 4, dy: 0 }, { dx: -4, dy: 0 }, { dx: 0, dy: 4 }, { dx: 0, dy: -4 }]); } var res = []; for (var i = 0; i < moves.length; i++) { var nx = x + moves[i].dx; var ny = y + moves[i].dy; if (isInsideGrid(nx, ny) && cellFree(nx, ny)) { res.push({ x: nx, y: ny }); } } return res; } function straightLineShots(x, y) { // Up, Down, Left, Right var dirs = [{ dx: 0, dy: -1 }, { dx: 0, dy: 1 }, { dx: -1, dy: 0 }, { dx: 1, dy: 0 }]; var shots = []; var maxShotDistance = 7; for (var d = 0; d < dirs.length; d++) { var nx = x, ny = y; var distance = 0; while (distance < maxShotDistance) { // limit to 7 blocks nx += dirs[d].dx; ny += dirs[d].dy; distance++; if (!isInsideGrid(nx, ny)) break; if (cellBlocked(nx, ny)) break; shots.push({ x: nx, y: ny, dir: dirs[d] }); if (isGoal(nx, ny, turn === 'player')) break; } } return shots; } function highlightCells(cells, color) { for (var i = 0; i < cells.length; i++) { var hl = LK.getAsset('target_indicator', { width: cellSize - 10, height: cellSize - 10, anchorX: 0.5, anchorY: 0.5, x: gridOriginX + cells[i].x * cellSize + cellSize / 2, y: gridOriginY + cells[i].y * cellSize + cellSize / 2, alpha: 0.7 }); game.addChild(hl); highlightOverlays.push(hl); } } function clearHighlights() { for (var i = 0; i < highlightOverlays.length; i++) { highlightOverlays[i].destroy(); } highlightOverlays = []; } function spawnRandomPowerUp() { var types = ['speed', 'shield', 'multishot']; var type = types[Math.floor(Math.random() * types.length)]; // Find empty cell for (var tries = 0; tries < 20; tries++) { var x = Math.floor(Math.random() * gridCols); var y = Math.floor(Math.random() * gridRows); if (cellFree(x, y) && !getPowerUpAt(x, y)) { var powerUp = new PowerUp(); powerUp.init(type); powerUp.setGridPos(x, y); powerUps.push(powerUp); game.addChild(powerUp); grid[y][x].occupied = 'powerup'; break; } } } function getPowerUpAt(x, y) { for (var i = 0; i < powerUps.length; i++) { if (powerUps[i].gridX === x && powerUps[i].gridY === y) { return powerUps[i]; } } return null; } function removePowerUp(powerUp) { grid[powerUp.gridY][powerUp.gridX].occupied = null; for (var i = 0; i < powerUps.length; i++) { if (powerUps[i] === powerUp) { powerUps.splice(i, 1); break; } } powerUp.destroy(); } function updatePowerUpEffects() { // Update all pawn power-up effects var allPawns = playerPawns.concat(aiPawns); for (var i = 0; i < allPawns.length; i++) { var pawn = allPawns[i]; if (pawn.speedBoost > 0) pawn.speedBoost--; if (pawn.shield > 0) pawn.shield--; if (pawn.multiShot > 0) pawn.multiShot--; } } var highlightOverlays = []; // --- Wall Generation (Tetris shapes) --- var tetrisShapes = [ // I [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 0, y: 3 }], // O [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 1 }], // T [{ x: 0, y: 0 }, { x: -1, y: 1 }, { x: 0, y: 1 }, { x: 1, y: 1 }], // L [{ x: 0, y: 0 }, { x: 0, y: 1 }, { x: 0, y: 2 }, { x: 1, y: 2 }], // S [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: -1, y: 1 }]]; function randomWallShape() { var idx = Math.floor(Math.random() * tetrisShapes.length); return tetrisShapes[idx]; } function canPlaceWallAt(shape, ox, oy) { for (var i = 0; i < shape.length; i++) { var x = ox + shape[i].x; var y = oy + shape[i].y; if (!isInsideGrid(x, y)) return false; if (grid[y][x].occupied) return false; // Don't block ball or pawns if (ball && ball.gridX === x && ball.gridY === y) return false; if (getPawnAt(x, y)) return false; } return true; } function placeRandomWall() { // Try up to 10 times to find a spot for (var tries = 0; tries < 10; tries++) { var shape = randomWallShape(); var ox = Math.floor(Math.random() * (gridCols - 2)) + 1; var oy = Math.floor(Math.random() * (gridRows - 2)) + 1; if (canPlaceWallAt(shape, ox, oy)) { var cells = []; for (var i = 0; i < shape.length; i++) { var x = ox + shape[i].x; var y = oy + shape[i].y; cells.push({ x: x, y: y }); } var wall = new Wall(); wall.init(cells, wallIdCounter); wall.wallId = wallIdCounter; wallIdCounter++; walls.push(wall); gameElements.push(wall); game.addChild(wall); for (var i = 0; i < cells.length; i++) { grid[cells[i].y][cells[i].x].occupied = 'wall'; grid[cells[i].y][cells[i].x].wallId = wall.wallId; } break; } } } // --- Turn Logic --- function startPlayerTurn() { turn = 'player'; turnCounter++; // Turn transition animation var turnMsg = new Text2('YOUR TURN', { size: 100, fill: 0x00ff00 }); turnMsg.anchor.set(0.5, 0.5); turnMsg.x = 1024; turnMsg.y = 1366; turnMsg.alpha = 0; game.addChild(turnMsg); tween(turnMsg, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(turnMsg, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { turnMsg.destroy(); } }); } }); setInfo("Your turn: Tap a pawn to move or shoot"); clearHighlights(); selectedPawn = null; validMoves = []; validShots = []; gameLocked = false; // Reduce power-up durations updatePowerUpEffects(); } function startAITurn() { turn = 'ai'; turnCounter++; // Turn transition animation var turnMsg = new Text2('AI TURN', { size: 100, fill: 0xff0000 }); turnMsg.anchor.set(0.5, 0.5); turnMsg.x = 1024; turnMsg.y = 1366; turnMsg.alpha = 0; game.addChild(turnMsg); tween(turnMsg, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(turnMsg, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { turnMsg.destroy(); } }); } }); setInfo("AI's turn..."); clearHighlights(); selectedPawn = null; validMoves = []; validShots = []; gameLocked = true; // Reduce power-up durations updatePowerUpEffects(); LK.setTimeout(aiTakeTurn, 700); } function endTurn() { // Power-up spawning (every 4 turns, 30% chance) if (turnCounter % 4 === 0 && Math.random() < 0.3) { spawnRandomPowerUp(); } // Wall spawning (reduced frequency but still random) if (Math.random() < 0.03) { placeRandomWall(); } // Check win conditions if (playerScore >= goalToWin) { gameStats.gamesPlayed++; gameStats.wins++; storage.gameStats = gameStats; LK.showYouWin(); return; } else if (aiScore >= goalToWin) { gameStats.gamesPlayed++; gameStats.losses++; storage.gameStats = gameStats; LK.showGameOver(); return; } if (turn === 'player') { startAITurn(); } else { startPlayerTurn(); } } // --- Ball Movement and Goal Check --- function moveBallTo(x, y, onFinish) { // Remove old ball from grid grid[ball.gridY][ball.gridX].occupied = null; ball.setGridPos(x, y); grid[y][x].occupied = 'ball'; ball.flash(); if (onFinish) LK.setTimeout(onFinish, 200); } function shootBall(fromX, fromY, toX, toY, dir, onFinish) { // Animate ball along the path, but limit to 7 blocks max var path = []; var nx = fromX, ny = fromY; var maxShotDistance = 7; var distance = 0; while (distance < maxShotDistance) { nx += dir.dx; ny += dir.dy; distance++; if (!isInsideGrid(nx, ny)) break; if (cellBlocked(nx, ny)) break; path.push({ x: nx, y: ny }); if (isGoal(nx, ny, turn === 'player')) break; if (isGoal(nx, ny, turn === 'ai')) break; } function animateStep(idx) { if (idx >= path.length) { if (onFinish) onFinish(); return; } moveBallTo(path[idx].x, path[idx].y, function () { animateStep(idx + 1); }); } animateStep(0); } // --- Player Input Handling --- game.down = function (x, y, obj) { if (gameLocked) return; // Convert to grid coordinates var gx = Math.floor((x - gridOriginX) / cellSize); var gy = Math.floor((y - gridOriginY) / cellSize); if (!isInsideGrid(gx, gy)) return; // If no pawn selected, select a pawn if (!selectedPawn) { for (var i = 0; i < playerPawns.length; i++) { var pawn = playerPawns[i]; if (pawn.gridX === gx && pawn.gridY === gy) { selectedPawn = pawn; pawn.flash(); // Show knight moves (with potential speed boost) validMoves = knightMoves(gx, gy, pawn); highlightCells(validMoves, 0x00ff00); // If pawn is adjacent to ball, allow to pick up if (Math.abs(ball.gridX - gx) + Math.abs(ball.gridY - gy) === 1) { validMoves.push({ x: ball.gridX, y: ball.gridY }); } // If pawn is on ball, allow to shoot if (gx === ball.gridX && gy === ball.gridY) { validShots = straightLineShots(gx, gy); highlightCells(validShots, 0xffa500); } return; } } } else { // If clicked on a valid move, move pawn for (var i = 0; i < validMoves.length; i++) { if (validMoves[i].x === gx && validMoves[i].y === gy) { // Check for power-up collection var powerUp = getPowerUpAt(gx, gy); if (powerUp) { powerUp.applyEffect(selectedPawn); removePowerUp(powerUp); setInfo("Power-up collected: " + powerUp.type.toUpperCase() + "!"); } // Move pawn grid[selectedPawn.gridY][selectedPawn.gridX].occupied = null; selectedPawn.setGridPos(gx, gy); grid[gy][gx].occupied = 'player'; // If moved onto ball, pick up if (gx === ball.gridX && gy === ball.gridY) { selectedPawn.hasBall = true; setInfo("You have the ball! Move again or tap a direction to shoot."); // Allow dribbling: highlight knight moves and shots again (with speed boost) validMoves = knightMoves(gx, gy, selectedPawn); validShots = straightLineShots(gx, gy); clearHighlights(); highlightCells(validMoves, 0x00ff00); highlightCells(validShots, 0xffa500); return; } clearHighlights(); endTurn(); return; } } // If pawn has ball and clicked on valid shot, shoot if (selectedPawn.hasBall) { // Check for shot for (var i = 0; i < validShots.length; i++) { if (validShots[i].x === gx && validShots[i].y === gy) { selectedPawn.hasBall = false; clearHighlights(); shootBall(selectedPawn.gridX, selectedPawn.gridY, gx, gy, validShots[i].dir, function () { // Check for goal if (isGoal(gx, gy, true)) { playerScore++; updateScore(); setInfo("GOAL! You scored!"); // Beautiful goal effect: flash screen, ball animation, and shake goal LK.effects.flashScreen(0x00ff00, 400); // Animate ball scaling up and fading out for a goal "pop" tween.to(ball, { scaleX: 2, scaleY: 2, alpha: 0 }, 350, { easing: 'easeOutCubic' }); // Animate bottom goal shaking tween.to(goalBotImg, { x: goalBotImg.x + 20 }, 60, { yoyo: true, repeat: 3 }); tween.to(goalBotImg, { x: goalBotImg.x - 20 }, 60, { yoyo: true, repeat: 3 }); if (playerScore >= goalToWin) { LK.setTimeout(function () { LK.showYouWin(); }, 600); return; } LK.setTimeout(function () { resetAfterGoal(false); }, 1200); } else { endTurn(); } }); return; } } // Check for dribble move (knight move with ball) for (var i = 0; i < validMoves.length; i++) { if (validMoves[i].x === gx && validMoves[i].y === gy) { // Move pawn and ball together grid[selectedPawn.gridY][selectedPawn.gridX].occupied = null; selectedPawn.setGridPos(gx, gy); grid[gy][gx].occupied = 'player'; moveBallTo(gx, gy); // Check for power-up collection during dribble var powerUp = getPowerUpAt(gx, gy); if (powerUp) { powerUp.applyEffect(selectedPawn); removePowerUp(powerUp); setInfo("Power-up collected! Tap direction to shoot!"); } else { setInfo("Tap a direction to shoot!"); } validShots = straightLineShots(gx, gy); validMoves = []; // Only allow shoot after dribble, not another move clearHighlights(); highlightCells(validShots, 0xffa500); return; } } } // Deselect if clicked elsewhere clearHighlights(); selectedPawn = null; validMoves = []; validShots = []; } }; // --- AI Logic --- function aiTakeTurn() { // --- AI STRATEGY: All 3 pawns act, with passing, shooting, and blocking --- // 1. Try to shoot if any pawn is on the ball // 2. Try to pass if a pawn can reach the ball and another can shoot // 3. Otherwise, move pawns to block or approach ball // Helper: Find all possible moves for a pawn function pawnMoves(pawn) { return knightMoves(pawn.gridX, pawn.gridY, pawn); } // 1. Try to shoot if any pawn is on the ball for (var i = 0; i < aiPawns.length; i++) { var pawn = aiPawns[i]; if (pawn.gridX === ball.gridX && pawn.gridY === ball.gridY) { var shots = straightLineShots(pawn.gridX, pawn.gridY); // Prefer shooting downwards (towards player goal) var bestShot = null; for (var j = 0; j < shots.length; j++) { if (shots[j].dir.dy > 0) { bestShot = shots[j]; break; } } if (!bestShot && shots.length > 0) bestShot = shots[0]; if (bestShot) { shootBall(pawn.gridX, pawn.gridY, bestShot.x, bestShot.y, bestShot.dir, function () { if (isGoal(bestShot.x, bestShot.y, false)) { aiScore++; updateScore(); setInfo("AI scored!"); LK.effects.flashScreen(0xff0000, 400); tween.to(ball, { scaleX: 2, scaleY: 2, alpha: 0 }, 350, { easing: 'easeOutCubic' }); tween.to(goalTopImg, { x: goalTopImg.x + 20 }, 60, { yoyo: true, repeat: 3 }); tween.to(goalTopImg, { x: goalTopImg.x - 20 }, 60, { yoyo: true, repeat: 3 }); if (aiScore >= goalToWin) { LK.setTimeout(function () { LK.showGameOver(); }, 600); return; } LK.setTimeout(function () { resetAfterGoal(true); }, 1200); } else { endTurn(); } }); return; } } } // 2. Try to pass: If a pawn can move onto the ball, and another pawn can shoot from there var passFound = false; for (var i = 0; i < aiPawns.length; i++) { var mover = aiPawns[i]; var moves = pawnMoves(mover); for (var j = 0; j < moves.length; j++) { if (moves[j].x === ball.gridX && moves[j].y === ball.gridY) { // Simulate: If this pawn moves onto ball, can another pawn shoot next turn? for (var k = 0; k < aiPawns.length; k++) { if (k === i) continue; var shooter = aiPawns[k]; // Can shooter reach the new ball position in one move? var shooterMoves = knightMoves(shooter.gridX, shooter.gridY); for (var m = 0; m < shooterMoves.length; m++) { if (shooterMoves[m].x === moves[j].x && shooterMoves[m].y === moves[j].y) { // Simulate shooter on ball, can shoot? var shots = straightLineShots(moves[j].x, moves[j].y); var bestShot = null; for (var n = 0; n < shots.length; n++) { if (shots[n].dir.dy > 0) { bestShot = shots[n]; break; } } if (!bestShot && shots.length > 0) bestShot = shots[0]; if (bestShot) { // Move mover onto ball grid[mover.gridY][mover.gridX].occupied = null; mover.setGridPos(moves[j].x, moves[j].y); grid[moves[j].y][moves[j].x].occupied = 'ai'; mover.hasBall = true; // Next turn, shooter will shoot passFound = true; endTurn(); return; } } } } } } } // 3. Otherwise, move all pawns: one towards ball, others block or approach // Find the pawn closest to the ball var bestPawn = null; var minDist = 9999; for (var i = 0; i < aiPawns.length; i++) { var pawn = aiPawns[i]; var dist = Math.abs(pawn.gridX - ball.gridX) + Math.abs(pawn.gridY - ball.gridY); if (dist < minDist) { minDist = dist; bestPawn = pawn; } } // Move bestPawn towards ball if (bestPawn) { var moves = knightMoves(bestPawn.gridX, bestPawn.gridY); var bestMove = null; minDist = 9999; for (var i = 0; i < moves.length; i++) { var dist = Math.abs(moves[i].x - ball.gridX) + Math.abs(moves[i].y - ball.gridY); if (dist < minDist) { minDist = dist; bestMove = moves[i]; } } if (bestMove) { grid[bestPawn.gridY][bestPawn.gridX].occupied = null; bestPawn.setGridPos(bestMove.x, bestMove.y); grid[bestMove.y][bestMove.x].occupied = 'ai'; // If moved onto ball, pick up and shoot next turn if (bestMove.x === ball.gridX && bestMove.y === ball.gridY) { bestPawn.hasBall = true; } } } // Move other pawns to block or approach player pawns for (var i = 0; i < aiPawns.length; i++) { var pawn = aiPawns[i]; if (pawn === bestPawn) continue; // Try to block: move towards the player pawn closest to the ball var closestPlayer = null; var minPlayerDist = 9999; for (var j = 0; j < playerPawns.length; j++) { var pdist = Math.abs(playerPawns[j].gridX - ball.gridX) + Math.abs(playerPawns[j].gridY - ball.gridY); if (pdist < minPlayerDist) { minPlayerDist = pdist; closestPlayer = playerPawns[j]; } } if (closestPlayer) { var moves = knightMoves(pawn.gridX, pawn.gridY); var bestBlock = null; var minBlockDist = 9999; for (var k = 0; k < moves.length; k++) { var dist = Math.abs(moves[k].x - closestPlayer.gridX) + Math.abs(moves[k].y - closestPlayer.gridY); if (dist < minBlockDist && cellFree(moves[k].x, moves[k].y)) { minBlockDist = dist; bestBlock = moves[k]; } } if (bestBlock) { grid[pawn.gridY][pawn.gridX].occupied = null; pawn.setGridPos(bestBlock.x, bestBlock.y); grid[bestBlock.y][bestBlock.x].occupied = 'ai'; } } } endTurn(); } // --- Reset After Goal --- function resetAfterGoal(aiScored) { // Remove all walls for (var i = 0; i < walls.length; i++) { walls[i].destroy(); } walls = []; // Remove all power-ups for (var i = 0; i < powerUps.length; i++) { powerUps[i].destroy(); } powerUps = []; gameElements = []; // Clear grid for (var y = 0; y < gridRows; y++) { for (var x = 0; x < gridCols; x++) { grid[y][x].occupied = null; grid[y][x].wallId = null; } } // Reset pawns for (var i = 0; i < playerPawns.length; i++) { playerPawns[i].destroy(); } for (var i = 0; i < aiPawns.length; i++) { aiPawns[i].destroy(); } playerPawns = []; aiPawns = []; placePawns(); // Clear all power-up effects from pawns var allPawns = playerPawns.concat(aiPawns); for (var i = 0; i < allPawns.length; i++) { allPawns[i].speedBoost = 0; allPawns[i].shield = 0; allPawns[i].multiShot = 0; allPawns[i].hasBall = false; } // Reset ball at center and show it for a moment before resuming play placeBall(true); clearHighlights(); selectedPawn = null; validMoves = []; validShots = []; gameLocked = false; setInfo(''); // Wait 900ms before resuming play, so the ball is visible at center after a goal LK.setTimeout(function () { if (aiScored) { startPlayerTurn(); } else { startAITurn(); } }, 900); } // --- Game Update (not used for logic, but could be for animations) --- game.update = function () { // Check if ball is in the top goal area (AI's goal, y === 0, goalCols) if (ball && goalCols.indexOf(ball.gridX) !== -1 && ball.gridY === 0) { // Player scores! playerScore++; updateScore(); setInfo("GOAL! You scored!"); LK.effects.flashScreen(0x00ff00, 400); tween.to(ball, { scaleX: 2, scaleY: 2, alpha: 0 }, 350, { easing: 'easeOutCubic' }); tween.to(goalTopImg, { x: goalTopImg.x + 20 }, 60, { yoyo: true, repeat: 3 }); tween.to(goalTopImg, { x: goalTopImg.x - 20 }, 60, { yoyo: true, repeat: 3 }); if (playerScore >= goalToWin) { LK.setTimeout(function () { LK.showYouWin(); }, 600); } else { LK.setTimeout(function () { resetAfterGoal(false); }, 1200); } } // Check if ball is in the bottom goal area (Player's goal, y === gridRows-1, goalCols) if (ball && goalCols.indexOf(ball.gridX) !== -1 && ball.gridY === gridRows - 1) { // AI scores! aiScore++; updateScore(); setInfo("AI scored!"); LK.effects.flashScreen(0xff0000, 400); tween.to(ball, { scaleX: 2, scaleY: 2, alpha: 0 }, 350, { easing: 'easeOutCubic' }); tween.to(goalBotImg, { x: goalBotImg.x + 20 }, 60, { yoyo: true, repeat: 3 }); tween.to(goalBotImg, { x: goalBotImg.x - 20 }, 60, { yoyo: true, repeat: 3 }); if (aiScore >= goalToWin) { LK.setTimeout(function () { LK.showGameOver(); }, 600); } else { LK.setTimeout(function () { resetAfterGoal(true); }, 1200); } } }; // --- Game Statistics Display --- var statsTxt = new Text2('Games: ' + gameStats.gamesPlayed + ' | W: ' + gameStats.wins + ' | L: ' + gameStats.losses, { size: 40, fill: 0x888888 }); statsTxt.anchor.set(1, 0); statsTxt.x = 2048 - 20; statsTxt.y = 20; game.addChild(statsTxt); // --- Start Game --- updateScore(); startPlayerTurn();
===================================================================
--- original.js
+++ change.js
@@ -1,8 +1,9 @@
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
@@ -61,8 +62,76 @@
LK.effects.flashObject(self, 0xffff00, 300);
};
return self;
});
+// --- PowerUp: Spawnable items with special effects ---
+var PowerUp = Container.expand(function () {
+ var self = Container.call(this);
+ self.gridX = 0;
+ self.gridY = 0;
+ self.type = 'speed'; // 'speed', 'shield', 'multishot'
+ self.powerUpAsset = null;
+ self.init = function (type) {
+ self.type = type;
+ var colors = {
+ 'speed': 0x00ff00,
+ 'shield': 0x0080ff,
+ 'multishot': 0xff8000
+ };
+ self.powerUpAsset = self.attachAsset('target_indicator', {
+ width: cellSize * 0.8,
+ height: cellSize * 0.8,
+ color: colors[type] || 0xffffff,
+ shape: 'ellipse',
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Pulsing animation
+ self.startPulse();
+ };
+ self.startPulse = function () {
+ tween(self.powerUpAsset, {
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 800,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(self.powerUpAsset, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 800,
+ easing: tween.easeInOut,
+ onFinish: self.startPulse
+ });
+ }
+ });
+ };
+ self.setGridPos = function (gx, gy) {
+ self.gridX = gx;
+ self.gridY = gy;
+ self.x = gridOriginX + gx * cellSize + cellSize / 2;
+ self.y = gridOriginY + gy * cellSize + cellSize / 2;
+ };
+ self.applyEffect = function (pawn) {
+ switch (self.type) {
+ case 'speed':
+ pawn.speedBoost = 3; // Extra moves for 3 turns
+ LK.effects.flashObject(pawn, 0x00ff00, 500);
+ break;
+ case 'shield':
+ pawn.shield = 2; // Blocks shots for 2 turns
+ LK.effects.flashObject(pawn, 0x0080ff, 500);
+ break;
+ case 'multishot':
+ pawn.multiShot = 1; // Can shoot multiple times
+ LK.effects.flashObject(pawn, 0xff8000, 500);
+ break;
+ }
+ };
+ return self;
+});
// --- Wall: Tetris block wall, occupies multiple cells ---
var Wall = Container.expand(function () {
var self = Container.call(this);
self.cells = []; // [{x, y}]
@@ -100,10 +169,10 @@
/****
* Game Code
****/
-// --- GridCell: For grid logic, not a display object ---
// --- Grid Setup ---
+// --- GridCell: For grid logic, not a display object ---
var GridCell = function GridCell(x, y) {
this.x = x;
this.y = y;
this.occupied = null; // null, 'player', 'ai', 'wall', 'ball'
@@ -140,8 +209,15 @@
var aiScore = 0;
var goalToWin = 3;
var scoreTxt = null;
var infoTxt = null;
+var powerUps = [];
+var turnCounter = 0;
+var gameStats = storage.gameStats || {
+ gamesPlayed: 0,
+ wins: 0,
+ losses: 0
+};
// --- Draw grid cell backgrounds ---
var goalCols = [];
for (var i = Math.floor(gridCols / 2) - 2; i <= Math.floor(gridCols / 2) + 2; i++) {
goalCols.push(i);
@@ -314,11 +390,11 @@
}
function cellFree(x, y) {
if (!isInsideGrid(x, y)) return false;
var occ = grid[y][x].occupied;
- return occ === null || occ === 'ball';
+ return occ === null || occ === 'ball' || occ === 'powerup';
}
-function knightMoves(x, y) {
+function knightMoves(x, y, pawn) {
var moves = [{
dx: 1,
dy: 3
}, {
@@ -356,8 +432,36 @@
}, {
dx: 1,
dy: -1
}];
+ // Add speed boost moves if pawn has speed power-up
+ if (pawn && pawn.speedBoost > 0) {
+ moves = moves.concat([{
+ dx: 2,
+ dy: 2
+ }, {
+ dx: -2,
+ dy: 2
+ }, {
+ dx: 2,
+ dy: -2
+ }, {
+ dx: -2,
+ dy: -2
+ }, {
+ dx: 4,
+ dy: 0
+ }, {
+ dx: -4,
+ dy: 0
+ }, {
+ dx: 0,
+ dy: 4
+ }, {
+ dx: 0,
+ dy: -4
+ }]);
+ }
var res = [];
for (var i = 0; i < moves.length; i++) {
var nx = x + moves[i].dx;
var ny = y + moves[i].dy;
@@ -428,8 +532,54 @@
highlightOverlays[i].destroy();
}
highlightOverlays = [];
}
+function spawnRandomPowerUp() {
+ var types = ['speed', 'shield', 'multishot'];
+ var type = types[Math.floor(Math.random() * types.length)];
+ // Find empty cell
+ for (var tries = 0; tries < 20; tries++) {
+ var x = Math.floor(Math.random() * gridCols);
+ var y = Math.floor(Math.random() * gridRows);
+ if (cellFree(x, y) && !getPowerUpAt(x, y)) {
+ var powerUp = new PowerUp();
+ powerUp.init(type);
+ powerUp.setGridPos(x, y);
+ powerUps.push(powerUp);
+ game.addChild(powerUp);
+ grid[y][x].occupied = 'powerup';
+ break;
+ }
+ }
+}
+function getPowerUpAt(x, y) {
+ for (var i = 0; i < powerUps.length; i++) {
+ if (powerUps[i].gridX === x && powerUps[i].gridY === y) {
+ return powerUps[i];
+ }
+ }
+ return null;
+}
+function removePowerUp(powerUp) {
+ grid[powerUp.gridY][powerUp.gridX].occupied = null;
+ for (var i = 0; i < powerUps.length; i++) {
+ if (powerUps[i] === powerUp) {
+ powerUps.splice(i, 1);
+ break;
+ }
+ }
+ powerUp.destroy();
+}
+function updatePowerUpEffects() {
+ // Update all pawn power-up effects
+ var allPawns = playerPawns.concat(aiPawns);
+ for (var i = 0; i < allPawns.length; i++) {
+ var pawn = allPawns[i];
+ if (pawn.speedBoost > 0) pawn.speedBoost--;
+ if (pawn.shield > 0) pawn.shield--;
+ if (pawn.multiShot > 0) pawn.multiShot--;
+ }
+}
var highlightOverlays = [];
// --- Wall Generation (Tetris shapes) ---
var tetrisShapes = [
// I
@@ -551,30 +701,110 @@
}
// --- Turn Logic ---
function startPlayerTurn() {
turn = 'player';
+ turnCounter++;
+ // Turn transition animation
+ var turnMsg = new Text2('YOUR TURN', {
+ size: 100,
+ fill: 0x00ff00
+ });
+ turnMsg.anchor.set(0.5, 0.5);
+ turnMsg.x = 1024;
+ turnMsg.y = 1366;
+ turnMsg.alpha = 0;
+ game.addChild(turnMsg);
+ tween(turnMsg, {
+ alpha: 1,
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 300,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(turnMsg, {
+ alpha: 0
+ }, {
+ duration: 500,
+ onFinish: function onFinish() {
+ turnMsg.destroy();
+ }
+ });
+ }
+ });
setInfo("Your turn: Tap a pawn to move or shoot");
clearHighlights();
selectedPawn = null;
validMoves = [];
validShots = [];
gameLocked = false;
+ // Reduce power-up durations
+ updatePowerUpEffects();
}
function startAITurn() {
turn = 'ai';
+ turnCounter++;
+ // Turn transition animation
+ var turnMsg = new Text2('AI TURN', {
+ size: 100,
+ fill: 0xff0000
+ });
+ turnMsg.anchor.set(0.5, 0.5);
+ turnMsg.x = 1024;
+ turnMsg.y = 1366;
+ turnMsg.alpha = 0;
+ game.addChild(turnMsg);
+ tween(turnMsg, {
+ alpha: 1,
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 300,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(turnMsg, {
+ alpha: 0
+ }, {
+ duration: 500,
+ onFinish: function onFinish() {
+ turnMsg.destroy();
+ }
+ });
+ }
+ });
setInfo("AI's turn...");
clearHighlights();
selectedPawn = null;
validMoves = [];
validShots = [];
gameLocked = true;
+ // Reduce power-up durations
+ updatePowerUpEffects();
LK.setTimeout(aiTakeTurn, 700);
}
function endTurn() {
- // After each turn, maybe spawn a wall
- if (Math.random() < 0.05) {
+ // Power-up spawning (every 4 turns, 30% chance)
+ if (turnCounter % 4 === 0 && Math.random() < 0.3) {
+ spawnRandomPowerUp();
+ }
+ // Wall spawning (reduced frequency but still random)
+ if (Math.random() < 0.03) {
placeRandomWall();
}
+ // Check win conditions
+ if (playerScore >= goalToWin) {
+ gameStats.gamesPlayed++;
+ gameStats.wins++;
+ storage.gameStats = gameStats;
+ LK.showYouWin();
+ return;
+ } else if (aiScore >= goalToWin) {
+ gameStats.gamesPlayed++;
+ gameStats.losses++;
+ storage.gameStats = gameStats;
+ LK.showGameOver();
+ return;
+ }
if (turn === 'player') {
startAITurn();
} else {
startPlayerTurn();
@@ -633,10 +863,10 @@
var pawn = playerPawns[i];
if (pawn.gridX === gx && pawn.gridY === gy) {
selectedPawn = pawn;
pawn.flash();
- // Show knight moves
- validMoves = knightMoves(gx, gy);
+ // Show knight moves (with potential speed boost)
+ validMoves = knightMoves(gx, gy, pawn);
highlightCells(validMoves, 0x00ff00);
// If pawn is adjacent to ball, allow to pick up
if (Math.abs(ball.gridX - gx) + Math.abs(ball.gridY - gy) === 1) {
validMoves.push({
@@ -655,18 +885,25 @@
} else {
// If clicked on a valid move, move pawn
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].x === gx && validMoves[i].y === gy) {
+ // Check for power-up collection
+ var powerUp = getPowerUpAt(gx, gy);
+ if (powerUp) {
+ powerUp.applyEffect(selectedPawn);
+ removePowerUp(powerUp);
+ setInfo("Power-up collected: " + powerUp.type.toUpperCase() + "!");
+ }
// Move pawn
grid[selectedPawn.gridY][selectedPawn.gridX].occupied = null;
selectedPawn.setGridPos(gx, gy);
grid[gy][gx].occupied = 'player';
// If moved onto ball, pick up
if (gx === ball.gridX && gy === ball.gridY) {
selectedPawn.hasBall = true;
setInfo("You have the ball! Move again or tap a direction to shoot.");
- // Allow dribbling: highlight knight moves and shots again
- validMoves = knightMoves(gx, gy);
+ // Allow dribbling: highlight knight moves and shots again (with speed boost)
+ validMoves = knightMoves(gx, gy, selectedPawn);
validShots = straightLineShots(gx, gy);
clearHighlights();
highlightCells(validMoves, 0x00ff00);
highlightCells(validShots, 0xffa500);
@@ -736,10 +973,17 @@
grid[selectedPawn.gridY][selectedPawn.gridX].occupied = null;
selectedPawn.setGridPos(gx, gy);
grid[gy][gx].occupied = 'player';
moveBallTo(gx, gy);
- // Allow shoot after dribble
- setInfo("Tap a direction to shoot!");
+ // Check for power-up collection during dribble
+ var powerUp = getPowerUpAt(gx, gy);
+ if (powerUp) {
+ powerUp.applyEffect(selectedPawn);
+ removePowerUp(powerUp);
+ setInfo("Power-up collected! Tap direction to shoot!");
+ } else {
+ setInfo("Tap a direction to shoot!");
+ }
validShots = straightLineShots(gx, gy);
validMoves = []; // Only allow shoot after dribble, not another move
clearHighlights();
highlightCells(validShots, 0xffa500);
@@ -761,9 +1005,9 @@
// 2. Try to pass if a pawn can reach the ball and another can shoot
// 3. Otherwise, move pawns to block or approach ball
// Helper: Find all possible moves for a pawn
function pawnMoves(pawn) {
- return knightMoves(pawn.gridX, pawn.gridY);
+ return knightMoves(pawn.gridX, pawn.gridY, pawn);
}
// 1. Try to shoot if any pawn is on the ball
for (var i = 0; i < aiPawns.length; i++) {
var pawn = aiPawns[i];
@@ -937,8 +1181,13 @@
for (var i = 0; i < walls.length; i++) {
walls[i].destroy();
}
walls = [];
+ // Remove all power-ups
+ for (var i = 0; i < powerUps.length; i++) {
+ powerUps[i].destroy();
+ }
+ powerUps = [];
gameElements = [];
// Clear grid
for (var y = 0; y < gridRows; y++) {
for (var x = 0; x < gridCols; x++) {
@@ -955,8 +1204,16 @@
}
playerPawns = [];
aiPawns = [];
placePawns();
+ // Clear all power-up effects from pawns
+ var allPawns = playerPawns.concat(aiPawns);
+ for (var i = 0; i < allPawns.length; i++) {
+ allPawns[i].speedBoost = 0;
+ allPawns[i].shield = 0;
+ allPawns[i].multiShot = 0;
+ allPawns[i].hasBall = false;
+ }
// Reset ball at center and show it for a moment before resuming play
placeBall(true);
clearHighlights();
selectedPawn = null;
@@ -1047,7 +1304,16 @@
}, 1200);
}
}
};
+// --- Game Statistics Display ---
+var statsTxt = new Text2('Games: ' + gameStats.gamesPlayed + ' | W: ' + gameStats.wins + ' | L: ' + gameStats.losses, {
+ size: 40,
+ fill: 0x888888
+});
+statsTxt.anchor.set(1, 0);
+statsTxt.x = 2048 - 20;
+statsTxt.y = 20;
+game.addChild(statsTxt);
// --- Start Game ---
updateScore();
startPlayerTurn();
\ No newline at end of file