【问题标题】:JavaScript Tetris tetrominoes move apart after movement and rotationJavaScript 俄罗斯方块 tetrominoes 在移动和旋转后分开
【发布时间】:2020-04-22 16:20:28
【问题描述】:

通过制作俄罗斯方块游戏来学习 JavaScript。

问题: 当我尝试移动(从起始位置向左、向右或向下)一块然后旋转它时,旋转的部分会伸展开来。当我回到起始位置时,一切正常。 此外,当我不旋转作品而仅将其向左/向右/向下移动时,一切都很好。 我认为我的旋转中心固定在网格上,而不是固定在一块上。

你可以在这里玩游戏:Here

这是我的 github:Here

临时控制:

输入和向上箭头后:开始游戏

左箭头:向左移动

右箭头:向右移动

向上箭头:旋转

向下箭头:向下移动一行

说明:

我的 tetrominoes 和我的网格由数组(基于类)组成。网格来自 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);
        }
    }
}

我认为旋转中心存在问题,即它定位在四骨牌的起始药水中,而不是在四骨牌的当前中心。但也许你们可以帮助我做得更好?

Tecnogirl 建议的解决方案: 我正在移动所有将制作 tetromino 的块(所以整个 tetro 阵列),但我只对实际使用的块着色(那些在 tetromino 下的块)。删除了 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();
    }
}

在主游戏循环中,也有一些变化(因为不再有碰撞检测():

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

【问题讨论】:

    标签: javascript arrays tetris


    【解决方案1】:

    您首先将您的旋转位置定义为一组基本块。这是对构成旋转位置的每个基本块的引用数组。

    当您执行 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值,只需将当前块的颜色去掉,然后在它旁边的块上绘制颜色即可。

    【讨论】:

    • 我假设是这样的,但无法命名。感谢您澄清问题。嗯,颜色变化的东西也会改变我对项目的整个概念。但这样做的好处是,我可以改变单独的四联骨牌的颜色,这是我下一步要做的事情。非常感谢您阅读我的代码,理解它并向我解释:-)。
    • 我会在 5 小时内解决我的问题 ;-)。但是我还有一个问题。如果我只移动颜色而不移动棋子,那么棋子还会在同一个地方吗?就像玩家会看到颜色发生变化,但棋子本身仍会直接向下移动。我们是不是搞错了?
    猜你喜欢
    • 1970-01-01
    • 2013-03-17
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多