123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- import { Theme } from "../Theme.js"
- import Tile2 from "./Tile2.js"
- import AsyncTween from "../../AsyncTween.js"
- import { Easing } from "../../Easing.js"
- import { Point } from "../../spatial/Point.js"
- import { ActionQueue, MatchTilesAction, SpawnTileAction, SwapTileAction, TileFallAction } from "../../ActionQueue.js"
- class Board {
- constructor() {
- this.tiles = []
- this.position = new Point(0, 0)
- this.actionQueue = new ActionQueue()
- this.selectedTiles = []
- }
- init(canvasBounds) {
- this.boardSize = { x: 7, y: 7 }
- for (let y = 0; y < this.boardSize.y; y++) {
- for (let x = 0; x < this.boardSize.x; x++) {
- this.spawnTile(x, y)
- }
- }
- this.onResize(canvasBounds)
- // setTimeout(() => {
- // console.log("checking for matches on load")
- this.checkForMatches()
- // }, 2000)
- }
- spawnTile(x, y) {
- const tileType = Math.floor(Math.random() * Object.values(Theme.Colors.TileColors).length)
- const newTile = new Tile2(this, x, y, tileType)
- this.tiles.push(newTile)
- return newTile
- }
- draw(ctx) {
- ctx.save()
- ctx.translate(-this.position.x, -this.position.y)
- ctx.fillStyle = Theme.Colors.umber
- ctx.beginPath()
- ctx.rect(0, 0,
- this.boardSize.x * (Board.TILE_PADDING + Board.TILE_SIZE),
- this.boardSize.y * (Board.TILE_PADDING + Board.TILE_SIZE))
- ctx.fill()
- this.tiles.forEach((tile) => {
- tile.draw(ctx)
- })
- ctx.restore()
- }
- update(delta) {
- }
- onResize(canvasBounds) {
- let narrowest = canvasBounds.width
- let isVertical = true
- if (canvasBounds.width > canvasBounds.height) {
- narrowest = canvasBounds.height
- isVertical = false
- }
- Board.TILE_SIZE = Math.min(64, Math.max(40, Math.floor((narrowest - this.boardSize.x * 4) / this.boardSize.x)))
- const offset = new Point(
- 0,
- -(canvasBounds.height / 2) + (10 * (Board.TILE_PADDING + Board.TILE_SIZE)) / 2
- )
- if (!isVertical) {
- offset.x = (canvasBounds.width / 2) - (10 * (Board.TILE_PADDING + Board.TILE_SIZE)) / 2
- offset.y = 0
- }
- this.position.x = this.boardSize.x * (Board.TILE_PADDING + Board.TILE_SIZE) / 2
- this.position.y = this.boardSize.y * (Board.TILE_PADDING + Board.TILE_SIZE) / 2
- this.position.offset(offset)
- }
- onInputMove(position, isDown) {
- const offsetPosition = position.addition(this.position)
- this.tiles.forEach((tile) => {
- tile.onInputMove(offsetPosition, isDown)
- })
- }
- onInputDown(position) {
- const offsetPosition = position.addition(this.position)
- this.tiles.forEach((tile) => {
- tile.onInputDown(offsetPosition)
- })
- }
- onInputUp(position) {
- const offsetPosition = position.addition(this.position)
- this.tiles.forEach((tile) => {
- tile.onInputUp(offsetPosition)
- })
- }
- selectTile(tile) {
- if (this.selectedTiles.includes(tile) || this.selectedTiles.length == 2) {
- tile.isSelected = false
- return
- }
- this.selectedTiles.push(tile)
- tile.isSelected = true
- if (this.selectedTiles.length == 2) {
- this.actionQueue.push(new SwapTileAction(this.selectedTiles[0], this.selectedTiles[1]))
- this.actionQueue.execute(SwapTileAction, () => this.validToSwap(this.selectedTiles[0], this.selectedTiles[1])).then(() => {
- this.tiles.forEach((tile) => tile.isSelected = false)
- this.selectedTiles = []
- this.checkForMatches()
- }, () => {
- this.selectedTiles.forEach((tile) => tile.isSelected = false)
- this.selectedTiles.length = 0
- })
- }
- }
- validToSwap(firstTile, otherTile) {
- if (firstTile.position.x + 1 == otherTile.position.x && firstTile.position.y == otherTile.position.y) {
- return true
- }
- if (firstTile.position.x - 1 == otherTile.position.x && firstTile.position.y == otherTile.position.y) {
- return true
- }
- if (firstTile.position.x == otherTile.position.x && firstTile.position.y + 1 == otherTile.position.y) {
- return true
- }
- if (firstTile.position.x == otherTile.position.x && firstTile.position.y - 1 == otherTile.position.y) {
- return true
- }
- return false
- }
- deselectTile(tileToDeselect) {
- tileToDeselect.isSelected = false
- this.selectedTiles = this.selectedTiles.filter((tile) => tile != tileToDeselect)
- }
- checkForMatches() {
- const tilesToPop = []
- //five in a row horizontal
- this.tiles.forEach((tile, index, array) => {
- if (tilesToPop.includes(tile)) {
- return
- }
- const validTiles = this.tiles.filter((checkedTile) => !tilesToPop.includes(checkedTile) && tile.type == checkedTile.type && checkedTile.position.y == tile.position.y && (checkedTile.position.x == tile.position.x + 2 || checkedTile.position.x == tile.position.x + 1 || checkedTile.position.x == tile.position.x - 1 || checkedTile.position.x == tile.position.x - 2))
- if (validTiles.length == 4) {
- tilesToPop.push(tile, ...validTiles)
- this.actionQueue.push(new MatchTilesAction([tile, ...validTiles]))
- return
- }
- })
- //five in a row vertical
- this.tiles.forEach((tile, index, array) => {
- if (tilesToPop.includes(tile)) {
- return
- }
- const validTiles = this.tiles.filter((checkedTile) => !tilesToPop.includes(checkedTile) && tile.type == checkedTile.type && checkedTile.position.x == tile.position.x && (checkedTile.position.y == tile.position.y + 2 || checkedTile.position.y == tile.position.y + 1 || checkedTile.position.y == tile.position.y - 1 || checkedTile.position.y == tile.position.y - 2))
- if (validTiles.length == 4) {
- tilesToPop.push(tile, ...validTiles)
- this.actionQueue.push(new MatchTilesAction([tile, ...validTiles]))
- return
- }
- })
- //four in a row horizontal
- this.tiles.forEach((tile, index, array) => {
- if (tilesToPop.includes(tile)) {
- return
- }
- const validTiles = this.tiles.filter((checkedTile) => !tilesToPop.includes(checkedTile) && tile.type == checkedTile.type && checkedTile.position.y == tile.position.y && (checkedTile.position.x == tile.position.x + 2 || checkedTile.position.x == tile.position.x + 1 || checkedTile.position.x == tile.position.x - 1))
- if (validTiles.length == 3) {
- tilesToPop.push(tile, ...validTiles)
- this.actionQueue.push(new MatchTilesAction([tile, ...validTiles]))
- return
- }
- })
- //four in a row vertical
- this.tiles.forEach((tile, index, array) => {
- if (tilesToPop.includes(tile)) {
- return
- }
- const validTiles = this.tiles.filter((checkedTile) => !tilesToPop.includes(checkedTile) && tile.type == checkedTile.type && checkedTile.position.x == tile.position.x && (checkedTile.position.y == tile.position.y + 2 || checkedTile.position.y == tile.position.y + 1 || checkedTile.position.y == tile.position.y - 1))
- if (validTiles.length == 3) {
- tilesToPop.push(tile, ...validTiles)
- this.actionQueue.push(new MatchTilesAction([tile, ...validTiles]))
- return
- }
- })
- //5 in an L shape
- //TODO ugh this one is hard
- //three in a row horizontal
- this.tiles.forEach((tile, index, array) => {
- if (tilesToPop.includes(tile)) {
- return
- }
- const validTiles = this.tiles.filter((checkedTile) => !tilesToPop.includes(checkedTile) && tile.type == checkedTile.type && checkedTile.position.y == tile.position.y && (checkedTile.position.x == tile.position.x + 1 || checkedTile.position.x == tile.position.x - 1))
- if (validTiles.length == 2) {
- tilesToPop.push(tile, ...validTiles)
- this.actionQueue.push(new MatchTilesAction([tile, ...validTiles]))
- return
- }
- })
- //three in a row vertical
- this.tiles.forEach((tile, index, array) => {
- if (tilesToPop.includes(tile)) {
- return
- }
- const validTiles = this.tiles.filter((checkedTile) => !tilesToPop.includes(checkedTile) && tile.type == checkedTile.type && checkedTile.position.x == tile.position.x && (checkedTile.position.y == tile.position.y + 1 || checkedTile.position.y == tile.position.y - 1))
- if (validTiles.length == 2) {
- tilesToPop.push(tile, ...validTiles)
- this.actionQueue.push(new MatchTilesAction([tile, ...validTiles]))
- return
- }
- })
- tilesToPop.forEach((tile) => {
- tile.isSelected = true
- })
- if (tilesToPop.length == 0) {
- return
- }
- this.actionQueue.execute(MatchTilesAction).then(() => {
- this.tiles = this.tiles.filter((tile) => !tilesToPop.includes(tile))
- this.spawnAndCascade()
- })
- }
- spawnAndCascade() {
- for (let x = 0; x < this.boardSize.x; x++) {
- const columnTiles = this.tiles.filter((tile) => tile.position.x == x)
- if (columnTiles.length == this.boardSize.y) {
- continue
- }
- if (columnTiles.length != this.boardSize.y) {
- this.actionQueue.push(new SpawnTileAction(x, this.boardSize.y - columnTiles.length))
- }
- }
- this.collapse()
- this.actionQueue.execute(SpawnTileAction, (x, y) => this.spawnTile(x, y)).then(() => {
- this.collapse().then(() => {
- this.checkForMatches()
- })
- })
-
- }
- collapse() {
- for (let x = 0; x < this.boardSize.x; x++) {
- const columnTiles = this.tiles.filter((tile) => tile.position.x == x).sort((tileA, tileB) => tileA.position.y < tileB.position.y)
- let bottom = this.boardSize.y
- columnTiles.forEach((tile, index) => {
- if (tile.position.y < bottom) {
- bottom -= 1
- this.actionQueue.push(new TileFallAction(tile, bottom))
- }
- })
- }
- return this.actionQueue.execute(TileFallAction)
- }
- }
- Board.TILE_PADDING = 4
- Board.TILE_SIZE = 64
- export default Board
|