UNPKG

jsge

Version:

Javascript Game Engine

477 lines (425 loc) 14.3 kB
import { DrawImageObject } from "../../src/base/2d/DrawImageObject.js"; import { DrawRectObject } from "../../src/base/2d/DrawRectObject.js"; import { DrawObjectFactory } from "../../src/base/DrawObjectFactory.js"; import { countDistance, angle_2points } from "../../src/utils.js"; import { PEASANT_ACTIONS, ANIMATION, GAME_EVENTS, GAME_UNITS, BUILDING_STATE } from "./const.js"; class UnitBase extends DrawImageObject { #health; /** * @type {undefined | DrawObjectFactory} */ #draw; /** * @type {undefined | null | DrawRectObject} */ #frame; /** * @type {boolean} */ #isSelected = false; constructor(mapX, mapY, width, height, key, imageIndex = 0, drawImageFactory, health) { super(mapX, mapY, width, height, key, imageIndex); this.#draw = drawImageFactory; } get health() { return this.#health; } set health(value) { this.#health = value; } get isSelected() { return this.#isSelected; } set isSelected(value) { this.#isSelected = value; if(value === true) { this.#frame = this.#draw.rect(this.x - this.width/2, this.y - this.height/2, this.width, this.height, "rgba(255,255,255,0.2)"); } else if (this.#frame) { console.log("remove frame"); this.#frame.destroy(); } } get frame() { return this.#frame; } } class UnitBuilding extends UnitBase { #PROGRESS_STEP = 50; #unitBuildProgress = 0; #unitBuildDuration = 0; #selfBuildingDuration = 0; /** * 0 - 1 */ #selfBuildingProgress; #eventsAggregator; #unitProgressTimer; #selfProgressTimer; #progressLine; #state = BUILDING_STATE.BUILDING_SELF; constructor(mapX, mapY, width, height, key, imageIndex, drawFactory, eventsAggregator, buildingProgress = 0) { super(mapX, mapY, width, height, key, imageIndex, drawFactory); this.#eventsAggregator = eventsAggregator; this.#selfBuildingDuration = GAME_UNITS[key].duration; this.#selfBuildingProgress = buildingProgress; if (buildingProgress === 0) { this.#startSelfBuilding(); } } get isBuildingUnit() { return !!this.#unitProgressTimer; } get state() { return this.#state; } buildUnit = (unitType) => { console.log("build unit: ", unitType); this.#state = BUILDING_STATE.BUILDING_UNIT; switch (unitType) { case GAME_UNITS.PEASANT.name: this.#unitBuildDuration = GAME_UNITS.PEASANT.duration; this.#createProgressLine(); this.#startBuildUnitProgress(); break; } } #createProgressLine = () => { this.#progressLine = document.createElement("div"), console.log("create progress line"); this.#progressLine.style.width = 0 + "px"; this.#progressLine.style.height = "2px"; this.#progressLine.style.backgroundColor = "#666"; this.#progressLine.style.position = "fixed"; this.#progressLine.style.top = 28 + "px"; this.#progressLine.style.left = 0 + "px"; document.body.appendChild(this.#progressLine); } #startBuildUnitProgress = () => { console.log("start build progress") if (this.#unitProgressTimer) { console.log("already building"); return; } const duration = this.#selfBuildingDuration, windowWidth = document.body.offsetWidth, step = this.#PROGRESS_STEP, stepWidth = windowWidth / duration * 100; let currentWidth = stepWidth; this.#unitProgressTimer = setInterval(() => { if (this.#unitBuildProgress < duration) { this.#unitBuildProgress += step; currentWidth += stepWidth; this.#progressLine.style.width = currentWidth + "px"; console.log("progress build"); } else { console.log("progress done"); clearInterval(this.#unitProgressTimer); this.#unitProgressTimer = null; this.#unitBuildProgress = 0; this.#progressLine.style.width = 0 + "px"; this.#eventsAggregator.dispatchEvent(new CustomEvent(GAME_EVENTS.PEASANT_BUILT, {detail: this})); this.#state = BUILDING_STATE.READY; } }, this.#PROGRESS_STEP); } #startSelfBuilding = () => { console.log("start self building"); const duration = this.#selfBuildingDuration, windowWidth = document.body.offsetWidth, step = this.#PROGRESS_STEP, stepWidth = windowWidth / duration * 100; let currentWidth = stepWidth; this.#selfProgressTimer = setInterval(() => { if (this.#selfBuildingProgress < duration) { this.#selfBuildingProgress += step; currentWidth += stepWidth; //this.#progressLine.style.width = currentWidth + "px"; console.log("progress build"); } else { console.log("progress done"); clearInterval(this.#selfProgressTimer); this.#selfProgressTimer = null; this.#selfBuildingProgress = 0; //this.#progressLine.style.width = 0 + "px"; this.#eventsAggregator.dispatchEvent(new CustomEvent(GAME_EVENTS.HOUSE_BUILT, {detail: this})); this.#state = BUILDING_STATE.READY; } }, this.#PROGRESS_STEP); } } class UnitPeasant extends UnitBase { /** * @type {string} */ #activeAction; #targetTree; #grabGoldmine; #closestTownCenter; #hasGold; #hasWood; #woodAmount = 0; #targetPoint; #buildingType; #eventsAggregator; constructor(mapX, mapY, width, height, closestTownCenter, drawFactory, eventsAggregator) { super(mapX, mapY, width, height, GAME_UNITS.PEASANT.name, 0, drawFactory, 50); this.addAnimation(ANIMATION.MOVE_DOWN, [1, 2, 3, 4], true); this.addAnimation(ANIMATION.MOVE_UP, [6, 7, 8, 9], true); this.addAnimation(ANIMATION.MOVE_RIGHT, [11, 12, 13, 14], true); this.addAnimation(ANIMATION.MOVE_LEFT, [16, 17, 18, 19], true); this.addAnimation(ANIMATION.CARRY_DOWN, [21, 22, 23, 24], true); this.addAnimation(ANIMATION.CARRY_UP, [26, 27, 28, 29], true); this.addAnimation(ANIMATION.CARRY_RIGHT, [31, 32, 33, 34], true); this.addAnimation(ANIMATION.CARRY_LEFT, [36, 37, 38, 39], true); this.addAnimation(ANIMATION.FIGHT_DOWN, [40, 41, 42], true); this.addAnimation(ANIMATION.FIGHT_UP, [45, 46, 47], true); this.addAnimation(ANIMATION.FIGHT_RIGHT, [50, 51, 52], true); this.addAnimation(ANIMATION.FIGHT_LEFT, [55, 56, 57], true); this.#closestTownCenter = closestTownCenter; this.#eventsAggregator = eventsAggregator; } get activeAction() { return this.#activeAction; } get targetTree() { return this.#targetTree; } get targetPoint() { return this.#targetPoint; } get buildingType() { return this.#buildingType; } activateGrabGold = (mine) => { console.log("start collecting gold"); this.#grabGoldmine = mine; this.#activeAction = PEASANT_ACTIONS.DRAG_GOLD; } activateIdle = () => { this.#activeAction = PEASANT_ACTIONS.IDLE; this.imageIndex = 0; } activateDragTree = (tree) => { this.#activeAction = PEASANT_ACTIONS.DRAG_WOOD; if (tree) { this.#targetTree = tree; } } activateChopTree = () => { this.#activeAction = PEASANT_ACTIONS.CHOP_WOOD; } askForClosestTree = () => { this.#eventsAggregator.dispatchEvent(new CustomEvent(GAME_EVENTS.REQUEST_FOR_CLOSEST_TREE, { detail: {peasant: this, tree: this.#targetTree}})); } dragWood = () => { if (this.#hasWood) { // move to the TownCenter const tX = this.#closestTownCenter.x, tY = this.#closestTownCenter.y; if (countDistance(this, {x:tX, y: tY}) < 25) { // reached this.#hasWood = false; this.#woodAmount = 0; //console.log("+ 10 tree milord!!"); this.#eventsAggregator.dispatchEvent(new CustomEvent(GAME_EVENTS.WOOD_MINED, { detail: 10 })); } else { this.#targetPoint = [tX, tY]; this.stepMoveWith(); } } else { // move to the Gold mine const tX = this.#targetTree.x, tY = this.#targetTree.y; if (this.#targetTree.health <= 0) { console.log("stop drag tree"); const activeAnimation = this.activeAnimation; if (activeAnimation) { this.stopRepeatedAnimation(activeAnimation); } this.activateIdle(); this.askForClosestTree(); } else if (countDistance(this, {x:tX, y: tY}) < 8) { // reached this.activateChopTree(); } else { this.#targetPoint = [tX, tY]; this.stepMoveWith(); } } } grabGold = () => { if (this.#hasGold) { // move to the TownCenter const tX = this.#closestTownCenter.x, tY = this.#closestTownCenter.y; if (countDistance(this, {x:tX, y: tY}) < 25) { // reached this.#hasGold = false; //console.log("+ 10 gold milord!!"); this.#eventsAggregator.dispatchEvent(new CustomEvent(GAME_EVENTS.GOLD_MINED, { detail: 10 })); } else { this.#targetPoint = [tX, tY]; this.stepMoveWith(); } } else { // move to the Gold mine const tX = this.#grabGoldmine.x, tY = this.#grabGoldmine.y; if (this.#grabGoldmine.goldAmount <= 0) { console.log("gold mine is empty"); const activeAnimation = this.activeAnimation; if (activeAnimation) { this.stopRepeatedAnimation(activeAnimation); } this.activateIdle(); } else if (countDistance(this, {x:tX, y: tY}) < 8) { // reached this.#hasGold = true; this.#grabGoldmine.goldAmount -= 10; if (this.#grabGoldmine.goldAmount <= 0) { this.#eventsAggregator.dispatchEvent(new CustomEvent(GAME_EVENTS.GOLD_MINE_EMPTY, { detail: this.#grabGoldmine})); } } else { this.#targetPoint = [tX, tY]; this.stepMoveWith(); } } } chopTree = () => { if (this.#woodAmount < 10) { this.#woodAmount = Math.round((this.#woodAmount + .05) * 100) / 100; this.#targetTree.health = Math.round((this.#targetTree.health - .05) * 100) / 100; const direction = angle_2points(this.x, this.y, this.#targetTree.x, this.#targetTree.y); if (direction > -Math.PI/4 && direction < Math.PI/4) { //console.log("chop right"); if (this.activeAnimation !== ANIMATION.FIGHT_RIGHT) { this.emit(ANIMATION.FIGHT_RIGHT); } } else if (direction > Math.PI/4 && direction < 3*Math.PI/4) { //console.log("chop down"); if (this.activeAnimation !== ANIMATION.FIGHT_DOWN) { this.emit(ANIMATION.FIGHT_DOWN) } } else if (direction > 3*Math.PI/4 || direction < -3*Math.PI/4) { //console.log("chop left"); if (this.activeAnimation !== ANIMATION.FIGHT_LEFT) { this.emit(ANIMATION.FIGHT_LEFT); } } else if (direction > -3*Math.PI/4 && direction < Math.PI/4) { if (this.activeAnimation !== ANIMATION.FIGHT_UP) { this.emit(ANIMATION.FIGHT_UP); } } } else { console.log(this.#woodAmount); this.#hasWood = true; this.activateDragTree(); if (this.#targetTree.health <= 0) { this.#eventsAggregator.dispatchEvent(new CustomEvent(GAME_EVENTS.TREE_EMPTY, { detail: this.#targetTree })); } } } stepMoveWith = () => { const x = this.x, y = this.y, tX = this.#targetPoint[0], tY = this.#targetPoint[1], hasGold = this.#hasGold || this.#hasWood; const forceToUse = 0.4,//this.#moveSpeed, direction = angle_2points(x, y, tX, tY), newCoordX = x + forceToUse * Math.cos(direction), newCoordY = y + forceToUse * Math.sin(direction); if (direction > -Math.PI/4 && direction < Math.PI/4) { //console.log("move right"); if (hasGold && this.activeAnimation !== ANIMATION.CARRY_RIGHT) { this.emit(ANIMATION.CARRY_RIGHT); } else if (!hasGold && this.activeAnimation !== ANIMATION.MOVE_RIGHT) this.emit(ANIMATION.MOVE_RIGHT); } else if (direction >= Math.PI/4 && direction < 3*Math.PI/4) { //console.log("move down"); if (hasGold && this.activeAnimation !== ANIMATION.CARRY_DOWN) { this.emit(ANIMATION.CARRY_DOWN) } else if (!hasGold && this.activeAnimation !== ANIMATION.MOVE_DOWN) this.emit(ANIMATION.MOVE_DOWN); } else if (direction > 3*Math.PI/4 || direction < -3*Math.PI/4) { //console.log("move left"); if (hasGold && this.activeAnimation !== ANIMATION.CARRY_LEFT) { this.emit(ANIMATION.CARRY_LEFT); } else if (!hasGold && this.activeAnimation !== ANIMATION.MOVE_LEFT) this.emit(ANIMATION.MOVE_LEFT); } else if (direction > -3*Math.PI/4 && direction < Math.PI/4) { //console.log("move up"); if (hasGold && this.activeAnimation !== ANIMATION.CARRY_UP) { this.emit(ANIMATION.CARRY_UP); } else if (!hasGold && this.activeAnimation !== ANIMATION.MOVE_UP) this.emit(ANIMATION.MOVE_UP); } else { console.log("unrecognized move to ", direction); } this.x = newCoordX; this.y = newCoordY; if (this.isSelected) { this.frame.x = newCoordX - this.width/2; this.frame.y = newCoordY - this.height/2; } } stepMove = () => { const x = this.x, y = this.y, tX = this.#targetPoint[0], tY = this.#targetPoint[1]; if (countDistance(this, {x:tX, y: tY}) < 5) { console.log("reached"); const activeAnimation = this.activeAnimation; if (activeAnimation) { this.stopRepeatedAnimation(activeAnimation); } this.activateIdle(); } else { const forceToUse = 0.4,//this.#moveSpeed, direction = angle_2points(x, y, tX, tY), newCoordX = x + forceToUse * Math.cos(direction), newCoordY = y + forceToUse * Math.sin(direction); if (direction > -Math.PI/4 && direction < Math.PI/4) { //console.log("move right"); if (this.activeAnimation !== ANIMATION.MOVE_RIGHT) this.emit(ANIMATION.MOVE_RIGHT); } else if (direction >= Math.PI/4 && direction < 3*Math.PI/4) { //console.log("move down"); if (this.activeAnimation !== ANIMATION.MOVE_DOWN) this.emit(ANIMATION.MOVE_DOWN); } else if (direction > 3*Math.PI/4 || direction < -3*Math.PI/4) { //console.log("move left"); if (this.activeAnimation !== ANIMATION.MOVE_LEFT) this.emit(ANIMATION.MOVE_LEFT); } else if (direction > -3*Math.PI/4 && direction < Math.PI/4) { //console.log("move up"); if (this.activeAnimation !== ANIMATION.MOVE_UP) this.emit(ANIMATION.MOVE_UP); } else { console.log("unrecognized move to ", direction); } this.x = newCoordX; this.y = newCoordY; if (this.isSelected) { this.frame.x = newCoordX - this.width/2; this.frame.y = newCoordY - this.height/2; } } } activateStartBuilding = (targetX, targetY, type) => { this.#activeAction = PEASANT_ACTIONS.BUILD; this.#targetPoint = [targetX, targetY]; this.#buildingType = type; } activateMoveToTargetPoint = (targetX, targetY) => { this.#activeAction = PEASANT_ACTIONS.MOVE; this.#targetPoint = [targetX, targetY]; } } export { UnitPeasant, UnitBuilding };