Code edit (2 edits merged)
Please save this source code
User prompt
var TutorialScreen = Container.expand(function () { var self = Container.call(this); // Title var titleText = new Text2('TUTORIAL', { size: 150, fill: '#FFFFFF' }); titleText.anchor.set(0.5, 0); titleText.y = 2732 / 3 -150; // Position in top third of screen this variable is not changing the position of the title: titleText.y = 2732 / 3 -150; // Position in top third of screen
Code edit (1 edits merged)
Please save this source code
User prompt
The Tutorial texts are overlapping, fix their position, the Tutorial page title should be in the top third of the screen centered in x
User prompt
Animate grow and shrink each button, on move the title to the top third of the screen centered in x ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Create a new level for the main menu
User prompt
Add an background image
User prompt
the archer must attack any enemy character in the line with attackRange tiles forward of him ex: x x x x x <- attack any character in this line _ _ _ archer
User prompt
change the attack zone of the archers, to be any tile in the line of its attackRange
User prompt
the wizard has attack range of 3, correct the code to correspond to these variables: case 'wizard': self.health = 90; self.attackStrength = 60; self.moveRange = 2; // Can move up to 2 tiles in any direction self.attackRange = 3; // Attack 6 tiles ahead and surrounding
User prompt
you should update the values of each character for both teams and make the ai react accordingly
Code edit (1 edits merged)
Please save this source code
User prompt
create something like this but for the movement and attack zones: switch (type) { case 'king': self.health = 200; self.attackStrength = 30; break; case 'warrior': self.health = 250; self.attackStrength = 40; break; case 'knight': self.health = 130; self.attackStrength = 35; break; case 'wizard': self.health = 80; self.attackStrength = 50; break; case 'archer': self.health = 90; self.attackStrength = 45; break;
User prompt
change the color of the health text to be golden yellow
Code edit (1 edits merged)
Please save this source code
User prompt
Only the warrior should kill the king in one hit, because the warrior kills every enemy in one hit, all the other characters should take a normal hit against the king
User prompt
Add critical damage for this : knights are strong against archers, archers against mages, mages against knights. And when its critical damage add special UI saying critical damage and how much it took of the oponent and make it animated ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Lets Add an attack strenght variable for each character and an health variable for each character
User prompt
Adjust the mage attack, it should be 6 tiles ahead of the mage, and can only attack one of the tiles that is directly around that tile including that tile
User prompt
Adjust the mage attack, it should be 6 tiles ahead of the mage, and can only attack one of the tiles that is directly around that tile
User prompt
Something is wrong, it should be one turn each, the player is not allowed to play after first turn. Refactor the whole code if needed
User prompt
remove the next turn button
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
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var AIPlayer = Container.expand(function () { var self = Container.call(this); self.makeMove = function () { // Only make a move if it's AI's turn if (game.gameState !== 'aiTurn') { return false; } 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; } // Look for advantageous critical attacks first var criticalAttack = attacks.find(function (attack) { var target = game.grid[attack.row][attack.col].occupiedBy; return target && isCriticalDamage(unit.type, target.type); }); if (criticalAttack) { game.selectUnit(unit); game.attackCell(game.grid[criticalAttack.row][criticalAttack.col]); return true; } // For warriors, prioritize attacks to use their instant kill if (unit.type === 'warrior' && attacks.length > 0) { game.selectUnit(unit); game.attackCell(game.grid[attacks[0].row][attacks[0].col]); return true; } // For wizards, prioritize attack positions that can hit multiple enemies if (unit.type === 'wizard' && attacks.length > 0) { // Try to find attack that might hit multiple enemies due to area effect var bestAttack = attacks[0]; var bestCount = 0; for (var j = 0; j < attacks.length; j++) { var attack = attacks[j]; var adjacentCells = getAdjacentCells(attack.row, attack.col); var enemyCount = 0; // Count adjacent enemy units for (var k = 0; k < adjacentCells.length; k++) { var cell = adjacentCells[k]; if (cell.occupied && cell.occupiedBy.team === 'blue') { enemyCount++; } } if (enemyCount > bestCount) { bestCount = enemyCount; bestAttack = attack; } } game.selectUnit(unit); game.attackCell(game.grid[bestAttack.row][bestAttack.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); // Give priority to certain unit types based on their strengths if (unit.type === 'knight') { // Knights are mobile, so give them priority dist -= 2; } else if (unit.type === 'archer') { // Archers should try to get in position but not too close if (dist > 4) dist -= 1; // Encourage moving closer if far away else if (dist < 3) dist += 2; // Discourage getting too close } else if (unit.type === 'warrior') { // Warriors should get close for their instant kill dist -= 3; } else if (unit.type === 'wizard') { // Wizards should stay at medium distance for area attacks if (dist > 3 && dist < 6) dist -= 2; } 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)); // Special movement strategy based on unit type if (closestUnit.type === 'knight') { // Knights should try to position for attack next turn var potentialAttackRange = Math.abs(move.row - playerKing.row) + Math.abs(move.col - playerKing.col); if (potentialAttackRange <= closestUnit.attackRange + 1) { moveScore += 3; } } else if (closestUnit.type === 'archer') { // Archers want to be at their optimal attack range var distAfterMove = Math.abs(move.row - playerKing.row) + Math.abs(move.col - playerKing.col); if (distAfterMove >= 3 && distAfterMove <= 5) { moveScore += 4; } } else if (closestUnit.type === 'wizard') { // Wizards prefer positions that might hit multiple units next turn var adjacentCells = getAdjacentCells(move.row, move.col); var playerUnitsNearby = 0; for (var j = 0; j < adjacentCells.length; j++) { var cell = adjacentCells[j]; if (cell.occupied && cell.occupiedBy.team === 'blue') { playerUnitsNearby++; } } moveScore += playerUnitsNearby * 2; } if (moveScore > bestMoveScore) { bestMove = move; bestMoveScore = moveScore; } } if (bestMove) { game.selectUnit(closestUnit); game.moveSelectedUnit(bestMove.row, bestMove.col); return true; } } } // Check if any unit is in danger and try to move it to safety var unitsInDanger = units.filter(function (unit) { // Check if any player unit could attack this unit in the next turn var playerUnits = game.getTeamUnits('blue'); for (var i = 0; i < playerUnits.length; i++) { var playerUnit = playerUnits[i]; // Calculate if the player unit could potentially attack this AI unit var rowDiff = Math.abs(playerUnit.row - unit.row); var colDiff = Math.abs(playerUnit.col - unit.col); // Check if in potential attack range based on unit type var inDanger = false; if (playerUnit.type === 'warrior' && rowDiff + colDiff <= playerUnit.moveRange + playerUnit.attackRange) { inDanger = true; } else if (playerUnit.type === 'archer' && colDiff === 0 && rowDiff <= playerUnit.attackRange + 1) { inDanger = true; } else if (playerUnit.type === 'knight' && (rowDiff === 0 || colDiff === 0) && rowDiff + colDiff <= playerUnit.attackRange + 1) { inDanger = true; } else if (playerUnit.type === 'wizard' && rowDiff + colDiff <= playerUnit.moveRange + 2) { inDanger = true; } // If king is in danger, prioritize its safety if (inDanger && unit.isKing) { return true; } else if (inDanger && unit.health < 50) { return true; } } return false; }); if (unitsInDanger.length > 0) { // Prioritize king safety var unitToSave = unitsInDanger.find(function (unit) { return unit.isKing; }) || unitsInDanger[0]; var moves = unitToSave.getPossibleMoves(game.grid); if (moves.length > 0) { // Find safest move (furthest from player units) var playerUnits = game.getTeamUnits('blue'); var bestMove = null; var bestSafetyScore = -Infinity; for (var i = 0; i < moves.length; i++) { var move = moves[i]; var safetyScore = 0; // Calculate safety based on distance from all player units for (var j = 0; j < playerUnits.length; j++) { var playerUnit = playerUnits[j]; var dist = Math.abs(move.row - playerUnit.row) + Math.abs(move.col - playerUnit.col); safetyScore += dist; } if (safetyScore > bestSafetyScore) { bestSafetyScore = safetyScore; bestMove = move; } } if (bestMove) { game.selectUnit(unitToSave); 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 CriticalDamageEffect = Container.expand(function () { var self = Container.call(this); self.init = function (damage, x, y) { // Create the critical hit text with animation var critText = new Text2('CRITICAL HIT!', { size: 80, fill: '#FF0000' }); critText.anchor.set(0.5, 0.5); self.addChild(critText); // Create the damage text var damageText = new Text2('-' + damage, { size: 100, fill: '#FFFF00' }); damageText.anchor.set(0.5, 0.5); damageText.y = 80; self.addChild(damageText); // Position the effect self.x = x; self.y = y; // Initial scale and alpha self.scale.set(0.1); self.alpha = 0; // Animate in tween(self, { scaleX: 1.2, scaleY: 1.2, alpha: 1 }, { duration: 300, easing: tween.elasticOut }); // Animate out after showing LK.setTimeout(function () { tween(self, { scaleX: 1.5, scaleY: 1.5, alpha: 0, y: self.y - 100 }, { duration: 700, easing: tween.easeOutQuad, onFinish: function onFinish() { self.parent.removeChild(self); } }); }, 1200); return self; }; 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 SettingsScreen = Container.expand(function () { var self = Container.call(this); // Title var titleText = new Text2('SETTINGS', { size: 150, fill: '#FFFFFF' }); titleText.anchor.set(0.5, 0); titleText.y = 100; self.addChild(titleText); // Create toggle button var createToggle = function createToggle(text, yPos, initialState) { var container = new Container(); container.y = yPos; // Label var label = new Text2(text, { size: 80, fill: '#FFFFFF' }); label.anchor.set(0, 0.5); container.addChild(label); // Toggle background var toggleBg = LK.getAsset('grid_cell_dark', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 100, alpha: 0.8 }); toggleBg.x = 900; container.addChild(toggleBg); // Toggle indicator var indicator = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); indicator.x = initialState ? 950 : 850; indicator.y = 0; container.addChild(indicator); // State container.state = initialState; // Toggle functionality toggleBg.down = function (x, y, obj) { container.state = !container.state; tween(indicator, { x: container.state ? 950 : 850 }, { duration: 200, easing: tween.easeOutQuad }); }; return container; }; // Create difficulty slider var createSlider = function createSlider(text, yPos, initialValue) { var container = new Container(); container.y = yPos; // Label var label = new Text2(text, { size: 80, fill: '#FFFFFF' }); label.anchor.set(0, 0.5); container.addChild(label); // Slider background var sliderBg = LK.getAsset('grid_cell_dark', { anchorX: 0, anchorY: 0.5, width: 500, height: 40, alpha: 0.8 }); sliderBg.x = 650; container.addChild(sliderBg); // Slider handle var handle = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); handle.x = 650 + initialValue * 500; container.addChild(handle); // Value display var valueText = new Text2(initialValue.toString(), { size: 60, fill: '#FFFFFF' }); valueText.anchor.set(0, 0.5); valueText.x = 1200; container.addChild(valueText); // State container.value = initialValue; // Slider functionality var isDragging = false; handle.down = function (x, y, obj) { isDragging = true; }; game.move = function (x, y, obj) { if (isDragging) { var localPos = sliderBg.toLocal(obj.position); var newX = Math.max(0, Math.min(500, localPos.x)); handle.x = 650 + newX; container.value = Math.round(newX / 500 * 10) / 10; valueText.setText(container.value.toString()); } }; game.up = function (x, y, obj) { isDragging = false; }; return container; }; // Create settings controls var soundToggle = createToggle('Sound Effects', 400, true); var musicToggle = createToggle('Music', 550, true); var difficultySlider = createSlider('AI Difficulty', 700, 0.5); // Add controls to container self.addChild(soundToggle); self.addChild(musicToggle); self.addChild(difficultySlider); // Back button var backButton = new Container(); var backBg = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, width: 500, height: 120 }); var backText = new Text2('BACK', { size: 80, fill: '#000000' }); backText.anchor.set(0.5, 0.5); backButton.addChild(backBg); backButton.addChild(backText); backButton.x = 1024; backButton.y = 2500; self.addChild(backButton); // Back button functionality backButton.down = function (x, y, obj) { tween(backBg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; backButton.up = function (x, y, obj) { tween(backBg, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showTitleScreen(); } }); }; return self; }); var TitleScreen = Container.expand(function () { var self = Container.call(this); // Title text var titleText = new Text2('CHESS TACTICS', { size: 200, fill: '#FFFFFF' }); titleText.anchor.set(0.5, 0.5); self.addChild(titleText); // Create buttons for different game modes var createButton = function createButton(text, yOffset) { var button = new Container(); // Button background var bg = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, width: 800, height: 150 }); button.addChild(bg); // Button text var buttonText = new Text2(text, { size: 100, fill: '#000000' }); buttonText.anchor.set(0.5, 0.5); button.addChild(buttonText); // Position button button.y = yOffset; // Button hover/press effects button.down = function (x, y, obj) { tween(bg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; button.up = function (x, y, obj) { tween(bg, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut }); }; return button; }; // Create menu buttons var playButton = createButton('PLAY GAME', 100); var tutorialButton = createButton('TUTORIAL', 300); var settingsButton = createButton('SETTINGS', 500); // Add buttons to container self.addChild(playButton); self.addChild(tutorialButton); self.addChild(settingsButton); // Button functionality playButton.down = function (x, y, obj) { tween(playButton.children[0], { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; playButton.up = function (x, y, obj) { tween(playButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.startGame(); } }); }; tutorialButton.down = function (x, y, obj) { tween(tutorialButton.children[0], { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; tutorialButton.up = function (x, y, obj) { tween(tutorialButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showTutorial(); } }); }; settingsButton.down = function (x, y, obj) { tween(settingsButton.children[0], { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; settingsButton.up = function (x, y, obj) { tween(settingsButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showSettings(); } }); }; return self; }); var TutorialScreen = Container.expand(function () { var self = Container.call(this); // Title var titleText = new Text2('TUTORIAL', { size: 150, fill: '#FFFFFF' }); titleText.anchor.set(0.5, 0); titleText.y = 100; self.addChild(titleText); // Create unit examples var createUnitExample = function createUnitExample(type, team, description, xPos, yPos) { var container = new Container(); container.x = xPos; container.y = yPos; // Unit graphic var unitAsset = LK.getAsset(type + '_' + team, { anchorX: 0.5, anchorY: 0.5, scale: 0.8 }); container.addChild(unitAsset); // Unit description var descText = new Text2(description, { size: 60, fill: '#FFFFFF', wordWrap: true, wordWrapWidth: 400 }); descText.anchor.set(0.5, 0); descText.y = 120; container.addChild(descText); return container; }; // Create unit examples var kingExample = createUnitExample('king', 'blue', 'KING: Protect at all costs. Lose the king and you lose the game!', 400, 300); var warriorExample = createUnitExample('warrior', 'blue', 'WARRIOR: Strong frontline unit with instant kill ability', 1600, 300); var knightExample = createUnitExample('knight', 'blue', 'KNIGHT: Fast unit that moves in straight lines', 400, 600); var wizardExample = createUnitExample('wizard', 'blue', 'WIZARD: Area damage that affects adjacent units', 1600, 600); var archerExample = createUnitExample('archer', 'blue', 'ARCHER: Long-range attacker that hits units in a line', 1000, 900); // Add unit examples to container self.addChild(kingExample); self.addChild(warriorExample); self.addChild(knightExample); self.addChild(wizardExample); self.addChild(archerExample); // Back button var backButton = new Container(); var backBg = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, width: 500, height: 120 }); var backText = new Text2('BACK', { size: 80, fill: '#000000' }); backText.anchor.set(0.5, 0.5); backButton.addChild(backBg); backButton.addChild(backText); backButton.x = 1024; backButton.y = 2500; self.addChild(backButton); // Back button functionality backButton.down = function (x, y, obj) { tween(backBg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; backButton.up = function (x, y, obj) { tween(backBg, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showTitleScreen(); } }); }; 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; self.health = 100; // Base health for all units self.attackStrength = 20; // Base attack strength for all units // 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'; // Set different health and attack values based on unit type switch (type) { case 'king': self.health = 250; self.attackStrength = 35; self.moveRange = 1; // Can move 1 tile in any direction self.attackRange = 1; // Can attack 1 tile forward break; case 'warrior': self.health = 280; self.attackStrength = 45; self.moveRange = 1; // Can move 1 tile in any direction self.attackRange = 1; // Can attack 1 tile forward break; case 'knight': self.health = 150; self.attackStrength = 40; self.moveRange = 3; // Can move up to 3 tiles horizontally or vertically self.attackRange = 2; // Can attack in movement range break; case 'wizard': self.health = 90; self.attackStrength = 60; self.moveRange = 2; // Can move up to 2 tiles in any direction self.attackRange = 3; // Attack 6 tiles ahead and surrounding break; case 'archer': self.health = 100; self.attackStrength = 50; self.moveRange = 1; // Can move sideways freely, 1 tile forward self.attackRange = 4; // Can attack up to 8 tiles ahead break; } 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) { // Wizard can attack up to 3 tiles away in any direction var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); // Total distance (Manhattan distance) should be less than or equal to attack range return rowDiff + colDiff <= self.attackRange && !(rowDiff === 0 && colDiff === 0); }; // 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 up to moveRange tile in any direction return rowDiff <= self.moveRange && colDiff <= self.moveRange && !(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 - self.attackRange && targetCol === self.col; } else { return targetRow === self.row + self.attackRange && 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 moveRange tiles return rowDiff === 0 && colDiff > 0 && colDiff <= self.moveRange || colDiff === 0 && rowDiff > 0 && rowDiff <= self.moveRange; }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // Knight can attack along the same paths as movement var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); return rowDiff === 0 && colDiff > 0 && colDiff <= self.attackRange || colDiff === 0 && rowDiff > 0 && rowDiff <= self.attackRange; }; 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 moveRange spaces return rowDiff <= self.moveRange && colDiff <= self.moveRange && !(rowDiff === 0 && colDiff === 0); }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // King only attacks forward based on team direction and attack range var forwardRow = self.team === 'blue' ? self.row - self.attackRange : self.row + self.attackRange; 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 moveRange tiles forward if (self.team === 'blue') { return colDiff > 0 && rowDiff === 0 || // sideways targetRow === self.row - self.moveRange && colDiff === 0; // forward } else { return colDiff > 0 && rowDiff === 0 || // sideways targetRow === self.row + self.moveRange && colDiff === 0; // forward } }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // Can attack any enemy in the line attackRange tiles forward if (self.team === 'blue') { // For blue team, attack any cell in the same column forward (up) within attack range return targetCol === self.col && targetRow < self.row && self.row - targetRow <= self.attackRange; } else { // For red team, attack any cell in the same column forward (down) within attack range return targetCol === self.col && targetRow > self.row && targetRow - self.row <= self.attackRange; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Import tween plugin // Game constants // Background image asset var GRID_ROWS = 10; var GRID_COLS = 5; var CELL_SIZE = 250; // Significantly 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 = 'mainMenu'; // mainMenu, tutorial, settings, playerTurn, aiTurn, gameOver var ai = new AIPlayer(); var statusText = new Text2('Player Turn', { size: 120, // Significantly increased text size fill: 0xFFFFFF }); // Screen instances var titleScreen = new TitleScreen(); var tutorialScreen = new TutorialScreen(); var settingsScreen = new SettingsScreen(); // Position screens at center titleScreen.x = 1024; titleScreen.y = 1366; tutorialScreen.x = 1024; tutorialScreen.y = 1366; settingsScreen.x = 1024; settingsScreen.y = 1366; // Initialize the game board function initializeGame() { // Add background image first so it's behind other elements var background = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChild(background); // First show the title screen instead of starting the game directly game.showTitleScreen(); // Add status text (hidden initially, shown during gameplay) statusText.anchor.set(0.5, 0); statusText.x = 2048 / 2; statusText.y = 50; statusText.visible = false; LK.gui.top.addChild(statusText); } // Create all units for both teams function createUnits() { // Blue team (player) - bottom of the board // Formation: Knight, Warrior, Warrior, Warrior, Knight (row 8) // Formation: Archer, Mage, King, Mage, Archer (row 9) createUnit('knight', 'blue', 8, 0); createUnit('warrior', 'blue', 8, 1); createUnit('warrior', 'blue', 8, 2); createUnit('warrior', 'blue', 8, 3); createUnit('knight', 'blue', 8, 4); createUnit('archer', 'blue', 9, 0); createUnit('wizard', 'blue', 9, 1); createUnit('king', 'blue', 9, 2); createUnit('wizard', 'blue', 9, 3); createUnit('archer', 'blue', 9, 4); // Red team (AI) - top of the board // Formation: Knight, Warrior, Warrior, Warrior, Knight (row 1) // Formation: Archer, Mage, King, Mage, Archer (row 0) createUnit('knight', 'red', 1, 0); createUnit('warrior', 'red', 1, 1); createUnit('warrior', 'red', 1, 2); createUnit('warrior', 'red', 1, 3); createUnit('knight', 'red', 1, 4); createUnit('archer', 'red', 0, 0); createUnit('wizard', 'red', 0, 1); createUnit('king', 'red', 0, 2); createUnit('wizard', 'red', 0, 3); createUnit('archer', 'red', 0, 4); } // 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 health display unit.healthText = new Text2(unit.health.toString(), { size: 50, fill: 0xFFD700 // Golden yellow color for better visibility }); unit.healthText.anchor.set(0.5, 0.5); unit.healthText.y = unit.unitGraphic.height / 2 + 10; unit.addChild(unit.healthText); // 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 (game.gameState === 'playerTurn') { selectUnit(unit); } }; } // Animate unit entry with enhanced effect tween(unit.unitGraphic, { scaleX: 1.0, scaleY: 1.0, alpha: 0.8 }, { duration: 600, easing: tween.elasticOut, delay: 100 * (row + col) % 5 // Staggered appearance for visual interest }); return unit; } // Handle cell click game.handleCellClick = function (cell) { if (!selectedUnit || game.gameState !== 'playerTurn') { 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(); // Enhanced selection animation with glow effect tween(selectedUnit.unitGraphic, { scaleX: 1.2, scaleY: 1.2, alpha: 1.0 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { tween(selectedUnit.unitGraphic, { scaleX: 1.0, scaleY: 1.0, alpha: 0.9 }, { duration: 200, 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; // Enhanced attack animation sequence tween(selectedUnit, { x: selectedUnit.x + normalizedX * 1.5, // More pronounced lunge y: selectedUnit.y + normalizedY * 1.5 }, { duration: 200, easing: tween.easeOutQuad, onFinish: function onFinish() { // More dramatic visual flash on target LK.effects.flashObject(targetUnit, 0xff0000, 400); // Return attacker to original position tween(selectedUnit, { x: originalX, y: originalY }, { duration: 200, easing: tween.easeOutQuad, onFinish: function onFinish() { // Check for critical damage var isCritical = isCriticalDamage(selectedUnit.type, targetUnit.type); var damageMultiplier = isCritical ? getCriticalDamageMultiplier() : 1.0; var actualDamage = Math.floor(selectedUnit.attackStrength * damageMultiplier); // Perform attack after animation if (selectedUnit.hasInstantKill && !targetUnit.isKing) { // Warrior's instant kill works on all enemies except kings removeUnit(targetUnit); } else if (targetUnit.isKing) { // King only dies in one hit if attacked by a warrior if (selectedUnit.type === 'warrior') { removeUnit(targetUnit); } else { // Apply normal damage to king var isCritical = isCriticalDamage(selectedUnit.type, targetUnit.type); var damageMultiplier = isCritical ? getCriticalDamageMultiplier() : 1.0; var actualDamage = Math.floor(selectedUnit.attackStrength * damageMultiplier); targetUnit.health -= actualDamage; targetUnit.healthText.setText(targetUnit.health.toString()); if (targetUnit.health <= 0) { removeUnit(targetUnit); } } } else if (selectedUnit.isAreaAttacker) { // Area attack affects target and adjacent units of opposite team var adjacentCells = getAdjacentCells(cell.row, cell.col); // Apply damage instead of instant kill targetUnit.health -= actualDamage; targetUnit.healthText.setText(targetUnit.health.toString()); // Show critical hit effect if applicable if (isCritical) { var critEffect = new CriticalDamageEffect().init(actualDamage, targetUnit.x, targetUnit.y - 50); game.addChild(critEffect); // Add stronger visual feedback tween(targetUnit, { scaleX: 0.8, scaleY: 0.8, rotation: 0.2 }, { duration: 100, easing: tween.easeOutQuad, onFinish: function onFinish() { tween(targetUnit, { scaleX: 1.0, scaleY: 1.0, rotation: 0 }, { duration: 200, easing: tween.elasticOut }); } }); } if (targetUnit.health <= 0) { removeUnit(targetUnit); } for (var i = 0; i < adjacentCells.length; i++) { var adjCell = adjacentCells[i]; if (adjCell.occupied && adjCell.occupiedBy.team !== selectedUnit.team) { var adjTargetUnit = adjCell.occupiedBy; var adjDamage = Math.floor(actualDamage / 2); // Half damage for adjacent units adjTargetUnit.health -= adjDamage; adjTargetUnit.healthText.setText(adjTargetUnit.health.toString()); if (adjTargetUnit.health <= 0) { removeUnit(adjTargetUnit); } } } } else { // Normal attack targetUnit.health -= actualDamage; targetUnit.healthText.setText(targetUnit.health.toString()); // Show critical hit effect if applicable if (isCritical) { var critEffect = new CriticalDamageEffect().init(actualDamage, targetUnit.x, targetUnit.y - 50); game.addChild(critEffect); // Add stronger visual feedback for critical hit tween(targetUnit, { scaleX: 0.7, scaleY: 0.7, rotation: 0.3 }, { duration: 100, easing: tween.easeOutQuad, onFinish: function onFinish() { tween(targetUnit, { scaleX: 1.0, scaleY: 1.0, rotation: 0 }, { duration: 300, easing: tween.elasticOut }); } }); } if (targetUnit.health <= 0) { 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'); // Execute AI turn with delay for better visibility LK.setTimeout(function () { if (ai.makeMove()) { // AI successfully made a move, turn will be ended in the attack/move handlers } else { // AI couldn't make a move, switch back to player gameState = 'playerTurn'; statusText.setText('Player Turn'); } }, 500); // Small delay for better user experience } 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 to determine critical damage relationships function isCriticalDamage(attackerType, targetType) { // Knights are strong against archers if (attackerType === 'knight' && targetType === 'archer') { return true; } // Archers are strong against mages/wizards if (attackerType === 'archer' && targetType === 'wizard') { return true; } // Mages/wizards are strong against knights if (attackerType === 'wizard' && targetType === 'knight') { return true; } return false; } // Make isCriticalDamage available to the game object game.isCriticalDamage = isCriticalDamage; function getCriticalDamageMultiplier() { // Critical damage is 2x normal damage return 2.0; } // 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; game.getAdjacentCells = getAdjacentCells; // Create a getter/setter for game state to ensure consistency Object.defineProperty(game, 'gameState', { get: function get() { return gameState; }, set: function set(value) { gameState = value; } }); // Screen management functions game.showTitleScreen = function () { // Clear any existing game elements game.removeAllGameElements(); // Show title screen game.addChild(titleScreen); game.removeChild(tutorialScreen); game.removeChild(settingsScreen); // Hide status text during main menu statusText.visible = false; // Set game state gameState = 'mainMenu'; }; game.showTutorial = function () { // Show tutorial screen game.removeChild(titleScreen); game.addChild(tutorialScreen); game.removeChild(settingsScreen); // Set game state gameState = 'tutorial'; }; game.showSettings = function () { // Show settings screen game.removeChild(titleScreen); game.removeChild(tutorialScreen); game.addChild(settingsScreen); // Set game state gameState = 'settings'; }; game.startGame = function () { // Clear screens game.removeChild(titleScreen); game.removeChild(tutorialScreen); game.removeChild(settingsScreen); // Initialize the game 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 createUnits(); // Show status text during gameplay statusText.visible = true; statusText.setText('Player Turn'); // Set game state gameState = 'playerTurn'; }; game.removeAllGameElements = function () { // Remove grid cells if they exist for (var row = 0; row < grid.length; row++) { for (var col = 0; col < grid[row].length; col++) { if (grid[row][col]) { game.removeChild(grid[row][col]); } } } // Remove units for (var i = 0; i < units.length; i++) { game.removeChild(units[i]); } // Reset game variables grid = []; units = []; selectedUnit = null; }; // Initialize game initializeGame();
===================================================================
--- original.js
+++ change.js
@@ -339,8 +339,387 @@
}
};
return self;
});
+var SettingsScreen = Container.expand(function () {
+ var self = Container.call(this);
+ // Title
+ var titleText = new Text2('SETTINGS', {
+ size: 150,
+ fill: '#FFFFFF'
+ });
+ titleText.anchor.set(0.5, 0);
+ titleText.y = 100;
+ self.addChild(titleText);
+ // Create toggle button
+ var createToggle = function createToggle(text, yPos, initialState) {
+ var container = new Container();
+ container.y = yPos;
+ // Label
+ var label = new Text2(text, {
+ size: 80,
+ fill: '#FFFFFF'
+ });
+ label.anchor.set(0, 0.5);
+ container.addChild(label);
+ // Toggle background
+ var toggleBg = LK.getAsset('grid_cell_dark', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: 200,
+ height: 100,
+ alpha: 0.8
+ });
+ toggleBg.x = 900;
+ container.addChild(toggleBg);
+ // Toggle indicator
+ var indicator = LK.getAsset('grid_cell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: 80,
+ height: 80
+ });
+ indicator.x = initialState ? 950 : 850;
+ indicator.y = 0;
+ container.addChild(indicator);
+ // State
+ container.state = initialState;
+ // Toggle functionality
+ toggleBg.down = function (x, y, obj) {
+ container.state = !container.state;
+ tween(indicator, {
+ x: container.state ? 950 : 850
+ }, {
+ duration: 200,
+ easing: tween.easeOutQuad
+ });
+ };
+ return container;
+ };
+ // Create difficulty slider
+ var createSlider = function createSlider(text, yPos, initialValue) {
+ var container = new Container();
+ container.y = yPos;
+ // Label
+ var label = new Text2(text, {
+ size: 80,
+ fill: '#FFFFFF'
+ });
+ label.anchor.set(0, 0.5);
+ container.addChild(label);
+ // Slider background
+ var sliderBg = LK.getAsset('grid_cell_dark', {
+ anchorX: 0,
+ anchorY: 0.5,
+ width: 500,
+ height: 40,
+ alpha: 0.8
+ });
+ sliderBg.x = 650;
+ container.addChild(sliderBg);
+ // Slider handle
+ var handle = LK.getAsset('grid_cell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: 80,
+ height: 80
+ });
+ handle.x = 650 + initialValue * 500;
+ container.addChild(handle);
+ // Value display
+ var valueText = new Text2(initialValue.toString(), {
+ size: 60,
+ fill: '#FFFFFF'
+ });
+ valueText.anchor.set(0, 0.5);
+ valueText.x = 1200;
+ container.addChild(valueText);
+ // State
+ container.value = initialValue;
+ // Slider functionality
+ var isDragging = false;
+ handle.down = function (x, y, obj) {
+ isDragging = true;
+ };
+ game.move = function (x, y, obj) {
+ if (isDragging) {
+ var localPos = sliderBg.toLocal(obj.position);
+ var newX = Math.max(0, Math.min(500, localPos.x));
+ handle.x = 650 + newX;
+ container.value = Math.round(newX / 500 * 10) / 10;
+ valueText.setText(container.value.toString());
+ }
+ };
+ game.up = function (x, y, obj) {
+ isDragging = false;
+ };
+ return container;
+ };
+ // Create settings controls
+ var soundToggle = createToggle('Sound Effects', 400, true);
+ var musicToggle = createToggle('Music', 550, true);
+ var difficultySlider = createSlider('AI Difficulty', 700, 0.5);
+ // Add controls to container
+ self.addChild(soundToggle);
+ self.addChild(musicToggle);
+ self.addChild(difficultySlider);
+ // Back button
+ var backButton = new Container();
+ var backBg = LK.getAsset('grid_cell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8,
+ width: 500,
+ height: 120
+ });
+ var backText = new Text2('BACK', {
+ size: 80,
+ fill: '#000000'
+ });
+ backText.anchor.set(0.5, 0.5);
+ backButton.addChild(backBg);
+ backButton.addChild(backText);
+ backButton.x = 1024;
+ backButton.y = 2500;
+ self.addChild(backButton);
+ // Back button functionality
+ backButton.down = function (x, y, obj) {
+ tween(backBg, {
+ scaleX: 0.95,
+ scaleY: 0.95
+ }, {
+ duration: 100,
+ easing: tween.easeOutQuad
+ });
+ };
+ backButton.up = function (x, y, obj) {
+ tween(backBg, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.elasticOut,
+ onFinish: function onFinish() {
+ game.showTitleScreen();
+ }
+ });
+ };
+ return self;
+});
+var TitleScreen = Container.expand(function () {
+ var self = Container.call(this);
+ // Title text
+ var titleText = new Text2('CHESS TACTICS', {
+ size: 200,
+ fill: '#FFFFFF'
+ });
+ titleText.anchor.set(0.5, 0.5);
+ self.addChild(titleText);
+ // Create buttons for different game modes
+ var createButton = function createButton(text, yOffset) {
+ var button = new Container();
+ // Button background
+ var bg = LK.getAsset('grid_cell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8,
+ width: 800,
+ height: 150
+ });
+ button.addChild(bg);
+ // Button text
+ var buttonText = new Text2(text, {
+ size: 100,
+ fill: '#000000'
+ });
+ buttonText.anchor.set(0.5, 0.5);
+ button.addChild(buttonText);
+ // Position button
+ button.y = yOffset;
+ // Button hover/press effects
+ button.down = function (x, y, obj) {
+ tween(bg, {
+ scaleX: 0.95,
+ scaleY: 0.95
+ }, {
+ duration: 100,
+ easing: tween.easeOutQuad
+ });
+ };
+ button.up = function (x, y, obj) {
+ tween(bg, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.elasticOut
+ });
+ };
+ return button;
+ };
+ // Create menu buttons
+ var playButton = createButton('PLAY GAME', 100);
+ var tutorialButton = createButton('TUTORIAL', 300);
+ var settingsButton = createButton('SETTINGS', 500);
+ // Add buttons to container
+ self.addChild(playButton);
+ self.addChild(tutorialButton);
+ self.addChild(settingsButton);
+ // Button functionality
+ playButton.down = function (x, y, obj) {
+ tween(playButton.children[0], {
+ scaleX: 0.95,
+ scaleY: 0.95
+ }, {
+ duration: 100,
+ easing: tween.easeOutQuad
+ });
+ };
+ playButton.up = function (x, y, obj) {
+ tween(playButton.children[0], {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.elasticOut,
+ onFinish: function onFinish() {
+ game.startGame();
+ }
+ });
+ };
+ tutorialButton.down = function (x, y, obj) {
+ tween(tutorialButton.children[0], {
+ scaleX: 0.95,
+ scaleY: 0.95
+ }, {
+ duration: 100,
+ easing: tween.easeOutQuad
+ });
+ };
+ tutorialButton.up = function (x, y, obj) {
+ tween(tutorialButton.children[0], {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.elasticOut,
+ onFinish: function onFinish() {
+ game.showTutorial();
+ }
+ });
+ };
+ settingsButton.down = function (x, y, obj) {
+ tween(settingsButton.children[0], {
+ scaleX: 0.95,
+ scaleY: 0.95
+ }, {
+ duration: 100,
+ easing: tween.easeOutQuad
+ });
+ };
+ settingsButton.up = function (x, y, obj) {
+ tween(settingsButton.children[0], {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.elasticOut,
+ onFinish: function onFinish() {
+ game.showSettings();
+ }
+ });
+ };
+ return self;
+});
+var TutorialScreen = Container.expand(function () {
+ var self = Container.call(this);
+ // Title
+ var titleText = new Text2('TUTORIAL', {
+ size: 150,
+ fill: '#FFFFFF'
+ });
+ titleText.anchor.set(0.5, 0);
+ titleText.y = 100;
+ self.addChild(titleText);
+ // Create unit examples
+ var createUnitExample = function createUnitExample(type, team, description, xPos, yPos) {
+ var container = new Container();
+ container.x = xPos;
+ container.y = yPos;
+ // Unit graphic
+ var unitAsset = LK.getAsset(type + '_' + team, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scale: 0.8
+ });
+ container.addChild(unitAsset);
+ // Unit description
+ var descText = new Text2(description, {
+ size: 60,
+ fill: '#FFFFFF',
+ wordWrap: true,
+ wordWrapWidth: 400
+ });
+ descText.anchor.set(0.5, 0);
+ descText.y = 120;
+ container.addChild(descText);
+ return container;
+ };
+ // Create unit examples
+ var kingExample = createUnitExample('king', 'blue', 'KING: Protect at all costs. Lose the king and you lose the game!', 400, 300);
+ var warriorExample = createUnitExample('warrior', 'blue', 'WARRIOR: Strong frontline unit with instant kill ability', 1600, 300);
+ var knightExample = createUnitExample('knight', 'blue', 'KNIGHT: Fast unit that moves in straight lines', 400, 600);
+ var wizardExample = createUnitExample('wizard', 'blue', 'WIZARD: Area damage that affects adjacent units', 1600, 600);
+ var archerExample = createUnitExample('archer', 'blue', 'ARCHER: Long-range attacker that hits units in a line', 1000, 900);
+ // Add unit examples to container
+ self.addChild(kingExample);
+ self.addChild(warriorExample);
+ self.addChild(knightExample);
+ self.addChild(wizardExample);
+ self.addChild(archerExample);
+ // Back button
+ var backButton = new Container();
+ var backBg = LK.getAsset('grid_cell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8,
+ width: 500,
+ height: 120
+ });
+ var backText = new Text2('BACK', {
+ size: 80,
+ fill: '#000000'
+ });
+ backText.anchor.set(0.5, 0.5);
+ backButton.addChild(backBg);
+ backButton.addChild(backText);
+ backButton.x = 1024;
+ backButton.y = 2500;
+ self.addChild(backButton);
+ // Back button functionality
+ backButton.down = function (x, y, obj) {
+ tween(backBg, {
+ scaleX: 0.95,
+ scaleY: 0.95
+ }, {
+ duration: 100,
+ easing: tween.easeOutQuad
+ });
+ };
+ backButton.up = function (x, y, obj) {
+ tween(backBg, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.elasticOut,
+ onFinish: function onFinish() {
+ game.showTitleScreen();
+ }
+ });
+ };
+ return self;
+});
var Unit = Container.expand(function () {
var self = Container.call(this);
// Unit properties
self.type = "";
@@ -576,11 +955,11 @@
/****
* Game Code
****/
-// Background image asset
-// Game constants
// Import tween plugin
+// Game constants
+// Background image asset
var GRID_ROWS = 10;
var GRID_COLS = 5;
var CELL_SIZE = 250; // Significantly increased cell size
var GRID_PADDING_X = (2048 - GRID_COLS * CELL_SIZE) / 2;
@@ -588,15 +967,26 @@
// Game variables
var grid = [];
var units = [];
var selectedUnit = null;
-var gameState = 'playerTurn'; // playerTurn, aiTurn, gameOver
+var gameState = 'mainMenu'; // mainMenu, tutorial, settings, playerTurn, aiTurn, gameOver
var ai = new AIPlayer();
var statusText = new Text2('Player Turn', {
size: 120,
// Significantly increased text size
fill: 0xFFFFFF
});
+// Screen instances
+var titleScreen = new TitleScreen();
+var tutorialScreen = new TutorialScreen();
+var settingsScreen = new SettingsScreen();
+// Position screens at center
+titleScreen.x = 1024;
+titleScreen.y = 1366;
+tutorialScreen.x = 1024;
+tutorialScreen.y = 1366;
+settingsScreen.x = 1024;
+settingsScreen.y = 1366;
// Initialize the game board
function initializeGame() {
// Add background image first so it's behind other elements
var background = LK.getAsset('background', {
@@ -607,36 +997,15 @@
width: 2048,
height: 2732
});
game.addChild(background);
- // 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
+ // First show the title screen instead of starting the game directly
+ game.showTitleScreen();
+ // Add status text (hidden initially, shown during gameplay)
statusText.anchor.set(0.5, 0);
statusText.x = 2048 / 2;
statusText.y = 50;
+ statusText.visible = false;
LK.gui.top.addChild(statusText);
}
// Create all units for both teams
function createUnits() {
@@ -1138,6 +1507,88 @@
set: function set(value) {
gameState = value;
}
});
+// Screen management functions
+game.showTitleScreen = function () {
+ // Clear any existing game elements
+ game.removeAllGameElements();
+ // Show title screen
+ game.addChild(titleScreen);
+ game.removeChild(tutorialScreen);
+ game.removeChild(settingsScreen);
+ // Hide status text during main menu
+ statusText.visible = false;
+ // Set game state
+ gameState = 'mainMenu';
+};
+game.showTutorial = function () {
+ // Show tutorial screen
+ game.removeChild(titleScreen);
+ game.addChild(tutorialScreen);
+ game.removeChild(settingsScreen);
+ // Set game state
+ gameState = 'tutorial';
+};
+game.showSettings = function () {
+ // Show settings screen
+ game.removeChild(titleScreen);
+ game.removeChild(tutorialScreen);
+ game.addChild(settingsScreen);
+ // Set game state
+ gameState = 'settings';
+};
+game.startGame = function () {
+ // Clear screens
+ game.removeChild(titleScreen);
+ game.removeChild(tutorialScreen);
+ game.removeChild(settingsScreen);
+ // Initialize the game 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
+ createUnits();
+ // Show status text during gameplay
+ statusText.visible = true;
+ statusText.setText('Player Turn');
+ // Set game state
+ gameState = 'playerTurn';
+};
+game.removeAllGameElements = function () {
+ // Remove grid cells if they exist
+ for (var row = 0; row < grid.length; row++) {
+ for (var col = 0; col < grid[row].length; col++) {
+ if (grid[row][col]) {
+ game.removeChild(grid[row][col]);
+ }
+ }
+ }
+ // Remove units
+ for (var i = 0; i < units.length; i++) {
+ game.removeChild(units[i]);
+ }
+ // Reset game variables
+ grid = [];
+ units = [];
+ selectedUnit = null;
+};
// Initialize game
initializeGame();
\ No newline at end of file
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