class Game{ constructor(eventBus, grid, previewGrid, pieceFactory){ this.eventBus = eventBus; this.lastTime = performance.now(); this.dropCounter = 0; this.dropInterval = 300; this.grid = grid; this.previewGrid = previewGrid; this.pieceFactory = pieceFactory; this.bagGenerator = this.pieceFactory.bagGenerator(); this.loopRequestID = null; this.currentPiece = null; this.nextPiece = null; this.level = 1; this.lines = 0; this.score = 0; this.moveHandler = this.moveHandler.bind(this); this.lockPiece = this.lockPiece.bind(this); this._setupInputListeners(); this.loop = this.loop.bind(this); this.eventBus.emit("update", this.uiState()); this.subscriptions = []; // Подписки. // Смотреть здесь this.unsubscribleStartGameplay = this.eventBus.on("start-gameplay", ({})=>{ this._setupInputListeners(); }); this.unsubscribleStopGameplay = this.eventBus.on("stop-gameplay", ({})=>{ this.unSetupInputListeners(); }) } getRenderState(){ return { matrix:this.grid.matrix, piece:this.currentPiece, nextMatrix:this.previewGrid.matrix, nextPiece:this.nextPiece, }; } moveHandler({dx, dy}){ //Деструктуризация moveState this.move(dx, dy); } _setupInputListeners() { this.move_off = this.eventBus.on("move", this.moveHandler); this.rotate_off = this.eventBus.on("rotate", ()=>{ this.rotate(); }); this.lockPiece_off = this.eventBus.on("lockPiece", this.lockPiece); } unSetupInputListeners() { // Вызываем сохраненные функции-отписки, которые мы получили от eventBus.on() if(this.move_off) this.move_off(); if(this.rotate_off) this.rotate_off(); if(this.lockPiece_off) this.lockPiece_off(); } loop(time){ const deltaTime = time - this.lastTime; this.lastTime = time; this.dropCounter += deltaTime; if (this.dropCounter > this.dropInterval) { this.eventBus.emit("move", {dx:0, dy:1}); this.dropCounter -= this.dropInterval; } this.eventBus.emit("render", this.getRenderState()); this.loopRequestID = window.requestAnimationFrame(this.loop); } spawnNewPiece() { if(this.nextPiece == null) { const currentType = this.bagGenerator.next().value; const nextType = this.bagGenerator.next().value; this.currentPiece = this.pieceFactory.generatePieceByType(currentType, this.grid.width, this.grid.height); this.nextPiece = this.pieceFactory.generatePieceByType(nextType, this.previewGrid.width, this.previewGrid.height, true); } else{ const nextType = this.bagGenerator.next().value; this.currentPiece = this.pieceFactory.generatePieceByType(this.nextPiece.type, this.grid.width, this.grid.height); this.nextPiece = this.pieceFactory.generatePieceByType(nextType, this.previewGrid.width, this.previewGrid.height, true); } } move(dx, dy){ if(this.currentPiece === null) return; const moved = this.currentPiece.move(dx, dy); if(!this.grid.isCollision(moved)){ this.currentPiece = moved; /*if (dy === 1) { this.dropCounter = 0; }*/ }else if(dy == 1){ //this.eventBus.emit("render", this.getRenderState()); this.eventBus.emit("lockPiece",{piece:this.currentPiece}); } } rotate(){ if(this.currentPiece === null) return; const rotated = this.currentPiece.rotate(); if(!this.grid.isCollision(rotated)){ this.currentPiece = rotated; } } async lockPiece({piece}){ this.grid.matrix = this.grid.getMergedMatrix(piece); const blinkedIndexes = this.grid.getBlinkedIndexes(); if(blinkedIndexes.length > 0){ this.eventBus.emit("force-render", this.getRenderState()); // await this.eventBus.emitAsync("animate",{count:4, time:100, indexes:blinkedIndexes, matrix:this.grid.matrix}); this.lines += this.grid.deleteLines(); this.eventBus.emit("update", this.uiState()); } this.spawnNewPiece(); if(this.grid.isCollision(this.currentPiece)){ this.eventBus.emit("gameEnd",{}); } } uiState(){ return { level:this.level, lines:this.lines, score:this.score } } start(){ if(this.loopRequestID) return; this.spawnNewPiece(); this.lastTime = performance.now(); this.loopRequestID = window.requestAnimationFrame(this.loop) } }