/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Character = Container.expand(function () { var self = Container.call(this); var characterGraphics = self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); self.row = 0; self.col = 0; self.previousRow = 0; self.previousCol = 0; self.moveToTile = function (tile) { self.previousRow = self.row; self.previousCol = self.col; self.x = tile.x; self.y = tile.y; self.row = tile.row; self.col = tile.col; LK.getSound('move').play(); }; self.returnToPreviousPosition = function () { if (hexGrid[self.previousRow] && hexGrid[self.previousRow][self.previousCol]) { var previousTile = hexGrid[self.previousRow][self.previousCol]; self.x = previousTile.x; self.y = previousTile.y; self.row = self.previousRow; self.col = self.previousCol; LK.getSound('move').play(); } }; return self; }); var HexTile = Container.expand(function (type, row, col) { var self = Container.call(this); self.type = type; self.row = row; self.col = col; self.hasBuilding = false; self.building = null; var assetName = 'hexGrass'; if (type === 'barn') { assetName = 'hexRed'; } else if (type === 'well') { assetName = 'hexBlue'; } else if (type === 'orchard') { assetName = 'hexPurple'; } else if (type === 'wheat') { assetName = 'hexYellow'; } else if (type === 'stable') { assetName = 'hexBrown'; } self.originalAssetName = assetName; // Store original asset name for restoration var hexGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.addBuilding = function () { if (self.hasBuilding || self.type === 'grass') { return false; } var buildingAsset = null; var points = 0; if (self.type === 'barn') { buildingAsset = 'barn'; points = 15; } else if (self.type === 'well') { buildingAsset = 'well'; points = 10; } else if (self.type === 'orchard') { buildingAsset = 'orchard'; points = 20; } else if (self.type === 'wheat') { buildingAsset = 'wheat'; points = 12; } else if (self.type === 'stable') { buildingAsset = 'stable'; points = 18; } if (buildingAsset) { // Change the hex tile to grass when building is constructed hexGraphics.destroy(); hexGraphics = self.attachAsset('hexGrass', { anchorX: 0.5, anchorY: 0.5 }); self.building = self.attachAsset(buildingAsset, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.25, scaleY: 1.25 }); self.hasBuilding = true; LK.getSound('build').play(); // Play building-specific sound after construction sound LK.setTimeout(function () { if (self.type === 'barn') { LK.getSound('barnSound').play(); } else if (self.type === 'well') { LK.getSound('wellSound').play(); } else if (self.type === 'orchard') { LK.getSound('orchardSound').play(); } else if (self.type === 'wheat') { LK.getSound('wheatSound').play(); } else if (self.type === 'stable') { LK.getSound('stableSound').play(); } }, 200); // Start breathing animation for the building self.startBuildingBreathing(); return points; } return 0; }; self.startBuildingBreathing = function () { if (self.building) { // Create continuous breathing animation var breatheIn = function breatheIn() { tween(self.building, { scaleX: 1.375, scaleY: 1.375 }, { duration: 2000, easing: tween.easeInOut, onFinish: breatheOut }); }; var breatheOut = function breatheOut() { tween(self.building, { scaleX: 1.125, scaleY: 1.125 }, { duration: 2000, easing: tween.easeInOut, onFinish: breatheIn }); }; breatheIn(); } }; self.removeBuilding = function () { if (self.hasBuilding && self.building) { // Stop any ongoing breathing animation tween.stop(self.building); self.building.destroy(); self.building = null; self.hasBuilding = false; // Restore original hex graphics hexGraphics.destroy(); hexGraphics = self.attachAsset(self.originalAssetName, { anchorX: 0.5, anchorY: 0.5 }); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x8BC34A }); /**** * Game Code ****/ // Game state var currentTurn = 1; var maxTurns = 20; var score = 0; var character = null; var hexGrid = []; var selectedTile = null; var gameStarted = false; var hasMovedThisTurn = false; var lastTurnBuilding = null; // Track building created this turn var lastTurnPoints = 0; // Track points gained this turn var isBuilding = false; // Track if character is currently building var showingMenu = true; // Track if we're showing the menu var menuContainer = null; // Container for menu elements // Game history for proper undo functionality var gameHistory = []; // Hex grid dimensions var gridWidth = 6; var gridHeight = 12; var hexSize = 200; var hexHeight = 173; // UI positioning offsets var scoreTextOffset = 300; // Create menu function createMenu() { menuContainer = new Container(); // Create PLAY button container var playButtonContainer = new Container(); var playButtonBox = LK.getAsset('buildButtonBg', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.2 }); playButtonContainer.addChild(playButtonBox); var playButton = new Text2('PLAY', { size: 100, fill: 0xFFFFFF, font: "Ink Free" }); playButton.anchor.set(0.5, 0.5); playButtonContainer.addChild(playButton); // Position in center of screen playButtonContainer.x = 1024; // Center X playButtonContainer.y = 1000; // Center Y - moved up double // Create high score display container var highScoreContainer = new Container(); var highScoreBackground = LK.getAsset('scoreContainerBg', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.25, scaleY: 1.75 }); highScoreContainer.addChild(highScoreBackground); var highScore = storage.highScore || 0; var highScoreText = new Text2('High Score: ' + highScore, { size: 45, fill: 0x000000, font: "Ink Free" }); highScoreText.anchor.set(0.5, 0.5); highScoreContainer.addChild(highScoreText); // Create mountain asset that extends to bottom margin var bottomBackgroundContainer = new Container(); var bottomBackground = LK.getAsset('mountain', { anchorX: 0.5, anchorY: 0.5, scaleX: 10.24, scaleY: 6.0 }); bottomBackgroundContainer.addChild(bottomBackground); bottomBackgroundContainer.x = 1024; // Center X bottomBackgroundContainer.y = 2400; // Position to extend to bottom menuContainer.addChild(bottomBackgroundContainer); // Create title asset container var titleAssetContainer = new Container(); // Create title background asset - rectangular shape var titleBackground = LK.getAsset('buildButtonBg', { anchorX: 0.5, anchorY: 0.5, scaleX: 4.0, scaleY: 1.5 }); titleBackground.alpha = 0.9; // Semi-transparent background titleAssetContainer.addChild(titleBackground); // Create game title container var gameTitleContainer = new Container(); var gameTitle = new Text2('Diagonal Farm Builder', { size: 200, fill: 0xFFFFFF, font: "Ink Free" }); gameTitle.anchor.set(0.5, 0.5); gameTitleContainer.addChild(gameTitle); titleAssetContainer.addChild(gameTitleContainer); titleAssetContainer.x = 1024; // Center X titleAssetContainer.y = 500; // Move title up from 600 to 500 menuContainer.addChild(titleAssetContainer); // Start title rotation animation var rotateRight = function rotateRight() { tween(titleAssetContainer, { rotation: 15 * Math.PI / 180 // Convert 15 degrees to radians }, { duration: 3000, easing: tween.easeInOut, onFinish: rotateLeft }); }; var rotateLeft = function rotateLeft() { tween(titleAssetContainer, { rotation: -15 * Math.PI / 180 // Convert -15 degrees to radians }, { duration: 3000, easing: tween.easeInOut, onFinish: rotateRight }); }; rotateRight(); // Start the rotation animation // Position high score container above the background asset highScoreContainer.x = 1024; // Center X highScoreContainer.y = 1700; // Position above the background asset - moved up highScoreContainer.scaleX = 1.875; // Original X scale (0% increase) highScoreContainer.scaleY = 2.1875; // Increase Y scale by 25% (1.75 * 1.25) menuContainer.addChild(highScoreContainer); // Add click handler playButtonContainer.down = function (x, y, obj) { // Animate button press tween(playButtonContainer, { scaleY: 0.9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(playButtonContainer, { scaleY: 1.0 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { startGame(); } }); } }); }; menuContainer.addChild(playButtonContainer); game.addChild(menuContainer); } // UI elements // Create turn container with background box var turnContainer = new Container(); var turnBackgroundBox = LK.getAsset('turnContainerBg', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.25, scaleY: 1.0 }); turnContainer.addChild(turnBackgroundBox); var turnText = new Text2('Turn: 1/20', { size: 60, fill: 0x000000, font: "Ink Free" }); turnText.anchor.set(0.5, 0.5); turnContainer.addChild(turnText); LK.gui.topLeft.addChild(turnContainer); turnContainer.x = scoreTextOffset + 25; turnContainer.y = 130; // Create score container with background box var scoreContainer = new Container(); var scoreBackgroundBox = LK.getAsset('scoreContainerBg', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.25, scaleY: 1.0 }); scoreContainer.addChild(scoreBackgroundBox); var scoreText = new Text2('Score: 0', { size: 60, fill: 0x000000, font: "Ink Free" }); scoreText.anchor.set(0.5, 0.5); scoreContainer.addChild(scoreText); LK.gui.topRight.addChild(scoreContainer); scoreContainer.x = -scoreTextOffset - 25; scoreContainer.y = 130; // Create building list container var buildingListContainer = new Container(); var buildingTypes = [{ asset: 'barn', points: 15, name: 'Barn' }, { asset: 'well', points: 10, name: 'Well' }, { asset: 'orchard', points: 20, name: 'Orchard' }, { asset: 'wheat', points: 12, name: 'Wheat' }, { asset: 'stable', points: 18, name: 'Stable' }]; for (var i = 0; i < buildingTypes.length; i++) { var buildingItem = new Container(); // Add building icon var buildingIcon = buildingItem.attachAsset(buildingTypes[i].asset, { anchorX: 0, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); // Add points text var pointsText = new Text2(buildingTypes[i].points + ' pts', { size: 36, fill: 0xFFFFFF, font: "Ink Free" }); pointsText.anchor.set(0, 0.5); pointsText.x = 100; buildingItem.addChild(pointsText); // Position each building item vertically buildingItem.y = i * 70 - 140; // Center the list vertically buildingListContainer.addChild(buildingItem); } LK.gui.bottom.addChild(buildingListContainer); buildingListContainer.x = -600; // Position to the left of buttons buildingListContainer.y = -200; // Center vertically between buttons // Create button containers with background boxes var buildButtonContainer = new Container(); var buildButtonBox = LK.getAsset('buildButtonBg', { anchorX: 0.5, anchorY: 0.5 }); buildButtonContainer.addChild(buildButtonBox); var buildButton = new Text2('BUILD', { size: 80, fill: 0xFFFFFF, font: "Ink Free" }); buildButton.anchor.set(0.5, 0.5); buildButton.y = -20; buildButtonContainer.addChild(buildButton); var buildDescription = new Text2('Build on special tiles', { size: 48, fill: 0xFFFFFF, font: "Ink Free" }); buildDescription.anchor.set(0.5, 0.5); buildDescription.y = 30; buildButtonContainer.addChild(buildDescription); LK.gui.bottom.addChild(buildButtonContainer); buildButtonContainer.y = -100; var returnButtonContainer = new Container(); var returnButtonBox = LK.getAsset('returnButtonBg', { anchorX: 0.5, anchorY: 0.5 }); returnButtonContainer.addChild(returnButtonBox); var returnButton = new Text2('RETURN', { size: 80, fill: 0xFFFFFF, font: "Ink Free" }); returnButton.anchor.set(0.5, 0.5); returnButton.y = -20; returnButtonContainer.addChild(returnButton); var returnDescription = new Text2('Undo last turn', { size: 48, fill: 0xFFFFFF, font: "Ink Free" }); returnDescription.anchor.set(0.5, 0.5); returnDescription.y = 30; returnButtonContainer.addChild(returnDescription); LK.gui.bottom.addChild(returnButtonContainer); returnButtonContainer.y = -300; // Create hex grid function createHexGrid() { var startX = 200; var startY = 500; var specialTypes = ['barn', 'well', 'orchard', 'wheat', 'stable']; var specialCounts = { barn: 0, well: 0, orchard: 0, wheat: 0, stable: 0 }; var validPositions = []; var tiles = []; // First pass: collect all valid positions and create tiles array for (var row = 0; row < gridHeight; row++) { hexGrid[row] = []; for (var col = 0; col < gridWidth; col++) { var xOffset = row % 2 * (hexSize * 0.75); var x = startX + col * (hexSize * 1.5) + xOffset; var y = startY + row * (hexHeight * 0.75); // Skip if position would be off screen if (x > 1900 || y > 2400) { continue; } validPositions.push({ row: row, col: col, x: x, y: y }); tiles.push('grass'); // Initialize all as grass } } // Guarantee at least 1 of each special type for (var i = 0; i < specialTypes.length; i++) { if (validPositions.length > 0) { var randomIndex = Math.floor(Math.random() * validPositions.length); tiles[randomIndex] = specialTypes[i]; specialCounts[specialTypes[i]]++; } } // Add more special tiles randomly, respecting the maximum of 5 per type for (var j = 0; j < validPositions.length; j++) { if (tiles[j] === 'grass' && Math.random() < 0.15) { var availableTypes = []; for (var k = 0; k < specialTypes.length; k++) { if (specialCounts[specialTypes[k]] < 5) { availableTypes.push(specialTypes[k]); } } if (availableTypes.length > 0) { var selectedType = availableTypes[Math.floor(Math.random() * availableTypes.length)]; tiles[j] = selectedType; specialCounts[selectedType]++; } } } // Second pass: create actual tiles with determined types for (var m = 0; m < validPositions.length; m++) { var pos = validPositions[m]; var tile = new HexTile(tiles[m], pos.row, pos.col); tile.x = pos.x; tile.y = pos.y; hexGrid[pos.row][pos.col] = tile; game.addChild(tile); } } // Get adjacent tiles (only diagonals) function getAdjacentTiles(row, col) { var adjacent = []; var directions; if (row % 2 === 0) { directions = [[-1, -1], [-1, 0], [1, -1], [1, 0]]; // All diagonal moves for even rows } else { directions = [[-1, 0], [-1, 1], [1, 0], [1, 1]]; // All diagonal moves for odd rows } for (var i = 0; i < directions.length; i++) { var newRow = row + directions[i][0]; var newCol = col + directions[i][1]; if (newRow >= 0 && newRow < gridHeight && newCol >= 0 && newCol < gridWidth && hexGrid[newRow] && hexGrid[newRow][newCol]) { adjacent.push(hexGrid[newRow][newCol]); } } return adjacent; } // Start the actual game function startGame() { showingMenu = false; // Hide menu if (menuContainer) { menuContainer.destroy(); menuContainer = null; } // Show UI elements turnContainer.visible = true; scoreContainer.visible = true; buildingListContainer.visible = true; buildButtonContainer.visible = true; returnButtonContainer.visible = true; // Initialize game initGame(); } // Initialize game function initGame() { createHexGrid(); // Collect all available tiles var availableTiles = []; for (var row = 0; row < gridHeight; row++) { for (var col = 0; col < gridWidth; col++) { if (hexGrid[row] && hexGrid[row][col]) { availableTiles.push(hexGrid[row][col]); } } } // Place character on random available tile if (availableTiles.length > 0) { var randomIndex = Math.floor(Math.random() * availableTiles.length); var randomTile = availableTiles[randomIndex]; character = new Character(); character.moveToTile(randomTile); game.addChild(character); gameStarted = true; } } // Save current game state to history function saveGameState() { var currentState = { turn: currentTurn, score: score, characterRow: character.row, characterCol: character.col, buildings: [] }; // Save all buildings in the grid for (var row = 0; row < gridHeight; row++) { for (var col = 0; col < gridWidth; col++) { if (hexGrid[row] && hexGrid[row][col] && hexGrid[row][col].hasBuilding) { currentState.buildings.push({ row: row, col: col, type: hexGrid[row][col].type }); } } } // Keep only the last two states - add current state and limit to 2 entries gameHistory.push(currentState); if (gameHistory.length > 2) { gameHistory.shift(); // Remove oldest state if we have more than 2 } } // Update UI function updateUI() { turnText.setText('Turn: ' + currentTurn + '/' + maxTurns); scoreText.setText('Score: ' + score); } // Check if character can move to tile function canMoveTo(tile) { var adjacents = getAdjacentTiles(character.row, character.col); return adjacents.indexOf(tile) !== -1; } // End turn function endTurn() { // Save state before incrementing turn to capture previous turn state saveGameState(); currentTurn++; selectedTile = null; hasMovedThisTurn = false; lastTurnBuilding = null; // Reset building tracking lastTurnPoints = 0; // Reset points tracking if (character) { character.previousRow = character.row; character.previousCol = character.col; } if (currentTurn > maxTurns) { LK.setScore(score); resetGameAndShowMenu(); return; } updateUI(); } // Handle tile clicks game.down = function (x, y, obj) { if (showingMenu || !gameStarted || hasMovedThisTurn || isBuilding) { return; } // Check if clicking on a hex tile for (var row = 0; row < gridHeight; row++) { for (var col = 0; col < gridWidth; col++) { if (hexGrid[row] && hexGrid[row][col]) { var tile = hexGrid[row][col]; var distance = Math.sqrt(Math.pow(x - tile.x, 2) + Math.pow(y - tile.y, 2)); if (distance < 100) { if (canMoveTo(tile)) { character.moveToTile(tile); selectedTile = tile; hasMovedThisTurn = true; endTurn(); } return; } } } } }; // Build button handler buildButtonContainer.down = function (x, y, obj) { // Animate button press with Y scale reduction tween(buildButtonContainer, { scaleY: 0.9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(buildButtonContainer, { scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); } }); if (!gameStarted) { return; } var currentTile = null; for (var row = 0; row < gridHeight; row++) { for (var col = 0; col < gridWidth; col++) { if (hexGrid[row] && hexGrid[row][col] && hexGrid[row][col].row === character.row && hexGrid[row][col].col === character.col) { currentTile = hexGrid[row][col]; break; } } } if (currentTile && currentTile.type !== 'grass' && !currentTile.hasBuilding && !isBuilding) { var points = currentTile.addBuilding(); if (points > 0) { isBuilding = true; // Block all input during building animation score += points; lastTurnBuilding = currentTile; // Track building created this turn lastTurnPoints = points; // Track points gained this turn updateUI(); // Create dust effect at current tile position var dustEffect = LK.getAsset('dust', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); dustEffect.x = currentTile.x; dustEffect.y = currentTile.y; game.addChild(dustEffect); // Animate dust growing while character bobs tween(dustEffect, { scaleX: 2.25, scaleY: 2.25, alpha: 0.85 }, { duration: 500, easing: tween.easeOut }); // Animate character bobbing up and down for half a second tween(character, { y: character.y - 20 }, { duration: 250, easing: tween.easeInOut, onFinish: function onFinish() { tween(character, { y: character.y + 20 }, { duration: 250, easing: tween.easeInOut, onFinish: function onFinish() { // Animate dust shrinking and disappearing tween(dustEffect, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { dustEffect.destroy(); isBuilding = false; // Re-enable input after animation } }); } }); } }); } } }; // Return button handler returnButtonContainer.down = function (x, y, obj) { // Animate button press with Y scale reduction tween(returnButtonContainer, { scaleY: 0.9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(returnButtonContainer, { scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); } }); if (!gameStarted || currentTurn <= 1 || gameHistory.length < 2 || isBuilding) { return; } // Get the second most recent saved state (skip the most recent one) var lastState = gameHistory[gameHistory.length - 2]; // Remove both the most recent and second most recent states from history gameHistory.pop(); // Remove all current buildings for (var row = 0; row < gridHeight; row++) { for (var col = 0; col < gridWidth; col++) { if (hexGrid[row] && hexGrid[row][col] && hexGrid[row][col].hasBuilding) { hexGrid[row][col].removeBuilding(); } } } // Restore game state currentTurn = lastState.turn; score = lastState.score; // Move character back to previous position if (hexGrid[lastState.characterRow] && hexGrid[lastState.characterRow][lastState.characterCol]) { var previousTile = hexGrid[lastState.characterRow][lastState.characterCol]; character.x = previousTile.x; character.y = previousTile.y; character.row = lastState.characterRow; character.col = lastState.characterCol; } // Restore buildings for (var i = 0; i < lastState.buildings.length; i++) { var building = lastState.buildings[i]; if (hexGrid[building.row] && hexGrid[building.row][building.col]) { hexGrid[building.row][building.col].addBuilding(); } } selectedTile = null; hasMovedThisTurn = false; lastTurnBuilding = null; lastTurnPoints = 0; updateUI(); }; // Hide all UI elements initially turnContainer.visible = false; scoreContainer.visible = false; buildingListContainer.visible = false; buildButtonContainer.visible = false; returnButtonContainer.visible = false; // Show menu initially createMenu(); updateUI(); // Start character breathing animation function startCharacterBreathing() { var breatheIn = function breatheIn() { tween(character, { scaleY: 1.2 }, { duration: 2000, easing: tween.easeInOut, onFinish: breatheOut }); }; var breatheOut = function breatheOut() { tween(character, { scaleY: 1.0 }, { duration: 2000, easing: tween.easeInOut, onFinish: breatheIn }); }; breatheIn(); } // Start character breathing animation after character is created if (character) { startCharacterBreathing(); } // Start background music LK.playMusic('backgroundMusic'); // Background color cycling var backgroundColors = [0x8BC34A, 0x87CEEB, 0xDDA0DD, 0xF0E68C, 0xFFA07A, 0x98FB98]; var currentColorIndex = 0; function cycleBackgroundColor() { currentColorIndex = (currentColorIndex + 1) % backgroundColors.length; var currentColor = backgroundColors[currentColorIndex === 0 ? backgroundColors.length - 1 : currentColorIndex - 1]; var nextColor = backgroundColors[currentColorIndex]; // Extract RGB components from hex colors var currentR = currentColor >> 16 & 0xFF; var currentG = currentColor >> 8 & 0xFF; var currentB = currentColor & 0xFF; var nextR = nextColor >> 16 & 0xFF; var nextG = nextColor >> 8 & 0xFF; var nextB = nextColor & 0xFF; // Create a temporary object to tween the RGB components var colorTween = { r: currentR, g: currentG, b: currentB }; tween(colorTween, { r: nextR, g: nextG, b: nextB }, { duration: 3000, easing: tween.easeInOut, onFinish: function onFinish() { // Continue cycling LK.setTimeout(cycleBackgroundColor, 2000); } }); // Update the actual background color during the tween var _updateColor = function updateColor() { var r = Math.floor(colorTween.r); var g = Math.floor(colorTween.g); var b = Math.floor(colorTween.b); var combinedColor = r << 16 | g << 8 | b; game.setBackgroundColor(combinedColor); if (r !== nextR || g !== nextG || b !== nextB) { LK.setTimeout(_updateColor, 16); // ~60fps updates } }; _updateColor(); } // Reset game and show menu function resetGameAndShowMenu() { // Update high score if current score is higher var currentHighScore = storage.highScore || 0; if (score > currentHighScore) { storage.highScore = score; } // Reset all game variables currentTurn = 1; score = 0; gameStarted = false; hasMovedThisTurn = false; lastTurnBuilding = null; lastTurnPoints = 0; isBuilding = false; selectedTile = null; showingMenu = true; // Clear game history gameHistory = []; // Remove character if (character) { character.destroy(); character = null; } // Remove all hex tiles for (var row = 0; row < gridHeight; row++) { for (var col = 0; col < gridWidth; col++) { if (hexGrid[row] && hexGrid[row][col]) { hexGrid[row][col].destroy(); } } } hexGrid = []; // Hide UI elements turnContainer.visible = false; scoreContainer.visible = false; buildingListContainer.visible = false; buildButtonContainer.visible = false; returnButtonContainer.visible = false; // Show menu again createMenu(); updateUI(); } // Start the color cycling after a short delay LK.setTimeout(cycleBackgroundColor, 2000);
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Character = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
self.row = 0;
self.col = 0;
self.previousRow = 0;
self.previousCol = 0;
self.moveToTile = function (tile) {
self.previousRow = self.row;
self.previousCol = self.col;
self.x = tile.x;
self.y = tile.y;
self.row = tile.row;
self.col = tile.col;
LK.getSound('move').play();
};
self.returnToPreviousPosition = function () {
if (hexGrid[self.previousRow] && hexGrid[self.previousRow][self.previousCol]) {
var previousTile = hexGrid[self.previousRow][self.previousCol];
self.x = previousTile.x;
self.y = previousTile.y;
self.row = self.previousRow;
self.col = self.previousCol;
LK.getSound('move').play();
}
};
return self;
});
var HexTile = Container.expand(function (type, row, col) {
var self = Container.call(this);
self.type = type;
self.row = row;
self.col = col;
self.hasBuilding = false;
self.building = null;
var assetName = 'hexGrass';
if (type === 'barn') {
assetName = 'hexRed';
} else if (type === 'well') {
assetName = 'hexBlue';
} else if (type === 'orchard') {
assetName = 'hexPurple';
} else if (type === 'wheat') {
assetName = 'hexYellow';
} else if (type === 'stable') {
assetName = 'hexBrown';
}
self.originalAssetName = assetName; // Store original asset name for restoration
var hexGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.addBuilding = function () {
if (self.hasBuilding || self.type === 'grass') {
return false;
}
var buildingAsset = null;
var points = 0;
if (self.type === 'barn') {
buildingAsset = 'barn';
points = 15;
} else if (self.type === 'well') {
buildingAsset = 'well';
points = 10;
} else if (self.type === 'orchard') {
buildingAsset = 'orchard';
points = 20;
} else if (self.type === 'wheat') {
buildingAsset = 'wheat';
points = 12;
} else if (self.type === 'stable') {
buildingAsset = 'stable';
points = 18;
}
if (buildingAsset) {
// Change the hex tile to grass when building is constructed
hexGraphics.destroy();
hexGraphics = self.attachAsset('hexGrass', {
anchorX: 0.5,
anchorY: 0.5
});
self.building = self.attachAsset(buildingAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.25,
scaleY: 1.25
});
self.hasBuilding = true;
LK.getSound('build').play();
// Play building-specific sound after construction sound
LK.setTimeout(function () {
if (self.type === 'barn') {
LK.getSound('barnSound').play();
} else if (self.type === 'well') {
LK.getSound('wellSound').play();
} else if (self.type === 'orchard') {
LK.getSound('orchardSound').play();
} else if (self.type === 'wheat') {
LK.getSound('wheatSound').play();
} else if (self.type === 'stable') {
LK.getSound('stableSound').play();
}
}, 200);
// Start breathing animation for the building
self.startBuildingBreathing();
return points;
}
return 0;
};
self.startBuildingBreathing = function () {
if (self.building) {
// Create continuous breathing animation
var breatheIn = function breatheIn() {
tween(self.building, {
scaleX: 1.375,
scaleY: 1.375
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: breatheOut
});
};
var breatheOut = function breatheOut() {
tween(self.building, {
scaleX: 1.125,
scaleY: 1.125
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: breatheIn
});
};
breatheIn();
}
};
self.removeBuilding = function () {
if (self.hasBuilding && self.building) {
// Stop any ongoing breathing animation
tween.stop(self.building);
self.building.destroy();
self.building = null;
self.hasBuilding = false;
// Restore original hex graphics
hexGraphics.destroy();
hexGraphics = self.attachAsset(self.originalAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x8BC34A
});
/****
* Game Code
****/
// Game state
var currentTurn = 1;
var maxTurns = 20;
var score = 0;
var character = null;
var hexGrid = [];
var selectedTile = null;
var gameStarted = false;
var hasMovedThisTurn = false;
var lastTurnBuilding = null; // Track building created this turn
var lastTurnPoints = 0; // Track points gained this turn
var isBuilding = false; // Track if character is currently building
var showingMenu = true; // Track if we're showing the menu
var menuContainer = null; // Container for menu elements
// Game history for proper undo functionality
var gameHistory = [];
// Hex grid dimensions
var gridWidth = 6;
var gridHeight = 12;
var hexSize = 200;
var hexHeight = 173;
// UI positioning offsets
var scoreTextOffset = 300;
// Create menu
function createMenu() {
menuContainer = new Container();
// Create PLAY button container
var playButtonContainer = new Container();
var playButtonBox = LK.getAsset('buildButtonBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.2
});
playButtonContainer.addChild(playButtonBox);
var playButton = new Text2('PLAY', {
size: 100,
fill: 0xFFFFFF,
font: "Ink Free"
});
playButton.anchor.set(0.5, 0.5);
playButtonContainer.addChild(playButton);
// Position in center of screen
playButtonContainer.x = 1024; // Center X
playButtonContainer.y = 1000; // Center Y - moved up double
// Create high score display container
var highScoreContainer = new Container();
var highScoreBackground = LK.getAsset('scoreContainerBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.25,
scaleY: 1.75
});
highScoreContainer.addChild(highScoreBackground);
var highScore = storage.highScore || 0;
var highScoreText = new Text2('High Score: ' + highScore, {
size: 45,
fill: 0x000000,
font: "Ink Free"
});
highScoreText.anchor.set(0.5, 0.5);
highScoreContainer.addChild(highScoreText);
// Create mountain asset that extends to bottom margin
var bottomBackgroundContainer = new Container();
var bottomBackground = LK.getAsset('mountain', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10.24,
scaleY: 6.0
});
bottomBackgroundContainer.addChild(bottomBackground);
bottomBackgroundContainer.x = 1024; // Center X
bottomBackgroundContainer.y = 2400; // Position to extend to bottom
menuContainer.addChild(bottomBackgroundContainer);
// Create title asset container
var titleAssetContainer = new Container();
// Create title background asset - rectangular shape
var titleBackground = LK.getAsset('buildButtonBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.0,
scaleY: 1.5
});
titleBackground.alpha = 0.9; // Semi-transparent background
titleAssetContainer.addChild(titleBackground);
// Create game title container
var gameTitleContainer = new Container();
var gameTitle = new Text2('Diagonal Farm Builder', {
size: 200,
fill: 0xFFFFFF,
font: "Ink Free"
});
gameTitle.anchor.set(0.5, 0.5);
gameTitleContainer.addChild(gameTitle);
titleAssetContainer.addChild(gameTitleContainer);
titleAssetContainer.x = 1024; // Center X
titleAssetContainer.y = 500; // Move title up from 600 to 500
menuContainer.addChild(titleAssetContainer);
// Start title rotation animation
var rotateRight = function rotateRight() {
tween(titleAssetContainer, {
rotation: 15 * Math.PI / 180 // Convert 15 degrees to radians
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: rotateLeft
});
};
var rotateLeft = function rotateLeft() {
tween(titleAssetContainer, {
rotation: -15 * Math.PI / 180 // Convert -15 degrees to radians
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: rotateRight
});
};
rotateRight(); // Start the rotation animation
// Position high score container above the background asset
highScoreContainer.x = 1024; // Center X
highScoreContainer.y = 1700; // Position above the background asset - moved up
highScoreContainer.scaleX = 1.875; // Original X scale (0% increase)
highScoreContainer.scaleY = 2.1875; // Increase Y scale by 25% (1.75 * 1.25)
menuContainer.addChild(highScoreContainer);
// Add click handler
playButtonContainer.down = function (x, y, obj) {
// Animate button press
tween(playButtonContainer, {
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playButtonContainer, {
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
startGame();
}
});
}
});
};
menuContainer.addChild(playButtonContainer);
game.addChild(menuContainer);
}
// UI elements
// Create turn container with background box
var turnContainer = new Container();
var turnBackgroundBox = LK.getAsset('turnContainerBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.25,
scaleY: 1.0
});
turnContainer.addChild(turnBackgroundBox);
var turnText = new Text2('Turn: 1/20', {
size: 60,
fill: 0x000000,
font: "Ink Free"
});
turnText.anchor.set(0.5, 0.5);
turnContainer.addChild(turnText);
LK.gui.topLeft.addChild(turnContainer);
turnContainer.x = scoreTextOffset + 25;
turnContainer.y = 130;
// Create score container with background box
var scoreContainer = new Container();
var scoreBackgroundBox = LK.getAsset('scoreContainerBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.25,
scaleY: 1.0
});
scoreContainer.addChild(scoreBackgroundBox);
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0x000000,
font: "Ink Free"
});
scoreText.anchor.set(0.5, 0.5);
scoreContainer.addChild(scoreText);
LK.gui.topRight.addChild(scoreContainer);
scoreContainer.x = -scoreTextOffset - 25;
scoreContainer.y = 130;
// Create building list container
var buildingListContainer = new Container();
var buildingTypes = [{
asset: 'barn',
points: 15,
name: 'Barn'
}, {
asset: 'well',
points: 10,
name: 'Well'
}, {
asset: 'orchard',
points: 20,
name: 'Orchard'
}, {
asset: 'wheat',
points: 12,
name: 'Wheat'
}, {
asset: 'stable',
points: 18,
name: 'Stable'
}];
for (var i = 0; i < buildingTypes.length; i++) {
var buildingItem = new Container();
// Add building icon
var buildingIcon = buildingItem.attachAsset(buildingTypes[i].asset, {
anchorX: 0,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
// Add points text
var pointsText = new Text2(buildingTypes[i].points + ' pts', {
size: 36,
fill: 0xFFFFFF,
font: "Ink Free"
});
pointsText.anchor.set(0, 0.5);
pointsText.x = 100;
buildingItem.addChild(pointsText);
// Position each building item vertically
buildingItem.y = i * 70 - 140; // Center the list vertically
buildingListContainer.addChild(buildingItem);
}
LK.gui.bottom.addChild(buildingListContainer);
buildingListContainer.x = -600; // Position to the left of buttons
buildingListContainer.y = -200; // Center vertically between buttons
// Create button containers with background boxes
var buildButtonContainer = new Container();
var buildButtonBox = LK.getAsset('buildButtonBg', {
anchorX: 0.5,
anchorY: 0.5
});
buildButtonContainer.addChild(buildButtonBox);
var buildButton = new Text2('BUILD', {
size: 80,
fill: 0xFFFFFF,
font: "Ink Free"
});
buildButton.anchor.set(0.5, 0.5);
buildButton.y = -20;
buildButtonContainer.addChild(buildButton);
var buildDescription = new Text2('Build on special tiles', {
size: 48,
fill: 0xFFFFFF,
font: "Ink Free"
});
buildDescription.anchor.set(0.5, 0.5);
buildDescription.y = 30;
buildButtonContainer.addChild(buildDescription);
LK.gui.bottom.addChild(buildButtonContainer);
buildButtonContainer.y = -100;
var returnButtonContainer = new Container();
var returnButtonBox = LK.getAsset('returnButtonBg', {
anchorX: 0.5,
anchorY: 0.5
});
returnButtonContainer.addChild(returnButtonBox);
var returnButton = new Text2('RETURN', {
size: 80,
fill: 0xFFFFFF,
font: "Ink Free"
});
returnButton.anchor.set(0.5, 0.5);
returnButton.y = -20;
returnButtonContainer.addChild(returnButton);
var returnDescription = new Text2('Undo last turn', {
size: 48,
fill: 0xFFFFFF,
font: "Ink Free"
});
returnDescription.anchor.set(0.5, 0.5);
returnDescription.y = 30;
returnButtonContainer.addChild(returnDescription);
LK.gui.bottom.addChild(returnButtonContainer);
returnButtonContainer.y = -300;
// Create hex grid
function createHexGrid() {
var startX = 200;
var startY = 500;
var specialTypes = ['barn', 'well', 'orchard', 'wheat', 'stable'];
var specialCounts = {
barn: 0,
well: 0,
orchard: 0,
wheat: 0,
stable: 0
};
var validPositions = [];
var tiles = [];
// First pass: collect all valid positions and create tiles array
for (var row = 0; row < gridHeight; row++) {
hexGrid[row] = [];
for (var col = 0; col < gridWidth; col++) {
var xOffset = row % 2 * (hexSize * 0.75);
var x = startX + col * (hexSize * 1.5) + xOffset;
var y = startY + row * (hexHeight * 0.75);
// Skip if position would be off screen
if (x > 1900 || y > 2400) {
continue;
}
validPositions.push({
row: row,
col: col,
x: x,
y: y
});
tiles.push('grass'); // Initialize all as grass
}
}
// Guarantee at least 1 of each special type
for (var i = 0; i < specialTypes.length; i++) {
if (validPositions.length > 0) {
var randomIndex = Math.floor(Math.random() * validPositions.length);
tiles[randomIndex] = specialTypes[i];
specialCounts[specialTypes[i]]++;
}
}
// Add more special tiles randomly, respecting the maximum of 5 per type
for (var j = 0; j < validPositions.length; j++) {
if (tiles[j] === 'grass' && Math.random() < 0.15) {
var availableTypes = [];
for (var k = 0; k < specialTypes.length; k++) {
if (specialCounts[specialTypes[k]] < 5) {
availableTypes.push(specialTypes[k]);
}
}
if (availableTypes.length > 0) {
var selectedType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
tiles[j] = selectedType;
specialCounts[selectedType]++;
}
}
}
// Second pass: create actual tiles with determined types
for (var m = 0; m < validPositions.length; m++) {
var pos = validPositions[m];
var tile = new HexTile(tiles[m], pos.row, pos.col);
tile.x = pos.x;
tile.y = pos.y;
hexGrid[pos.row][pos.col] = tile;
game.addChild(tile);
}
}
// Get adjacent tiles (only diagonals)
function getAdjacentTiles(row, col) {
var adjacent = [];
var directions;
if (row % 2 === 0) {
directions = [[-1, -1], [-1, 0], [1, -1], [1, 0]]; // All diagonal moves for even rows
} else {
directions = [[-1, 0], [-1, 1], [1, 0], [1, 1]]; // All diagonal moves for odd rows
}
for (var i = 0; i < directions.length; i++) {
var newRow = row + directions[i][0];
var newCol = col + directions[i][1];
if (newRow >= 0 && newRow < gridHeight && newCol >= 0 && newCol < gridWidth && hexGrid[newRow] && hexGrid[newRow][newCol]) {
adjacent.push(hexGrid[newRow][newCol]);
}
}
return adjacent;
}
// Start the actual game
function startGame() {
showingMenu = false;
// Hide menu
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
}
// Show UI elements
turnContainer.visible = true;
scoreContainer.visible = true;
buildingListContainer.visible = true;
buildButtonContainer.visible = true;
returnButtonContainer.visible = true;
// Initialize game
initGame();
}
// Initialize game
function initGame() {
createHexGrid();
// Collect all available tiles
var availableTiles = [];
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
if (hexGrid[row] && hexGrid[row][col]) {
availableTiles.push(hexGrid[row][col]);
}
}
}
// Place character on random available tile
if (availableTiles.length > 0) {
var randomIndex = Math.floor(Math.random() * availableTiles.length);
var randomTile = availableTiles[randomIndex];
character = new Character();
character.moveToTile(randomTile);
game.addChild(character);
gameStarted = true;
}
}
// Save current game state to history
function saveGameState() {
var currentState = {
turn: currentTurn,
score: score,
characterRow: character.row,
characterCol: character.col,
buildings: []
};
// Save all buildings in the grid
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
if (hexGrid[row] && hexGrid[row][col] && hexGrid[row][col].hasBuilding) {
currentState.buildings.push({
row: row,
col: col,
type: hexGrid[row][col].type
});
}
}
}
// Keep only the last two states - add current state and limit to 2 entries
gameHistory.push(currentState);
if (gameHistory.length > 2) {
gameHistory.shift(); // Remove oldest state if we have more than 2
}
}
// Update UI
function updateUI() {
turnText.setText('Turn: ' + currentTurn + '/' + maxTurns);
scoreText.setText('Score: ' + score);
}
// Check if character can move to tile
function canMoveTo(tile) {
var adjacents = getAdjacentTiles(character.row, character.col);
return adjacents.indexOf(tile) !== -1;
}
// End turn
function endTurn() {
// Save state before incrementing turn to capture previous turn state
saveGameState();
currentTurn++;
selectedTile = null;
hasMovedThisTurn = false;
lastTurnBuilding = null; // Reset building tracking
lastTurnPoints = 0; // Reset points tracking
if (character) {
character.previousRow = character.row;
character.previousCol = character.col;
}
if (currentTurn > maxTurns) {
LK.setScore(score);
resetGameAndShowMenu();
return;
}
updateUI();
}
// Handle tile clicks
game.down = function (x, y, obj) {
if (showingMenu || !gameStarted || hasMovedThisTurn || isBuilding) {
return;
}
// Check if clicking on a hex tile
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
if (hexGrid[row] && hexGrid[row][col]) {
var tile = hexGrid[row][col];
var distance = Math.sqrt(Math.pow(x - tile.x, 2) + Math.pow(y - tile.y, 2));
if (distance < 100) {
if (canMoveTo(tile)) {
character.moveToTile(tile);
selectedTile = tile;
hasMovedThisTurn = true;
endTurn();
}
return;
}
}
}
}
};
// Build button handler
buildButtonContainer.down = function (x, y, obj) {
// Animate button press with Y scale reduction
tween(buildButtonContainer, {
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(buildButtonContainer, {
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
if (!gameStarted) {
return;
}
var currentTile = null;
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
if (hexGrid[row] && hexGrid[row][col] && hexGrid[row][col].row === character.row && hexGrid[row][col].col === character.col) {
currentTile = hexGrid[row][col];
break;
}
}
}
if (currentTile && currentTile.type !== 'grass' && !currentTile.hasBuilding && !isBuilding) {
var points = currentTile.addBuilding();
if (points > 0) {
isBuilding = true; // Block all input during building animation
score += points;
lastTurnBuilding = currentTile; // Track building created this turn
lastTurnPoints = points; // Track points gained this turn
updateUI();
// Create dust effect at current tile position
var dustEffect = LK.getAsset('dust', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
dustEffect.x = currentTile.x;
dustEffect.y = currentTile.y;
game.addChild(dustEffect);
// Animate dust growing while character bobs
tween(dustEffect, {
scaleX: 2.25,
scaleY: 2.25,
alpha: 0.85
}, {
duration: 500,
easing: tween.easeOut
});
// Animate character bobbing up and down for half a second
tween(character, {
y: character.y - 20
}, {
duration: 250,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(character, {
y: character.y + 20
}, {
duration: 250,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Animate dust shrinking and disappearing
tween(dustEffect, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
dustEffect.destroy();
isBuilding = false; // Re-enable input after animation
}
});
}
});
}
});
}
}
};
// Return button handler
returnButtonContainer.down = function (x, y, obj) {
// Animate button press with Y scale reduction
tween(returnButtonContainer, {
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(returnButtonContainer, {
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
if (!gameStarted || currentTurn <= 1 || gameHistory.length < 2 || isBuilding) {
return;
}
// Get the second most recent saved state (skip the most recent one)
var lastState = gameHistory[gameHistory.length - 2];
// Remove both the most recent and second most recent states from history
gameHistory.pop();
// Remove all current buildings
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
if (hexGrid[row] && hexGrid[row][col] && hexGrid[row][col].hasBuilding) {
hexGrid[row][col].removeBuilding();
}
}
}
// Restore game state
currentTurn = lastState.turn;
score = lastState.score;
// Move character back to previous position
if (hexGrid[lastState.characterRow] && hexGrid[lastState.characterRow][lastState.characterCol]) {
var previousTile = hexGrid[lastState.characterRow][lastState.characterCol];
character.x = previousTile.x;
character.y = previousTile.y;
character.row = lastState.characterRow;
character.col = lastState.characterCol;
}
// Restore buildings
for (var i = 0; i < lastState.buildings.length; i++) {
var building = lastState.buildings[i];
if (hexGrid[building.row] && hexGrid[building.row][building.col]) {
hexGrid[building.row][building.col].addBuilding();
}
}
selectedTile = null;
hasMovedThisTurn = false;
lastTurnBuilding = null;
lastTurnPoints = 0;
updateUI();
};
// Hide all UI elements initially
turnContainer.visible = false;
scoreContainer.visible = false;
buildingListContainer.visible = false;
buildButtonContainer.visible = false;
returnButtonContainer.visible = false;
// Show menu initially
createMenu();
updateUI();
// Start character breathing animation
function startCharacterBreathing() {
var breatheIn = function breatheIn() {
tween(character, {
scaleY: 1.2
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: breatheOut
});
};
var breatheOut = function breatheOut() {
tween(character, {
scaleY: 1.0
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: breatheIn
});
};
breatheIn();
}
// Start character breathing animation after character is created
if (character) {
startCharacterBreathing();
}
// Start background music
LK.playMusic('backgroundMusic');
// Background color cycling
var backgroundColors = [0x8BC34A, 0x87CEEB, 0xDDA0DD, 0xF0E68C, 0xFFA07A, 0x98FB98];
var currentColorIndex = 0;
function cycleBackgroundColor() {
currentColorIndex = (currentColorIndex + 1) % backgroundColors.length;
var currentColor = backgroundColors[currentColorIndex === 0 ? backgroundColors.length - 1 : currentColorIndex - 1];
var nextColor = backgroundColors[currentColorIndex];
// Extract RGB components from hex colors
var currentR = currentColor >> 16 & 0xFF;
var currentG = currentColor >> 8 & 0xFF;
var currentB = currentColor & 0xFF;
var nextR = nextColor >> 16 & 0xFF;
var nextG = nextColor >> 8 & 0xFF;
var nextB = nextColor & 0xFF;
// Create a temporary object to tween the RGB components
var colorTween = {
r: currentR,
g: currentG,
b: currentB
};
tween(colorTween, {
r: nextR,
g: nextG,
b: nextB
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Continue cycling
LK.setTimeout(cycleBackgroundColor, 2000);
}
});
// Update the actual background color during the tween
var _updateColor = function updateColor() {
var r = Math.floor(colorTween.r);
var g = Math.floor(colorTween.g);
var b = Math.floor(colorTween.b);
var combinedColor = r << 16 | g << 8 | b;
game.setBackgroundColor(combinedColor);
if (r !== nextR || g !== nextG || b !== nextB) {
LK.setTimeout(_updateColor, 16); // ~60fps updates
}
};
_updateColor();
}
// Reset game and show menu
function resetGameAndShowMenu() {
// Update high score if current score is higher
var currentHighScore = storage.highScore || 0;
if (score > currentHighScore) {
storage.highScore = score;
}
// Reset all game variables
currentTurn = 1;
score = 0;
gameStarted = false;
hasMovedThisTurn = false;
lastTurnBuilding = null;
lastTurnPoints = 0;
isBuilding = false;
selectedTile = null;
showingMenu = true;
// Clear game history
gameHistory = [];
// Remove character
if (character) {
character.destroy();
character = null;
}
// Remove all hex tiles
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
if (hexGrid[row] && hexGrid[row][col]) {
hexGrid[row][col].destroy();
}
}
}
hexGrid = [];
// Hide UI elements
turnContainer.visible = false;
scoreContainer.visible = false;
buildingListContainer.visible = false;
buildButtonContainer.visible = false;
returnButtonContainer.visible = false;
// Show menu again
createMenu();
updateUI();
}
// Start the color cycling after a short delay
LK.setTimeout(cycleBackgroundColor, 2000);
Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "Hex Farm Builder" and with the description "Strategic turn-based farming game on a hexagonal grid where players move a character and build farm structures on special colored tiles to maximize points in 20 turns.". No text on banner!
Quítale el techo y aleja un poco la perspectiva
Un pozo con una cubeta llena de agua. In-Game asset. No shadows
Vuelve la parcela más densa de trigo
Una plantación de frutas rojas. In-Game asset. No shadows
Polvo de construcción denso. In-Game asset. No shadows
Rectángulo de madera color rojo. In-Game asset. 2d. High contrast. No shadows
Rectángulo de madera color café. In-Game asset. 2d. High contrast. No shadows
Elimina el fondo y que se vea derecho respecto al monitor
Cima de una colina redondeada con un sendero que lleva a la cima, mucho césped. In-Game asset. 2d. High contrast. No shadows