簡體   English   中英

在多個畫布上繪制的HTML5圖像沒有顯示在其中一個上

[英]HTML5 Drawing on multiple canvases images don't show up on one of them

研究一種模擬棋盤的概念驗證的面向對象的javascript項目。 目前,我已經設置了四個畫布,每個畫布設置為兩個不同的面板和兩個“側欄”畫布,這些畫布顯示了當前的回合以及相關游戲的所有棋子列表。 這是當前情況的屏幕截圖:

http://i.imgur.com/GPoVkK2.png

問題是,無論出於何種原因,第二個側邊欄中的元素都是在第一個側邊欄中繪制的,而我一直無法弄清原因。

以下是該項目的所有代碼文件,它們已盡我所能進行解釋:

index.html

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript" src="scripts/Marker.js"></script>
    <script type="text/javascript" src="scripts/TurnMarker.js"></script>
    <script type="text/javascript" src="scripts/GameToken.js"></script>
    <script type="text/javascript" src="scripts/GameBoard.js"></script>
    <script type="text/javascript" src="scripts/Validation.js"></script>
    <script type="text/javascript" src="scripts/Main.js"></script>
</head>
<body onLoad=initialize()>

<canvas id="gameBoard" width="400" height="400" style="border:1px solid #000000; position=relative;">
Your browser doesn't support HTML5 canvas.
</canvas>
<canvas id="sideBar" width="50" height="400" style="border:1px solid #000000; position=relative;">
</canvas>

<canvas id="gameBoardWizard" width="400" height="400" style="border:1px solid #000000; position=relative;">
Your browser doesn't support HTML5 canvas.
</canvas>
<canvas id="sideBarWizard" width="50" height="400" style="border:1px solid #000000; position=relative;">
</canvas>
</body>
</html>

Main.js

/*** Chess Board Program
* Author: Alex Jensen
* CS 3160: Concepts of Programming Languages
* 12/5/14
*/

var gameBoards = [];

/** Initialize is called when the page loads (set up in the HTML below)
*  
*/
function initialize()
{
    createBoard("gameBoard", "sideBar" ,8 , 8);
    createBoard("gameBoardWizard", "sideBarWizard" ,8, 8);
    // setInterval is a super awesome javascript function and I love it.
    setInterval(function() {draw()}, 100);
}

/** CreateBoard is a helper function for Initialize that is responsible for loading a game board into the list of game boards.
*   boardID= String title of the HTML5 table within the HTML index file.
*/
function createBoard(boardID, sideBarID, numSquaresRows, numSquaresColumns)
{
    var initBoardValidator = [];
    for (var i=0;i<numSquaresColumns;i++) 
    {
        initBoardValidator[i] = [];
        for (var j=0;j<numSquaresRows;j++) 
        {
            initBoardValidator[i][j] = null;
        }
    }

    var gameBoard = new GameBoard(boardID, sideBarID, numSquaresRows, numSquaresColumns, initBoardValidator, [], []);   
    gameBoard.tokens = createDefaultTokens(gameBoard);
    gameBoard.takenTokens = createDefaultTakeMarkers(gameBoard);
    gameBoards[gameBoards.length] = gameBoard;
}

/** Helper function for initialize which creates all the tokens and stores them in appropriate locations.
*
*/
function createDefaultTokens(game)
{
    tokens = [];
    // Create Pawns
    for (var i = 0; i < 8; i++)
    {
        tokens[tokens.length] = new GameToken(game, "WP", 1, 'images/wp.png', i * game.squareWidth, game.squareHeight, pawnValidator);
        tokens[tokens.length] = new GameToken(game, "BP", 2, 'images/bp.png', i * game.squareWidth, game.squareHeight * 6, pawnValidator);
    }
    // Create other pieces
    tokens[tokens.length] = new GameToken(game, "WR", 1, 'images/wr.png', 0, 0, rookValidator);
    tokens[tokens.length] = new GameToken(game, "WN", 1, 'images/wn.png', game.squareWidth, 0, knightValidator);
    tokens[tokens.length] = new GameToken(game, "WB", 1, 'images/wb.png', game.squareWidth * 2, 0, bishopValidator);
    tokens[tokens.length] = new GameToken(game, "WQ", 1, 'images/wq.png', game.squareWidth * 3, 0, queenValidator);
    tokens[tokens.length] = new GameToken(game, "WK", 1, 'images/wk.png', game.squareWidth * 4, 0, kingValidator);
    tokens[tokens.length] = new GameToken(game, "WB", 1, 'images/wb.png', game.squareWidth * 5, 0, bishopValidator);
    tokens[tokens.length] = new GameToken(game, "WN", 1, 'images/wn.png', game.squareWidth * 6, 0, knightValidator);
    tokens[tokens.length] = new GameToken(game, "WR", 1, 'images/wr.png', game.squareWidth * 7, 0, rookValidator);
    tokens[tokens.length] = new GameToken(game, "BR", 2, 'images/br.png', 0, game.squareWidth * 7, rookValidator);
    tokens[tokens.length] = new GameToken(game, "BN", 2, 'images/bn.png', game.squareWidth, game.squareHeight * 7, knightValidator);
    tokens[tokens.length] = new GameToken(game, "BB", 2, 'images/bb.png', game.squareWidth * 2, game.squareHeight * 7, bishopValidator);
    tokens[tokens.length] = new GameToken(game, "BQ", 2, 'images/bq.png', game.squareWidth * 3, game.squareHeight * 7, queenValidator);
    tokens[tokens.length] = new GameToken(game, "BK", 2, 'images/bk.png', game.squareWidth * 4, game.squareHeight * 7, kingValidator);
    tokens[tokens.length] = new GameToken(game, "BB", 2, 'images/bb.png', game.squareWidth * 5, game.squareHeight * 7, bishopValidator);
    tokens[tokens.length] = new GameToken(game, "BN", 2, 'images/bn.png', game.squareWidth * 6, game.squareHeight * 7, knightValidator);
    tokens[tokens.length] = new GameToken(game, "BR", 2, 'images/br.png', game.squareWidth * 7, game.squareHeight * 7, rookValidator);
    return tokens;
}

function createDefaultTakeMarkers(game)
{
    var takenTokens = [];
    // Create Pawns
    for (var i = 0; i < 8; i++)
    {
        takenTokens[takenTokens.length] = new Marker("WP", 1, 'images/wp.png', 5, (i * 20) + 5);
        takenTokens[takenTokens.length] = new Marker("BP", 1, 'images/bp.png', 5, game.sideBar.height - ((i * 20) + 25));
    }

    // Create other pieces
    takenTokens[takenTokens.length] = new Marker("WR", 1, 'images/wr.png', 25, 5);
    takenTokens[takenTokens.length] = new Marker("WN", 1, 'images/wn.png', 25, 25);
    takenTokens[takenTokens.length] = new Marker("WB", 1, 'images/wb.png', 25, 45);
    takenTokens[takenTokens.length] = new Marker("WQ", 1, 'images/wq.png', 25, 65);
    takenTokens[takenTokens.length] = new Marker("WK", 1, 'images/wk.png', 25, 85);
    takenTokens[takenTokens.length] = new Marker("WB", 1, 'images/wb.png', 25, 105);
    takenTokens[takenTokens.length] = new Marker("WN", 1, 'images/wn.png', 25, 125);
    takenTokens[takenTokens.length] = new Marker("WR", 1, 'images/wr.png', 25, 145);
    takenTokens[takenTokens.length] = new Marker("BR", 1, 'images/br.png', 25, game.sideBar.height - 25);
    takenTokens[takenTokens.length] = new Marker("BN", 1, 'images/bn.png', 25, game.sideBar.height - 45);
    takenTokens[takenTokens.length] = new Marker("BB", 1, 'images/bb.png', 25, game.sideBar.height - 65);
    takenTokens[takenTokens.length] = new Marker("BQ", 1, 'images/bq.png', 25, game.sideBar.height - 85);
    takenTokens[takenTokens.length] = new Marker("BK", 1, 'images/bk.png', 25, game.sideBar.height - 105);
    takenTokens[takenTokens.length] = new Marker("BB", 1, 'images/bb.png', 25, game.sideBar.height - 125);
    takenTokens[takenTokens.length] = new Marker("BN", 1, 'images/bn.png', 25, game.sideBar.height - 145);
    takenTokens[takenTokens.length] = new Marker("BR", 1, 'images/br.png', 25, game.sideBar.height - 165);

    console.log(takenTokens);
    return takenTokens;
}

/** Helper function for draw responsible for drawing each gameBoard
 *
 */
function draw()
{
    for (var i = 0; i < gameBoards.length; i++)
    {
        gameBoards[i].draw();
    }
}

GameBoard.js

function bind(scope, fn) {
   return function() {
      return fn.apply(scope, arguments);
   }
}

function GameBoard(boardID, sideBarID, numSquareRows, numSquareColumns, validator, tokens, takenTokens)
{   
    this.game = document.getElementById(boardID);
    this.gameContext = this.game.getContext("2d");
    var gamerect = this.game.getBoundingClientRect();
    //this.gameContext.translate(gamerect.left, gamerect.top);
    this.sideBar = document.getElementById(sideBarID);
    this.sideBarContext = sideBar.getContext("2d");
    var siderect = this.sideBar.getBoundingClientRect();
    //this.sideBarContext.translate(siderect.left, siderect.top);
    this.boardWidth = this.game.width;
    this.boardHeight = this.game.height;
    this.squareWidth = this.boardWidth / numSquareColumns;
    this.squareHeight = this.boardHeight / numSquareRows;
    if (this.squareHeight % 1 != 0) alert("WARNING: squareHeight is not a solid number, the program might not work correctly! Always ensure that the board height divided by the number of rows comes out as a whole number.");
    if (this.squareWidth % 1 != 0) alert("WARNING: squareWidth is not a solid number, the program might not work correctly! Always ensure that the board width divided by the number of columns comes out as a whole number.");

    this.validator = validator;
    this.tokens = tokens;
    this.takenTokens = takenTokens;


    this.turnOrderToken = new TurnMarker('images/wturn.png', 'images/bturn.png', siderect.width / 2 - 20, siderect.height / 2 - 20, 40, 40);

    this.activePlayer = 1; // Whose turn is it?
    this.selectedToken = null; // What token is currently being dragged around?
    this.takePiece = null; 

    // Event listeners function nearly identically to how they are handled in C#.
    this.game.addEventListener("mousedown", bind(this, this.onMouseDown), false);
    this.game.addEventListener("mousemove", bind(this, this.onMouseMove), false);
    this.game.addEventListener("mouseup", bind(this, this.onMouseUp), false);

    /** Helper function for drawBoard responsible for swapping between two colors whenever it is called.
    *
    */
    this.swapColor = function swapColor()
    {
        if (this.gameContext.fillStyle != '#0000ff')
        {
            this.gameContext.fillStyle = '#0000ff';
        } else {
            this.gameContext.fillStyle = '#ffffff';
        }
    }

    /** Responsible for drawing all the tokens
    *
    */
    this.drawTokens = function drawTokens()
    {
        for (var i = 0; i < this.tokens.length; i++)
        {
            var token = this.tokens[i];
            this.gameContext.drawImage(token.image, token.x, token.y, this.squareWidth, this.squareHeight);
        }
    }

    /** Responsible for drawing the checkerboard.
    *
    */
    this.drawBoard = function drawBoard()
    {
        this.gameContext.clearRect(0, 0, this.boardWidth, this.boardHeight);
        for (var i = 0; i < this.boardWidth; i += this.squareWidth) 
        {
            for (var j = 0; j < this.boardHeight; j += this.squareHeight) 
            {
            this.swapColor();
            this.gameContext.fillRect(i,j,this.squareWidth,this.squareHeight);
            }
        this.swapColor();
        }
    }

    this.drawMarkers = function drawMarkers()
    {
        for (var i = 0; i < this.takenTokens.length; i++)
        {
            var marker = this.takenTokens[i];
            console.log(marker.image + " " + marker.x + " " +  marker.y + " " +  marker.width + " " +  marker.height);
            if (marker.visible)
            {
                this.sideBarContext.drawImage(marker.image, marker.x, marker.y, marker.width, marker.height);
            }
        }
    }

    this.drawTurnMarker = function drawTurnMarker()
    {
        if (this.activePlayer == 1)
        {
            console.log(this.turnOrderToken.player1Image + " " + this.turnOrderToken.x + " " +  this.turnOrderToken.y + " " +  this.turnOrderToken.width + " " +  this.turnOrderToken.height);
            this.sideBarContext.drawImage(this.turnOrderToken.player1Image, this.turnOrderToken.x, this.turnOrderToken.y, this.turnOrderToken.width, this.turnOrderToken.height);
        }
        else
        {
            this.sideBarContext.drawImage(this.turnOrderToken.player2Image, this.turnOrderToken.x, this.turnOrderToken.y, this.turnOrderToken.width, this.turnOrderToken.height);
        }
    }

    /** Container method which runs all draw functions on the board.
     *
     */
    this.draw = function draw()
    {
        this.drawBoard();
        this.drawTokens();
        this.drawMarkers();
        this.drawTurnMarker();
    }

    /** Removes tokens from the board and adds them to the list of captured pieces in the sidebar
    *
    */
    this.capture = function capture(token)
    {
        for (var i  = 0; i < this.tokens.length; i++)
        {
            var takenToken = this.tokens[i];
            if (takenToken.x == token.x && takenToken.y == token.y)
            {
                this.tokens.splice(i, 1);
                break;
            }
        }
        for (var i  = 0; i < this.takenTokens.length; i++)
        {
            var takenToken = this.takenTokens[i];
            if (takenToken.name == token.name && takenToken.visible == false)
            {
                console.log(takenToken);
                takenToken.visible = true;
                break;
            }
        }
    }
}

/** Event that fires when the mouse button is released
*  Listeners in gameBoard
*/
GameBoard.prototype.onMouseUp = function (event)
{
    if (this.selectedToken != null)
    {
        var gridx = Math.round(this.selectedToken.x / this.squareWidth);
        var gridy = Math.round(this.selectedToken.y / this.squareHeight);

        // Snap to the nearest tile
        this.selectedToken.x = (gridx * this.squareWidth);
        this.selectedToken.y = (gridy * this.squareHeight);

        // Check to see if the move that was made is legal
        this.takePiece = this.validator[gridx][gridy];
        if (this.selectedToken.movementValidator())
        {
            // If it was, then advance the turn
            if (this.activePlayer == 1)
            {
                this.activePlayer = 2;
            } 
            else 
            {
                this.activePlayer = 1;
            }
        } 
        else 
        {
            // Otherwise move the token back to where it was
            this.selectedToken.x = this.selectedToken.initX;
            this.selectedToken.y = this.selectedToken.initY;
        }

        // Wherever the token ends up, update the grid to reflect that.
        this.validator[this.selectedToken.initX / this.squareWidth][this.selectedToken.initY / this.squareHeight] = null;
        this.validator[this.selectedToken.x / this.squareWidth][this.selectedToken.y / this.squareHeight] = this.selectedToken;
        this.selectedToken = null;
    }
}

/**
 *
 */
GameBoard.prototype.onMouseDown = function(event)
{
    var rect = this.game.getBoundingClientRect();
    var mousePos = {x:event.clientX - rect.left, y:event.clientY - rect.top};
    for (var i = 0; i < this.tokens.length; i++)
    {
        token = this.tokens[i];
        // if you clicked this token and it's your turn
        if (mousePos.x > token.x && mousePos.y > token.y && mousePos.x < token.x + this.squareWidth && mousePos.y < token.y + this.squareHeight && token.player == this.activePlayer)
        {
            this.selectedToken = token;

            // Store where the token was before we picked it up. That way if we make an illegal move we can restore it to its initial location
            this.selectedToken.initX = token.x;
            this.selectedToken.initY = token.y;
        }
    }
}

/** Event that fires when the mouse position is updated
*  Listeners in gameBoard
*/
GameBoard.prototype.onMouseMove = function(event)
{
    if (this.selectedToken != null)
    {
        var rect = this.game.getBoundingClientRect();
        var mousePos = {x:event.clientX - rect.left, y:event.clientY - rect.top};
        this.selectedToken.x = mousePos.x - (this.squareWidth / 2);
        this.selectedToken.y = mousePos.y - (this.squareHeight / 2);
    }
}

Marker.js

/** Marker is a visual widget used to show taken pieces. 
*  player= The player associated with the marker
*  tokenImagePath= The valid path to the location of the marker texture
*  x,y= location of marker on the sidebar
*/
function Marker(name, player, markerPath, x, y)
{
    this.name = name;
    this.image = new Image();
    this.x = x;
    this.y = y;
    this.width = 20;
    this.height = 20;
    this.player = player;
    this.image.src = markerPath;
    this.visible = true;
}

GameToken.js

/** GameToken represents a chess piece. 
*  player= The player the chess piece belongs to
*  tokenImagePath= The valid path to the location of the chess piece texture
*  x,y= location of token on the board
*  movementValidator= Function to determine whether a move made by this token is legal or not. 
*  Validators are different for different types of tokens.
*/
function GameToken(game, name, player, tokenImagePath, x, y, movementValidator)
{
    this.game = game;
    this.name = name;
    this.image = new Image();
    this.x = x;
    this.y = y;
    game.validator[x / game.squareWidth][y / game.squareHeight] = this;
    this.player = player;
    this.image.src = tokenImagePath;
    this.movementValidator = movementValidator;
}

最后是一個WIP驗證腳本,以檢查合法行為

/** Specific validation code for Pawns.
*
*/
function pawnValidator()
{
    // Pawns are tricky to validate because they can move one square directly forward, but can't take the square directly
    // in front of them, and can only move diagonally when they can capture. In addition, they can move two squares 
    // forward as long as they're in starting position.
    if (this.takePiece != null)
    {
        // If the square we moved to has an enemy in it and we've made a legal move with the pawn to take that piece
        if ((this.takePiece.player != this.player && 
            (this.x == this.initX + this.squareWidth || this.x == this.initX - this.squareWidth) &&
            ((this.player == 1 && this.y == this.initY + this.squareHeight) ||
            (this.player == 2 && this.y == this.initY - this.squareHeight))))
        {
            // We're allowed to remove the token here because we've validated that the pawn has made the correct movement to take the piece.
            capture(takePiece);
            takePiece = null;
            return true;
        }
        else
        {
            takePiece = null;
            return false;
        }
    }
    // The pawn is not capturing, so check to see that the move it is making is legal
    else if (this.x == this.initX)
    {
        if (this.player == 1)
        {
            if ((this.y == this.initY + this.game.squareHeight) || (this.y == this.initY + (2*this.game.squareHeight)) && this.initY == (this.game.squareHeight))
            {
                return true;
            }
        }
        else if (this.y == this.initY - this.game.squareHeight || (this.y == this.initY - (2*this.game.squareHeight)) && this.initY == (6*this.game.squareHeight))
        {
            {
                return true;
            }
        }
    }
    return false;
}

/** Specific validation code for Rooks.
*
*/
function rookValidator()
{
    // First check if the movement made was legal for a rook (straight line)
    if (this.x == this.initX || this.y == this.initY)
    {
    // Next check if the movement made went through any other pieces
        if (lineValidation(this.initX, this.initY, this.x, this.y))
        {
            if (this.game.takePiece != null) 
            {
                this.game.capture(this.game.takePiece);
            }
            this.game.takePiece = null;
            return true;
        }
    }
    return false;
}

/** Specific validation code for Knights.
*
*/
function knightValidator()
{
    // First check if the movement made was legal for a knight using relative positioning
    var relativeX = Math.abs(this.x - this.initX) / this.game.squareWidth;
    var relativeY = Math.abs(this.y - this.initY) / this.game.squareHeight;
    if ((relativeX == 1 && relativeY == 2) || (relativeX == 2 && relativeY == 1))
    {
        // Knights can jump, so we don't need to validate the movement further
        if (this.game.takePiece != null) 
        {
            this.game.capture(this.game.takePiece);
        }
        takePiece = null;
        return true;
    }
}

/** Specific validation code for Bishops.
*
*/
function bishopValidator()
{
    // First check if the movement made was legal for a bishop (diagonal line)
    if (Math.abs(this.x - this.initX) == Math.abs(this.y - this.initY))
    {
        // Next check if the movement made went through any other pieces
        if (lineValidation(this.initX, this.initY, this.x, this.y))
        {
            if (takePiece != null) 
            {
                capture(takePiece);
            }
            takePiece = null;
            return true;
        }
    }
}

/** Specific validation code for Kings.
*
*/
function kingValidator()
{
    // First check if the movement made was legal for a king using relative positioning
    var relativeX = Math.abs(this.x - this.initX) / squareSize;
    var relativeY = Math.abs(this.y - this.initY) / squareSize;
    if ((relativeX == 1 && relativeY == 1) || (relativeX == 1 && relativeY == 0) || (relativeX == 0 && relativeY == 1))
    {
        // TODO: Check to see if the move puts the king in check. That's a little past the scope of this project but would make for a nice addition.
        if (takePiece != null) 
        {
            capture(takePiece);
        }
        takePiece = null;
        return true;
    }
}

/** Specific validation code for Queens.
*
*/
function queenValidator()
{
    // First check if the movement made was legal for a queen (diagonal line or straight line)
    if ((Math.abs(this.x - this.initX) == Math.abs(this.y - this.initY)) ||
    (this.x == this.initX || this.y == this.initY))
    {
        // Next check if the movement made went through any other pieces
        if (lineValidation(this.initX, this.initY, this.x, this.y))
        {
            if (takePiece != null) 
            {
                capture(takePiece);
            }
            takePiece = null;
            return true;
        }
    }
}

/** Checks each square traveled over a line to see if it has traveled through another piece
*  IMPORTANT: This function only works if the move is legal! If the move made is impossible in chess this function
*  will not work correctly!
*/
function lineValidation(startX, startY, endX, endY)
{
    while (startX != endX || startY != endY)
    {
        if (startX < endX) startX += squareSize;
        if (startY < endY) startY += squareSize;
        if (startX > endX) startX -= squareSize;
        if (startY > endY) startY -= squareSize;
        var checkTake = gameBoardValidator[startX / squareSize][startY / squareSize];
        if (checkTake != null && (startX != endX || startY != endY))
        {
            return false;
        }
    }
    return true;
}

兩種游戲都可以工作,但是第二個側面畫布中的UI元素似乎總是在第一個畫布中繪制。 有人看到我發瘋了嗎?

在您的GameBoard對象中,您嘗試從window.sideBar而不是this.sideBar獲取上下文(它應該在控制台中產生錯誤):

this.sideBarContext = sideBar.getContext("2d");

將該行更改為:

this.sideBarContext = this.sideBar.getContext("2d");
                      ^^^^

它應該工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM