Search code examples
javascriptarraysobjectcanvastetris

getting undefined at random times


i will try to add only relevant code but just in case its needed full page is here, and feel free to check it out on github as well.

i am building a tetris game using canvas/javascript and part of it

    //drop the falling piece by one space
function dropByOne(){
        //loop through the four squares that make up the piece
    for ( i = 3; i > -1; i-- ) {
            //empty old spot of piece
        board[ fallingPiecePos[i].y ][ fallingPiecePos[i].x ] = 0;
            //drop position place-holder by one row
        fallingPiecePos[i].y++;
            //add square to new spot
        board[ fallingPiecePos[i].y ][ fallingPiecePos[i].x ] = fallingPiece;
    }
}

board is a 20*10 array, fallingPiecePos is a array of objects with numerical x and y values, i.e. [{y:0,x:4},{y:0,x:5},{y:0,x:6},{y:0,x:7}] (line piece) or [{y:0,x:4},{y:0,x:5},{y:1,x:4},{y:1,x:5}] (square) that are rendered into board with the following code:

for ( i = 0; i < 4; i++ ) {
    board[ fallingPiecePos[i].y ][ fallingPiecePos[i].x ] = fallingPiece;
}

fallingPiece is a randomly assigned number (1-7) used by canvas to render the piece as the right color.

hope thats clear enough, now the problem is that whenever fallingPiece has a value it has had before i get

TypeError: board[fallingPiecePos[i].y] is undefined
[Break On This Error]   

board[ fallingPiecePos[i].y ][ fallingPiecePos[i].x ] = fallingPiece;

(board[ fallingPiecePos[i].y ][ fallingPiecePos[i].x ] = fallingPiece; is the last line of above code-block)

i have a function nothingIsBelow() which checks if the piece has reached the bottom, so i am pretty stumped as to why this is happening.

edit

i wasnt clear enough on this point before it works fine the first 3-4 pieces (aside for piece collision protection) and only gives me above error when fallingPiece has a previously held value

edit

it seems that the issue is like this i have a array shapes

var shapes = [
    [{y:0,x:4},{y:0,x:5},{y:0,x:6},{y:0,x:7}],
    [{y:0,x:4},{y:0,x:5},{y:0,x:6},{y:1,x:4}],
    [{y:0,x:4},{y:0,x:5},{y:0,x:6},{y:1,x:5}],
    [{y:0,x:4},{y:0,x:5},{y:0,x:6},{y:1,x:6}],
    [{y:0,x:4},{y:0,x:5},{y:1,x:4},{y:1,x:5}],
    [{y:0,x:4},{y:0,x:5},{y:1,x:3},{y:1,x:4}],
    [{y:0,x:4},{y:0,x:5},{y:1,x:5},{y:1,x:6}]
];

and i have a line of code assigning a shape to a new piece

fallingPiecePos = shapes[fallingPiece - 1];

it seems that when i later refer to fallingPiecePos and change the value (fallingPiecePos[i].y++;), it changes the value in shapes as well

in simple terms the following code

var myArray = [
     [{a:0,b:1},{a:1,b:1}],
     [{a:0,b:0},{a:1,b:0}]
];

var foo = myArray[0];

foo[0].a++;
console.log(myArray[0][0][a]);

will give me 1 because not only foo but also myArray was updated, so how can i make a variable which holds a new array (foo) holding the values of myArray[0] and can be updated without updating myArray[0].


Solution

  • You are modifying your shapes array. When a particular piece falls and you update its position you actually update that array as opposed to just fallingPiecePos exclusively. This means that when piece n falls the first time, it stops at row board[19], but when it is chosen again it ends up in board[20], which does not exist.

    You can check this by checking the contents of your shapes array when you run the game - note that the positions change. To fix this you'd need to either avoid modifying your array of shapes for each piece or resetting the array values each time a piece is chosen.

    Example:

    function writePiece() { 
        var copy = JSON.parse(JSON.stringify(shapes)); 
        fallingPiecePos = copy[fallingPiece - 1]; 
        for ( i = 0; i < 4; i++ ) { 
            board[ fallingPiecePos[i].y ][ fallingPiecePos[i].x ] = fallingPiece; 
        } 
    }