JavaScript Тетромино тетриса раздвигаются после движения и вращения - PullRequest
0 голосов
/ 21 апреля 2020

Изучение JavaScript путем создания игры в тетрис.

Проблема: Когда я пытаюсь переместить (влево, вправо или вниз из начальной позиции) фигуру, а затем повернуть ее, вращаемая фигура растягивается. , Когда я go возвращаюсь в исходное положение, все работает нормально. Также, когда я не вращаю часть, а только перемещаю ее влево / вправо / вниз, тогда все также хорошо. Я думаю, что у меня есть центр вращения, привязанный к сетке, но не к части.

Здесь вы можете играть в игру: Здесь

Вот мой github: Здесь

Временные элементы управления:

Ввод и после стрелка вверх: начать игру

осталось стрелка: двигаться влево

стрелка вправо: двигаться вправо

стрелка вверх: вращаться

стрелка вниз: двигаться на один ряд вниз

Описание:

Мои тетромино и сетка сделаны из массивов (на основе классов). Сетка происходит от SimpleBlock {} и GridBlock {}. Мои тетромино сделаны из Simple Block {} и

    class SimpleBlock{
    constructor(tempSquareColor, boardPosX, boardPosY){
        this.x = boardPosX;
        this.y = boardPosY;
        this.squareColor = tempSquareColor;
    }
}

class GridBlock extends SimpleBlock{
    constructor(tempSquareColor, boardPosX, boardPosY){
        super(tempSquareColor, boardPosX, boardPosY);

        ctx.fillStyle = this.squareColor;
        ctx.strokeStyle = "black";
        ctx.lineWidth = 3;
        ctx.fillRect(this.x * squareSize, this.y * squareSize, squareSize, squareSize);
        ctx.strokeRect(this.x * squareSize, this.y * squareSize, squareSize, squareSize);
    }
}

var gameBoardSquared = [];

function drawSquaredGameBoard() {
    for(var row = 0; row < gameBoardRows; row++){
        gameBoardSquared[row] = [];
        for(var col = 0; col < gameBoardColumns; col++){
            gameBoardSquared[row][col] = new GridBlock("white", row, col);
        }
    }
}

Мои тетромино:

class BasicBlock extends SimpleBlock{
    constructor(tempSquareColor, boardPosX, boardPosY){
        super(tempSquareColor, boardPosX, boardPosY);
    }

    drawBlock(){
        ctx.fillStyle = this.squareColor;
        ctx.strokeStyle = "black";
        ctx.lineWidth = 3;
        ctx.fillRect(this.x * squareSize, this.y * squareSize, squareSize, squareSize);
        ctx.strokeRect(this.x * squareSize, this.y * squareSize, squareSize, squareSize);
    }

    undrawBlock(){
        ctx.fillStyle = "white";
        ctx.strokeStyle = "black";
        ctx.lineWidth = 3;
        ctx.fillRect(this.x * squareSize, this.y * squareSize, squareSize, squareSize);
        ctx.strokeRect(this.x * squareSize, this.y * squareSize, squareSize, squareSize);
    }

    moveLeft(){
        this.x--;
    }

    moveRight(){
        this.x++;
    }

    slowFall(){
        this.y++;
    }
}

//Tetrominos

//Declaration of variables, of a [4x4] tetromino array. Excluding the cells, that will never be used (like tetro3)
var tetrominoes = [];
var tetrominoI = [];
var tetrominoJ = [];
var tetrominoL = [];
var tetrominoO = [];
var tetrominoS = [];
var tetrominoT = [];
var tetrominoZ = [];

function makeNewRandomTetromino(){
    var tetro = [];
    tetro[0] = new BasicBlock("blue", 4, 0);
    tetro[1] = new BasicBlock("blue", 5, 0);
    tetro[2] = new BasicBlock("blue", 6, 0);
    tetro[4] = new BasicBlock("blue", 4, 1);
    tetro[5] = new BasicBlock("blue", 5, 1);
    tetro[6] = new BasicBlock("blue", 6, 1);
    tetro[7] = new BasicBlock("blue", 7, 1);
    tetro[8] = new BasicBlock("blue", 4, 2);
    tetro[9] = new BasicBlock("blue", 5, 2);
    tetro[10] = new BasicBlock("blue", 6, 2);
    tetro[11] = new BasicBlock("blue", 7, 2);
    tetro[13] = new BasicBlock("blue", 5, 3);
    tetro[14] = new BasicBlock("blue", 6, 3);

    // var tetrominoJ0 = [        
    //     tetro[1].tempSquareColor = "yellow",
    //     tetro[5].tempSquareColor = "yellow",
    //     tetro[8].tempSquareColor = "yellow",
    //     tetro[9].tempSquareColor = "yellow",
    // ];


    // var tetrominoJ1 = [        
    //     tetro[4].tempSquareColor = "yellow",
    //     tetro[5].tempSquareColor = "yellow",
    //     tetro[6].tempSquareColor = "yellow",
    //     tetro[10].tempSquareColor = "yellow",
    // ];

    // var tetrominoI = [];

    tetrominoI[0] = [tetro[1], tetro[5], tetro[9], tetro[13]];
    tetrominoI[1] = [tetro[8], tetro[9], tetro[10], tetro[11]];
    tetrominoI[2] = [tetro[2], tetro[6], tetro[10], tetro[14]];
    tetrominoI[3] = [tetro[4], tetro[5], tetro[6], tetro[7]];

    // for(var i of tetrominoI){
    //     i.squareColor == "magenta";
    // }

    // var tetrominoJ = [];

    tetrominoJ[0] = [tetro[1], tetro[5], tetro[8], tetro[9]];
    tetrominoJ[1] = [tetro[6], tetro[4], tetro[5], tetro[10]];
    tetrominoJ[2] = [tetro[1], tetro[2], tetro[5], tetro[9]];
    tetrominoJ[3] = [tetro[0], tetro[4], tetro[5], tetro[6]];

    // var tetrominoL = [];

    tetrominoL[0] = [tetro[0], tetro[1], tetro[5], tetro[9]];
    tetrominoL[1] = [tetro[4], tetro[5], tetro[6], tetro[8]];
    tetrominoL[2] = [tetro[1], tetro[5], tetro[9], tetro[10]];
    tetrominoL[3] = [tetro[2], tetro[4], tetro[5], tetro[6]];

    // for(var i of tetrominoL){
    //     i.squareColor == "orange";
    // }

    // var tetrominoO = [];

    tetrominoO[0] = [tetro[1], tetro[2], tetro[5], tetro[6]];
    tetrominoO[1] = [tetro[1], tetro[2], tetro[5], tetro[6]];
    tetrominoO[2] = [tetro[1], tetro[2], tetro[5], tetro[6]];
    tetrominoO[3] = [tetro[1], tetro[2], tetro[5], tetro[6]];

    // for(var i of tetrominoO){
    //     i.squareColor == "yellow";
    // }

    // var tetrominoS = [];

    tetrominoS[0] = [tetro[0], tetro[4], tetro[5], tetro[9]];
    tetrominoS[1] = [tetro[5], tetro[6], tetro[8], tetro[9]];
    tetrominoS[2] = [tetro[1], tetro[5], tetro[6], tetro[10]];
    tetrominoS[3] = [tetro[1], tetro[2], tetro[4], tetro[5]];

    // for(var i of tetrominoS){
    //     i.squareColor == "green";
    // }

    // var tetrominoT = [];

    tetrominoT[0] = [tetro[1], tetro[4], tetro[5], tetro[9]];
    tetrominoT[1] = [tetro[4], tetro[5], tetro[6], tetro[9]];
    tetrominoT[2] = [tetro[1], tetro[5], tetro[6], tetro[9]];
    tetrominoT[3] = [tetro[1], tetro[4], tetro[5], tetro[6]];

    // for(var i of tetrominoT){
    //     i.squareColor == "purple";
    // }

    // var tetrominoZ = [];

    tetrominoZ[0] = [tetro[1], tetro[4], tetro[5], tetro[8]];
    tetrominoZ[1] = [tetro[4], tetro[5], tetro[9], tetro[10]];
    tetrominoZ[2] = [tetro[2], tetro[5], tetro[6], tetro[9]];
    tetrominoZ[3] = [tetro[0], tetro[1], tetro[5], tetro[6]];

    // for(var i of tetrominoZ){
    //     i.squareColor == "red";
    // }

    var i = Math.floor(Math.random() * tetrominoZ.length);
    var tetrominoesArr = [tetrominoO[i], tetrominoJ[i], tetrominoS[i], tetrominoZ[i], tetrominoT[i], tetrominoL[i], tetrominoI[i]];

    var x = Math.floor(Math.random() * tetrominoesArr.length);
    tetrominoes = tetrominoesArr[x];
}

И функции, которые управляют ими:

function rotateTetromino(){

    for(let i of tetrominoes){
        i.undrawBlock();
    }

    if(tetrominoes == tetrominoI[0]){
        tetrominoes = tetrominoI[1];
    } else if(tetrominoes == tetrominoI[1]){
        tetrominoes = tetrominoI[2];
    } else if(tetrominoes == tetrominoI[2]){
        tetrominoes = tetrominoI[3];
    } else if(tetrominoes == tetrominoI[3]){
        tetrominoes = tetrominoI[0];
    } else if(tetrominoes == tetrominoJ[0]){
        tetrominoes = tetrominoJ[1];
    } else if(tetrominoes == tetrominoJ[1]){
        tetrominoes = tetrominoJ[2];
    } else if(tetrominoes == tetrominoJ[2]){
        tetrominoes = tetrominoJ[3];
    } else if(tetrominoes == tetrominoJ[3]){
        tetrominoes = tetrominoJ[0];
    } else if(tetrominoes == tetrominoL[0]){
        tetrominoes = tetrominoL[1];
    } else if(tetrominoes == tetrominoL[1]){
        tetrominoes = tetrominoL[2];
    } else if(tetrominoes == tetrominoL[2]){
        tetrominoes = tetrominoL[3];
    } else if(tetrominoes == tetrominoL[3]){
        tetrominoes = tetrominoL[0];
    } else if(tetrominoes == tetrominoO[0]){
        tetrominoes = tetrominoO[1];
    } else if(tetrominoes == tetrominoO[1]){
        tetrominoes = tetrominoO[2];
    } else if(tetrominoes == tetrominoO[2]){
        tetrominoes = tetrominoO[3];
    } else if(tetrominoes == tetrominoO[3]){
        tetrominoes = tetrominoO[0];
    } else if(tetrominoes == tetrominoS[0]){
        tetrominoes = tetrominoS[1];
    } else if(tetrominoes == tetrominoS[1]){
        tetrominoes = tetrominoS[2];
    } else if(tetrominoes == tetrominoS[2]){
        tetrominoes = tetrominoS[3];
    } else if(tetrominoes == tetrominoS[3]){
        tetrominoes = tetrominoS[0];
    } else if(tetrominoes == tetrominoT[0]){
        tetrominoes = tetrominoT[1];
    } else if(tetrominoes == tetrominoT[1]){
        tetrominoes = tetrominoT[2];
    } else if(tetrominoes == tetrominoT[2]){
        tetrominoes = tetrominoT[3];
    } else if(tetrominoes == tetrominoT[3]){
        tetrominoes = tetrominoT[0];
    } else if(tetrominoes == tetrominoZ[0]){
        tetrominoes = tetrominoZ[1];
    } else if(tetrominoes == tetrominoZ[1]){
        tetrominoes = tetrominoZ[2];
    } else if(tetrominoes == tetrominoZ[2]){
        tetrominoes = tetrominoZ[3];
    } else if(tetrominoes == tetrominoZ[3]){
        tetrominoes = tetrominoZ[0];
    }
    for(let i of tetrominoes){
        i.drawBlock();
    }
}

function moveTetrominoesLeft(){

    if(tetrominoes.some(k => k.x - 1 < 0) || tetrominoes.some(k => k.squareColor == gameBoardSquared[k.x-1][k.y].squareColor)){
        for(let i of tetrominoes){
            i.drawBlock();
        }
    }
    else{
        for(let i of tetrominoes){
            i.undrawBlock();
        }
        for(let i of tetrominoes){
            i.moveLeft();
            i.drawBlock();
        }
    }
}

function moveTetrominoesRight(){

    if(tetrominoes.some(k => k.x + 1 > gameBoardSquared.length-1) || tetrominoes.some(k => k.squareColor == gameBoardSquared[k.x+1][k.y].squareColor)){
        for(let i of tetrominoes){
            i.drawBlock();
        }
    }
    else{
        for(var i of tetrominoes){
            i.undrawBlock();
        }
        for(var i of tetrominoes){
            i.moveRight();
            i.drawBlock();
        }
    }
}

function tetrominoesSlowFall(){

    for(let i of tetrominoes){
        i.undrawBlock();
    }
    for(let i of tetrominoes){
        i.slowFall();
        i.drawBlock();
    }
}

function collisionDetection(){
    const topBoardBorder = 3;
    for(var i of tetrominoes){
        if(tetrominoes.some(k => k.squareColor == gameBoardSquared[k.x][k.y].squareColor) && tetrominoes.some(k => k.y < topBoardBorder)){
            console.log("Game Over");
            gameOver = true;
        }
        if(tetrominoes.some(k => k.squareColor == gameBoardSquared[k.x][k.y+1].squareColor)){
            for(var i of tetrominoes){
                i.drawBlock();
                gameBoardSquared[i.x][i.y] = i;
            }
            return true;
        }
        else if(tetrominoes.some(k => k.y > playableGameBoardLength-1)){
            for(var i of tetrominoes){
                i.drawBlock();
                gameBoardSquared[i.x][i.y] = i;
            }
            return true;
        }
    }
    return false;
}

function clearRow(){
    for(var rows = 0; rows < gameBoardColumns - 1; rows++){
        while(gameBoardSquared.every(k => k[rows].squareColor == "blue")){
            for(var i = 0; i < gameBoardSquared.length; i++){
                gameBoardSquared[i].splice(rows, 1);
            }
            for(var i = 0; i < gameBoardSquared.length; i++){
                gameBoardSquared[i].unshift(new GridBlock("white", i, rows));
            }
        console.log("clearRow(): ");
        console.log(gameBoardSquared);
        }
    }
}

Я думаю, что Существует проблема с центром вращения, то есть положением onet в исходном зелье тетромино, а не в текущем центре тетромино. Но, может быть, вы, ребята, могли бы помочь мне лучше?

Решение, предложенное Tecnogirl: я перемещаю все блоки, из которых получится тетромино (то есть весь массив тетро), но окрашиваю только те, которые на самом деле используется (те, которые находятся под тетромино). Удалил функцию collisionDetection () и поместил ее часть в функции moveTetrominoesLeft (), moveTetrominoesRight (), tetrominoesSlowFall (). Вот часть, которую я изменил:

    function moveTetrominoesLeft(){
    if(tetrominoes.some(k => k.x - 1 < 0) || tetrominoes.some(k => k.squareColor !== "white" && gameBoardSquared[k.x-1][k.y].squareColor !== "white")){
        for(let i of tetrominoes){
            i.drawBlock();
        }
    }
    else{
        for(let i of tetro){
            i.undrawBlock();
            i.moveLeft();
        }
        for(let i of tetrominoes){
            i.drawBlock();
        }
    }
}

function moveTetrominoesRight(){
    if(tetrominoes.some(k => k.x + 1 > gameBoardSquared.length-1) || tetrominoes.some(k => k.squareColor !== "white" && gameBoardSquared[k.x+1][k.y].squareColor !== "white")){
        for(let i of tetrominoes){
            i.drawBlock();
        }
    }
    else{
        for(let i of tetro){
            i.undrawBlock();
            i.moveRight();
        }
        for(let i of tetrominoes){
            i.drawBlock();
        }
    }
}

function tetrominoesSlowFall(){
    const topBoardBorder = 3;
    for(var i of tetrominoes){
        if(tetrominoes.some(k => k.squareColor !== "white" && gameBoardSquared[k.x][k.y].squareColor !== "white" && tetrominoes.some(k => k.y < topBoardBorder))){
            console.log("Game Over");
            gameOver = true;
        }
    }
    if(tetrominoes.some(k => k.y > playableGameBoardLength-1)){
        for(var i of tetrominoes){
            i.drawBlock();
            gameBoardSquared[i.x][i.y] = i;
        }
        isCollision = true;
    }
    else if(tetrominoes.some(k => k.squareColor !== "white" && gameBoardSquared[k.x][k.y+1].squareColor !== "white")){
        for(var i of tetrominoes){
            i.drawBlock();
            gameBoardSquared[i.x][i.y] = i;
        }
        isCollision =  true;
    }
    for(let i of tetro){
        i.undrawBlock();
        i.slowFall();
    }
    for(let i of tetrominoes){
        i.drawBlock();
    }
}

, а также в основной игре l oop, есть некоторые изменения (так как больше нет collisionDetection ():

function updateGameBoard(){
    if(!gameOver){
        colourTetromino();
        if(isCollision){
            clearRow();
            drawUpdatedGameBoard();
            makeNewRandomTetromino();
            isCollision = false;
        }
        else{
            tetrominoesSlowFall();
            drawUpdatedGameBoard();
        }
    }
    else{
        clearInterval(myInterval);
        alert("Game Over");
    }

}

function startGame(key){

    if (key === "Enter"){
        myInterval;
        drawSquaredGameBoard();
        makeNewRandomTetromino();
    }

    else if (key==="ArrowUp"){
        rotateTetromino();
    }

    else if (key==="ArrowLeft"){
        moveTetrominoesLeft();
    }

    else if (key==="ArrowRight"){
        moveTetrominoesRight();
    }

    else if (key==="ArrowDown"){
        updateGameBoard();
    }

    else
        console.log("Psst, press 'Enter' to start");
}

1 Ответ

1 голос
/ 21 апреля 2020

Сначала вы определяете свои вращающиеся позиции как массив базовых блоков. Это массив ссылок на каждый блок Basi c, который составляет повернутую позицию.

Когда вы выполняете block.moveLeft (), вы изменяете значение x на число, отличное от исходного. Это означает, что объекты, сохраненные в массиве каждой позиции, изменились на новое значение x, поэтому при попытке поворота позиции больше не имеют смысла.

Пример:

Посмотрите на tetrominoS. Его первая позиция

tetrominoS[0] = [tetro[0], tetro[4], tetro[5], tetro[9]] // the position you first defined

В памяти:

tetro[0] = ссылка на BasicBlock (x = 4, y = 0)

tetro[4] = ссылка на BasicBlock (x = 4, y = 1)

tetro[5] = ссылка на BasicBlock (x = 5, y = 1)

tetro[9] = ссылка на BasicBlock (x = 5, y = 2)

Затем вы делаете: moveLeft () (например)

Перемещение влево изменяет все значения x на x-1, поэтому вы делаете

BasicBlock (x = 4, y = 0).x--; tetro[0], теперь указывающее на BasicBlock (x = 3, y = 0)

BasicBlock (x = 4, y = 1).x--; tetro[4] теперь указывает на BasicBlock (x = 3, y = 1)

BasicBlock (x = 5, y = 1).x--; tetro[5] теперь указывает на BasicBlock (x = 4, y = 1)

BasicBlock (x = 5, y = 2).x--; tetro[9] теперь указывает на BasicBlock (x = 4, y = 2)

Тогда вы поверните:

следующая позиция tetrominoS равна tetrominoS[1], что составляет

tetrominoS[1] = [tetro[5], tetro[6], tetro[8], tetro[9]];

, но помните, что tetro [5] и tetro [9] были изменены! Таким образом, мы получаем:

tetrominoS[1] = [BasicBlock (x = 4, y = 1), tetro[6] (unchanged), tetro[8] (unchanged), BasicBlock (x = 4, y = 2)];

, что не то, что вам нужно.

Решение:

Вместо изменения значения X блоков, когда вы хотите переместить кусок слева просто удалите цвет текущего блока и нарисуйте цвет рядом с ним.

...