123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- // @flow
-
- import Piece from './Piece';
- import ScoreManager from './ScoreManager';
- import GridManager from './GridManager';
- import type {CustomThemeType} from '../../../managers/ThemeManager';
- import type {GridType} from '../components/GridComponent';
-
- export type TickCallbackType = (
- score: number,
- level: number,
- grid: GridType,
- ) => void;
-
- export type ClockCallbackType = (time: number) => void;
-
- export type EndCallbackType = (
- time: number,
- score: number,
- isRestart: boolean,
- ) => void;
-
- export type MovementCallbackType = (grid: GridType, score?: number) => void;
-
- 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;
-
- tickCallback: TickCallbackType;
-
- clockCallback: ClockCallbackType;
-
- endCallback: EndCallbackType;
-
- theme: CustomThemeType;
-
- constructor(height: number, width: number, theme: CustomThemeType) {
- this.height = height;
- this.width = width;
- this.gameRunning = false;
- this.gamePaused = false;
- this.theme = theme;
- this.autoRepeatActivationDelay = 300;
- this.autoRepeatDelay = 50;
- this.nextPieces = [];
- this.nextPiecesCount = 3;
- this.scoreManager = new ScoreManager();
- this.gridManager = new GridManager(
- this.getWidth(),
- this.getHeight(),
- this.theme,
- );
- }
-
- getHeight(): number {
- return this.height;
- }
-
- getWidth(): number {
- return this.width;
- }
-
- getCurrentGrid(): GridType {
- return this.gridManager.getCurrentGrid();
- }
-
- 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];
- this.stopTick();
- this.startTick();
- }
-
- startClock() {
- this.gameTimeInterval = setInterval(() => {
- this.onClock(this.clockCallback);
- }, 1000);
- }
-
- startTick() {
- this.gameTickInterval = setInterval(() => {
- this.onTick(this.tickCallback);
- }, this.gameTick);
- }
-
- stopClock() {
- clearInterval(this.gameTimeInterval);
- }
-
- stopTick() {
- clearInterval(this.gameTickInterval);
- }
-
- stopGameTime() {
- this.stopClock();
- this.stopTick();
- }
-
- startGameTime() {
- this.startClock();
- this.startTick();
- }
-
- onTick(callback: TickCallbackType) {
- 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: ClockCallbackType) {
- this.gameTime += 1;
- callback(this.gameTime);
- }
-
- canUseInput(): boolean {
- return this.gameRunning && !this.gamePaused;
- }
-
- rightPressed(callback: MovementCallbackType) {
- this.isPressedIn = true;
- this.movePressedRepeat(true, callback, 1, 0);
- }
-
- leftPressedIn(callback: MovementCallbackType) {
- this.isPressedIn = true;
- this.movePressedRepeat(true, callback, -1, 0);
- }
-
- downPressedIn(callback: MovementCallbackType) {
- this.isPressedIn = true;
- this.movePressedRepeat(true, callback, 0, 1);
- }
-
- movePressedRepeat(
- isInitial: boolean,
- callback: MovementCallbackType,
- 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: MovementCallbackType) {
- if (!this.canUseInput()) return;
-
- if (
- this.currentObject.tryRotate(
- this.gridManager.getCurrentGrid(),
- this.getWidth(),
- this.getHeight(),
- )
- )
- callback(this.gridManager.getCurrentGrid());
- }
-
- getNextPiecesPreviews(): Array<GridType> {
- const finalArray = [];
- for (let i = 0; i < this.nextPieces.length; i += 1) {
- const gridSize = this.nextPieces[i].getCurrentShape().getCurrentShape()[0]
- .length;
- finalArray.push(this.gridManager.getEmptyGrid(gridSize, gridSize));
- 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.theme));
- }
- }
-
- 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) this.stopGameTime();
- else this.startGameTime();
- }
-
- endGame(isRestart: boolean) {
- this.gameRunning = false;
- this.gamePaused = false;
- this.stopGameTime();
- this.endCallback(this.gameTime, this.scoreManager.getScore(), isRestart);
- }
-
- startGame(
- tickCallback: TickCallbackType,
- clockCallback: ClockCallbackType,
- endCallback: EndCallbackType,
- ) {
- 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.theme,
- );
- this.nextPieces = [];
- this.generateNextPieces();
- this.createTetromino();
- tickCallback(
- this.scoreManager.getScore(),
- this.scoreManager.getLevel(),
- this.gridManager.getCurrentGrid(),
- );
- clockCallback(this.gameTime);
- this.startTick();
- this.startClock();
- this.tickCallback = tickCallback;
- this.clockCallback = clockCallback;
- this.endCallback = endCallback;
- }
- }
|