In this new installment of the series, we will see how to display the board and the piece that is currently going down on the screen. To do this, we will have to draw it in the browser, and the option we have to do so is the Canvas HTML element.
class Canvas { static SEPARATION = 2; #_painting = false; #_element = null; #_board = null; #_piece = null; constructor(element, board) { element.width = 5 ( board.cols * Board.PIXEL_SIZE ); element.height = 5 ( board.rows * Board.PIXEL_SIZE ); this._board = board; this._element = element; } // más cosas... }
This class Canvas represents the HTML element of the same name, which is passed as a parameter in the constructor. Since you are going to draw the board, it is also passed as a parameter, in order to access the points to draw.
The first thing it does is size the element Canvas to accommodate the board, according to the dimensions that the board itself reports through its properties cols and rows. The board also tells us how many pixels makes up a point of each piece or each cell of the board, through PIXEL_SIZE.
Let's stop detours. We have to paint the board and the piece that is descending at that moment, right? Well, let's get to it.
class Canvas { // más cosas... paint() { if ( this._painting ) { return; } const ctx = this.element.getContext( "2d" ); const SEP = Canvas.SEPARATION; this._painting = true; this.clear(); this.paintBoard( ctx, SEP ); this.paintPiece( ctx, SEP ); this._painting = false; } clear() { const ctx = this.element.getContext( "2d" ); ctx.clearRect( 0, 0, this.element.width, this.element.height ); } }
First we take the context for 2D, which will allow us to draw on the canvas. Out of curiosity, there is also a context for 3D, which is based on WebGL.
We have some guards (_painting), which prevent several threads from executing the method at the same time (at different points), at a given time. This could happen if the method was executed for longer than the time between redraws. Although well, in that case we would have many other problems...
The next step is to delete what was on the screen in the previous redraw (frame). We do this with the clear() method, which uses clearRect() to delete the image on the canvas.
And then we paint the board, and then the piece that comes down at that moment. Well, that would be it. Ale, delivery completed.
I said no. Let's see how the board and the piece are painted. The first thing is to paint the board. SEP is the separation that we will leave between the pieces and the board square. This box is the first thing we draw in the code paragraph titled Draw frame. It is a simple rectangle that can be drawn with strokeRect(), which accepts four parameters with the position of the upper left vertex, and then its width and height.
class Canvas { // más cosas... paintBoard(ctx, SEP) { // Draw frame ctx.strokeWidth = 1; ctx.strokeStyle = this.board.color; ctx.strokeRect( 1, 1, this.element.width - 1, this.element.height -1 ); // Draw board for(let numRow = 0; numRowNext comes a nested loop (rows and columns), so we'll see which of the cells on the board have content (an integer 1, versus an integer 0), and then draw a small square with side PIXEL_SIZE.
Thus, the first loop loops through the rows until Board.rows. We then obtain the complete row with the method getRow(), to traverse it with the inner loop, until Board.cols.
So, given a cell in row/column f/c, Board.getCell(f, c), and taking into account that JavaScript has a constructor for Boolean that accepts an integer that with any value except 0, means true, we paint a square with side PIXEL_SIZE. So, to know where to paint the row f, we have to multiply by PIXEL_SIZE and add the separation between the board box and the first cell. Since they are square, we will find the column c in the same way: SEP (c * PIXEL_SIZE).
Painting the piece
We do something similar with the pieces. By having a shape (shape), which is nothing more than a matrix, we will again have two loops, the outer one for rows and the inner one for columns.
class Canvas { // más cosas... paintPiece(ctx, SEP) { const SHAPE = this.piece.shape; for(let numRow = 0; numRowAgain, if we find a 1, we will paint a square with side PIXEL_SIZE. The position to paint each square that makes up the piece is given by the row/column position of the piece itself (Piece.row/Piece. cabbage). You have to multiply this by PIXEL_SIZE and add the separation with the box.
Right now, what we'll be able to see is pretty... bland. The board is empty, and we don't have a game loop, so the pieces don't even go down. We will discuss that topic in the next installment, so that we can begin to see something similar to the image above.
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3