Code edit (9 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: newCell is not defined' in or related to this line: 'self.cellX = Math.floor(newCell.cellX / tileSize);' Line Number: 805
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '8')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '7')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '6')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'unit')' in or related to this line: 'gameMap.cells[self.cellX][self.cellY].unit = self;' Line Number: 747
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '9.366666666666676')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (3 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'spice')' in or related to this line: 'if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) {' Line Number: 833
Code edit (1 edits merged)
Please save this source code
/**** * Classes ****/ var ActionItemIcon = Container.expand(function (action, x, y) { var self = Container.call(this); self.action = action; self.asset = self.attachAsset(action.icon, { anchorX: 0.5, anchorY: 0.5, x: x, y: y, width: 200, height: 200 }); self.asset.on('down', function () { if (self.action && typeof self.action.handler === 'function') { currentSelection.selectedAction = self.action.code; currentUserActionState = UserActionState.SET_ORDER_TARGET; console.log('Wait target for action ' + self.action.name); //self.action.handler(); if (!targetMoveCursor) { targetMoveCursor = game.addChild(new TargetMoveCursor()); } highlightBorder(self.asset.x); } else { currentSelection.selectedAction = null; } }); self.label = new Text2(action.name, { size: 30, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); self.label.x = self.asset.x - action.name.length / 2 * 13; self.label.y = self.asset.y + 120; self.addChild(self.label); return self; }); var ActionRepository = Container.expand(function () { var self = Container.call(this); self.actions = { 'harvest': { 'code': 'harvest', 'name': 'Harvest', 'icon': 'harvestIcon', 'handler': harvestActionLogic }, 'move': { 'code': 'move', 'name': 'Move', 'icon': 'moveIcon', 'handler': moveActionLogic }, 'return': { 'code': 'return', 'name': 'Retreat', 'icon': 'returnIcon', 'handler': function handler() {/* Return action logic */} } }; self.getActionInfo = function (actionType) { return self.actions[actionType]; }; return self; }); 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, width: 200, height: 200 }); self.asset.on('down', function () { if (!self.asset.interactive) { return; } if (currentBuildingForPlacement) { currentUserActionState = UserActionState.PLACING_BUILDINGS; console.log("User is placing ", currentBuildingForPlacement); game.addChild(currentBuildingForPlacement); return; } var progressDisplay = new BuildingProgressDisplay(self); game.addChild(progressDisplay); enqueueBuildable(self, progressDisplay); game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.alpha = 0.75; } }); }); 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 * 13; self.label.y = self.asset.y + 120; self.addChild(self.label); self.setLabelToPlace = function () { self.label.setText('Place'); self.label.x = self.asset.x - 38; // Recalculate x position for new text }; self.restoreLabel = function () { self.label.setText(buildableInfo.name); self.label.x = self.asset.x - buildableInfo.name.length / 2 * 13; // Recalculate x position for new text }; 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, 'energy': 0, 'constructionTime': 10, 'className': 'ConstructionYard', 'buildable': ['windTrap', 'spiceRefinery'] }, 'windTrap': { 'name': 'Wind Trap', 'cost': 300, 'energy': 100, 'constructionTime': 2, 'className': 'WindTrap', 'buildable': [] }, 'spiceRefinery': { 'name': 'Spice Refinery', 'cost': 600, 'energy': -50, 'constructionTime': 1, 'className': 'SpiceRefinery', 'buildable': [] } // Add more buildables as needed }; self.getBuildableInfo = function (type) { return self.buildables[type]; }; 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 * tileSize; self.y = y * tileSize; self.type = type; self.isBuilding = true; 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), // Color building to player tint }); self.asset.x = self.x; self.asset.y = self.y; self.buildingQueue = []; // Initialize building-specific properties 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; }); var SpiceRefinery = Building.expand(function (x, y, playerId) { var self = Building.call(this, x, y, 'spiceRefinery', 'Spice Refinery', playerId, 3, 2); // Additional properties and methods for SpiceRefinery can be added here return self; }); var ConstructionYard = Building.expand(function (x, y, playerId) { var self = Building.call(this, x, y, 'constructionYard', 'Construction Yard', playerId, 2, 2, buildableRepository.getBuildableInfo('constructionYard').buildable); // Additional properties and methods for ConstructionYard can be added here 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; }); var CancelActionButton = Container.expand(function (x, y) { var self = Container.call(this); self.asset = self.attachAsset('cancelAction', { anchorX: 0.5, anchorY: 0.5, x: x, y: y }); // Add a label 'Cancel' below the cancel action button self.label = new Text2('Cancel', { size: 30, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); self.label.x = self.asset.x - 40; self.label.y = self.asset.y + 120; self.addChild(self.label); self.asset.on('down', function () { // Handle cancel action logic here if (currentBuildingForPlacement) { player1.spice += buildableRepository.getBuildableInfo(currentBuildingForPlacement.type).cost; updateBaseInfo(); currentBuildingForPlacement.destroy(); currentBuildingForPlacement = null; currentUserActionState = UserActionState.NAVIGATING; self.visible = false; // Hide the CancelActionButton } // Restore labels on all BuildableItemIcon instances game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.restoreLabel(); } }); console.log('Cancel action button pressed and building placement cancelled.'); }); 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; }); var IconBorder = Container.expand(function (x, y) { var self = Container.call(this); self.asset = self.attachAsset('iconBorder', { anchorX: 0.5, anchorY: 0.5, x: x, y: y }); return self; }); // Initialize game elements // Map class to represent the grid-based map system var Map = Container.expand(function () { var self = Container.call(this); // Method to clear spice from a specified cell self.clearCellSpice = function (x, y) { if (self.cells[x] && self.cells[x][y]) { self.cells[x][y].spice = false; if (self.cells[x][y].spiceAsset) { self.cells[x][y].spiceAsset.destroy(); self.cells[x][y].spiceAsset = null; } // Update spiceSpots array spiceSpots = spiceSpots.filter(function (spot) { return spot.x !== x || spot.y !== y; }); } }; 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, spiceAsset: 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 () { self.removeChildren(); // Move tiles instead of the view //console.log("viewPort ", viewPort); for (var x = viewPort.wCellX; x < viewPort.wCellX + viewPort.cellW; x++) { for (var y = viewPort.wCellY; y < viewPort.wCellY + viewPort.cellH; 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 coord = worldCellToScreenCell(x, y); var screenX = coord.cellX * 100; var screenY = coord.cellY * 100; */ //console.log("cell " + x, ',' + y + " =>" + screenX, screenY); var screenCoord = worldCellToScreenCoord(x, y); var screenX = screenCoord.x; var screenY = screenCoord.y; asset.x = screenX; asset.y = screenY; if (!asset.parent) { self.addChild(asset); } // Render spice terrain if (cell.spice) { var spiceAsset = cell.spiceAsset; spiceAsset.x = screenX; spiceAsset.y = screenY; if (!spiceAsset.parent) { self.addChild(spiceAsset); } } // Render buildings var building = cell.building; if (building) { //console.log("Building at ", x, y, " screen : ", screenX, screenY); building.asset.x = screenX - (building.cellW - 2) / 2 * tileSize; // Adjust for building size building.asset.y = screenY - (building.cellH - 2) / 2 * tileSize; // Adjust for building size self.addChild(building.asset); } } } } }; self.getNavigationMesh = function () { // Create and return the navigation mesh for pathfinding }; self.findPath = function (start, end, ignoreSpecificBuilding) { console.log("findPath ", start, end); // A* pathfinding algorithm implementation // Avoid buildings by checking if the cell is occupied var openSet = []; var closedSet = []; var path = []; var startNode = { x: start.x, y: start.y, f: 0, g: 0, h: 0, parent: null }; var endNode = { x: end.x, y: end.y, f: 0, g: 0, h: 0, parent: null }; openSet.push(startNode); while (openSet.length > 0) { var lowestIndex = 0; for (var i = 0; i < openSet.length; i++) { if (openSet[i].f < openSet[lowestIndex].f) { lowestIndex = i; } } var currentNode = openSet[lowestIndex]; if (currentNode.x === endNode.x && currentNode.y === endNode.y) { var curr = currentNode; while (curr.parent) { var prev = curr.parent; if (prev) { // Calculate relative move var moveX = curr.x - prev.x; var moveY = curr.y - prev.y; console.log("Pushing : " + moveX, ',', moveY); path.push({ cellX: moveX, cellY: moveY }); } curr = curr.parent; } path.reverse(); console.log("Return 1", path); return path; } openSet.splice(lowestIndex, 1); closedSet.push(currentNode); var neighbors = getNeighbors(currentNode); for (i = 0; i < neighbors.length; i++) { var neighbor = neighbors[i]; if (closedSet.findIndex(function (node) { return node.x === neighbor.x && node.y === neighbor.y; }) !== -1 || self.cells[neighbor.x][neighbor.y].building && !ignoreSpecificBuilding) { // TODO : Be more specific here ! ignore just 1 building continue; } var gScore = currentNode.g + 1; // 1 is the distance from a node to a neighbor var gScoreIsBest = false; if (openSet.findIndex(function (node) { return node.x === neighbor.x && node.y === neighbor.y; }) === -1) { gScoreIsBest = true; neighbor.h = heuristic(neighbor, endNode); openSet.push(neighbor); } else if (gScore < neighbor.g) { gScoreIsBest = true; } if (gScoreIsBest) { neighbor.parent = currentNode; neighbor.g = gScore; neighbor.f = neighbor.g + neighbor.h; } } } console.log("Return 2", path); return path; }; function heuristic(node, endNode) { // Use Manhattan distance as heuristic return Math.abs(node.x - endNode.x) + Math.abs(node.y - endNode.y); } function getNeighbors(node) { // Get all valid neighbors (up, down, left, right) var neighbors = []; var directions = [{ x: -1, y: 0 }, { x: 1, y: 0 }, { x: 0, y: -1 }, { x: 0, y: 1 }]; directions.forEach(function (dir) { var newX = node.x + dir.x; var newY = node.y + dir.y; if (newX >= 0 && newX < self.cells.length && newY >= 0 && newY < self.cells[0].length) { neighbors.push({ x: newX, y: newY }); } }); return neighbors; } self.lastInputPosition = null; self.handleDrag = function (input) { // Clamp the view center to the map boundaries /*var targetX = Math.max(11, Math.min(self.currentViewCenter.x + input.x, mapXSize - 4)); var targetY = Math.max(14, Math.min(self.currentViewCenter.y + input.y, mapYSize - 9)); self.currentViewCenter.x = Math.round(self.currentViewCenter.x + (targetX - self.currentViewCenter.x) * dragSpeed); self.currentViewCenter.y = Math.round(self.currentViewCenter.y + (targetY - self.currentViewCenter.y) * dragSpeed); */ /* viewPort.wX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wX + input.x)); viewPort.wY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wY + input.y)); viewPort.wCellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wX + input.x)); viewPort.wCellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wY + input.y)); */ viewPort.wCellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wCellX + input.x)); viewPort.wCellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wCellY + input.y)); viewPort.wX = viewPort.wCellX * tileSize; viewPort.wY = viewPort.wCellY * tileSize; console.log("handling drag...", input, input.x, input.y); // Update the Text2 object with the new coordinates self.viewCenterText.setText(self.currentViewCenter.x + ', ' + self.currentViewCenter.y + '\r\n' + viewPort.wCellX + ',' + viewPort.wCellY); //selectionMarker.setOnElement(currentSelection); }; 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 Player = Container.expand(function (playerId, tint) { var self = Container.call(this); self.playerId = playerId; self.resources = 0; self.tint = 0xFFFFFF; self.spice = 1000; // Initialize spice property with 1000 self.energy = 0; // Initialize spice property with 1000 // Initialize player-specific properties here self.buildings = []; // Array to store all the player's buildings self.units = []; // Array to store all the player's units // ... self.addUnit = function (unit) { // Add the unit to the player's units array self.units.push(unit); // Update any unit-related properties or behaviors // ... }; self.addBuilding = function (building) { // Add the building to the player's buildings array self.buildings.push(building); // Update the energy production based on the new building self.updateEnergy(); // If the building can produce or store resources, update those as well // ... (additional resource management code can be added here) }; self.updateEnergy = function () { var counter = 0; // Iterate through all buildings owned by the player self.buildings.forEach(function (building) { // Sum the energy provided by the building var buildingInfo = buildableRepository.getBuildableInfo(building.type); console.log("Count energy of " + buildingInfo.name); var buildingInfo = buildableRepository.getBuildableInfo(building.type); counter = Math.min(Math.max(counter + buildingInfo.energy, 0), 100); }); self.energy = counter; console.log("Player " + self.playerId + " energy updated: " + self.energy); }; return self; }); 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 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 SelectionMarker = Container.expand(function () { var self = Container.call(this); self.selectionCross = self.attachAsset('selectionCross', { anchorX: 0.5, anchorY: 0.5, alpha: 1 }); self.selectionCircle = self.attachAsset('selectionCircle', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.alpha = 0.5; self.visible = false; // Initially, we display the selectionCross self.addChild(self.selectionCross); self.currentElement = null; self.setOnElement = function (element) { //console.log('SelectionMarker setOnElement:', element); self.currentElement = element; if (!element) { self.visible = false; return; } var elementDeltaX = 0; var elementDeltaY = 0; if (element.isBuilding) { elementDeltaX = element.cellW / 2 * tileSize; elementDeltaY = element.cellH / 2 * tileSize; self.selectionCross.alpha = 1; self.selectionCircle.alpha = 0; } if (element.isUnit) { elementDeltaX = 0; elementDeltaY = 500; self.selectionCross.alpha = 0; self.selectionCircle.alpha = 0.9; } var centerDeltaX = (gameMap.currentViewCenter.x - 15) * 100; var centerDeltaY = (gameMap.currentViewCenter.y - 15) * 100; //var cellElt = screenCoordToWorldCell(element.x, element.y); var cellElt = worldCoordToScreenCell(element.x, element.y); console.log("element at : " + element.x + ',' + element.y); //self.x = element.x - centerDeltaX + elementDeltaX; //self.y = element.y - centerDeltaY + elementDeltaY; self.x = cellElt.cellX * tileSize + elementDeltaX; self.y = cellElt.cellY * tileSize + elementDeltaY; console.log("SelectionMarker at : " + cellElt.wCellX + ',' + cellElt.wCellY + ' => ' + self.x + ',' + self.y); self.visible = true; }; self.hide = function () { console.log('SelectionMarker hidden'); self.visible = false; }; return self; }); var TargetMoveCursor = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('targetMoveCursor', { anchorX: 0.5, anchorY: 0.5 }); self.updatePosition = function (position) { //console.log("moving at : " + position.x + ',' + position.y); self.x = position.x; self.y = position.y; }; game.on('move', function (obj) { if (currentUserActionState != UserActionState.SET_ORDER_TARGET) { return; } //console.log("moving cursor"); var pos = obj.event.getLocalPosition(game); if (pos.y > game.height * 0.80) { self.visible = false; } else { self.visible = true; self.updatePosition(pos); } }); /*game.on('up', function () { self.destroy(); });*/ return self; }); var Unit = Container.expand(function (cellX, cellY, playerId, type) { var self = Container.call(this); self.moveAlongPath = function (path, callback) { console.log("moveAlongPath", path, callback); self.path = path; self.pathIndex = 0; self.isMoving = true; self.onArrivedCallback = callback; }; self.updateMovement = function (delta) { //console.log("updateMovement", delta); if (!self.isMoving) { //console.log("updateMovement not moving ", self.path, self.pathIndex, self.onArrivedCallback); return; } if (!self.path || self.pathIndex >= self.path.length) { console.log("updateMovement will stop ", self.path, self.pathIndex, self.onArrivedCallback); self.isMoving = false; if (self.onArrivedCallback) { console.log("updateMovement call onArrivedCallback 1"); self.onArrivedCallback(); self.onArrivedCallback = null; } return; } var targetPathStep = self.path[self.pathIndex]; var targetCell = { cellX: self.cellX + targetPathStep.cellX, cellY: self.cellY + targetPathStep.cellY }; var fixedX = Math.floor((self.x - (gameMap.currentViewCenter.x + viewSize) * 100) / 100); var fixedY = Math.floor((self.y - (gameMap.currentViewCenter.y + viewSize) * 100) / 100); var coords = getCoordsForUnit(self); //console.log("self.x/y", self.x, self.y); //console.log("asset.x/y", self.asset.x, self.asset.y); //console.log("parent.x/y", self.parent.x, self.parent.y); //console.log("coords", coords.x, coords.y); //console.log("moving...", { // x: self.cellX, // y: self.cellY //}, ' to ', targetCell, ' fixed :' + fixedX + ',' + fixedY); //var targetCoords = getCoordsForUnit(targetCell); var targetCoords = worldCellToScreenCoord(targetCell.cellX, targetCell.cellY); //console.log("targetCoords", targetCoords.x, targetCoords.y); var dx = targetCoords.x + tileSize / 2 - self.x; var dy = targetCoords.y + tileSize / 2 - self.y; var distance = Math.sqrt(dx * dx + dy * dy); //console.log("distance", distance, ' / dx,dy=' + dx, ',', dy); var step = self.speed * delta; if (distance < step) { //console.log("reached step", distance); self.x = targetCoords.x + tileSize / 2; self.y = targetCoords.y + tileSize / 2; // Update map gameMap.cells[self.cellX][self.cellY].unit = null; self.cellX = targetCell.cellX; self.cellY = targetCell.cellY; // Update map gameMap.cells[self.cellX][self.cellY].unit = self; self.pathIndex++; if (self.pathIndex >= self.path.length) { self.isMoving = false; if (self.onArrivedCallback) { console.log("updateMovement call onArrivedCallback 2"); self.onArrivedCallback(); self.onArrivedCallback = null; } } } else { //console.log("advance by ", dx / distance * step); var angle = Math.atan2(dy, dx); self.asset.rotation = angle - Math.PI / 2; self.x += Math.cos(angle) * step; self.y += Math.sin(angle) * step; } if (selectionMarker.currentElement == self) { //console.log("current selection moving..."); selectionMarker.setOnElement(self); } }; self.playerId = playerId; var unitInfo = unitRepository.getUnitInfo(type); self.name = unitInfo.name; self.type = type; self.isUnit = true; self.actions = unitInfo.actions; self.asset = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, tint: getPlayerTint(playerId) }); self.speed = 200; // Set the unit speed self.cellX = cellX; self.cellY = cellY; self.x = cellX * tileSize; self.y = cellY * tileSize; self.cellW = 1; self.cellH = 1; /* var targetCoords = getCoordsForUnit(self); self.x = targetCoords.x; self.y = targetCoords.y; */ console.log("New unit " + self.name + ' at ', self.x, ',', self.y, ' [' + self.cellX + ',' + self.cellY + ']'); self.asset.on('down', function () { console.log("Unit selected"); currentSelection = self; selectionMarker.setOnElement(currentSelection); currentUserActionState = UserActionState.GIVING_ORDERS; updateActionBoard(); }); self.onArrivedCallback = null; self.handleDrag = function () { var newCoord = worldCellToScreenCoord(self.cellX, self.cellY); self.x = newCoord.x; self.y = newCoord.y; var newCoord = worldCoordToScreenCoord(self.cellX, self.cellY); self.x = newCoord.x; self.y = newCoord.y; self.cellX = Math.floor(self.x / tileSize); self.cellY = Math.floor(self.y / tileSize); /*var newCell= worldCellToScreenCell(self.cellX, self.cellY); self.cellX = newCell.cellX; self.cellY = newCell.cellY;*/ }; return self; }); var UnitHarvester = Unit.expand(function (x, y, playerId) { var self = Unit.call(this, x, y, playerId, 'unitHarvester'); self.harvestedSpiceCapacity = 600; self.harvestedSpiceOnTripCounter = 0; self.harvestedSpiceOnCellCounter = 0; self.harvestingMode = 0; // 0 : Idle / 1 : harvesting / 2 : unload self.harvestSpeed = 2; // TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!! 0.25; // Adjust this value to control the speed of harvesting self.unloadSpeed = 1; // TEMP DEBUG !!!TEMP DEBUG !!!TEMP DEBUG !!! 0.25; // Adjust this value to control the speed of harvesting self.startHarvesting = function () { console.log("startHarvesting..."); var closestSpiceSpot = findClosestSpiceSpot(self.cellX, self.cellY); if (closestSpiceSpot) { console.log("closestSpiceSpot :", closestSpiceSpot); var path = gameMap.findPath({ x: self.cellX, y: self.cellY }, { x: closestSpiceSpot.x, y: closestSpiceSpot.y }); console.log("path :", path); self.moveAlongPath(path); self.harvestingMode = 1; } }; self.startUnloading = function () { self.harvestingMode = 2; console.log("Unloading spice..."); }; self.update = function () { if (self.harvestingMode == 1 && self.harvestedSpiceOnCellCounter < 200 && gameMap.cells[self.cellX][self.cellY].spice) { self.harvestedSpiceOnTripCounter += self.harvestSpeed; self.harvestedSpiceOnCellCounter += self.harvestSpeed; //console.log('Harvested Spice Counter:', self.harvestedSpiceOnCellCounter); //, ' cell ' + self.cellX + ',' + self.cellY, ' of map ', gameMap.cells[self.cellX][self.cellY]); if (self.harvestedSpiceOnCellCounter >= 200) { self.asset.tint = 0xFFFFFF; gameMap.clearCellSpice(self.cellX, self.cellY); if (self.harvestedSpiceOnTripCounter >= self.harvestedSpiceCapacity) { self.harvestedSpiceOnCellCounter = 0; var closestRefinery = findClosestRefinery(self); if (closestRefinery) { var path = gameMap.findPath({ x: self.cellX, y: self.cellY }, { x: closestRefinery.cellX, y: closestRefinery.cellY }, closestRefinery); if (path.length > 0) { console.log("Returning to Refiniery..."); self.moveAlongPath(path, self.startUnloading); } else { console.warn("No path to Refinery !"); } } } else { self.harvestedSpiceOnCellCounter = 0; self.startHarvesting(); } } else { // Make the unit blink in orange more smoothly var blinkPhase = Math.sin(Date.now() * 0.01) * 0.5 + 0.5; self.asset.tint = blinkPhase < 0.5 ? 0xFFA500 : 0xFFFFFF; self.asset.rotation += 45 / 400 * (Math.PI / 180); } } if (self.harvestingMode == 2) { self.harvestedSpiceOnTripCounter -= self.unloadSpeed; // Add the unloaded spice to the player's spice counter player1.spice += self.unloadSpeed; // TODO : update for Player 2 updateBaseInfo(); // Make the unit blink in green to indicate unloading var blinkPhase = Math.sin(Date.now() * 0.01) * 0.5 + 0.5; self.asset.tint = blinkPhase < 0.5 ? 0x00FFA5 : 0xFFFFFF; if (self.harvestedSpiceOnTripCounter <= 0) { console.log("Unloading finished..."); self.asset.tint = 0xFFFFFF; self.harvestedSpiceOnTripCounter = 0; self.harvestingMode = 0; // Reset harvesting mode self.startHarvesting(); // Start a new harvesting cycle } } }; // Additional properties and methods for UnitHarvester can be added here return self; }); //{15.1} var UnitRepository = Container.expand(function () { var self = Container.call(this); self.units = { 'unitHarvester': { 'name': 'Spice Harvester', 'cost': 400, 'energy': 0, 'constructionTime': 5, 'className': 'UnitHarvester', 'actions': ['harvest', 'move', 'return'] } // Add more units as needed }; self.getUnitInfo = function (type) { return self.units[type]; }; return self; }); /**** * Initialize Game ****/ // Event listeners // Instantiate and initialize the Map var game = new LK.Game({ backgroundColor: 0x000000 // Init game with black background }); /**** * Game Code ****/ // Global function to find the closest refinery to a given unit function findClosestRefinery(unit) { var closestRefinery = null; var minDistance = Number.MAX_VALUE; var playerBuildings = unit.playerId === player1.playerId ? player1.buildings : player2.buildings; console.log("Player has " + playerBuildings.length + " buildings"); playerBuildings.forEach(function (building) { if (building instanceof SpiceRefinery) { console.log("Found Refinery at " + building.cellX + "," + building.cellY); var dx = unit.cellX - building.cellX; var dy = unit.cellY - building.cellY; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistance) { closestRefinery = building; minDistance = distance; } } }); console.log("OK result ", closestRefinery); return closestRefinery ? { cellX: closestRefinery.cellX, cellY: closestRefinery.cellY } : null; } function spawnUnit(unitType, x, y, playerId) { var unitInfo = unitRepository.getUnitInfo(unitType); var unit; switch (unitInfo.className) { case 'UnitHarvester': unit = new UnitHarvester(x, y, playerId); // Find the first available place around the refinery var path = findAvailablePositionAroundRefinery(x, y); if (path.length > 0) { unit.moveAlongPath(path, function () { harvestActionLogic(unit); }); } break; // Add additional cases for other unit classes as needed default: throw new Error('Unknown unit class: ' + unitInfo.className); } gameMap.cells[x][y].unit = unit; if (playerId === player1.playerId) { player1.addUnit(unit); } else if (playerId === player2.playerId) { player2.addUnit(unit); } game.addChild(unit); return unit; } function findAvailablePositionAroundRefinery(refineryX, refineryY) { var directions = [{ x: -1, y: 0 }, { x: 1, y: 0 }, { x: 0, y: -1 }, { x: 0, y: 1 }]; for (var i = 0; i < directions.length; i++) { var checkX = refineryX + directions[i].x; var checkY = refineryY + directions[i].y; if (gameMap.cells[checkX] && gameMap.cells[checkX][checkY] && !gameMap.cells[checkX][checkY].unit && !gameMap.cells[checkX][checkY].building) { return [{ cellX: directions[i].x, cellY: directions[i].y }]; // Return relative move to the first available cell } } return []; // No available position found } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function moveActionLogic(targetUnit, destinationX, destinationY) { console.log("MoveActionLogic...", destinationX, ',', destinationY); if (targetUnit && targetUnit.isUnit) { var path = gameMap.findPath({ x: targetUnit.cellX, y: targetUnit.cellY }, { x: destinationX, y: destinationY }); targetUnit.moveAlongPath(path); } } function harvestActionLogic(targetUnit, destinationX, destinationY) { console.log("HarvestActionLogic...", targetUnit, ' pos=', destinationX, ',', destinationY); if (targetUnit && targetUnit.isUnit && targetUnit.type === "unitHarvester") { var path = []; if (destinationX && destinationY) { path = gameMap.findPath({ x: targetUnit.cellX, y: targetUnit.cellY }, { x: destinationX, y: destinationY }); } if (path.length > 0) { console.log("Valid harvesting, path:", path); targetUnit.moveAlongPath(path, targetUnit.startHarvesting); } else { console.log("No path, direct harvesting "); targetUnit.startHarvesting(); } } } function highlightBorder(borderX) { var iconBorders = game.children.filter(function (child) { return child instanceof IconBorder; }); for (var i = 0; i < iconBorders.length; i++) { var iconAsset = iconBorders[i].asset; iconAsset.tint = iconAsset.x === borderX ? 0xffAAAA : 0xFFFFFF; } } function getEnergyColor(energy) { if (energy < 25) { return '#ff1100'; // Red color for low energy } else if (energy < 75) { return '#d26600'; // Orange color for medium energy } else { return '#037d50'; // Original green color for high energy } } function checkBuildingPlacement(newBuilding, cellX, cellY) { if (newBuilding && 'cellW' in newBuilding) { for (var w = 0; w < newBuilding.cellW; w++) { for (var h = 0; h < newBuilding.cellH; h++) { if (!gameMap.cells[cellX + w] || !gameMap.cells[cellX + w][cellY + h] || gameMap.cells[cellX + w][cellY + h].terrain !== 'rock' || gameMap.cells[cellX + w][cellY + h].building) { return false; } } } } return true; } function enqueueBuildable(selectedBuildable, progressDisplay) { console.log("enqueueBuildable...", selectedBuildable); if (!currentSelection || !currentSelection.buildable.includes(selectedBuildable.type)) { console.log("Cannot build this item here."); return; } var buildableInfo = buildableRepository.getBuildableInfo(selectedBuildable.type); if (player1.spice < buildableInfo.cost) { console.log("Not enough resources to build."); return; } updateBaseInfo(); var constructionTime = buildableInfo.constructionTime; var building; switch (buildableInfo.className) { case 'ConstructionYard': building = new ConstructionYard(0, 0, player1.playerId); break; case 'WindTrap': building = new WindTrap(0, 0, player1.playerId); break; case 'SpiceRefinery': building = new SpiceRefinery(0, 0, player1.playerId); break; // Add cases for other buildings as needed } building.constructionProgress = 0; building.constructionTimer = LK.setInterval(function () { building.constructionProgress += 0.1; var progressFraction = building.constructionProgress / constructionTime; building.progressDisplay.setProgress(progressFraction); // Deduct spice progressively based on construction progress var costPerTick = buildableInfo.cost * 0.1 / constructionTime; player1.spice -= costPerTick; updateBaseInfo(); if (building.constructionProgress >= constructionTime) { LK.clearInterval(building.constructionTimer); console.log(selectedBuildable.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; game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.asset.interactive = true; child.alpha = 1.0; } }); } }, 100); building.progressDisplay = progressDisplay; currentSelection.buildingQueue.push(building); game.children.forEach(function (child) { if (child instanceof BuildableItemIcon) { child.asset.interactive = false; } }); // Instantiate and display the CancelActionButton on the command panel cancelActionBtn = new CancelActionButton(commandPanel.x + commandPanel.width - 200, commandPanel.y + 200); game.addChild(cancelActionBtn); } 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) { console.log("applyCellOccupation", cellX, cellY, " to ", cellX + w, cellY + h); 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 = 20 * 2; var mapYSize = 21 * 2; var tileSize = 100; var mapHeight = game.height * 0.80; var viewSize = Math.ceil(Math.max(game.width, game.height) / 2 / 100); var viewPort = { wX: 0, wY: 0, wCellX: 0, wCellY: 0, cellW: Math.floor(game.width / tileSize), // ~20 cellH: Math.floor(mapHeight / tileSize) // ~21 }; // Init view port viewPort.wCellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, viewPort.wCellX)); // + game.width/2)); viewPort.wCellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, viewPort.wCellY)); // + game.height/2)); viewPort.wX = viewPort.wCellX * tileSize; viewPort.wY = viewPort.wCellY * tileSize; var dragSpeed = 0.15; var gameMap = new Map(); var buildableRepository = new BuildableRepository(); var unitRepository = new UnitRepository(); var actionRepository = new ActionRepository(); // Define user action states var UserActionState = { NAVIGATING: 'navigating', BUILDING: 'building', PLACING_BUILDINGS: 'placing_buildings', GIVING_ORDERS: 'giving_orders', SET_ORDER_TARGET: 'set_order_target' }; // Current state of user action var currentUserActionState = UserActionState.NAVIGATING; var globalTerrain = null; var player1 = null; var player2 = null; var spiceSpots = []; // Global variable to keep track of the previous energy level var previousEnergyLevel = 0; var currentSelection = null; var currentBuildingForPlacement = null; var selectionMarker = null; var tickCounter = 0; var fps = 0; // Gui var commandPanel = null; var player1SpiceText = null; var player1EnergyText = null; var energyOffsetSufix = '% '; var currentSelectionText = null; var fpsText = null; var targetMoveCursor = null; var cancelActionBtn = 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.25) }; console.log("rockIlot1Center : ", rockIlot1Center); 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); var initialConstructionYard = new ConstructionYard(rockIlot1Center.x, rockIlot1Center.y, 1); gameMap.cells[rockIlot1Center.x][rockIlot1Center.y].building = initialConstructionYard; applyCellOccupation(rockIlot1Center.x, rockIlot1Center.y); player1.addBuilding(initialConstructionYard); // Add a new harvester to player 1 //spawnUnit('unitHarvester', rockIlot1Center.x, rockIlot1Center.y - 2, player1.playerId); // 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); var initialConstructionYard2 = new ConstructionYard(rockIlot2Center.x, rockIlot2Center.y, 2); gameMap.cells[rockIlot2Center.x][rockIlot2Center.y].building = initialConstructionYard2; applyCellOccupation(rockIlot2Center.x, rockIlot2Center.y); player2.addBuilding(initialConstructionYard2); gameMap.initTerrain(mapXSize, mapYSize); // Initialize with a 20x20 grid initSpiceSpots(); 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); } function initSpiceSpots() { var quarterWidth = Math.floor(mapXSize / 2); var quarterHeight = Math.floor(mapYSize / 2); for (var i = 0; i < 4; i++) { var startX = i % 2 * quarterWidth; var startY = Math.floor(i / 2) * quarterHeight; var ilotCenterX = startX + Math.floor(Math.random() * quarterWidth); var ilotCenterY = startY + Math.floor(Math.random() * quarterHeight); var ilotRadius = 2 + Math.floor(Math.random() * 3); // Radius between 2 and 4 for (var x = ilotCenterX - ilotRadius; x <= ilotCenterX + ilotRadius; x++) { for (var y = ilotCenterY - ilotRadius; y <= ilotCenterY + ilotRadius; y++) { if (x >= 0 && x < mapXSize && y >= 0 && y < mapYSize && globalTerrain[x][y] === 0) { globalTerrain[x][y] = 2; // Mark as spice spiceSpots.push({ x: x, y: y }); gameMap.cells[x][y].spice = true; gameMap.cells[x][y].spiceAsset = LK.getAsset('terrainSpice', { x: x * 100, y: y * 100 }); } } } } } //#region Event listeners var dragStart = null; var dragDelta = 0; function handleDragStart(obj) { console.log("Drag start..."); dragStart = obj.event.getLocalPosition(game); } function handleDragMove(obj) { var currentPos = obj.event.getLocalPosition(game); var input = { x: currentPos.x, y: currentPos.y }; updateMouseCoords(input.x, input.y); if (currentUserActionState === UserActionState.PLACING_BUILDINGS) { //console.log("User is moving building..." + Math.floor(input.x) + ',' + Math.floor(input.y), currentBuildingForPlacement); var cellCoord = screenCoordToWorldCell(input.x, input.y); //getCellForPlacement(input.x, input.y, currentBuildingForPlacement); var cellX = cellCoord.wCellX; var cellY = cellCoord.wCellY; var isValidPlacement = checkBuildingPlacement(currentBuildingForPlacement, cellX, cellY); //console.log("Verif coords : " + cellX + ',' + cellY); if (currentBuildingForPlacement && currentBuildingForPlacement.asset) { currentBuildingForPlacement.asset.tint = isValidPlacement ? 0x00FF00 : 0xFF0000; currentBuildingForPlacement.visible = input.y + currentBuildingForPlacement.cellH * tileSize < mapHeight; } //var cursorCellCoord = getCursorCellForMovement(input, currentBuildingForPlacement); currentBuildingForPlacement.x = (cellX + currentBuildingForPlacement.cellW / 2) * tileSize; //cursorCellCoord.cellX; currentBuildingForPlacement.y = (cellY + currentBuildingForPlacement.cellH / 2) * tileSize; //cursorCellCoord.cellY; //console.log("Follow coords : " + currentBuildingForPlacement.x + ',' + currentBuildingForPlacement.y); } else if (dragStart) { //console.log("Drag move..."); var deltaX = currentPos.x - dragStart.x; var deltaY = currentPos.y - dragStart.y; var inputPosition = { x: Math.round(-deltaX / tileSize), y: Math.round(-deltaY / tileSize) }; var allUnits = player1.units.concat(player2.units); var vpWX = viewPort.wX; var vpWY = viewPort.wY; console.log("vp before : " + viewPort.wX + ',' + viewPort.wY); gameMap.handleDrag(inputPosition); allUnits.forEach(function (unit) { console.log("unit coords : " + unit.x + ',' + unit.y); unit.handleDrag(inputPosition); /* console.log("unit cells : " + unit.cellX + ',' + unit.cellY); console.log("delta coords : " + deltaX + ',' + deltaY); console.log("vp after : " + (viewPort.wX) + ',' + (viewPort.wY)); console.log("vp Delta : " + (viewPort.wX-vpWX) + ',' + (viewPort.wY-vpWY)); */ //var newCoord = worldCoordToScreenCoord(unit.x, unit.y); //console.log("newCoord : " + newCoord.x + ',' + newCoord.y); /*unit.x = newCoord.x; unit.y = newCoord.y; unit.cellX = Math.floor(unit.x / tileSize); unit.cellY = Math.floor(unit.y / tileSize); */ //unit.cellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, unit.cellX + inputPosition.x)); //unit.cellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, unit.cellY + inputPosition.y)); /* var worldOldPos = worldCoordToScreenCoord(unit.x, unit.y); var newWorldPos = screenCoordToWorldCoord(worldOldPos.x, worldOldPos.y); console.log("newWorldPos : " + newWorldPos.wX + ',' + newWorldPos.wY); unit.x = newWorldPos.wX; unit.y = newWorldPos.wY; unit.cellX = Math.floor(unit.x / tileSize); unit.cellX = Math.floor(unit.y * tileSize); */ /* unit.cellX += deltaX; unit.cellY += deltaY; unit.x += deltaX * tileSize; unit.y += deltaY * tileSize; */ /* var targetX = Math.max(11, Math.min(gameMap.currentViewCenter.x + inputPosition.x, mapXSize - 4)); var targetY = Math.max(14, Math.min(gameMap.currentViewCenter.y + inputPosition.y, mapYSize - 9)); var newCenterX = Math.round(gameMap.currentViewCenter.x + (targetX - gameMap.currentViewCenter.x) * dragSpeed); var newCenterY = Math.round(gameMap.currentViewCenter.y + (targetY - gameMap.currentViewCenter.y) * dragSpeed); var deltaX = gameMap.currentViewCenter.x - newCenterX; var deltaY = gameMap.currentViewCenter.y - newCenterY; //console.log("target coords : " + targetX + ',' + targetY); //console.log("center coords : " + gameMap.currentViewCenter.x + ',' + gameMap.currentViewCenter.y); //console.log("input coords : " + inputPosition.x + ',' + inputPosition.y); console.log("delta coords : " + deltaX + ',' + deltaY); unit.x += deltaX * tileSize; unit.y += deltaY * tileSize; */ }); dragDelta = Math.sqrt(deltaX * deltaX + deltaY * deltaY); selectionMarker.setOnElement(currentSelection); } } function handleDragEnd(obj) { var currentPos = obj.event.getLocalPosition(game); var input = { x: currentPos.x, y: currentPos.y }; console.log("Clicked at " + input.x + ',' + input.y); if (input.y > game.height * 0.80) { console.log("Clicked on board at " + input.x + ',' + input.y); dragStart = null; dragDelta = 0; return; } if (currentUserActionState === UserActionState.PLACING_BUILDINGS) { var cellCoord = screenCoordToWorldCell(input.x, input.y); //getCellForPlacement(input.x, input.y, currentBuildingForPlacement); var cellX = cellCoord.wCellX; var cellY = cellCoord.wCellY; /* var cellCoord = getCellForPlacement(input.x, input.y, currentBuildingForPlacement); var cellX = cellCoord.cellX; var cellY = cellCoord.cellY; */ var isValidPlacement = checkBuildingPlacement(currentBuildingForPlacement, cellX, cellY); if (!isValidPlacement) { return; } console.log("Placing building ", currentBuildingForPlacement, " at " + cellX + ',' + cellY); handleBuildingPlacement(currentBuildingForPlacement, cellX, cellY); currentUserActionState = UserActionState.NAVIGATING; dragStart = null; dragDelta = 0; } else if (currentUserActionState === UserActionState.SET_ORDER_TARGET) { if (currentSelection && currentSelection.isUnit) { var cellCoord = convertCoordsToCell(input.x, input.y); currentSelection.destinationTarget = { x: cellCoord.cellX, y: cellCoord.cellY }; console.log(currentSelection.name + ' received new destination target: ' + cellCoord.cellX + ',' + cellCoord.cellY); // Call the action handler with the target position if (currentSelection.actions && currentSelection.selectedAction) { console.log(currentSelection.selectedAction + ' received '); var actionInfo = actionRepository.getActionInfo(currentSelection.selectedAction); if (actionInfo && actionInfo.handler) { console.log('Call action handler : ', actionInfo); actionInfo.handler(currentSelection, cellCoord.cellX, cellCoord.cellY); } } if (targetMoveCursor) { console.log('hiding move cursor ...'); targetMoveCursor.visible = false; } } highlightBorder(); currentUserActionState = UserActionState.NAVIGATING; dragStart = null; dragDelta = 0; } else { // Normal click var clickCell = screenCoordToWorldCell(input.x, input.y); var cellX = clickCell.wCellX; var cellY = clickCell.wCellY; console.log("Click at cell " + cellX + ',' + cellY); var deltaToSelection = 99; if (currentSelection && currentSelection.isUnit) { var selCell = getCellForUnit(currentSelection); console.log("currentSelection = " + currentSelection.name + " at " + selCell.cellX + ',' + selCell.cellY); deltaToSelection = Math.sqrt(Math.pow(Math.abs(selCell.cellX - cellX), 2) + Math.pow(Math.abs(selCell.cellY - cellY), 2)); } if (cellX >= 0 && cellX < gameMap.cells.length && cellY >= 0 && cellY < gameMap.cells[cellX].length) { var cell = gameMap.cells[cellX][cellY]; if (!cell.building && !cell.unit && deltaToSelection > 1) { if (dragDelta < tileSize * 0.25) { currentSelection = null; selectionMarker.setOnElement(); selectionMarker.hide(); console.log("Nothing selected at " + cellX + ',' + cellY, " deltaToSelection=" + deltaToSelection, " dragDelta=", dragDelta); updateActionBoard(); } } else if (cell.building) { console.log("Selected building at " + cellX + ',' + cellY); currentSelection = cell.building; selectionMarker.setOnElement(currentSelection); updateActionBoard(); } else if (cell.unit) { console.log("Selected cell with unit at " + cellX + ',' + cellY); console.log("unit at " + cell.unit.x + ',' + cell.unit.y); } } dragStart = null; dragDelta = 0; } } 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) { console.log("handle " + building.name + " Placement at " + 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.cellX = cellX; building.cellY = cellY; building.x = cellX * tileSize; building.y = cellY * tileSize; building.asset.tint = 0xFFFFFF; gameMap.addChild(building); // Call addBuilding for the player who owns the building if (building.playerId === player1.playerId) { player1.addBuilding(building); } else if (building.playerId === player2.playerId) { player2.addBuilding(building); } applyCellOccupation(cellX, cellY); console.log(building.name + ' placed at ' + cellX + ',' + cellY); if (player1.playerId === building.playerId) { player1.updateEnergy(); updateBaseInfo(); } if (building instanceof SpiceRefinery) { spawnUnit('unitHarvester', cellX, cellY, building.playerId); } currentUserActionState = UserActionState.NAVIGATING; currentBuildingForPlacement = null; if (cancelActionBtn) { cancelActionBtn.visible = false; } updateActionBoard(); }; // Screen <-> World Coordinates var screenCoordToWorldCell = function screenCoordToWorldCell(x, y) { var wCellX = Math.floor(x / tileSize) + viewPort.wCellX; var wCellY = Math.floor(y / tileSize) + viewPort.wCellY; return { wCellX: wCellX, wCellY: wCellY }; }; var screenCoordToWorldCoord = function screenCoordToWorldCoord(x, y) { var wX = x + viewPort.wX; var wY = y + viewPort.wY; return { wX: wX, wY: wY }; }; var screenCellToWorldCell = function screenCellToWorldCell(cellX, cellY) { var wCellX = cellX + viewPort.wCellX; var wCellY = cellY + viewPort.wCellY; return { wCellX: wCellX, wCellY: wCellY }; }; var screenCellToWorldCoord = function screenCellToWorldCoord(cellX, cellY) { var wX = cellX * tileSize + viewPort.wX; var wY = cellY * tileSize + viewPort.wY; return { wX: wX, wY: wY }; }; // World <-> Screen Coordinates var worldCoordToScreenCell = function worldCoordToScreenCell(wX, wY) { var cellX = Math.floor(wX / tileSize) - viewPort.wCellX; var cellY = Math.floor(wY / tileSize) - viewPort.wCellY; return { cellX: cellX, cellY: cellY }; }; var worldCoordToScreenCoord = function worldCoordToScreenCoord(wX, wY) { var x = wX - viewPort.wX; var y = wY - viewPort.wY; return { x: x, y: y }; }; var worldCellToScreenCell = function worldCellToScreenCell(wCellX, wCellY) { var cellX = wCellX - viewPort.wCellX; var cellY = wCellY - viewPort.wCellY; return { cellX: cellX, cellY: cellY }; }; var worldCellToScreenCoord = function worldCellToScreenCoord(wCellX, wCellY) { var x = wCellX * tileSize - viewPort.wX; var y = wCellY * tileSize - viewPort.wY; return { x: x, y: y }; }; var getScreenToWorldCell = function getScreenToWorldCell(x, y) { var wCellX = Math.floor(x / tileSize) + viewPort.wX; var wCellY = Math.floor(y / tileSize) + viewPort.wY; return { wCellX: wCellX, wCellY: wCellY }; }; var getScreenToWorldCoord = function getScreenToWorldCoord(x, y) { var wX = x + viewPort.wX * tileSize; var wY = y + viewPort.wY * tileSize; return { wX: wX, wY: wY }; }; var convertCoordsToCell = function convertCoordsToCell(x, y) { return { cellX: Math.floor(x / 100) + gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 3, cellY: Math.floor(y / 100) + gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100) }; }; var getCellForPlacement = function getCellForPlacement(x, y, building) { var cX = Math.floor(x / 100) + gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 4; var cY = Math.floor(y / 100) + gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100) - 1; if (building && building.cellW && building.cellH) { return { cellX: cX + Math.floor(building.cellW / 2), cellY: cY + Math.floor(building.cellH / 2) }; } else { return { cellX: cX, cellY: cY }; } }; var getCellForUnit = function getCellForUnit(unit) { var centerDeltaX = gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100); var centerDeltaY = gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100); var cX = Math.floor(unit.x / 100) + centerDeltaX + unit.cellW / 2 + Math.floor(unit.cellW / 2) - 5; var cY = Math.floor(unit.y / 100) + centerDeltaY + Math.floor(unit.cellH / 2) + unit.cellH / 2 - 7; return { cellX: cX, cellY: cY }; }; var getCoordsForUnit = function getCoordsForCell(cell) { //console.log("getCoordsForUnit :", cell.cellX, ',', cell.cellY); //console.log("currentViewCenter :", gameMap.currentViewCenter.x, ',', gameMap.currentViewCenter.y); var centerDeltaX = -1; var centerDeltaY = -6; var x = (cell.cellX + centerDeltaX) * 100 + 50; var y = (cell.cellY + centerDeltaY) * 100 + 50; /* var centerDeltaX = gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100) - 4; var centerDeltaY = gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100) - 6; var x = (cell.cellX + centerDeltaX) * 100; var y = (cell.cellY + centerDeltaY) * 100; */ //console.log("=> :", x, ',', y); return { x: x, y: y }; }; var getCursorCellForMovement = function getCursorCellForMovement(input, building) { var centerDeltaX = gameMap.currentViewCenter.x - Math.ceil(game.width / 2 / 100); var centerDeltaY = gameMap.currentViewCenter.y - Math.ceil(game.height / 2 / 100); var cX = (Math.floor(input.x / 100) + centerDeltaX + building.cellW / 2 + Math.floor(building.cellW / 2) - 5) * 100; var cY = (Math.floor(input.y / 100) + centerDeltaY + Math.floor(building.cellH / 2) + building.cellH / 2 - 7) * 100; return { cellX: cX, cellY: cY }; }; // Global function to find the closest spice spot to a given position var findClosestSpiceSpot = function findClosestSpiceSpot(x, y) { var closestSpot = null; var minDistance = Number.MAX_VALUE; spiceSpots.forEach(function (spot) { var dx = x - spot.x; var dy = y - spot.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistance) { closestSpot = spot; minDistance = distance; } }); return closestSpot; }; // Global function to handle action board updates var updateActionBoard = function updateActionBoard() { console.log('updateActionBoard...' + (currentSelection ? currentSelection.name : 'No selection')); currentSelectionText.setText(currentSelection ? currentSelection.name : ''); clearIconBorders(); displayBuildableItems(); // Call displayBuildableItems to show items that can be built displayActionItems(); // Call displayActionItems to show action items }; function clearIconBorders() { var iconBorders = game.children.filter(function (child) { return child instanceof IconBorder; }); iconBorders.forEach(function (border) { border.destroy(); }); } function displayBuildableItems() { console.log('updateActionBoard...', currentSelection); var buildableItemIcons = game.children.filter(function (child) { return child instanceof BuildableItemIcon; }); buildableItemIcons.forEach(function (icon) { //console.log('removing...', icon.type); icon.destroy(); }); if (currentSelection && currentSelection.playerId === player1.playerId && currentSelection.buildable && currentSelection.buildable.length) { var iconX = commandPanel.x + 200; // Starting X position for the first icon var iconY = commandPanel.y + 220; // Y position for all icons currentSelection.buildable.forEach(function (itemType) { //console.log('Add build button for ' + itemType); var border = new IconBorder(iconX, iconY); game.addChild(border); var icon = new BuildableItemIcon(itemType, iconX, iconY); game.addChild(icon); iconX += 300; // Increment X position for the next icon }); } } // Global function to display action items var displayActionItems = function displayActionItems() { console.log('displayActionItems...', currentSelection); var actionItemIcons = game.children.filter(function (child) { return child instanceof ActionItemIcon; }); actionItemIcons.forEach(function (icon) { console.log('removing...', icon.action.name); icon.destroy(); }); if (currentSelection && currentSelection.isUnit && currentSelection.actions && currentSelection.actions.length) { var iconX = commandPanel.x + 200; // Starting X position for the first icon var iconY = commandPanel.y + 220; // Y position for all icons currentSelection.actions.forEach(function (actionType) { console.log('Add action button for ', actionType); var actionInfo = actionRepository.getActionInfo(actionType); if (actionInfo) { console.log('ok Action found => display', actionInfo); var border = new IconBorder(iconX, iconY); game.addChild(border); var icon = new ActionItemIcon(actionInfo, iconX, iconY); game.addChild(icon); iconX += 300; // Increment X position for the next icon } else { console.log('Action not found', actionType); } }); } }; // Global function to update mouse coordinates text var updateMouseCoords = function updateMouseCoords(x, y) { /*var cellCoord = convertCoordsToCell(x, y); if (game.mouseCoordsText) { game.mouseCoordsText.setText(Math.floor(x) + ',' + Math.floor(y) + '\r\n' + cellCoord.cellX + ',' + cellCoord.cellY); }*/ /* var wCellCoords = getScreenToWorldCell(x, y); var wCoordCoords = getScreenToWorldCoord(x, y); if (game.mouseCoordsText) { game.mouseCoordsText.setText("S:" + Math.floor(x) + ',' + Math.floor(y) + '\r\n' + Math.floor(x / tileSize) + ',' + Math.floor(y / tileSize) + '\r\nW:' + Math.floor(wCellCoords.wCellX) + ',' + Math.floor(wCellCoords.wCellY) + '\r\n' + Math.floor(wCoordCoords.wX) + ',' + Math.floor(wCoordCoords.wY)); } */ var wCell = screenCoordToWorldCell(x, y); if (game.mouseCoordsText) { game.mouseCoordsText.setText("S:" + Math.floor(x) + ',' + Math.floor(y) + '\r\n' + Math.floor(x / tileSize) + ',' + Math.floor(y / tileSize) + '\r\nW:' + Math.floor(wCell.wCellX) + ',' + Math.floor(wCell.wCellY)); } gameMap.viewCenterText.setText(gameMap.currentViewCenter.x + ', ' + gameMap.currentViewCenter.y + '\r\n' + viewPort.wCellX + ',' + viewPort.wCellY); }; // Global function to update base info text var updateBaseInfo = function updateBaseInfo() { player1SpiceText.setText('| ' + player1.spice.toString()); // Animate the change of the energy value if (previousEnergyLevel !== player1.energy) { var energyDifference = player1.energy - previousEnergyLevel; var duration = 2000; // Duration of the animation in milliseconds var steps = duration / (1000 / 60); // Number of steps based on 60FPS var stepValue = energyDifference / steps; var currentStep = 0; var animateEnergyChange = function animateEnergyChange() { var energyColor = getEnergyColor(previousEnergyLevel); player1EnergyText.setStyle({ fill: energyColor }); if (currentStep < steps) { previousEnergyLevel += stepValue; player1EnergyText.setText(previousEnergyLevel.toFixed(0).toString() + energyOffsetSufix); currentStep++; LK.setTimeout(animateEnergyChange, 1000 / 60); } else { // Ensure the final value is set correctly player1EnergyText.setText(player1.energy.toString() + energyOffsetSufix); previousEnergyLevel = player1.energy; // Update the previous energy level } }; animateEnergyChange(); } else { player1EnergyText.setText(player1.energy.toString() + energyOffsetSufix); } }; var startFpsCounter = function startFpsCounter() { var fpsInterval = LK.setInterval(function () { // Set the FPS value to the tick counter fps = tickCounter; // Reset the tick counter tickCounter = 0; // Update the FPS text on the screen fpsText.setText('FPS: ' + fps); }, 1000); // 1000 milliseconds = 1 second }; function initGame() { // Create players player1 = new Player(1, 0x5e86ff); 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 mouse coordinates if (!game.mouseCoordsText) { game.mouseCoordsText = new Text2('0,0\r\n0,0', { size: 50, fill: '#ffffff', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); game.mouseCoordsText.anchor.set(0, 0); LK.gui.topLeft.addChild(game.mouseCoordsText); } // 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.25); LK.gui.topRight.addChild(player1SpiceText); // Create a Text2 object to display player1's energy level player1EnergyText = new Text2(player1.energy.toString() + energyOffsetSufix, { size: 50, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); player1EnergyText.anchor.set(1.0, 0.25); LK.gui.topRight.addChild(player1EnergyText); // Create a Text2 object to display the FPS in the bottom right corner fpsText = new Text2('', { size: 50, fill: '#000000', font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); fpsText.anchor.set(1.5, 1.0); LK.gui.bottomRight.addChild(fpsText); gameIsRunning = true; startFpsCounter(); } // Game tick LK.on('tick', function () { // Render the map and update unit movement each tick if (gameIsRunning) { gameMap.render(); /*if (currentSelection && currentSelection.isUnit) { currentSelection.updateMovement(1 / 60); // Assuming tick operates at 60FPS }*/ //game.addChild(newHarvester.asset); // TEMP DEBUG var allUnits = player1.units.concat(player2.units); allUnits.forEach(function (unit) { //console.log("render unit " + unit.name, unit.x, unit.y); // Ensure the unit is added to the game container, not 'self' which is not defined in this context //console.log(" unit parent ", unit.asset.parent.parent.parent); /*if (!unit.asset.parent.parent.parent) { console.log("First add unit !", unit.asset.parent.parent.parent); game.addChild(unit.asset); } else { }*/ //unit.updateMovement(1 / 60); // Assuming tick operates at 60FPS if (unit.update) { //unit.update(); } game.addChild(unit); /*var screenX = (unit.cellX - 2 - gameMap.currentViewCenter.x + viewSize) * unit.asset.width; var screenY = (unit.cellY - 3 - gameMap.currentViewCenter.y + viewSize) * unit.asset.height; unit.x = screenX; unit.y = screenY;*/ }); } tickCounter++; }); // Start the game with Player 1 construction yard preselected LK.setTimeout(function () { initGame(); currentSelection = gameMap.cells[rockIlot1Center.x][rockIlot1Center.y].building; selectionMarker.setOnElement(currentSelection); updateActionBoard(); }, 100);
===================================================================
--- original.js
+++ change.js
@@ -772,8 +772,21 @@
currentUserActionState = UserActionState.GIVING_ORDERS;
updateActionBoard();
});
self.onArrivedCallback = null;
+ self.handleDrag = function () {
+ var newCoord = worldCellToScreenCoord(self.cellX, self.cellY);
+ self.x = newCoord.x;
+ self.y = newCoord.y;
+ var newCoord = worldCoordToScreenCoord(self.cellX, self.cellY);
+ self.x = newCoord.x;
+ self.y = newCoord.y;
+ self.cellX = Math.floor(self.x / tileSize);
+ self.cellY = Math.floor(self.y / tileSize);
+ /*var newCell= worldCellToScreenCell(self.cellX, self.cellY);
+ self.cellX = newCell.cellX;
+ self.cellY = newCell.cellY;*/
+ };
return self;
});
var UnitHarvester = Unit.expand(function (x, y, playerId) {
var self = Unit.call(this, x, y, playerId, 'unitHarvester');
@@ -1306,8 +1319,9 @@
console.log("vp before : " + viewPort.wX + ',' + viewPort.wY);
gameMap.handleDrag(inputPosition);
allUnits.forEach(function (unit) {
console.log("unit coords : " + unit.x + ',' + unit.y);
+ unit.handleDrag(inputPosition);
/*
console.log("unit cells : " + unit.cellX + ',' + unit.cellY);
console.log("delta coords : " + deltaX + ',' + deltaY);
console.log("vp after : " + (viewPort.wX) + ',' + (viewPort.wY));
@@ -1316,9 +1330,9 @@
//var newCoord = worldCoordToScreenCoord(unit.x, unit.y);
//console.log("newCoord : " + newCoord.x + ',' + newCoord.y);
/*unit.x = newCoord.x;
unit.y = newCoord.y;
- unit.cellX = Math.floor(unit.x / tileSize);
+ unit.cellX = Math.floor(unit.x / tileSize);
unit.cellY = Math.floor(unit.y / tileSize);
*/
//unit.cellX = Math.max(0, Math.min(mapXSize - viewPort.cellW, unit.cellX + inputPosition.x));
//unit.cellY = Math.max(0, Math.min(mapYSize - viewPort.cellH, unit.cellY + inputPosition.y));
@@ -1728,10 +1742,10 @@
/*
var wCellCoords = getScreenToWorldCell(x, y);
var wCoordCoords = getScreenToWorldCoord(x, y);
if (game.mouseCoordsText) {
- game.mouseCoordsText.setText("S:" + Math.floor(x) + ',' + Math.floor(y)
- + '\r\n' + Math.floor(x / tileSize) + ',' + Math.floor(y / tileSize) + '\r\nW:' + Math.floor(wCellCoords.wCellX) + ',' + Math.floor(wCellCoords.wCellY) + '\r\n' + Math.floor(wCoordCoords.wX) + ',' + Math.floor(wCoordCoords.wY));
+ game.mouseCoordsText.setText("S:" + Math.floor(x) + ',' + Math.floor(y)
+ + '\r\n' + Math.floor(x / tileSize) + ',' + Math.floor(y / tileSize) + '\r\nW:' + Math.floor(wCellCoords.wCellX) + ',' + Math.floor(wCellCoords.wCellY) + '\r\n' + Math.floor(wCoordCoords.wX) + ',' + Math.floor(wCoordCoords.wY));
}
*/
var wCell = screenCoordToWorldCell(x, y);
if (game.mouseCoordsText) {
@@ -1850,11 +1864,11 @@
/*if (!unit.asset.parent.parent.parent) {
console.log("First add unit !", unit.asset.parent.parent.parent);
game.addChild(unit.asset);
} else { }*/
- unit.updateMovement(1 / 60); // Assuming tick operates at 60FPS
+ //unit.updateMovement(1 / 60); // Assuming tick operates at 60FPS
if (unit.update) {
- unit.update();
+ //unit.update();
}
game.addChild(unit);
/*var screenX = (unit.cellX - 2 - gameMap.currentViewCenter.x + viewSize) * unit.asset.width;
var screenY = (unit.cellY - 3 - gameMap.currentViewCenter.y + viewSize) * unit.asset.height;
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