You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Canvas绘图时,调用beginPath()和closePath()后仍无法设置不同fillStyle

解决Canvas元素颜色继承问题

我明白你遇到的困扰了——球总是跟着砖块的颜色走,没法用randomColor()生成专属的随机色。这其实是Canvas全局绘图状态特性加上你设置fillStyle的时机错误导致的,咱们一步步来修复:

问题根源拆解

你看原代码里的几个绘制函数,比如drawPaddle()和drawBricks(),都是先调用ctx.fill()再设置fillStyle——这完全搞反了顺序!Canvas的绘图属性(比如fillStyle)是先设置再生效的,先fill再改样式,等于这次绘制用的还是之前的全局样式,修改的样式只会影响下一次绘制。

另外,drawBall()里你在fill()之后才尝试设置fillStyle,这根本不会影响当前球的颜色;而且drawBricks()执行完后,全局fillStyle被设成了#00a6ff,下一次绘制球时,你没先给球设置专属颜色,自然就继承了砖块的颜色。

修改后的完整代码

我调整了fillStyle的设置顺序,还给球加了专门的颜色变量,方便碰撞时更新颜色:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 2;
var dy = -2;
var ballRadius = 10;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width - paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 3;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
// 新增:给球单独设置颜色变量
var ballColor = randomColor();

document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);

function randomColor() {
  var n = 16777215;
  var colorDec = rand(0, n);
  var colorHex = colorDec.toString(16);
  // 补全6位Hex,避免生成不完整的颜色代码
  return "#" + colorHex.padStart(6, '0');
}

function rand(min, max) {
  var min = min || 0, max = max || Number.MAX_SAFE_INTEGER;
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
  bricks[c] = [];
  for (var r = 0; r < brickRowCount; r++) {
    bricks[c][r] = { x: 0, y: 0, status: 1 };
  }
}

function keyDownHandler(e) {
  if (e.keyCode == 39) {
    rightPressed = true;
  } else if (e.keyCode == 37) {
    leftPressed = true;
  }
}

function keyUpHandler(e) {
  if (e.keyCode == 39) {
    rightPressed = false;
  } else if (e.keyCode == 37) {
    leftPressed = false;
  }
}

function collisionDetection() {
  for (var c = 0; c < brickColumnCount; c++) {
    for (var r = 0; r < brickRowCount; r++) {
      var b = bricks[c][r];
      if (b.status == 1) {
        if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) {
          dy = -dy;
          b.status = 0;
          // 碰撞砖块时更新球的颜色
          ballColor = randomColor();
        }
      }
    }
  }
}

function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
  // 先设置球的颜色,再执行填充
  ctx.fillStyle = ballColor;
  ctx.fill();
  ctx.closePath();
}

function drawPaddle() {
  ctx.beginPath();
  ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
  // 先设置 paddle 颜色,再填充
  ctx.fillStyle = "#00a6ff";
  ctx.fill();
  ctx.closePath();
}

function drawBricks() {
  for (var c = 0; c < brickColumnCount; c++) {
    for (var r = 0; r < brickRowCount; r++) {
      if (bricks[c][r].status == 1) {
        var brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
        var brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
        bricks[c][r].x = brickX;
        bricks[c][r].y = brickY;
        ctx.beginPath();
        ctx.rect(brickX, brickY, brickWidth, brickHeight);
        // 先设置砖块颜色,再填充
        ctx.fillStyle = "#00a6ff";
        ctx.fill();
        ctx.closePath();
      }
    }
  }
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBall();
  drawPaddle();
  drawBricks();
  collisionDetection();

  if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
    dx = -dx;
    // 碰到左右边界时更新球色
    ballColor = randomColor();
  }
  if (y + dy < ballRadius) {
    dy = -dy;
    // 碰到上边界时更新球色
    ballColor = randomColor();
  } else if (y + dy > canvas.height - ballRadius) {
    if (x > paddleX && x < paddleX + paddleWidth) {
      dy = -dy;
      // 碰到 paddle 时更新球色
      ballColor = randomColor();
    } else {
      alert("GAME OVER");
      document.location.reload();
    }
  }

  if (rightPressed && paddleX < canvas.width - paddleWidth) {
    paddleX += 7;
  } else if (leftPressed && paddleX > 0) {
    paddleX -= 7;
  }

  y += dy;
  x += dx;
}

setInterval(draw, 10);
* {
  padding: 0;
  margin: 0;
}
canvas {
  background: #eee;
  display: block;
  margin: 0 auto;
}
<canvas id="myCanvas" width="480" height="320"></canvas>

核心修改说明

  1. 调整fillStyle顺序:所有绘制函数里,先设置fillStyle再调用ctx.fill(),确保当前绘制用的是元素专属颜色。
  2. 新增ballColor变量:专门存储球的颜色,碰撞或碰到边界时更新这个变量,避免直接修改全局fillStyle干扰其他元素。
  3. 修复randomColor():用padStart(6, '0')补全Hex字符串到6位,防止生成不完整的颜色代码(比如#123变成#000123)。

这样改完后,球会保持随机颜色,paddle和砖块固定为#00a6ff,再也不会出现颜色继承的问题啦!

内容的提问来源于stack exchange,提问作者Aditya Thakur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:52:59