application-amicale/screens/Tetris/GameLogic.js

237 lines
6.9 KiB
JavaScript

// @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<Piece>;
#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;
}
}