// @flow import Piece from "./Piece"; import ScoreManager from "./ScoreManager"; import GridManager from "./GridManager"; export default class GameLogic { static levelTicks = [ 1000, 800, 600, 400, 300, 200, 150, 100, ]; scoreManager: ScoreManager; gridManager: GridManager; height: number; width: number; gameRunning: boolean; gamePaused: boolean; gameTime: number; currentObject: Piece; gameTick: number; gameTickInterval: IntervalID; gameTimeInterval: IntervalID; pressInInterval: TimeoutID; isPressedIn: boolean; autoRepeatActivationDelay: number; autoRepeatDelay: number; nextPieces: Array; nextPiecesCount: number; onTick: Function; onClock: Function; endCallback: Function; colors: Object; constructor(height: number, width: number, colors: Object) { this.height = height; this.width = width; this.gameRunning = false; this.gamePaused = false; this.colors = colors; this.autoRepeatActivationDelay = 300; this.autoRepeatDelay = 50; this.nextPieces = []; this.nextPiecesCount = 3; this.scoreManager = new ScoreManager(); this.gridManager = new GridManager(this.getWidth(), this.getHeight(), this.colors); } getHeight(): number { return this.height; } getWidth(): number { return this.width; } getCurrentGrid() { return this.gridManager.getCurrentGrid(); } isGameRunning(): boolean { return this.gameRunning; } isGamePaused(): boolean { return this.gamePaused; } onFreeze() { this.gridManager.freezeTetromino(this.currentObject, this.scoreManager); this.createTetromino(); } setNewGameTick(level: number) { if (level >= GameLogic.levelTicks.length) return; this.gameTick = GameLogic.levelTicks[level]; clearInterval(this.gameTickInterval); this.gameTickInterval = setInterval(this.onTick, this.gameTick); } onTick(callback: Function) { this.currentObject.tryMove(0, 1, this.gridManager.getCurrentGrid(), this.getWidth(), this.getHeight(), () => this.onFreeze()); callback( this.scoreManager.getScore(), this.scoreManager.getLevel(), this.gridManager.getCurrentGrid()); if (this.scoreManager.canLevelUp()) this.setNewGameTick(this.scoreManager.getLevel()); } onClock(callback: Function) { this.gameTime++; callback(this.gameTime); } canUseInput() { return this.gameRunning && !this.gamePaused } rightPressed(callback: Function) { this.isPressedIn = true; this.movePressedRepeat(true, callback, 1, 0); } leftPressedIn(callback: Function) { this.isPressedIn = true; this.movePressedRepeat(true, callback, -1, 0); } downPressedIn(callback: Function) { this.isPressedIn = true; this.movePressedRepeat(true, callback, 0, 1); } movePressedRepeat(isInitial: boolean, callback: Function, x: number, y: number) { if (!this.canUseInput() || !this.isPressedIn) return; const moved = this.currentObject.tryMove(x, y, this.gridManager.getCurrentGrid(), this.getWidth(), this.getHeight(), () => this.onFreeze()); if (moved) { if (y === 1) { this.scoreManager.incrementScore(); callback(this.gridManager.getCurrentGrid(), this.scoreManager.getScore()); } else callback(this.gridManager.getCurrentGrid()); } this.pressInInterval = setTimeout(() => this.movePressedRepeat(false, callback, x, y), isInitial ? this.autoRepeatActivationDelay : this.autoRepeatDelay); } pressedOut() { this.isPressedIn = false; clearTimeout(this.pressInInterval); } rotatePressed(callback: Function) { if (!this.canUseInput()) return; if (this.currentObject.tryRotate(this.gridManager.getCurrentGrid(), this.getWidth(), this.getHeight())) callback(this.gridManager.getCurrentGrid()); } getNextPiecesPreviews() { let finalArray = []; for (let i = 0; i < this.nextPieces.length; i++) { finalArray.push(this.gridManager.getEmptyGrid(4, 4)); this.nextPieces[i].toGrid(finalArray[i], true); } return finalArray; } recoverNextPiece() { this.currentObject = this.nextPieces.shift(); this.generateNextPieces(); } generateNextPieces() { while (this.nextPieces.length < this.nextPiecesCount) { this.nextPieces.push(new Piece(this.colors)); } } createTetromino() { this.pressedOut(); this.recoverNextPiece(); if (!this.currentObject.isPositionValid(this.gridManager.getCurrentGrid(), this.getWidth(), this.getHeight())) this.endGame(false); } togglePause() { if (!this.gameRunning) return; this.gamePaused = !this.gamePaused; if (this.gamePaused) { clearInterval(this.gameTickInterval); clearInterval(this.gameTimeInterval); } else { this.gameTickInterval = setInterval(this.onTick, this.gameTick); this.gameTimeInterval = setInterval(this.onClock, 1000); } } endGame(isRestart: boolean) { this.gameRunning = false; this.gamePaused = false; clearInterval(this.gameTickInterval); clearInterval(this.gameTimeInterval); this.endCallback(this.gameTime, this.scoreManager.getScore(), isRestart); } startGame(tickCallback: Function, clockCallback: Function, endCallback: Function) { if (this.gameRunning) this.endGame(true); this.gameRunning = true; this.gamePaused = false; this.gameTime = 0; this.scoreManager = new ScoreManager(); this.gameTick = GameLogic.levelTicks[this.scoreManager.getLevel()]; this.gridManager = new GridManager(this.getWidth(), this.getHeight(), this.colors); this.nextPieces = []; this.generateNextPieces(); this.createTetromino(); tickCallback( this.scoreManager.getScore(), this.scoreManager.getLevel(), this.gridManager.getCurrentGrid()); clockCallback(this.gameTime); this.onTick = this.onTick.bind(this, tickCallback); this.onClock = this.onClock.bind(this, clockCallback); this.gameTickInterval = setInterval(this.onTick, this.gameTick); this.gameTimeInterval = setInterval(this.onClock, 1000); this.endCallback = endCallback; } }