canvas 为什么不绘制多张图片

Why doesn't canvas draw multiple images

我有一个问题,canvas 只画了一张我让他画的图像。我已经看过代码并检查了所有内容,一切都很好,但 drawImage 或 image.onload 函数没有。 idk 为什么它这样做导致它应该在每次调用时绘制图像但它没有。它只是绘制了 1 次然后就完成了。也许我做错了什么,但在我看到它应该工作之后;

const canvas = document.getElementById("myCanvas")
const ctx = canvas.getContext("2d")


class Cell {
    constructor(x, y, w) {
        this.x = x
        this.y = y
        this.w = w
        this.bomb = false
        this.revealed = false
    }
    show() {
        const cell = new Path2D();
        cell.rect(this.x, this.y, this.w, this.w);
        ctx.stroke(cell);
        this.cell = cell;
    }
}

const w = canvas.width
const h = canvas.height
const ColumnRow = w / 15
const cells = []
const bombs = 5
const bombPosition = []
let checked = true

const arr = [
    [-1, 1],
    [0, 1],
    [1, 1],
    [1, 0],
    [1, -1],
    [0, -1],
    [-1, -1],
    [-1, 0]
]

function setup() {
    for (let x = 0; x < w - 1; x += ColumnRow) {
        for (let y = 0; y < h - 1; y += ColumnRow) {
            cells.push(new Cell(x, y, ColumnRow))
        }
    }
}

function drawCells() {
    for (let c of cells) {
        c.show()
    }
}

function numOfBombs() {
    for (let i = 0; i < bombs; i++) {
        if (bombPosition.length < bombs) {
            let randomX = Math.floor(Math.random() * w / ColumnRow) * ColumnRow
            let randomY = Math.floor(Math.random() * h / ColumnRow) * ColumnRow

            for (let j = 0; j < bombPosition.length; j++) {
                if (bombPosition[j].x == randomX && bombPosition[j].y == randomY) {
                    numOfBombs()
                }
            }
            bombPosition.push({ x: randomX, y: randomY });
        } else {
            break;
        }
    }
}

function drawBomb() {
    let img = new Image();
    img.onload = function () {
        for (let i = 0; i < bombPosition.length; i++) {
            ctx.drawImage(img, bombPosition[i].x, bombPosition[i].y, ColumnRow, ColumnRow)
        }
    };
    img.src = "https://raw.githubusercontent.com/americosp/Minesweeper/master/Minesweeper/images/mine.png";

    //set cell bomb to true
    for (let i = 0; i < cells.length; i++) {
        for (let j = 0; j < bombPosition.length; j++) {
            if (cells[i].x == bombPosition[j].x && cells[i].y == bombPosition[j].y)
                cells[i].bomb = true
        }
    }
}

function drawNumbers() {
    for (let i = 0; i < cells.length; i++) {
        let totalBombs = 0;
        if (!cells[i].bomb) {
            for (let j = 0; j < arr.length; j++) {
                tmpx = cells[i].x + arr[j][0] * ColumnRow // 0 x
                tmpy = cells[i].y + arr[j][1] * ColumnRow // 1 y
                // console.log(tmpx);
                for (let k = 0; k < cells.length; k++) {
                    if (cells[k].x == tmpx && cells[k].y == tmpy) {
                        if (cells[k].bomb) {
                            totalBombs++;
                        }
                        break;
                    }
                }
            }
        }
        if (totalBombs > 0) {
            test(totalBombs, cells[i].x, cells[i].y)
        }
    }
}

let images = []

for (let i = 1; i < 9; i++) {

    let img = new Image()
    images.push(img)
}


function test(totalBombs, x, y) {
    images[totalBombs].onload = function () {
            ctx.drawImage(images[totalBombs], x, y, ColumnRow, ColumnRow)
    }

    images[totalBombs].src = `https://raw.githubusercontent.com/americosp/Minesweeper/master/Minesweeper/images/number_${totalBombs}.png`
}

function draw() {
    drawCells()
    if (checked) {
        drawBomb()
        drawNumbers()
        // coverCell()
        checked = false
    }
    requestAnimationFrame(draw)
}

function update() {
    setup()
    numOfBombs()
}
update()
draw()
// bombTest()
<canvas id="myCanvas" width="600" height="600"></canvas>

问题是您正在尝试加载图像并同时绘制它们。因此,当图像仍在加载时,您正在为每个数字替换 onload 函数。这是 Promise 的用武之地:

const canvas = document.getElementById("myCanvas")
const ctx = canvas.getContext("2d")


class Cell {
    constructor(x, y, w) {
        this.x = x
        this.y = y
        this.w = w
        this.bomb = false
        this.revealed = false
    }
    show() {
        const cell = new Path2D();
        cell.rect(this.x, this.y, this.w, this.w);
        ctx.stroke(cell);
        this.cell = cell;
    }
}

const w = canvas.width
const h = canvas.height
const ColumnRow = w / 15
const cells = []
const bombs = 5
const bombPosition = []
let checked = true

const arr = [
    [-1, 1],
    [0, 1],
    [1, 1],
    [1, 0],
    [1, -1],
    [0, -1],
    [-1, -1],
    [-1, 0]
]

function setup() {
    for (let x = 0; x < w - 1; x += ColumnRow) {
        for (let y = 0; y < h - 1; y += ColumnRow) {
            cells.push(new Cell(x, y, ColumnRow))
        }
    }
}

function drawCells() {
    for (let c of cells) {
        c.show()
    }
}

function numOfBombs() {
    for (let i = 0; i < bombs; i++) {
        if (bombPosition.length < bombs) {
            let randomX = Math.floor(Math.random() * w / ColumnRow) * ColumnRow
            let randomY = Math.floor(Math.random() * h / ColumnRow) * ColumnRow

            for (let j = 0; j < bombPosition.length; j++) {
                if (bombPosition[j].x == randomX && bombPosition[j].y == randomY) {
                    numOfBombs()
                }
            }
            bombPosition.push({ x: randomX, y: randomY });
        } else {
            break;
        }
    }
}

function drawBomb() {
    let img = new Image();
    img.onload = function () {
        for (let i = 0; i < bombPosition.length; i++) {
            ctx.drawImage(img, bombPosition[i].x, bombPosition[i].y, ColumnRow, ColumnRow)
        }
    };
    img.src = "https://raw.githubusercontent.com/americosp/Minesweeper/master/Minesweeper/images/mine.png";

    //set cell bomb to true
    for (let i = 0; i < cells.length; i++) {
        for (let j = 0; j < bombPosition.length; j++) {
            if (cells[i].x == bombPosition[j].x && cells[i].y == bombPosition[j].y)
                cells[i].bomb = true
        }
    }
}

function drawNumbers() {
    for (let i = 0; i < cells.length; i++) {
        let totalBombs = 0;
        if (!cells[i].bomb) {
            for (let j = 0; j < arr.length; j++) {
                tmpx = cells[i].x + arr[j][0] * ColumnRow // 0 x
                tmpy = cells[i].y + arr[j][1] * ColumnRow // 1 y
                // console.log(tmpx);
                for (let k = 0; k < cells.length; k++) {
                    if (cells[k].x == tmpx && cells[k].y == tmpy) {
                        if (cells[k].bomb) {
                            totalBombs++;
                        }
                        break;
                    }
                }
            }
        }
        if (totalBombs > 0) {
            test(totalBombs, cells[i].x, cells[i].y)
        }
    }
}

let images = []

for (let i = 1; i < 9; i++) {
    images.push(new Promise((resolve, reject) => 
    {
      const img = new Image();
      img.onload = () => resolve(img);
      img.onerror = () => reject(img);
      img.src = `https://raw.githubusercontent.com/americosp/Minesweeper/master/Minesweeper/images/number_${i}.png`;
    }))
}


function test(totalBombs, x, y) {
    images[totalBombs-1].then(function (img) {
            ctx.drawImage(img, x, y, ColumnRow, ColumnRow)
    });
}

function draw() {
    drawCells()
    if (checked) {
        drawBomb()
        drawNumbers()
        // coverCell()
        checked = false
    }
    requestAnimationFrame(draw)
}

function update() {
    setup()
    numOfBombs()
}
update()
draw()
// bombTest()
<canvas id="myCanvas" width="600" height="600"></canvas>