画布2D fillStyle有时不更新颜色

时间:2018-09-02 15:57:46

标签: javascript canvas

我正在使用2D breakout tutorial from MDN学习画布,并且有一个练习:尝试每次击球时将球的颜色更改为随机颜色。

在拉出球之前,我先检查球是否在墙内。如果它碰到球,首先我会生成一个随机的十六进制颜色,然后用该颜色绘制球。

但它有时仅适用。我已经记录了fillStyle对象的ctx属性,但是有时它不会将值更改为新颜色。

/* Reference to Canvas */
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

/* Start Ball Position */
let x = canvas.width / 2;
let y = canvas.height - 30;

/* Move Ball */
let dx = 2;
let dy = -2;

/* Ball Dimensions */
let ballRadius = 10;

/* Ball Color */
let ballColor = "#0095DD";

/* Draw Ball */
function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
  ctx.fillStyle = ballColor;
  ctx.fill();
  ctx.closePath();
  x += dx;
  y += dy;
}

/* Update Canvas */
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  bouncing();
  drawBall();
}

/**
 * If the ball goes outside the boundaries,
 * change the direction to the opposite
 */
function bouncing() {
  if(x + dx < ballRadius || x + dx > canvas.width - ballRadius) {
    dx = -dx;
    randomColor();
  }

  if(y + dy < ballRadius || y + dy > canvas.height - ballRadius) {
    dy = -dy;
    randomColor();
  }
}

/* Change the ball color to a random hex value */
function randomColor() {

  const hexColor = ['#'];
  const letters = ['A', 'B', 'C', 'D', 'E', 'F'];

  for(let digit = 0; digit < 6; digit++) {
    let value = Math.floor(Math.random() * 16);
    if(value > 9) {
      value = letters[value - 9];
    }
    hexColor.push(value);
  }
  
  ballColor = hexColor.join('');

}

setInterval(draw, 10);
html {
  box-sizing: border-box;
}

*, *::before, *::after {
  box-sizing: inherit;
  padding: 0; 
  margin: 0; 
}
      
canvas { 
  background: #eee; 
  display: block; 
  margin: 0 auto; 
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>2D breakout game</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <canvas id="myCanvas" width="480" height="170"></canvas>

  <script src="script.js"></script>
</body>
</html>

2 个答案:

答案 0 :(得分:0)

问题出在value = letters[value - 9];行中。这应该是value = letters[value - 10];

这是因为您想要的映射是:

10 -> A (letters[0])
11 -> B (letters[1])
12 -> C (letters[2])
13 -> D (letters[3])
14 -> E (letters[4])
15 -> F (letters[5])

所以您需要减去10而不是9。

答案 1 :(得分:-2)

您的代码运行正常,每次球反弹时都会调用函数randomColor,但是在颜色生成逻辑中,您可以获得无效的值,例如##A#AB可以轻松解决,将* 16更改为* 15即可解决。

但还要注意,有时您的随机颜色非常接近前一种颜色,因此看起来好像没有变化,但实际上却发生了变化,这是我相信大多数时候都可以看到的颜色。 / p>

您可以想出一个“智能随机”功能,该功能可以记住最近的2或3种颜色,并防止下一种与这些颜色相似,有关更多详细信息,如何比较颜色看起来是此问题的答案:
How to compare two colors for similarity/difference


在这里,我将您的randomColor的逻辑更改为包括色差逻辑,现在,下一个颜色将真正显示与前一个颜色的对比度

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.font = "Bold 30px courier new";
let x = y = 40
let dx = dy = 2;
let ballRadius = 40;
let ballColor = "#0095DD";

/* Change the ball color to a random hex value */
function randomColor() {  
  const hexColor = ['#'];
  const letters = ['A', 'B', 'C', 'D', 'E', 'F'];

  for(let digit = 0; digit < 6; digit++) {
    let value = Math.floor(Math.random() * 15);
    if(value > 9) {
      value = letters[value - 9];
    }
    hexColor.push(value);
  }
  
  if (colorDif(ballColor, hexColor.join('')) > 50)
    ballColor = hexColor.join('');
  else 
    randomColor();
}

function colorDif(color1, color2) {
  if (color1 == color2)  return 0;

  function squaredDelta(v1, v2) {
    return Math.pow(v1 - v2, 2);
  }

  function hexToRgb(hex) {
    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16)
    } : null;
  }

  var sum = 0;
  
  var c1 = hexToRgb(color1);
  var c2 = hexToRgb(color2);
  sum += squaredDelta(c1.r, c2.r);
  sum += squaredDelta(c1.g, c2.g);
  sum += squaredDelta(c1.b, c2.b);  
  var conversionIndex = 19.5075;
  return Math.sqrt(sum / conversionIndex);
};

function drawBall() {
  ctx.beginPath();
  ctx.fillText(ballColor,10,50);
  ctx.fillStyle = ballColor;
  ctx.arc(x, y, ballRadius, 0, Math.PI * 2);  
  ctx.fill();
  x += dx;      y += dy;
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  bouncing();
  drawBall();
}

function bouncing() {
  if(x + dx < ballRadius || x + dx > canvas.width - ballRadius) {
    dx = -dx;        randomColor();
  }
  if(y + dy < ballRadius || y + dy > canvas.height - ballRadius) {
    dy = -dy;        randomColor();
  }
}

setInterval(draw, 10);
*, *::before, *::after {margin: 0; }
<canvas id="myCanvas" width="480" height="170"></canvas>