User prompt
it doesnt let the player play after the first turn, from the second turn and on it shows only the next turn ui and doesnt let the player play
User prompt
Make it turn base, the Ai cant continuosly play
User prompt
Change the attack zone for the mage, it can only attack characters that is on tile around its attack tile
User prompt
The position of the characters in the blue team is inverted. THE line where tha king is should be below the line of the warriors and knights
User prompt
change the characters positioning, it should be Red: Archer, Mage, King, Mage, Archer Kinght, warrior, warrior, warrior, Knight Blue: Kinght, warrior, warrior, warrior, Knight Archer, Mage, King, Mage, Archer
User prompt
change the postition fo the characters for both teams. It should be like: blue team ex: Archer, Mage, King, Mage, Archer Knight, warrior, warrior, warrior, knight
User prompt
change the postition fo the characters for both teams. It should be like: blue team ex: Knight, warrior, warrior, warrior, knight Archer, Mage, King, Mage, Archer
User prompt
increase the size, make the whole arena fit to the screen
User prompt
Increase the size of everything, so that the board fits the screen ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Create game
Code edit (1 edits merged)
Please save this source code
User prompt
Tactical Kings: Battle of Champions
Initial prompt
Title: "Tactical Kings: Battle of Champions" A fantasy-themed, chess-inspired strategy game where players control unique units with predefined attack zones. Victory comes from eliminating the opponent’s King by strategically positioning characters on a 5x10 grid. Core Mechanics: Turn-Based Gameplay: Players take turns moving one character at a time, with automatic attacks occurring after movement. Pre-Calculated Attacks: Before moving, players see highlighted attack zones to plan the best positioning. Character Roles & Counters: Spear Knights → Strong melee attacks, move straight or sideways (1-3 tiles). Archers → Long-range (8 tiles forward), move sideways freely but only one tile forward if moving forward. Mages → Cast area spells 6 tiles ahead, damaging all surrounding enemies. Tank → Instant-kill attack (1 tile forward), slow movement (only 1 tile per turn). King → Moves freely like a chess queen, but only attacks 1 tile forward. AI Strategy: Simple pattern-following—AI moves towards optimal attack positions without complex decision trees. Minimal Animations: Basic sprite interpolation for movement, slight grow and shrink for idle, and a sprite change for attacks. Win Condition: Eliminate the opponent's King—no timers or alternative victory methods.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var AIPlayer = Container.expand(function () { var self = Container.call(this); self.makeMove = function () { var units = game.getTeamUnits('red'); var moveFound = false; // First priority: attack if possible for (var i = 0; i < units.length; i++) { var unit = units[i]; var attacks = unit.getPossibleAttacks(game.grid); if (attacks.length > 0) { // Prioritize attacking king var kingAttack = attacks.find(function (attack) { return game.grid[attack.row][attack.col].occupiedBy && game.grid[attack.row][attack.col].occupiedBy.isKing; }); if (kingAttack) { game.selectUnit(unit); game.attackCell(game.grid[kingAttack.row][kingAttack.col]); return true; } // Otherwise attack first available target game.selectUnit(unit); game.attackCell(game.grid[attacks[0].row][attacks[0].col]); return true; } } // Second priority: move toward player king var playerKing = game.getKing('blue'); if (playerKing) { // Find unit closest to player king that can move var closestUnit = null; var closestDistance = Infinity; for (var i = 0; i < units.length; i++) { var unit = units[i]; var moves = unit.getPossibleMoves(game.grid); if (moves.length > 0) { var dist = Math.abs(unit.row - playerKing.row) + Math.abs(unit.col - playerKing.col); if (dist < closestDistance) { closestUnit = unit; closestDistance = dist; } } } if (closestUnit) { var bestMove = null; var bestMoveScore = -Infinity; var moves = closestUnit.getPossibleMoves(game.grid); // Score each possible move for (var i = 0; i < moves.length; i++) { var move = moves[i]; var moveScore = closestDistance - (Math.abs(move.row - playerKing.row) + Math.abs(move.col - playerKing.col)); if (moveScore > bestMoveScore) { bestMove = move; bestMoveScore = moveScore; } } if (bestMove) { game.selectUnit(closestUnit); game.moveSelectedUnit(bestMove.row, bestMove.col); return true; } } } // Last resort: random move with random unit var movableUnits = units.filter(function (unit) { return unit.getPossibleMoves(game.grid).length > 0; }); if (movableUnits.length > 0) { var randomUnit = movableUnits[Math.floor(Math.random() * movableUnits.length)]; var possibleMoves = randomUnit.getPossibleMoves(game.grid); var randomMove = possibleMoves[Math.floor(Math.random() * possibleMoves.length)]; game.selectUnit(randomUnit); game.moveSelectedUnit(randomMove.row, randomMove.col); return true; } return false; // No move possible }; return self; }); var GridCell = Container.expand(function () { var self = Container.call(this); // Cell properties self.row = 0; self.col = 0; self.occupied = false; self.occupiedBy = null; self.highlighted = false; self.highlightType = null; // Create cell graphic var cellGraphic = self.attachAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); // Highlighting methods self.highlight = function (type) { if (self.highlightAsset) { self.removeChild(self.highlightAsset); } self.highlighted = true; self.highlightType = type; if (type === 'move') { self.highlightAsset = self.attachAsset('highlight_move', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } else if (type === 'attack') { self.highlightAsset = self.attachAsset('highlight_attack', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } else if (type === 'selected') { self.highlightAsset = self.attachAsset('highlight_selected', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } }; self.clearHighlight = function () { if (self.highlightAsset) { self.removeChild(self.highlightAsset); self.highlightAsset = null; } self.highlighted = false; self.highlightType = null; }; // Event handlers self.down = function (x, y, obj) { if (game.gameState === 'playerTurn') { game.handleCellClick(self); } }; return self; }); var Unit = Container.expand(function () { var self = Container.call(this); // Unit properties self.type = ""; self.team = ""; self.row = 0; self.col = 0; self.isKing = false; self.alive = true; self.selected = false; // Initialize with type and team self.init = function (type, team, row, col) { self.type = type; self.team = team; self.row = row; self.col = col; self.isKing = type === 'king'; var assetId = type + '_' + team; self.unitGraphic = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); return self; }; // Movement validation self.canMoveTo = function (targetRow, targetCol) { // Base movement logic to be overridden by specific unit types return false; }; // Attack validation self.canAttack = function (targetRow, targetCol) { // Base attack logic to be overridden by specific unit types return false; }; // Get possible move cells self.getPossibleMoves = function (grid) { var moves = []; for (var r = 0; r < grid.length; r++) { for (var c = 0; c < grid[r].length; c++) { if (this.canMoveTo(r, c) && !grid[r][c].occupied) { moves.push({ row: r, col: c }); } } } return moves; }; // Get possible attack cells self.getPossibleAttacks = function (grid) { var attacks = []; for (var r = 0; r < grid.length; r++) { for (var c = 0; c < grid[r].length; c++) { if (this.canAttack(r, c) && grid[r][c].occupied && grid[r][c].occupiedBy.team !== this.team) { attacks.push({ row: r, col: c }); } } } return attacks; }; // Move unit to new position self.moveTo = function (targetRow, targetCol) { self.row = targetRow; self.col = targetCol; }; // Select unit self.select = function () { self.selected = true; self.unitGraphic.alpha = 1.0; }; // Deselect unit self.deselect = function () { self.selected = false; self.unitGraphic.alpha = 0.8; }; return self; }); var Wizard = Unit.expand(function () { var self = Unit.call(this); // Override movement validation self.canMoveTo = function (targetRow, targetCol) { var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); // Wizard can move diagonally or in straight lines return rowDiff <= 2 && colDiff <= 2; }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // Cast area spells 6 tiles ahead var forwardLimit = self.team === 'blue' ? self.row - 6 : self.row + 6; var inRange = false; if (self.team === 'blue') { inRange = targetRow >= forwardLimit && targetRow < self.row; } else { inRange = targetRow <= forwardLimit && targetRow > self.row; } return inRange; }; // Wizards do area damage self.isAreaAttacker = true; return self; }); var Warrior = Unit.expand(function () { var self = Unit.call(this); // Override movement validation self.canMoveTo = function (targetRow, targetCol) { var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); // Warrior can only move 1 tile in any direction return rowDiff <= 1 && colDiff <= 1 && !(rowDiff === 0 && colDiff === 0); }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // Instant-kill attack (1 tile forward) if (self.team === 'blue') { return targetRow === self.row - 1 && targetCol === self.col; } else { return targetRow === self.row + 1 && targetCol === self.col; } }; // Warriors have instant kill ability self.hasInstantKill = true; return self; }); var Knight = Unit.expand(function () { var self = Unit.call(this); // Override movement validation self.canMoveTo = function (targetRow, targetCol) { // Knight moves straight or sideways (1-3 tiles) var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); // Can move horizontally or vertically up to 3 tiles return rowDiff === 0 && colDiff > 0 && colDiff <= 3 || colDiff === 0 && rowDiff > 0 && rowDiff <= 3; }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // Same as movement - can attack in movement range return self.canMoveTo(targetRow, targetCol); }; return self; }); var King = Unit.expand(function () { var self = Unit.call(this); // Override movement validation self.canMoveTo = function (targetRow, targetCol) { // King moves like a chess queen but limited distance var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); // Can move in any direction but maximum 1 space return rowDiff <= 1 && colDiff <= 1 && !(rowDiff === 0 && colDiff === 0); }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // King only attacks 1 tile forward based on team direction var forwardRow = self.team === 'blue' ? self.row - 1 : self.row + 1; return targetRow === forwardRow && targetCol === self.col; }; return self; }); var Archer = Unit.expand(function () { var self = Unit.call(this); // Override movement validation self.canMoveTo = function (targetRow, targetCol) { var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); // Can move sideways freely, but only one tile forward if (self.team === 'blue') { return colDiff > 0 && rowDiff === 0 || // sideways targetRow === self.row - 1 && colDiff === 0; // one forward } else { return colDiff > 0 && rowDiff === 0 || // sideways targetRow === self.row + 1 && colDiff === 0; // one forward } }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // Can attack up to 8 tiles ahead if (self.team === 'blue') { return targetCol === self.col && targetRow < self.row && self.row - targetRow <= 8; } else { return targetCol === self.col && targetRow > self.row && targetRow - self.row <= 8; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game constants // Import tween plugin var GRID_ROWS = 10; var GRID_COLS = 5; var CELL_SIZE = 180; // Increased cell size var GRID_PADDING_X = (2048 - GRID_COLS * CELL_SIZE) / 2; var GRID_PADDING_Y = (2732 - GRID_ROWS * CELL_SIZE) / 2; // Game variables var grid = []; var units = []; var selectedUnit = null; var gameState = 'playerTurn'; // playerTurn, aiTurn, gameOver var ai = new AIPlayer(); var statusText = new Text2('Player Turn', { size: 80, // Increased text size fill: 0xFFFFFF }); // Initialize the game board function initializeGame() { // Create grid for (var row = 0; row < GRID_ROWS; row++) { grid[row] = []; for (var col = 0; col < GRID_COLS; col++) { var cell = new GridCell(); cell.row = row; cell.col = col; cell.x = GRID_PADDING_X + col * CELL_SIZE + CELL_SIZE / 2; cell.y = GRID_PADDING_Y + row * CELL_SIZE + CELL_SIZE / 2; // Alternate cell colors if ((row + col) % 2 === 0) { cell.removeChild(cell.children[0]); // Remove default graphic cell.attachAsset('grid_cell_dark', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } grid[row][col] = cell; game.addChild(cell); } } // Create units for both teams createUnits(); // Add status text statusText.anchor.set(0.5, 0); statusText.x = 2048 / 2; statusText.y = 50; LK.gui.top.addChild(statusText); } // Create all units for both teams function createUnits() { // Blue team (player) - bottom of the board createUnit('king', 'blue', 9, 2); createUnit('knight', 'blue', 8, 1); createUnit('knight', 'blue', 8, 3); createUnit('archer', 'blue', 8, 0); createUnit('archer', 'blue', 8, 4); createUnit('wizard', 'blue', 9, 0); createUnit('wizard', 'blue', 9, 4); createUnit('warrior', 'blue', 9, 1); createUnit('warrior', 'blue', 9, 3); // Red team (AI) - top of the board createUnit('king', 'red', 0, 2); createUnit('knight', 'red', 1, 1); createUnit('knight', 'red', 1, 3); createUnit('archer', 'red', 1, 0); createUnit('archer', 'red', 1, 4); createUnit('wizard', 'red', 0, 0); createUnit('wizard', 'red', 0, 4); createUnit('warrior', 'red', 0, 1); createUnit('warrior', 'red', 0, 3); } // Create a single unit function createUnit(type, team, row, col) { var unit; // Create the appropriate unit type switch (type) { case 'king': unit = new King().init(type, team, row, col); break; case 'knight': unit = new Knight().init(type, team, row, col); break; case 'archer': unit = new Archer().init(type, team, row, col); break; case 'wizard': unit = new Wizard().init(type, team, row, col); break; case 'warrior': unit = new Warrior().init(type, team, row, col); break; } // Position unit unit.x = grid[row][col].x; unit.y = grid[row][col].y; unit.unitGraphic.alpha = 0.8; // Add subtle entry animation unit.unitGraphic.scale.set(0.1); unit.unitGraphic.alpha = 0.3; // Add unit to game game.addChild(unit); units.push(unit); // Mark cell as occupied grid[row][col].occupied = true; grid[row][col].occupiedBy = unit; // Add click handler for player units if (team === 'blue') { unit.down = function (x, y, obj) { if (gameState === 'playerTurn') { selectUnit(unit); } }; } // Animate unit entry tween(unit.unitGraphic, { scaleX: 1.0, scaleY: 1.0, alpha: 0.8 }, { duration: 500, easing: tween.elasticOut }); return unit; } // Handle cell click game.handleCellClick = function (cell) { if (!selectedUnit) return; // If cell is highlighted for movement if (cell.highlighted && cell.highlightType === 'move') { moveSelectedUnit(cell.row, cell.col); } // If cell is highlighted for attack else if (cell.highlighted && cell.highlightType === 'attack') { attackCell(cell); } }; // Select a unit function selectUnit(unit) { // Can only select your own units if (unit.team !== 'blue' && gameState === 'playerTurn') return; if (unit.team !== 'red' && gameState === 'aiTurn') return; // Deselect previous unit if there was one if (selectedUnit) { selectedUnit.deselect(); clearAllHighlights(); } // Select new unit selectedUnit = unit; selectedUnit.select(); // Add subtle pop animation tween(selectedUnit.unitGraphic, { scaleX: 1.1, scaleY: 1.1 }, { duration: 150, easing: tween.elasticOut, onFinish: function onFinish() { tween(selectedUnit.unitGraphic, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150, easing: tween.easeOutQuad }); } }); // Highlight cell under selected unit grid[unit.row][unit.col].highlight('selected'); // Highlight possible moves with delay for better visual feedback var possibleMoves = unit.getPossibleMoves(grid); for (var i = 0; i < possibleMoves.length; i++) { (function (index) { LK.setTimeout(function () { if (selectedUnit === unit) { // Only highlight if still selected var move = possibleMoves[index]; grid[move.row][move.col].highlight('move'); } }, index * 30); })(i); } // Highlight possible attacks with delay var possibleAttacks = unit.getPossibleAttacks(grid); for (var i = 0; i < possibleAttacks.length; i++) { (function (index) { LK.setTimeout(function () { if (selectedUnit === unit) { // Only highlight if still selected var attack = possibleAttacks[index]; grid[attack.row][attack.col].highlight('attack'); } }, (possibleMoves.length + index) * 30); })(i); } } // Move selected unit to new position function moveSelectedUnit(targetRow, targetCol) { if (!selectedUnit) return; // Update grid occupation grid[selectedUnit.row][selectedUnit.col].occupied = false; grid[selectedUnit.row][selectedUnit.col].occupiedBy = null; // Move unit with animation selectedUnit.moveTo(targetRow, targetCol); // Animate movement with tween var targetX = grid[targetRow][targetCol].x; var targetY = grid[targetRow][targetCol].y; tween(selectedUnit, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeOutQuad, onFinish: function onFinish() { // Update grid occupation at new position grid[targetRow][targetCol].occupied = true; grid[targetRow][targetCol].occupiedBy = selectedUnit; // Deselect unit and clear highlights selectedUnit.deselect(); clearAllHighlights(); selectedUnit = null; // Check if any attacks are possible after movement checkForAutoAttack(); // Switch turns endTurn(); } }); } // Attack a cell function attackCell(cell) { if (!selectedUnit || !cell.occupied || cell.occupiedBy.team === selectedUnit.team) return; var targetUnit = cell.occupiedBy; // Animate the attacker - "lunge" toward target var originalX = selectedUnit.x; var originalY = selectedUnit.y; var directionX = targetUnit.x - selectedUnit.x; var directionY = targetUnit.y - selectedUnit.y; var distance = Math.sqrt(directionX * directionX + directionY * directionY); var normalizedX = directionX / distance * 30; // small lunge var normalizedY = directionY / distance * 30; // Animation sequence tween(selectedUnit, { x: selectedUnit.x + normalizedX, y: selectedUnit.y + normalizedY }, { duration: 150, easing: tween.easeOutQuad, onFinish: function onFinish() { // Visual flash on target LK.effects.flashObject(targetUnit, 0xff0000, 300); // Return attacker to original position tween(selectedUnit, { x: originalX, y: originalY }, { duration: 200, easing: tween.easeOutQuad, onFinish: function onFinish() { // Perform attack after animation if (selectedUnit.hasInstantKill || targetUnit.isKing) { // Instant kill or attacking king always results in death removeUnit(targetUnit); } else if (selectedUnit.isAreaAttacker) { // Area attack affects target and adjacent units of opposite team var adjacentCells = getAdjacentCells(cell.row, cell.col); removeUnit(targetUnit); for (var i = 0; i < adjacentCells.length; i++) { var adjCell = adjacentCells[i]; if (adjCell.occupied && adjCell.occupiedBy.team !== selectedUnit.team) { removeUnit(adjCell.occupiedBy); } } } else { // Normal attack removeUnit(targetUnit); } // Deselect unit and clear highlights selectedUnit.deselect(); clearAllHighlights(); selectedUnit = null; // Switch turns endTurn(); } }); } }); } // Check if auto-attack is possible (for units that moved next to enemies) function checkForAutoAttack() { // Not implemented in this version - all attacks are chosen by player } // Get adjacent cells function getAdjacentCells(row, col) { var adjacent = []; var directions = [{ r: -1, c: 0 }, { r: 1, c: 0 }, { r: 0, c: -1 }, { r: 0, c: 1 }, { r: -1, c: -1 }, { r: -1, c: 1 }, { r: 1, c: -1 }, { r: 1, c: 1 }]; for (var i = 0; i < directions.length; i++) { var newRow = row + directions[i].r; var newCol = col + directions[i].c; if (newRow >= 0 && newRow < GRID_ROWS && newCol >= 0 && newCol < GRID_COLS) { adjacent.push(grid[newRow][newCol]); } } return adjacent; } // Remove a unit from the game function removeUnit(unit) { // Clear grid cell grid[unit.row][unit.col].occupied = false; grid[unit.row][unit.col].occupiedBy = null; // Remove from units array var index = units.indexOf(unit); if (index > -1) { units.splice(index, 1); } // Remove from display game.removeChild(unit); // Check for game over if a king was killed if (unit.isKing) { if (unit.team === 'blue') { endGame('red'); } else { endGame('blue'); } } } // Clear all highlights from the grid function clearAllHighlights() { for (var row = 0; row < GRID_ROWS; row++) { for (var col = 0; col < GRID_COLS; col++) { grid[row][col].clearHighlight(); } } } // End the current turn function endTurn() { if (gameState === 'playerTurn') { gameState = 'aiTurn'; statusText.setText('AI Turn'); // Small delay before AI makes its move LK.setTimeout(function () { ai.makeMove(); // Switch back to player turn gameState = 'playerTurn'; statusText.setText('Player Turn'); }, 500); } else if (gameState === 'aiTurn') { gameState = 'playerTurn'; statusText.setText('Player Turn'); } } // End the game with a winner function endGame(winner) { gameState = 'gameOver'; if (winner === 'blue') { statusText.setText('You Win!'); LK.showYouWin(); } else { statusText.setText('Game Over'); LK.showGameOver(); } } // Helper functions game.getTeamUnits = function (team) { return units.filter(function (unit) { return unit.team === team; }); }; game.getKing = function (team) { for (var i = 0; i < units.length; i++) { if (units[i].isKing && units[i].team === team) { return units[i]; } } return null; }; // Expose functions to game object for access from other classes game.selectUnit = selectUnit; game.moveSelectedUnit = moveSelectedUnit; game.attackCell = attackCell; game.grid = grid; game.gameState = gameState; // Initialize game initializeGame();
===================================================================
--- original.js
+++ change.js
@@ -1,5 +1,10 @@
/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
* Classes
****/
var AIPlayer = Container.expand(function () {
var self = Container.call(this);
@@ -339,11 +344,12 @@
/****
* Game Code
****/
// Game constants
+// Import tween plugin
var GRID_ROWS = 10;
var GRID_COLS = 5;
-var CELL_SIZE = 130;
+var CELL_SIZE = 180; // Increased cell size
var GRID_PADDING_X = (2048 - GRID_COLS * CELL_SIZE) / 2;
var GRID_PADDING_Y = (2732 - GRID_ROWS * CELL_SIZE) / 2;
// Game variables
var grid = [];
@@ -351,9 +357,10 @@
var selectedUnit = null;
var gameState = 'playerTurn'; // playerTurn, aiTurn, gameOver
var ai = new AIPlayer();
var statusText = new Text2('Player Turn', {
- size: 60,
+ size: 80,
+ // Increased text size
fill: 0xFFFFFF
});
// Initialize the game board
function initializeGame() {
@@ -434,8 +441,11 @@
// Position unit
unit.x = grid[row][col].x;
unit.y = grid[row][col].y;
unit.unitGraphic.alpha = 0.8;
+ // Add subtle entry animation
+ unit.unitGraphic.scale.set(0.1);
+ unit.unitGraphic.alpha = 0.3;
// Add unit to game
game.addChild(unit);
units.push(unit);
// Mark cell as occupied
@@ -448,8 +458,17 @@
selectUnit(unit);
}
};
}
+ // Animate unit entry
+ tween(unit.unitGraphic, {
+ scaleX: 1.0,
+ scaleY: 1.0,
+ alpha: 0.8
+ }, {
+ duration: 500,
+ easing: tween.elasticOut
+ });
return unit;
}
// Handle cell click
game.handleCellClick = function (cell) {
@@ -475,73 +494,144 @@
}
// Select new unit
selectedUnit = unit;
selectedUnit.select();
+ // Add subtle pop animation
+ tween(selectedUnit.unitGraphic, {
+ scaleX: 1.1,
+ scaleY: 1.1
+ }, {
+ duration: 150,
+ easing: tween.elasticOut,
+ onFinish: function onFinish() {
+ tween(selectedUnit.unitGraphic, {
+ scaleX: 1.0,
+ scaleY: 1.0
+ }, {
+ duration: 150,
+ easing: tween.easeOutQuad
+ });
+ }
+ });
// Highlight cell under selected unit
grid[unit.row][unit.col].highlight('selected');
- // Highlight possible moves
+ // Highlight possible moves with delay for better visual feedback
var possibleMoves = unit.getPossibleMoves(grid);
for (var i = 0; i < possibleMoves.length; i++) {
- var move = possibleMoves[i];
- grid[move.row][move.col].highlight('move');
+ (function (index) {
+ LK.setTimeout(function () {
+ if (selectedUnit === unit) {
+ // Only highlight if still selected
+ var move = possibleMoves[index];
+ grid[move.row][move.col].highlight('move');
+ }
+ }, index * 30);
+ })(i);
}
- // Highlight possible attacks
+ // Highlight possible attacks with delay
var possibleAttacks = unit.getPossibleAttacks(grid);
for (var i = 0; i < possibleAttacks.length; i++) {
- var attack = possibleAttacks[i];
- grid[attack.row][attack.col].highlight('attack');
+ (function (index) {
+ LK.setTimeout(function () {
+ if (selectedUnit === unit) {
+ // Only highlight if still selected
+ var attack = possibleAttacks[index];
+ grid[attack.row][attack.col].highlight('attack');
+ }
+ }, (possibleMoves.length + index) * 30);
+ })(i);
}
}
// Move selected unit to new position
function moveSelectedUnit(targetRow, targetCol) {
if (!selectedUnit) return;
// Update grid occupation
grid[selectedUnit.row][selectedUnit.col].occupied = false;
grid[selectedUnit.row][selectedUnit.col].occupiedBy = null;
- // Move unit
+ // Move unit with animation
selectedUnit.moveTo(targetRow, targetCol);
- selectedUnit.x = grid[targetRow][targetCol].x;
- selectedUnit.y = grid[targetRow][targetCol].y;
- // Update grid occupation at new position
- grid[targetRow][targetCol].occupied = true;
- grid[targetRow][targetCol].occupiedBy = selectedUnit;
- // Deselect unit and clear highlights
- selectedUnit.deselect();
- clearAllHighlights();
- selectedUnit = null;
- // Check if any attacks are possible after movement
- checkForAutoAttack();
- // Switch turns
- endTurn();
+ // Animate movement with tween
+ var targetX = grid[targetRow][targetCol].x;
+ var targetY = grid[targetRow][targetCol].y;
+ tween(selectedUnit, {
+ x: targetX,
+ y: targetY
+ }, {
+ duration: 300,
+ easing: tween.easeOutQuad,
+ onFinish: function onFinish() {
+ // Update grid occupation at new position
+ grid[targetRow][targetCol].occupied = true;
+ grid[targetRow][targetCol].occupiedBy = selectedUnit;
+ // Deselect unit and clear highlights
+ selectedUnit.deselect();
+ clearAllHighlights();
+ selectedUnit = null;
+ // Check if any attacks are possible after movement
+ checkForAutoAttack();
+ // Switch turns
+ endTurn();
+ }
+ });
}
// Attack a cell
function attackCell(cell) {
if (!selectedUnit || !cell.occupied || cell.occupiedBy.team === selectedUnit.team) return;
var targetUnit = cell.occupiedBy;
- // Perform attack
- if (selectedUnit.hasInstantKill || targetUnit.isKing) {
- // Instant kill or attacking king always results in death
- removeUnit(targetUnit);
- } else if (selectedUnit.isAreaAttacker) {
- // Area attack affects target and adjacent units of opposite team
- var adjacentCells = getAdjacentCells(cell.row, cell.col);
- removeUnit(targetUnit);
- for (var i = 0; i < adjacentCells.length; i++) {
- var adjCell = adjacentCells[i];
- if (adjCell.occupied && adjCell.occupiedBy.team !== selectedUnit.team) {
- removeUnit(adjCell.occupiedBy);
- }
+ // Animate the attacker - "lunge" toward target
+ var originalX = selectedUnit.x;
+ var originalY = selectedUnit.y;
+ var directionX = targetUnit.x - selectedUnit.x;
+ var directionY = targetUnit.y - selectedUnit.y;
+ var distance = Math.sqrt(directionX * directionX + directionY * directionY);
+ var normalizedX = directionX / distance * 30; // small lunge
+ var normalizedY = directionY / distance * 30;
+ // Animation sequence
+ tween(selectedUnit, {
+ x: selectedUnit.x + normalizedX,
+ y: selectedUnit.y + normalizedY
+ }, {
+ duration: 150,
+ easing: tween.easeOutQuad,
+ onFinish: function onFinish() {
+ // Visual flash on target
+ LK.effects.flashObject(targetUnit, 0xff0000, 300);
+ // Return attacker to original position
+ tween(selectedUnit, {
+ x: originalX,
+ y: originalY
+ }, {
+ duration: 200,
+ easing: tween.easeOutQuad,
+ onFinish: function onFinish() {
+ // Perform attack after animation
+ if (selectedUnit.hasInstantKill || targetUnit.isKing) {
+ // Instant kill or attacking king always results in death
+ removeUnit(targetUnit);
+ } else if (selectedUnit.isAreaAttacker) {
+ // Area attack affects target and adjacent units of opposite team
+ var adjacentCells = getAdjacentCells(cell.row, cell.col);
+ removeUnit(targetUnit);
+ for (var i = 0; i < adjacentCells.length; i++) {
+ var adjCell = adjacentCells[i];
+ if (adjCell.occupied && adjCell.occupiedBy.team !== selectedUnit.team) {
+ removeUnit(adjCell.occupiedBy);
+ }
+ }
+ } else {
+ // Normal attack
+ removeUnit(targetUnit);
+ }
+ // Deselect unit and clear highlights
+ selectedUnit.deselect();
+ clearAllHighlights();
+ selectedUnit = null;
+ // Switch turns
+ endTurn();
+ }
+ });
}
- } else {
- // Normal attack
- removeUnit(targetUnit);
- }
- // Deselect unit and clear highlights
- selectedUnit.deselect();
- clearAllHighlights();
- selectedUnit = null;
- // Switch turns
- endTurn();
+ });
}
// Check if auto-attack is possible (for units that moved next to enemies)
function checkForAutoAttack() {
// Not implemented in this version - all attacks are chosen by player
top view
make it have red-ish clothes
Make it seen from behind top view
make it seen from behind top view
make it just a grass field, and make it from 3 times far away
Create a logo for this game based on this description: Title: "Tactical Kings: Battle of Champions" A fantasy-themed, chess-inspired strategy game where players control unique units with predefined attack zones. Victory comes from eliminating the opponent’s King by strategically positioning characters on a 5x10 grid.. In-Game asset. 2d. High contrast. No shadows
make it wear more blue ish colors
make it from top view
paint the word silver
top view, seeing the back of the character
top down view, do not cut any elements off screen
Make it seen from his back, do not cut any elements off screen