Code edit (2 edits merged)
Please save this source code
User prompt
create a global variable to clearly handle userActionState (navigating, building, placing buildings, giving orders, ...) with comments
Code edit (1 edits merged)
Please save this source code
User prompt
in building.on('down', function () { console.log("User is placing ", building); currentBuildingForPlacement = building; game.addChild(building); building.visible = true; }); the even should be set on the BuildableItemIcon not the building itself
Code edit (4 edits merged)
Please save this source code
User prompt
Fix when clicking the finished building the log is : "Clicked on boardat 190.67083333333335,2362.041666666667" instead of "User is placing..."
User prompt
looks like : building.asset.on('down', function () { console.log("User is placing ", building); currentBuildingForPlacement = building; game.addChild(building); building.asset.visible = true; }); is not working : There is no log when clicking on the finished building !
Code edit (1 edits merged)
Please save this source code
User prompt
when the finished buiding is clicked, add it to the game so that its asset is visible
User prompt
when currentBuildingForPlacement is not null move the building with the mouse until user taps
Code edit (1 edits merged)
Please save this source code
User prompt
Fix Bug: 'Timeout.tick error: rockIlot1Center is not defined' in or related to this line: 'currentSelection = gameMap.cells[rockIlot1Center.x][rockIlot1Center.y].building;' Line Number: 567
User prompt
when game starts, preselect Player 1 construction yard
User prompt
Fix Bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'setLabelToPlace')' in or related to this line: 'progressDisplay.parentIcon.setLabelToPlace(); // Change label text to 'Place'' Line Number: 339
User prompt
when th buidling is finished buiding, temporarly remplace the name under the build icon by the text 'Place'
User prompt
add a handleBuilding placement function
User prompt
currentBuildingForPlacement should not be treated in handleDragEnd .
User prompt
Fix Bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'asset')' in or related to this line: 'self.asset.interactive = true;' Line Number: 336
User prompt
Now don't place the finished building automatically, instead the user must first click the ready BuildableItemIcon and the place the building on the map
User prompt
make the progressDisplay more fluid, update it every 100ms instead of every second
Code edit (1 edits merged)
Please save this source code
User prompt
restaure alpha of all BuildableItemIcons when building id finished
User prompt
during building, reduce alpha of all BuildableItemIcons
User prompt
during building, diable all BuildableItemIcons
Code edit (2 edits merged)
Please save this source code
/**** * Classes ****/ var BuildableItemIcon = Container.expand(function (type, x, y) { var self = Container.call(this); self.type = type; self.asset = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, x: x, y: y }); self.asset.on('down', function () { if (!self.asset.interactive) { return; } if (currentBuildingForPlacement) { console.log("User is placing ", currentBuildingForPlacement); game.addChild(currentBuildingForPlacement); return; } var progressDisplay = new BuildingProgressDisplay(self); game.addChild(progressDisplay); enqueueBuildable(type, progressDisplay); game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.alpha = 0.75; } }); /* self.on('down', function () { console.log("User is placing ", self); currentBuildingForPlacement = self; game.addChild(self); self.visible = true; }); */ }); var buildableInfo = buildableRepository.getBuildableInfo(type); self.label = new Text2(buildableInfo.name, { size: 30, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); self.label.x = self.asset.x - buildableInfo.name.length / 2 * 15; self.label.y = self.asset.y + 120; self.addChild(self.label); self.setLabelToPlace = function () { self.label.setText('Place'); self.label.x = self.asset.x - 'Place'.length / 2 * 15; // Recalculate x position for new text }; return self; }); var BuildingProgressDisplay = Container.expand(function (parentIcon) { var self = Container.call(this); self.parentIcon = parentIcon; self.progressAsset = self.attachAsset('buildingProgress', { anchorX: 0, anchorY: .5, alpha: 0.5, width: 0, x: parentIcon.asset.x - parentIcon.asset.width / 2, y: parentIcon.asset.y }); self.setProgress = function (progress) { self.progressAsset.width = parentIcon.asset.width * progress; }; self.hide = function () { self.visible = false; }; self.show = function () { self.visible = true; }; return self; }); // Initialize game elements // Map class to represent the grid-based map system var Map = Container.expand(function () { var self = Container.call(this); self.cells = []; self.init = function (width, height) { for (var x = 0; x < width; x++) { self.cells[x] = []; for (var y = 0; y < height; y++) { // Initialize each cell with default terrain, height, resources self.cells[x][y] = { height: 0, resources: null, terrain: null, asset: null, building: null }; } } }; self.initTerrain = function (width, height) { for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { // Initialize each cell with default terrain, height, resources self.cells[x][y].terrain = globalTerrain[x][y] === 1 ? 'rock' : 'sand'; self.cells[x][y].asset = globalTerrain[x][y] === 1 ? new Rock(x, y) : new Sand(x, y); } } }; self.currentViewCenter = { x: 15, y: 20 }; // Create a Text2 object to display the currentViewCenter coordinates self.viewCenterText = new Text2(self.currentViewCenter.x + ', ' + self.currentViewCenter.y, { size: 50, fill: '#ffffff', align: 'center' }); // Position the text at the top center of the screen LK.gui.top.addChild(self.viewCenterText); self.render = function () { // Move tiles instead of the view var viewSize = Math.ceil(Math.max(game.width, game.height) / 2 / 100); // Calculate viewSize based on game dimensions and tile size for (var x = self.currentViewCenter.x - viewSize - 1; x <= self.currentViewCenter.x + viewSize; x++) { for (var y = self.currentViewCenter.y - viewSize - 1; y <= self.currentViewCenter.y + viewSize; y++) { if (x >= 0 && x < self.cells.length && y >= 0 && y < self.cells[x].length) { var cell = self.cells[x][y]; var asset = cell.asset; var screenX = (x - self.currentViewCenter.x + viewSize) * asset.width; var screenY = (y - self.currentViewCenter.y + viewSize) * asset.height; asset.x = screenX; asset.y = screenY; if (!asset.parent) { self.addChild(asset); } // Render buildings var building = cell.building; if (building) { building.asset.x = screenX; building.asset.y = screenY; self.addChild(building.asset); } } } } }; self.getNavigationMesh = function () { // Create and return the navigation mesh for pathfinding }; self.findPath = function (start, end) { // Implement A* pathfinding algorithm // Return the path from start to end }; self.lastInputPosition = null; self.handleInput = function (input) { // Clamp the view center to the map boundaries self.currentViewCenter.x = Math.max(14, Math.min(input.x, mapXSize - 7)); self.currentViewCenter.y = Math.max(14, Math.min(input.y, mapYSize - 9)); // Update the Text2 object with the new coordinates self.viewCenterText.setText(self.currentViewCenter.x + ', ' + self.currentViewCenter.y); if (currentSelection) { selectionMarker.updatePosition(currentSelection.x, currentSelection.y); } }; self.checkCollisions = function () { // Handle collisions between units and obstacles }; self.serialize = function () { // Serialize map data to a file }; self.load = function (data) { // Load map data from a file }; }); var Sand = Container.expand(function (x, y) { var self = Container.call(this); self.asset = LK.getAsset('sand', { x: x * 100, y: y * 100 }); // Pre-create the asset for this cell return self.asset; }); var Rock = Container.expand(function (x, y) { var self = Container.call(this); self.asset = LK.getAsset('rock', { x: x * 100, y: y * 100 }); // Pre-create the asset for this cell return self.asset; }); var SelectionMarker = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('selectionCross', { anchorX: 0.5, anchorY: 0.5 }); self.alpha = 0.6; self.visible = false; self.updatePosition = function (x, y) { console.log('SelectionMarker updated to position:', x, y); var viewSize = Math.ceil(Math.max(game.width, game.height) / 2 / 100); self.x = x - (gameMap.currentViewCenter.x - 15) * 100; self.y = y - (gameMap.currentViewCenter.y - 15) * 100; self.visible = true; }; self.hide = function () { console.log('SelectionMarker hidden'); self.visible = false; }; return self; }); // Base Building class var Building = Container.expand(function (x, y, type, name, playerId, cellW, cellH, buildable) { var self = Container.call(this); self.cellX = x; self.cellY = y; self.cellW = cellW || 1; // Default to 1x1 if not specified self.cellH = cellH || 1; // Default to 1x1 if not specified self.x = x * 100; self.y = y * 100; self.type = type; self.playerId = playerId; self.name = name; self.buildable = buildable || []; // New property to store what the building can build self.asset = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, tint: getPlayerTint(playerId) }); self.asset.x = self.x; self.asset.y = self.y; self.buildingQueue = []; // Initialize building-specific properties here // ... return self; }); var ConstructionYard = Building.expand(function (x, y, playerId) { var self = Building.call(this, x, y, 'constructionYard', 'Construction Yard', playerId, 2, 2, ['windTrap']); // Additional properties and methods for ConstructionYard can be added here return self; }); var WindTrap = Building.expand(function (x, y, playerId) { var self = Building.call(this, x, y, 'windTrap', 'Wind Trap', playerId, 2, 2); // Additional properties and methods for WindTrap can be added here return self; }); // BuildableRepository class to store reference information about all buildables var BuildableRepository = Container.expand(function () { var self = Container.call(this); self.buildables = { 'constructionYard': { 'name': 'Construction Yard', 'cost': 300, 'constructionTime': 10, 'className': 'ConstructionYard', 'buildable': ['windTrap'] }, 'windTrap': { 'name': 'Wind Trap', 'cost': 300, 'constructionTime': 2, 'className': 'WindTrap', 'buildable': [] } // Add more buildables as needed }; self.getBuildableInfo = function (type) { return self.buildables[type]; }; return self; }); var Player = Container.expand(function (playerId, tint) { var self = Container.call(this); self.playerId = playerId; self.resources = 0; self.tint = tint; self.spice = 1000; // Initialize spice property with 1000 // Initialize player-specific properties here // ... return self; }); // Command Panel class var CommandPanel = Container.expand(function () { var self = Container.call(this); self.graphics = self.attachAsset('boardBackground', { width: game.width, height: game.height * 0.22, color: 0x333333 }); // Set the center box position to the center of the screen self.x = game.width / 2 - self.graphics.width / 2; self.y = game.height - self.height + game.height * 0.01; }); /**** * Initialize Game ****/ // Event listeners // Instantiate and initialize the Map var game = new LK.Game({ backgroundColor: 0x000000 // Init game with black background }); /**** * Game Code ****/ function enqueueBuildable(type, progressDisplay) { console.log("enqueueBuildable...", type); if (!currentSelection || !currentSelection.buildable.includes(type)) { console.log("Cannot build this item here."); return; } var buildableInfo = buildableRepository.getBuildableInfo(type); if (player1.spice < buildableInfo.cost) { console.log("Not enough resources to build."); return; } player1.spice -= buildableInfo.cost; player1SpiceText.setText(player1.spice.toString()); var constructionTime = buildableInfo.constructionTime; var building; switch (buildableInfo.className) { case 'ConstructionYard': building = new ConstructionYard(currentSelection.cellX, currentSelection.cellY, player1.playerId); break; case 'WindTrap': building = new WindTrap(currentSelection.cellX, currentSelection.cellY, player1.playerId); break; // Add cases for other buildings as needed } building.constructionProgress = 0; building.constructionTimer = LK.setInterval(function () { building.constructionProgress += 0.1; building.progressDisplay.setProgress(building.constructionProgress / constructionTime); if (building.constructionProgress >= constructionTime) { LK.clearInterval(building.constructionTimer); console.log(type + " construction completed."); building.constructionTimer = null; building.progressDisplay.hide(); if (progressDisplay.parentIcon && typeof progressDisplay.parentIcon.setLabelToPlace === 'function') { progressDisplay.parentIcon.setLabelToPlace(); // Change label text to 'Place' } console.log("Building Ready for placement ", building); currentBuildingForPlacement = building; /* building.asset.interactive = true; building.alpha = 1.0; building.on('down', function () { console.log("User is placing ", building); currentBuildingForPlacement = building; game.addChild(building); building.visible = true; }); */ } }, 100); building.progressDisplay = progressDisplay; currentSelection.buildingQueue.push(building); game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.asset.interactive = false; } }); } function displayBuildableItems() { if (!currentSelection || !currentSelection.buildable) { return; } var buildableItems = currentSelection.buildable; var iconX = commandPanel.x + 200; // Starting X position for the first icon var iconY = commandPanel.y + 200; // Y position for all icons buildableItems.forEach(function (itemType) { var icon = new BuildableItemIcon(itemType, iconX, iconY); game.addChild(icon); iconX += 100; // Increment X position for the next icon }); } var applyCellOccupation = function applyCellOccupation(cellX, cellY) { var building = gameMap.cells[cellX][cellY].building; if (building) { for (var w = 0; w < building.cellW; w++) { for (var h = 0; h < building.cellH; h++) { if (cellX + w < gameMap.cells.length && cellY + h < gameMap.cells[0].length) { gameMap.cells[cellX + w][cellY + h].building = building; } } } } }; var getPlayerTint = function getPlayerTint(id) { return player1.playerId === id ? player1.tint : player2.tint; }; var gameIsRunning = false; var mapXSize = 50; var mapYSize = 30; var gameMap = null; // Define user action states var UserActionState = { NAVIGATING: 'navigating', BUILDING: 'building', PLACING_BUILDINGS: 'placing_buildings', GIVING_ORDERS: 'giving_orders' }; // Current state of user action var currentUserActionState = UserActionState.NAVIGATING; var globalTerrain = null; var player1 = null; var player2 = null; var currentSelection = null; var currentBuildingForPlacement = null; var selectionMarker = null; var buildableRepository = new BuildableRepository(); // Gui var commandPanel = null; var player1SpiceText = null; var currentSelectionText = null; var rockIlot1Center = { x: 0, y: 0 }; // Prepare the map function prepareMap() { globalTerrain = new Array(mapXSize).fill(0).map(function () { return new Array(mapYSize).fill(0); }); gameMap = new Map(); gameMap.init(mapXSize, mapYSize); // Initialize with a 20x20 grid // Define a fixed rock ilot near the center left of the map rockIlot1Center = { x: Math.floor(mapXSize * 0.15), y: Math.floor(mapYSize * 0.5) }; var rockIlot1Radius = 4; for (var x = rockIlot1Center.x - rockIlot1Radius; x <= rockIlot1Center.x + rockIlot1Radius; x++) { for (var y = rockIlot1Center.y - rockIlot1Radius; y <= rockIlot1Center.y + rockIlot1Radius; y++) { if (x >= 0 && x < mapXSize && y >= 0 && y < mapYSize) { globalTerrain[x][y] = 1; } } } console.log("rockIlot1Center at " + rockIlot1Center.x + ',' + rockIlot1Center.y); gameMap.cells[rockIlot1Center.x][rockIlot1Center.y].building = new ConstructionYard(rockIlot1Center.x, rockIlot1Center.y, 1); applyCellOccupation(rockIlot1Center.x, rockIlot1Center.y); // Define a fixed rock ilot near the center right of the map var rockIlot2Center = { x: Math.floor(mapXSize * 0.85), y: Math.floor(mapYSize * 0.5) }; var rockIlot2Radius = 4; for (var x = rockIlot2Center.x - rockIlot2Radius; x <= rockIlot2Center.x + rockIlot2Radius; x++) { for (var y = rockIlot2Center.y - rockIlot2Radius; y <= rockIlot2Center.y + rockIlot2Radius; y++) { if (x >= 0 && x < mapXSize && y >= 0 && y < mapYSize) { globalTerrain[x][y] = 1; } } } console.log("rockIlot2Center at " + rockIlot2Center.x + ',' + rockIlot2Center.y); gameMap.cells[rockIlot2Center.x][rockIlot2Center.y].building = new ConstructionYard(rockIlot2Center.x, rockIlot2Center.y, 2); applyCellOccupation(rockIlot2Center.x, rockIlot2Center.y); gameMap.initTerrain(mapXSize, mapYSize); // Initialize with a 20x20 grid console.log('ConstructionYard1 cell :', gameMap.cells[rockIlot1Center.x][rockIlot1Center.y]); selectionMarker = new SelectionMarker(); // Add the map to the game game.addChild(gameMap); game.addChild(selectionMarker); } //#region Event listeners var dragStart = null; function handleDragStart(obj) { dragStart = obj.event.getLocalPosition(game); } function handleDragMove(obj) { if (currentBuildingForPlacement) { console.log("User is moving building..."); var currentPos = obj.event.getLocalPosition(game); currentBuildingForPlacement.x = currentPos.x; currentBuildingForPlacement.y = currentPos.y; } else if (dragStart) { var currentPos = obj.event.getLocalPosition(game); var deltaX = currentPos.x - dragStart.x; var deltaY = currentPos.y - dragStart.y; dragStart = currentPos; // Update dragStart to the current position var inputPosition = { x: gameMap.currentViewCenter.x - Math.round(deltaX / 100), y: gameMap.currentViewCenter.y - Math.round(deltaY / 100) }; gameMap.handleInput(inputPosition); } } function handleDragEnd(obj) { if (currentBuildingForPlacement) { var currentPos = obj.event.getLocalPosition(game); var cellX = Math.floor(currentPos.x / 100); var cellY = Math.floor(currentPos.y / 100); console.log("Placing building ", currentBuildingForPlacement, " at " + cellX + ',' + cellY); handleBuildingPlacement(currentBuildingForPlacement, cellX, cellY); currentBuildingForPlacement = null; } else { // Existing code for handling drag end without a building placement var currentPos = obj.event.getLocalPosition(game); var input = { x: currentPos.x, y: currentPos.y }; if (input.y > game.height * 0.80) { console.log("Clicked on board at " + input.x + ',' + input.y); dragStart = null; return; } var cellX = Math.floor(input.x / 100) + gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 3; var cellY = Math.floor(input.y / 100) + gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100); if (cellX >= 0 && cellX < gameMap.cells.length && cellY >= 0 && cellY < gameMap.cells[cellX].length) { var cell = gameMap.cells[cellX][cellY]; if (!cell.building) { currentSelection = null; selectionMarker.hide(); console.log("Nothing selected at " + cellX + ',' + cellY); updateActionBoard(); } } dragStart = null; } } game.on('down', handleDragStart); game.on('move', handleDragMove); game.on('up', handleDragEnd); //#endregion Event listeners // Global function to handle building placement var handleBuildingPlacement = function handleBuildingPlacement(building, cellX, cellY) { if (!gameMap.cells[cellX] || !gameMap.cells[cellX][cellY]) { console.log('Invalid cell for building placement.'); return; } var cell = gameMap.cells[cellX][cellY]; if (cell.building) { console.log('Cell is already occupied.'); return; } // Place the building on the map cell.building = building; building.x = cellX * 100; building.y = cellY * 100; gameMap.addChild(building); applyCellOccupation(cellX, cellY); console.log(building.name + ' placed at ' + cellX + ',' + cellY); }; // Global function to handle action board updates var updateActionBoard = function updateActionBoard() { // Update logic for the action board // This function can be called whenever the action board needs to be updated currentSelectionText.setText(currentSelection ? currentSelection.name : ''); if (currentSelection) { displayBuildableItems(); // Call displayBuildableItems to show items that can be built } else { // Hide all buildable item icons game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.visible = false; } }); } }; function initGame() { // Create players player1 = new Player(1, 0xAAAAff); player2 = new Player(2, 0xffAAAA); // Prepare the map prepareMap(); // Instantiate CommandPanel commandPanel = game.addChild(new CommandPanel()); // Create a Text2 object for current selection currentSelectionText = new Text2('', { size: 50, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); currentSelectionText.anchor.set(0.5, 6.8); LK.gui.bottom.addChild(currentSelectionText); // Create a Text2 object to display player1's spice level player1SpiceText = new Text2(player1.spice.toString(), { size: 50, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); player1SpiceText.anchor.set(1.0, 0); // Add the spice level text to the GUI overlay LK.gui.topRight.addChild(player1SpiceText); gameIsRunning = true; } // Game tick LK.on('tick', function () { // Render the map each tick if (gameIsRunning) { gameMap.render(); } }); // Start the game with Player 1 construction yard preselected LK.setTimeout(function () { initGame(); currentSelection = gameMap.cells[rockIlot1Center.x][rockIlot1Center.y].building; selectionMarker.updatePosition(currentSelection.x, currentSelection.y); updateActionBoard(); }, 100);
===================================================================
--- original.js
+++ change.js
@@ -498,9 +498,9 @@
x: currentPos.x,
y: currentPos.y
};
if (input.y > game.height * 0.80) {
- console.log("Clicked on boardat " + input.x + ',' + input.y);
+ console.log("Clicked on board at " + input.x + ',' + input.y);
dragStart = null;
return;
}
var cellX = Math.floor(input.x / 100) + gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 3;
a tileable sand terrain tile.
A square tileable rock terrain tile WITHOUT BBORDER. Single Game Texture. In-Game asset. 2d. No shadows. No Border
Zenith view of Dune's Wind Trap power facility square fence. Ressembles a bit to Sydney's Opera. Zenith view Directly from above.
grey cancel icon. UI
thin white circle empty.
0x5e86ff
Zenith view of a white rectangular Harvester shape of a garbage truck with a triangular head. Harvesting on sand, with flowing spice in the back. inside a square fence. Zenith view. Directly overhead. Plumb view.
Minimal Ui icon of an right sign aside with an icon of a target. sand background
Minimal icon of a home with direction icon pointing to the home. sand background
3 white flat isometric concentric circles like a target.
Remove background
Gray background
Minimal Ui icon of target sign on a fire icon.. sand background
top view of an explosion effect.
Simple heavy army tank factory buiding a tank with a crane. Square fence... Zenith view Directly overhead. Plumb view.
an empty black popup UI. UI