tetris/js/game.js

128 lines
5.0 KiB
JavaScript

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)
}
}