diff --git a/src/GameLogic/collisionManager.js b/src/GameLogic/collisionManager.js index 01f781c..8566e14 100644 --- a/src/GameLogic/collisionManager.js +++ b/src/GameLogic/collisionManager.js @@ -1,31 +1,40 @@ import { BlockTypeEnum } from "../Blocks/blockTypeEnum"; import { Constants } from "../constants"; import { Map } from "../Graphics/Map/map"; +import { AITankManager } from "../Tanks/aiTankManager"; +import { Tank } from "../Tanks/tank"; export class CollisionManager { /** - * @type {Map} + * @type {Map} _map */ _map; - constructor() { + /** + * + * @param {Tank} tank + * @param {AITankManager} aiManager + */ + constructor(tank, aiManager) { + this._mainTank = tank; + this._aiManager = aiManager; } attachMap(map) { this._map = map; } - checkCollisionForTank(xMin, xMax, yMin, yMax) { + checkCollisionForTank(xMin, xMax, yMin, yMax, tank) { if (!this._map) return false; - return (this._checkTankCollision(xMin, xMax, yMin, yMax) != null) || + return (this._checkTankCollision(xMin, xMax, yMin, yMax, tank) != null) || (this._checkBoundaries(xMin, xMax, yMin, yMax) != null) || (this._checkBlockCollision(xMin, xMax, yMin, yMax, false) != null); } - checkCollisionForShots(xMin, xMax, yMin, yMax, direction) { + checkCollisionForShots(xMin, xMax, yMin, yMax, direction, tank) { if (!this._map) return false; @@ -38,12 +47,34 @@ export class CollisionManager { return true; } - return this._checkBoundaries(xMin, xMax, yMin, yMax) != null; + if (this._checkBoundaries(xMin, xMax, yMin, yMax) != null) + return true; + + let collTank = this._checkTankCollision(xMin, xMax, yMin, yMax, tank); + + if (collTank) { + if (collTank.id == Constants.PLAYER_TANK_ID_IMAGE.getValue()) + this._mainTank.isDestroyed = true; + else { + this._aiManager.destroy(collTank); + } + + return true; + } + else { + return false; + } } - _checkTankCollision(xMin, xMax, yMin, yMax) { - //TODO with AI tanks + _checkTankCollision(xMin, xMax, yMin, yMax, tank) { + let tanks = [this._mainTank].concat(this._aiManager._activeTanks).filter(t => tank.x != t.x && tank.y != t.y); + + for (let tankToCheck of tanks) { + let box = tankToCheck.getCollisionBox(); + if (this.intersect(xMin, xMax, yMin, yMax, box.minX, box.maxX, box.minY, box.maxY)) return tankToCheck; + } + return null; } diff --git a/src/GameLogic/gameField.js b/src/GameLogic/gameField.js index edc9ced..ffe86dd 100644 --- a/src/GameLogic/gameField.js +++ b/src/GameLogic/gameField.js @@ -13,11 +13,15 @@ export class GameField { this.width = width; this.ctx = ctx; this.canvas = canvas; - this.collisionManager = new CollisionManager(); - this.tank = new Tank(Constants.PLAYER_TANK_ID_IMAGE.getValue(), 0, 0, this.collisionManager); - this.aiTanks = new AITankManager(this.collisionManager) this.tileset = null; this.map = null; + + + this.collisionManager = new CollisionManager(); + this.tank = new Tank(Constants.PLAYER_TANK_ID_IMAGE.getValue(), 0, 18*16, this.collisionManager); + this.aiTanks = new AITankManager(this.collisionManager); + this.collisionManager._aiManager = this.aiTanks; + this.collisionManager._mainTank = this.tank; } //add all tiles here! @@ -46,6 +50,12 @@ export class GameField { this.tileset.addTile(128, 0, 28, 28, Constants.PLAYER_TANK_ID_IMAGE.getValue() + DirectionEnum.Down.getValue()); this.tileset.addTile(192, 0, 28, 28, Constants.PLAYER_TANK_ID_IMAGE.getValue() + DirectionEnum.Right.getValue()); + //Enemy tank + this.tileset.addTile(256, 2, 28, 30, 200 + DirectionEnum.Up.getValue()); + this.tileset.addTile(320, 0, 28, 28, 200 + DirectionEnum.Left.getValue()); + this.tileset.addTile(386, 0, 28, 28, 200 + DirectionEnum.Down.getValue()); + this.tileset.addTile(452, 0, 28, 28, 200 + DirectionEnum.Right.getValue()); + await this.tileset.loadAll(); } @@ -55,10 +65,11 @@ export class GameField { } if (!this.map) { - this.map = await new MapParser().getMap(4, this.tileset); + this.map = await new MapParser().getMap(1, this.tileset); this.canvas.height = this.height; this.canvas.width = this.width; this.collisionManager.attachMap(this.map); + this.aiTanks.setCount(this.map._enemiesCount); } let lateDraw = []; @@ -67,7 +78,8 @@ export class GameField { for (let x = 0; x < this.map.width; x += 1) { for (let y = 0; y < this.map.height; y += 1) { this.ctx.fillStyle = "black"; - this.ctx.fillRect(x * Constants.TILE_SIZE.getValue(), y * Constants.TILE_SIZE.getValue(), Constants.TILE_SIZE.getValue(), Constants.TILE_SIZE.getValue()); + this.ctx.fillRect(x * Constants.TILE_SIZE.getValue(), y * Constants.TILE_SIZE.getValue(), + Constants.TILE_SIZE.getValue(), Constants.TILE_SIZE.getValue()); let element = this.map.getElement(x, y); if (element.getType() == BlockTypeEnum.Forest){ @@ -81,10 +93,14 @@ export class GameField { this.tank.draw(this.tileset, this.ctx); + this.aiTanks.drawAllTanks(this.tileset, this.ctx); + for (let el of lateDraw) { el.element.draw(this.ctx, el.x * Constants.TILE_SIZE.getValue(), el.y * Constants.TILE_SIZE.getValue()); } + if (this.aiTanks.isAllTanksDied()) return; + requestAnimationFrame(() => this.drawField()); } diff --git a/src/Tanks/aiTank.js b/src/Tanks/aiTank.js new file mode 100644 index 0000000..9fe69dc --- /dev/null +++ b/src/Tanks/aiTank.js @@ -0,0 +1,30 @@ +import { DirectionEnum } from "./directionEnum"; +import { Tank } from "./tank"; + +export class AITank extends Tank { + constructor(id, x, y, collision, aiManager) { + super(id, x, y, collision); + this._ai = aiManager; + + this.moveCount = 0; + this.shotChance = 15; + } + + move(direction) { + if (this.moveCount == 0) + this.setNewMoveDirectionAndCount(); + + super.move(this.direction); + this.moveCount--; + } + + shot() { + if (Math.floor(Math.random() * 100) + 1 <= this.shotChance) + super.shot(); + } + + setNewMoveDirectionAndCount(){ + this.moveCount = Math.floor(Math.random() * 100) + 5; + this.direction = DirectionEnum.array[Math.floor(Math.random() * DirectionEnum.array.length)]; + } +} \ No newline at end of file diff --git a/src/Tanks/aiTankManager.js b/src/Tanks/aiTankManager.js index 1c5380b..671aa1e 100644 --- a/src/Tanks/aiTankManager.js +++ b/src/Tanks/aiTankManager.js @@ -1,9 +1,39 @@ +import { AITank } from "./aiTank" + export class AITankManager { + constructor(collisionManager) { + this.MAX_TANKS_ON_FIELD = 1; + this._count = null; this._collision = collisionManager; this._canSpawn = false; - this._activeTanks = null; + this._activeTanks = []; + } + + drawAllTanks(tileset, ctx) { + for (let tank of this._activeTanks) { + tank.move(null); + tank.shot(); + tank.draw(tileset, ctx); + } + + this.tick(); + } + + tick() { + if (this.checkIfCanSpawn()){ + this._count--; + this._activeTanks.push(new AITank(200, 0, 0, this._collision, this)); + } + + if (this._activeTanks.length >= this.MAX_TANKS_ON_FIELD) + this._canSpawn = false; + } + + destroy(tank) { + this._activeTanks = this._activeTanks.filter(t => tank.x != t.x && tank.y != t.y); + this._canSpawn = true; } setCount(count) { diff --git a/src/Tanks/directionEnum.js b/src/Tanks/directionEnum.js index eb13824..1f10ea7 100644 --- a/src/Tanks/directionEnum.js +++ b/src/Tanks/directionEnum.js @@ -4,6 +4,8 @@ export class DirectionEnum { static Down = new DirectionEnum(3); static Right = new DirectionEnum(4); + static array = [this.Up, this.Left, this.Down, this.Right]; + constructor(value){ this._value = value; } diff --git a/src/Tanks/shotElement.js b/src/Tanks/shotElement.js index f45dea2..5855aaa 100644 --- a/src/Tanks/shotElement.js +++ b/src/Tanks/shotElement.js @@ -56,7 +56,7 @@ export class ShotManager { } checkCollision(minX, maxX, minY, maxY) { - return this.collisionManager.checkCollisionForShots(minX, maxX, minY, maxY, this.shot.direction); + return this.collisionManager.checkCollisionForShots(minX, maxX, minY, maxY, this.shot.direction, this.tank); } destroyShot() { diff --git a/src/Tanks/tank.js b/src/Tanks/tank.js index 9484863..d33b3a7 100644 --- a/src/Tanks/tank.js +++ b/src/Tanks/tank.js @@ -12,43 +12,51 @@ export class Tank { this.speed = 3.0; this.direction = DirectionEnum.Up; + this.isDestroyed = false; + this.shotManager = new ShotManager(collisionManager, this); } move(direction) { - const tanksize = Constants.TANK_SIZE.getValue(); - const collisionOffset = Constants.TANK_COLL_OFFSET.getValue() * tanksize; + const box = this.getCollisionBox(); this.direction = direction; - const collisionMinX = this.x + collisionOffset; - const collisionMaxX = this.x + tanksize - collisionOffset; - const collisionMinY = this.y + collisionOffset; - const collisionMaxY = this.y + tanksize - collisionOffset; - switch (direction) { case DirectionEnum.Up: - if (!this.collisionManager.checkCollisionForTank(collisionMinX, collisionMaxX, collisionMinY - this.speed, collisionMaxY - this.speed)) + if (!this.collisionManager.checkCollisionForTank(box.minX, box.maxX, box.minY - this.speed, box.maxY - this.speed, this)) this.y -= this.speed; break; case DirectionEnum.Left: - if (!this.collisionManager.checkCollisionForTank(collisionMinX - this.speed, collisionMaxX - this.speed, collisionMinY, collisionMaxY)) + if (!this.collisionManager.checkCollisionForTank(box.minX - this.speed, box.maxX - this.speed, box.minY, box.maxY, this)) this.x -= this.speed; break; case DirectionEnum.Right: - if (!this.collisionManager.checkCollisionForTank(collisionMinX + this.speed, collisionMaxX + this.speed, collisionMinY, collisionMaxY)) + if (!this.collisionManager.checkCollisionForTank(box.minX + this.speed, box.maxX + this.speed, box.minY, box.maxY, this)) this.x += this.speed; break; case DirectionEnum.Down: - if (!this.collisionManager.checkCollisionForTank(collisionMinX, collisionMaxX, collisionMinY + this.speed, collisionMaxY + this.speed)) + if (!this.collisionManager.checkCollisionForTank(box.minX, box.maxX, box.minY + this.speed, box.maxY + this.speed, this)) this.y += this.speed; break; } } + getCollisionBox() { + const tanksize = Constants.TANK_SIZE.getValue(); + const collisionOffset = Constants.TANK_COLL_OFFSET.getValue() * tanksize; + + return { + minX: this.x + collisionOffset, + maxX: this.x + tanksize - collisionOffset, + minY: this.y + collisionOffset, + maxY: this.y + tanksize - collisionOffset + } + } + shot() { let x, y = 0 const tanksize = Constants.TANK_SIZE.getValue();