UNPKG

jsge

Version:

Javascript Game Engine

873 lines (748 loc) 29.6 kB
import { GameStage, CONST } from "../../src/index.js"; import { isPointInsidePolygon, countDistance, randomFromArray, isPointRectIntersect } from "../../src/utils.js"; import { GAME_UNITS, GAME_EVENTS, GOLD_MINE_GOLD_AMOUNT, TREE_STUB_INDEX, TREE_FULL_HEALTH, PEASANT_ACTIONS } from "./const.js"; import { UnitPeasant, UnitBuilding } from "./units.js"; export class Strategy extends GameStage { #SLOW_SCROLL_POINT = 200; #QUICK_SCROLL_POINT = 50; #imageConverter = document.createElement("canvas"); #playerGold = 0; #playerGoldCounter; #playerWood = 0; #playerWoodCounter; #playerPeopleLimit = 5; // lets say town center increase limit to 5 and house to 3 #playerPeopleLimitCounter; #playerUnits = []; #playerBuildings = []; #neutralBuildings = []; #enemyUnits = []; #enemyBuildings = []; #treesLayer; #treesCutHealth = new Map(); #selectedItemText; #buildItems; #buildTemplate; #isBuildPlaceClear; #buildTemplateOverlap; #mouseX; #mouseY; #unitsCount = 0; #addUnitPosX = 0; register() { this.iLoader.addTileMap("s_map", "./strategy/strategy_map.tmj"); this.iLoader.addImage(GAME_UNITS.GOLD_MINE.name, "./strategy/images/MiniWorldSprites/Buildings/Wood/Resources.png"); this.iLoader.addImage(GAME_UNITS.TOWN_CENTER.name, "./strategy/images/MiniWorldSprites/Buildings/Red/RedKeep.png"); this.iLoader.addImage(GAME_UNITS.HOUSE.name, "./strategy/images/MiniWorldSprites/Buildings/Red/RedHouses.png"); this.iLoader.addImage(GAME_UNITS.BARRACKS.name, "./strategy/images/MiniWorldSprites/Buildings/Red/RedBarracks.png"); this.iLoader.addImage(GAME_UNITS.PEASANT.name, "./strategy/images/MiniWorldSprites/Characters/Workers/RedWorker/FarmerRed.png"); this.iLoader.addAudio("peasantWhat1", "./strategy/audio/peasantwhat1.mp3"); this.iLoader.addAudio("peasantWhat2", "./strategy/audio/peasantwhat2.mp3"); this.iLoader.addAudio("peasantWhat3", "./strategy/audio/peasantwhat3.mp3"); this.iLoader.addAudio("needMoreGold", "./strategy/audio/gruntnogold1.mp3"); this.iLoader.addAudio("needFood", "./strategy/audio/upkeepring.mp3") this.iLoader.addAudio("chopTree", "./strategy/audio/axemediumchopwood2.mp3"); this.iLoader.addAudio("cantBuildHere" , "./strategy/audio//peasantcannotbuildthere1.mp3"); this.timer = null; this.eventsAggregator = new EventTarget(); document.body.style.margin = 0; } init() { const [w, h] = this.stageData.canvasDimensions; // x, y, width, height, imageKey const ground = this.draw.tiledLayer("ground", "s_map"), water = this.draw.tiledLayer("water", "s_map", true), cliff = this.draw.tiledLayer("cliff", "s_map", true), bridge = this.draw.tiledLayer("bridge", "s_map"); this.#treesLayer = this.draw.tiledLayer("trees", "s_map", true); this.goldMine1 = this.draw.image(180, 76, 16, 16, GAME_UNITS.GOLD_MINE.name, 13); this.goldMine1.goldAmount = GOLD_MINE_GOLD_AMOUNT; this.#neutralBuildings.push(this.goldMine1); // this.shadowRect = this.draw.rect(0, 0, w, h, "rgba(0, 0, 0, 0.5)"); // this.shadowRect.blendFunc = [WebGLRenderingContext.ONE, WebGLRenderingContext.DST_COLOR]; // this.shadowRect.turnOffOffset(); // units const townCenter = new UnitBuilding(100, 120, 32, 32, GAME_UNITS.TOWN_CENTER.name, 0, this.draw, this.eventsAggregator, 1); this.#playerBuildings.push(townCenter); const peasant1 = new UnitPeasant(132, 105, 16, 16, townCenter, this.draw, this.eventsAggregator), peasant2 = new UnitPeasant(132, 121, 16, 16, townCenter, this.draw, this.eventsAggregator), peasant3 = new UnitPeasant(132, 137, 16, 16, townCenter, this.draw, this.eventsAggregator); this.addRenderObject(townCenter); this.addRenderObject(peasant1); this.addRenderObject(peasant2); this.addRenderObject(peasant3); this.#playerUnits.push(peasant1); this.#playerUnits.push(peasant2); this.#playerUnits.push(peasant3); this.chopTreeSound = this.iLoader.getAudio("chopTree"); this.peasantWhatAudioArr = [this.iLoader.getAudio("peasantWhat1"), this.iLoader.getAudio("peasantWhat2"), this.iLoader.getAudio("peasantWhat3") ]; // this.personSightView = this.draw.conus(55, 250, 200, "rgba(0,0,0,1)", Math.PI/3); // this.personSightView.rotation = -Math.PI/6; // this.personSightView._isMask = true; this.navItemBack = this.draw.text(w - 200, 60, "Main menu", "18px sans-serif", "black"); this.navItemBack.turnOffOffset(); this.registerListeners(); } start() { this.stageData.centerCameraPosition(100, 300); this.registerListeners(); this.#createUserInterface(); setTimeout(() => { const [w, h] = this.stageData.canvasDimensions; },100); this.#unitsCount = this.#playerUnits.length; console.log("strategy started"); } stop() { this.unregisterListeners(); document.getElementById("sidebar").remove(); } registerListeners() { this.#registerMouseListeners(); this.#registerKeyboardListeners(); this.#registerSystemEventsListeners(); } unregisterListeners() { this.#unregisterMouseListeners(); this.#unregisterKeyboardListeners(); this.#unregisterSystemEventsListeners(); } #registerKeyboardListeners() { document.addEventListener("keydown", this.#pressKeyAction); document.addEventListener("keyup", this.#removeKeyAction); } #unregisterKeyboardListeners() { document.removeEventListener("keydown", this.#pressKeyAction); document.removeEventListener("keyup", this.#removeKeyAction); } #registerMouseListeners() { document.addEventListener("mousemove", this.#mouseMoveAction); document.addEventListener("click", this.#mouseClickAction); } #unregisterMouseListeners() { document.removeEventListener("mousemove", this.#mouseMoveAction); document.removeEventListener("click", this.#mouseClickAction); } #createUserInterface = () => { const windowWidth = document.body.offsetWidth, sidebar = document.createElement("div"); sidebar.id = "sidebar"; sidebar.style.width = windowWidth + "px"; sidebar.style.height = "16px"; sidebar.style.padding = "6px"; sidebar.style.backgroundColor = "#ccc"; sidebar.style.position = "fixed"; sidebar.style.top = 0 + "px"; sidebar.style.left = 0 + "px"; sidebar.style.display = "flex"; document.body.appendChild(sidebar); const resourcesInfo = document.createElement("div"); resourcesInfo.style.display = "flex"; sidebar.appendChild(resourcesInfo); const playerGoldCounterText = document.createElement("div"); playerGoldCounterText.innerText = "Gold: "; resourcesInfo.appendChild(playerGoldCounterText); this.#playerGoldCounter = document.createElement("div"); this.#playerGoldCounter.innerText = this.#playerGold.toString(); this.#playerGoldCounter.style.marginRight = "6px"; resourcesInfo.appendChild(this.#playerGoldCounter); const playerWoodCounterText = document.createElement("div"); playerWoodCounterText.innerText = "Wood: "; resourcesInfo.appendChild(playerWoodCounterText); this.#playerWoodCounter = document.createElement("div"); this.#playerWoodCounter.innerText = this.#playerWood.toString(); this.#playerWoodCounter.style.marginRight = "6px"; resourcesInfo.appendChild(this.#playerWoodCounter); const playerPeopleCounterText = document.createElement("div"); playerPeopleCounterText.innerText = "People limits: "; resourcesInfo.appendChild(playerPeopleCounterText); this.#playerPeopleLimitCounter = document.createElement("div"); this.#playerPeopleLimitCounter.innerText = this.#playerUnits.length + "/" + this.#playerPeopleLimit.toString(); resourcesInfo.appendChild(this.#playerPeopleLimitCounter); const buildMenuContainer = document.createElement("div"); buildMenuContainer.style.display = "flex"; buildMenuContainer.style.marginLeft = "30px"; sidebar.appendChild(buildMenuContainer); this.#selectedItemText = document.createElement("div"); this.#selectedItemText.innerText = "Nothing is selected"; buildMenuContainer.appendChild(this.#selectedItemText); this.#buildItems = document.createElement("div"); buildMenuContainer.appendChild(this.#buildItems); } #pressKeyAction = (event) => { const code = event.code; console.log("pressed: ", code); if (code === "Space") { const townCenter = this.#playerBuildings.find((building) => building.key === GAME_UNITS.TOWN_CENTER.name); const newPeasant = new UnitPeasant(0, 0, 16, 16, townCenter, this.draw, this.eventsAggregator); const newPeasant2 = new UnitPeasant(0, 0, 16, 16, townCenter, this.draw, this.eventsAggregator); newPeasant.x = townCenter.x - this.#addUnitPosX; newPeasant.y = townCenter.y; newPeasant2.x = townCenter.x - this.#addUnitPosX; newPeasant2.y = townCenter.y - 16; this.addRenderObject(newPeasant); this.addRenderObject(newPeasant2); this.#playerUnits.push(newPeasant); this.#playerUnits.push(newPeasant2); this.#unitsCount++; this.#unitsCount++; newPeasant.activateMoveToTargetPoint(1500, 1500); newPeasant2.activateMoveToTargetPoint(1500, 1500); console.log("units: ", this.#unitsCount); this.#addUnitPosX -= 20; } }; #removeKeyAction = (event) => { const code = event.code; if (code === "Space") { this.#addUnitPosX = 0; } }; #mouseMoveAction = (e) => { const [xOffset, yOffset] = this.stageData.worldOffset, x = e.offsetX, y = e.offsetY, cursorPosX = x + xOffset, cursorPosY = y + yOffset, [ viewWidth, viewHeight ] = this.stageData.canvasDimensions, xShiftRight = viewWidth - x, yShiftBottom = viewHeight - y, xShift = viewWidth/2 + xOffset, yShift = viewHeight/2 + yOffset; let newPosX = xShift, newPosY = yShift; if (x < this.#QUICK_SCROLL_POINT) { //console.log("quick scroll left"); newPosX = xShift-20; } else if (x < this.#SLOW_SCROLL_POINT) { //console.log("slow scroll left"); newPosX = xShift-5; } if (xShiftRight < this.#QUICK_SCROLL_POINT) { //console.log("quick scroll right"); newPosX = xShift+20; } else if (xShiftRight < this.#SLOW_SCROLL_POINT) { //console.log("slow scroll right"); newPosX = xShift+20; } if (y < this.#QUICK_SCROLL_POINT) { //console.log("quick scroll up"); newPosY = yShift-20; } else if (y < this.#SLOW_SCROLL_POINT) { //console.log("slow scroll up"); newPosY = yShift-5; } if (yShiftBottom < this.#QUICK_SCROLL_POINT) { //console.log("quick scroll down"); newPosY = yShift+20; } else if (yShiftBottom < this.#SLOW_SCROLL_POINT) { //console.log("slow scroll down"); newPosY = yShift+5; } this.stageData.centerCameraPosition(newPosX, newPosY); this.#mouseX = cursorPosX; this.#mouseY = cursorPosY; if (this.#buildTemplate) { this.#buildTemplate.x = cursorPosX; this.#buildTemplate.y = cursorPosY; this.#buildTemplateOverlap.x = cursorPosX - this.#buildTemplateOverlap.width/2; this.#buildTemplateOverlap.y = cursorPosY - this.#buildTemplateOverlap.height/2; if (this.isBoundariesCollision(cursorPosX, cursorPosY, this.#buildTemplateOverlap) || this.isObjectsCollision(cursorPosX, cursorPosY, this.#buildTemplateOverlap, this.#playerBuildings) || this.isObjectsCollision(cursorPosX, cursorPosY, this.#buildTemplateOverlap, this.#neutralBuildings)) { this.#buildTemplateOverlap.bgColor = "rgba(224, 12, 21, 0.6)"; this.#isBuildPlaceClear = false; } else { this.#buildTemplateOverlap.bgColor = "rgba(0, 0, 0, 0.3"; this.#isBuildPlaceClear = true; } } const isNav1Traversed = isPointRectIntersect(e.offsetX, e.offsetY, this.navItemBack.boundariesBox); if (isNav1Traversed) { this.navItemBack.strokeStyle = "rgba(0, 0, 0, 0.3)"; this.canvasHtmlElement.style.cursor = "pointer"; } else if (this.navItemBack.strokeStyle) { this.navItemBack.strokeStyle = undefined; this.canvasHtmlElement.style.cursor = "default"; } else { this.canvasHtmlElement.style.cursor = "default"; } }; #mouseClickAction = (e) => { const target = e.target; if (target instanceof Image) { this.#processImageClick(e); } else if (this.#buildTemplate) { this.#processNewBuild(this.#buildTemplate.key); } else { this.#processMapClick(e); } const isNav1Click = isPointRectIntersect(e.offsetX, e.offsetY, this.navItemBack.boundariesBox); if (isNav1Click) { this.iSystem.stopGameStage("strategy_game"); this.canvasHtmlElement.style.cursor = "default"; this.iSystem.startGameStage("start"); } } #processNewBuild = (key) => { const cantBuildAudio = this.iLoader.getAudio("cantBuildHere"); if (this.#isBuildPlaceClear) { this.#playerUnits.forEach((unit) => { if (unit.isSelected) { unit.activateStartBuilding(this.#buildTemplateOverlap.x, this.#buildTemplateOverlap.y, key); if (unit.isSelected) { unit.isSelected = false; } // cleanup build menu this.#selectedItemText.innerText = ""; while (this.#buildItems.lastChild) { this.#buildItems.removeChild(this.#buildItems.lastChild); } // remove build helpers this.#buildTemplate.destroy(); this.#buildTemplateOverlap.destroy(); this.#buildTemplate = null; this.#buildTemplateOverlap = null; } }); } else { cantBuildAudio.play(); } } #processImageClick = (e) => { const target = e.target, type = target.id; switch (type) { case GAME_UNITS.PEASANT.name: this.#orderToBuildUnit(GAME_UNITS.PEASANT.name); break; case GAME_UNITS.HOUSE.name: this.#orderToBuildBuilding(GAME_UNITS.HOUSE.name); break; case GAME_UNITS.BARRACKS.name: this.#orderToBuildBuilding(GAME_UNITS.BARRACKS.name); break; } } #orderToBuildUnit = (type) => { console.log("order build ", type); const costWood = GAME_UNITS[type].cost.w, costGold = GAME_UNITS[type].cost.g; if (!this.#isEnoughGold(costGold)) { console.log("not enough gold"); this.iLoader.getAudio("needMoreGold").play(); } else if (!this.#isEnoughWood(costWood)) { console.log("not enough wood"); } else if (!this.#isEnoughHouses()) { this.iLoader.getAudio("needFood").play(); console.log("not enough houses"); } else { const townCenter = this.#playerBuildings.find((building) => building.key === GAME_UNITS.TOWN_CENTER.name); if (!townCenter.isBuildingUnit) { this.#playerGold -= costGold; this.#playerWood -= costWood; townCenter.buildUnit(type); } else { console.log("already building"); } } } #orderToBuildBuilding = (type) => { console.log("order build ", type); const costWood = GAME_UNITS[type].cost.w, costGold = GAME_UNITS[type].cost.g; if (!this.#isEnoughGold(costGold)) { console.log("not enough gold"); this.iLoader.getAudio("needMoreGold").play(); } else if (!this.#isEnoughWood(costWood)) { console.log("not enough wood"); } else { this.#playerGold -= costGold; this.#playerWood -= costWood; this.#buildTemplate = this.draw.image(this.#mouseX, this.#mouseY, 16, 16, type, 9); this.#buildTemplateOverlap = this.draw.rect(this.#mouseX - 8, this.#mouseY - 8, 16, 16, "rgba(0, 0, 0, 0.3"); this.#isBuildPlaceClear = false; } } #isEnoughGold(costGold) { const gold = this.#playerGold; return costGold <= gold; } #isEnoughWood(costWood) { const wood = this.#playerWood; return costWood <= wood; } #isEnoughHouses() { const units = this.#playerUnits.length, maxUnits = this.#playerPeopleLimit; console.log("u: ", units); console.log("l: ", maxUnits); return maxUnits > units; } #processMapClick = (e) => { let selectPlayerUnit = null, isTreeSelected = false, selectedNeutralBuilding = null, [ offsetX, offsetY ] = this.stageData.worldOffset, clickXWithOffset = e.offsetX + offsetX, clickYWithOffset = e.offsetY + offsetY; this.#playerUnits.forEach((unit) => { if (isPointInsidePolygon(clickXWithOffset - unit.x, clickYWithOffset - unit.y, unit.boundaries)) { this.#playerUnits.forEach((unit) => { console.log(unit.isSelected); if (unit.isSelected) { console.log("deselect"); unit.isSelected = false; } }); this.#playerBuildings.forEach((unit) => { if (unit.isSelected) { unit.isSelected = false; } }); selectPlayerUnit = unit; selectPlayerUnit.isSelected = true; this.#selectedItemText.innerText = "Peasant: "; while (this.#buildItems.lastChild) { this.#buildItems.removeChild(this.#buildItems.lastChild); } const peasantFrameHouse = this.iLoader.getImage(GAME_UNITS.HOUSE.name);//this.draw.image(startX, startY, 16, 16, "houses", randomFromArray([9, 10, 11])); const helper = this.#imageConverter.getContext("2d"); this.#imageConverter.width = 16; this.#imageConverter.height = 16; helper.clearRect(0, 0, window.innerWidth, window.innerHeight); helper.drawImage(peasantFrameHouse, 16, 48, 16, 16, 0, 0, 16, 16); const imageDataHouse = this.#imageConverter.toDataURL(); const houseImage = new Image(16, 16); houseImage.src = imageDataHouse; houseImage.id = GAME_UNITS.HOUSE.name; const peasantFrameBarracks = this.iLoader.getImage(GAME_UNITS.BARRACKS.name);//this.draw.image(startX + 18, startY, 16, 16, "barracks", 1); helper.clearRect(0, 0, window.innerWidth, window.innerHeight); helper.drawImage(peasantFrameBarracks, 16, 0, 16, 16, 0, 0, 16, 16); const imageDataBarracks = this.#imageConverter.toDataURL(); const barracksImage = new Image(16, 16); barracksImage.src = imageDataBarracks; barracksImage.id = GAME_UNITS.BARRACKS.name; this.#buildItems.appendChild(houseImage); this.#buildItems.appendChild(barracksImage); //remove current orders const activeAnimation = unit.activeAnimation; if (activeAnimation) { unit.stopRepeatedAnimation(activeAnimation); } unit.activateIdle(); randomFromArray(this.peasantWhatAudioArr).play(); } }); this.#playerBuildings.forEach((building) => { if (isPointInsidePolygon(clickXWithOffset - building.x, clickYWithOffset - building.y, building.boundaries)) { this.#playerUnits.forEach((unit) => { if (unit.isSelected) { unit.isSelected = false; } }); this.#playerBuildings.forEach((unit) => { if (unit.isSelected) { unit.isSelected = false; } }); selectPlayerUnit = building; selectPlayerUnit.isSelected = true; if (building.key === GAME_UNITS.TOWN_CENTER.name) { this.#selectedItemText.innerText = "TownCenter: "; while (this.#buildItems.lastChild) { this.#buildItems.removeChild(this.#buildItems.lastChild); } const peasantImage = this.iLoader.getImage(GAME_UNITS.PEASANT.name); const helper = this.#imageConverter.getContext("2d"); this.#imageConverter.width = 16; this.#imageConverter.height = 16; helper.clearRect(0, 0, window.innerWidth, window.innerHeight); helper.drawImage(peasantImage, 0, 0, 16, 16, 0, 0, 16, 16); const peasantData = this.#imageConverter.toDataURL(); const peasantImageHTML = new Image(16, 16); peasantImageHTML.src = peasantData; peasantImageHTML.id = GAME_UNITS.PEASANT.name; this.#buildItems.appendChild(peasantImageHTML); } } }); this.#neutralBuildings.forEach((unit) => { if (isPointInsidePolygon(clickXWithOffset - unit.x, clickYWithOffset - unit.y, unit.boundaries)) { console.log("clicked gold mine: ", unit); console.log("gold amount: ", unit.goldAmount) selectedNeutralBuilding = unit; } }); const xCell = Math.floor(clickXWithOffset / this.#treesLayer.tilemap.tilewidth), yCell = Math.floor(clickYWithOffset / this.#treesLayer.tilemap.tileheight), clickedCellIndex = this.#treesLayer.layerData.height * yCell + xCell, clickedCellTile = this.#treesLayer.layerData.data[clickedCellIndex]; if (clickedCellTile !== 0 && clickedCellTile !== TREE_STUB_INDEX) { console.log(clickedCellIndex); console.log("tree cell clicked"); isTreeSelected = true; } // if no new units selected, move selected units to click point if (selectPlayerUnit) { console.log("selected unit"); } else { this.#playerUnits.forEach((unit) => { if (unit.isSelected) { if (selectedNeutralBuilding) { console.log("do something with building: ", selectedNeutralBuilding); if (selectedNeutralBuilding.key === GAME_UNITS.GOLD_MINE.name && unit instanceof UnitPeasant) { unit.activateGrabGold(selectedNeutralBuilding); } } else if (isTreeSelected) { console.log("go, and cut tree"); let tree = this.#treesCutHealth.get(clickedCellIndex); if (!tree) { tree = new Tree(clickXWithOffset, clickYWithOffset, TREE_FULL_HEALTH, clickedCellIndex); this.#treesCutHealth.set(clickedCellIndex, tree); } unit.activateDragTree(tree); } else { unit.activateMoveToTargetPoint(clickXWithOffset, clickYWithOffset); } } }); } } #clickedBuildPeasant = (e) => { console.log("clicked build peasant"); console.log(e); } #render = () => { this.#playerUnits.forEach((unit, index) => { if (unit instanceof UnitPeasant) { const action = unit.activeAction; switch (action) { case PEASANT_ACTIONS.MOVE: unit.stepMove(); break; case PEASANT_ACTIONS.DRAG_GOLD: unit.grabGold(); break; case PEASANT_ACTIONS.DRAG_WOOD: unit.dragWood(); break; case PEASANT_ACTIONS.CHOP_WOOD: this.chopTreeSound.play(); unit.chopTree(); break; case PEASANT_ACTIONS.BUILD: if (countDistance(unit, {x:unit.targetPoint[0], y: unit.targetPoint[1]}) < 5) { console.log('start building here'); // to avoid duplicate call, check isSelected prop // remove peasant unit.stopRepeatedAnimation(unit.activeAnimation); unit.destroy(); // remove from array this.#playerUnits.splice(index, 1); const type = unit.buildingType; const [x, y] = unit.targetPoint; const newBuilding = new UnitBuilding(x, y, 16, 16, type, 0, this.draw, this.eventsAggregator); this.#playerBuildings.push(newBuilding); this.addRenderObject(newBuilding); } else { unit.stepMove(); } break; case PEASANT_ACTIONS.IDLE: break; } } }); } #registerSystemEventsListeners() { this.iSystem.addEventListener(CONST.EVENTS.SYSTEM.RENDER.START, this.#render); this.eventsAggregator.addEventListener(GAME_EVENTS.GOLD_MINED, this.#goldMined); this.eventsAggregator.addEventListener(GAME_EVENTS.WOOD_MINED, this.#woodMined); this.eventsAggregator.addEventListener(GAME_EVENTS.GOLD_MINE_EMPTY, this.#goldMineEmpty); this.eventsAggregator.addEventListener(GAME_EVENTS.TREE_EMPTY, this.#treeEmpty); this.eventsAggregator.addEventListener(GAME_EVENTS.REQUEST_FOR_CLOSEST_TREE, this.#requestForClosestTree); this.eventsAggregator.addEventListener(GAME_EVENTS.PEASANT_BUILT, this.#peasantBuilt); this.eventsAggregator.addEventListener(GAME_EVENTS.HOUSE_BUILT, this.#houseBuilt); } #unregisterSystemEventsListeners() { this.iSystem.removeEventListener(CONST.EVENTS.SYSTEM.RENDER.START, this.#render); this.eventsAggregator.removeEventListener(GAME_EVENTS.GOLD_MINED, this.#goldMined); this.eventsAggregator.removeEventListener(GAME_EVENTS.WOOD_MINED, this.#woodMined); this.eventsAggregator.removeEventListener(GAME_EVENTS.GOLD_MINE_EMPTY, this.#goldMineEmpty); this.eventsAggregator.removeEventListener(GAME_EVENTS.TREE_EMPTY, this.#treeEmpty); this.eventsAggregator.removeEventListener(GAME_EVENTS.REQUEST_FOR_CLOSEST_TREE, this.#requestForClosestTree); this.eventsAggregator.removeEventListener(GAME_EVENTS.PEASANT_BUILT, this.#peasantBuilt); this.eventsAggregator.removeEventListener(GAME_EVENTS.HOUSE_BUILT, this.#houseBuilt); } #goldMined = (e) => { const amount = e.detail; this.#playerGold += amount; this.#playerGoldCounter.innerText = this.#playerGold; } #woodMined = (e) => { const amount = e.detail; this.#playerWood += amount; this.#playerWoodCounter.innerText = this.#playerWood; } #goldMineEmpty = (e) => { this.goldMine1.imageIndex = 10; } #requestForClosestTree = (e) => { const peasant = e.detail.peasant, oldTreeIndex = e.detail.tree.index, tressLayer = this.#treesLayer.layerData.data, layerWidth = this.#treesLayer.layerData.width, layerHeight = this.#treesLayer.layerData.height, layerSize = layerWidth * layerHeight, nearestCellsIndexes = [], tilewidth = this.#treesLayer.tilemap.tilewidth, tileheight = this.#treesLayer.tilemap.tileheight;// -5; +5 on width and height for (let i = -5; i <= 5; i++) { let startItemIndex = oldTreeIndex + (i * this.#treesLayer.layerData.height); // *100 const rowIndex = Math.floor(startItemIndex/this.#treesLayer.layerData.height); if (startItemIndex >= 0 && startItemIndex <= layerSize) { // remove top and bottom indexes overflow for (let k = -5; k <= 5; k++) { const itemIndex = startItemIndex + k, colIndex = itemIndex - rowIndex * this.#treesLayer.layerData.height; if (itemIndex >= 0 && colIndex >= 0 && colIndex <= layerWidth) { // remove left and right indexes overflow nearestCellsIndexes.push([rowIndex, colIndex, itemIndex]); } } } } let closestTree, closestDistance; nearestCellsIndexes.forEach((indexes) => { const rowIndex = indexes[0], colIndex = indexes[1], itemIndex = indexes[2], cellItem = tressLayer[itemIndex]; if (cellItem !== 0 && cellItem !== TREE_STUB_INDEX) { const cellItemPosX = colIndex * tilewidth + tilewidth / 2, cellItemPosY = rowIndex * tileheight + tileheight / 2, distance = countDistance({x: peasant.x, y: peasant.y}, {x: cellItemPosX, y: cellItemPosY}); //console.log("item x: ", cellItemPosX); //console.log("item y: ", cellItemPosY); //console.log("distance: ", distance); //console.log("closest distance: ", closestDistance); if (!closestDistance || closestDistance > distance) { closestTree = this.#treesCutHealth.get(itemIndex); if (!closestTree) { closestTree = new Tree(cellItemPosX, cellItemPosY, TREE_FULL_HEALTH, itemIndex); this.#treesCutHealth.set(itemIndex, closestTree); } //console.log("set closest distance: ", distance); //console.log("tree: ", closestTree); closestDistance = distance; } } }); //console.log("old tree is ", oldTreeIndex); //console.log("closest tree is ", closestTree.index); if (closestDistance) { this.#treesCutHealth.set(closestTree.index, closestTree); const playerUnit = this.#playerUnits.find((unit) => unit.id === peasant.id); playerUnit.activateDragTree(closestTree); } } recursiveSearchForClosestTree = () => { } #treeEmpty = (e) => { const treeIndex = e.detail.index; this.#treesCutHealth.delete(treeIndex); this.#treesLayer.layerData.data[treeIndex] = TREE_STUB_INDEX; } #peasantBuilt = (e) => { const townCenter = e.detail, newPeasant = new UnitPeasant(0, 0, 16, 16, townCenter, this.draw, this.eventsAggregator); let posX = 20, posY = 20; while (this.isObjectsCollision(townCenter.x + posX, townCenter.y + posY, newPeasant, this.#playerUnits)) { posX -= 18; console.log("collision shift left"); } //console.log("no collision adding unit"); newPeasant.x = townCenter.x + posX; newPeasant.y = townCenter.y + posY; this.addRenderObject(newPeasant); this.#playerUnits.push(newPeasant); this.#playerPeopleLimitCounter.innerText = this.#playerUnits.length + "/" + this.#playerPeopleLimit.toString(); } #houseBuilt = (e) => { const house = e.detail, newPeasant = new UnitPeasant(0, 0, 16, 16, house, this.draw, this.eventsAggregator); let posX = 20, posY = 20; while (this.isObjectsCollision(house.x + posX, house.y + posY, newPeasant, this.#playerUnits)) { posX -= 18; console.log("collision shift left"); } newPeasant.x = house.x + posX; newPeasant.y = house.y + posY; this.addRenderObject(newPeasant); this.#playerUnits.push(newPeasant); house.imageIndex = 3; this.#playerPeopleLimit += 3; this.#playerPeopleLimitCounter.innerText = this.#playerUnits.length + "/" + this.#playerPeopleLimit.toString(); } move(dir) { let newX = this.tank.x, newY = this.tank.y; switch(dir) { case "left": newX = newX - 1; break; case "right": newX = newX + 1; break; case "top": newY = newY - 1; break; case "bottom": newY = newY + 1; break; } if (!this.isBoundariesCollision(newX, newY, this.tank)) { this.tank.x = newX; this.tank.y = newY; this.gun.x = newX; this.gun.y = newY; this.stageData.centerCameraPosition(newX, newY); } } stopAction = () => { clearInterval(this.timer); this.timer = null; } fireAction = () => { this.person.emit("fire"); } } class EvensAggregator extends EventTarget { } class Tree { #x; #y; #health; #index; constructor(x, y, treeHealth, index) { this.#x = x; this.#y = y; this.#index = index; this.#health = treeHealth; } get index() { return this.#index; } get x() { return this.#x; } get y() { return this.#y; } get health() { return this.#health; } set health (value) { this.#health = value; } }