Canvas 2D fillStyle иногда не обновляет цвет - PullRequest
0 голосов
/ 02 сентября 2018

Я изучаю холст с помощью учебника 2D Breakout от 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 голосов
/ 03 сентября 2018

Проблема в строке 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.

0 голосов
/ 02 сентября 2018

Ваш код работает нормально, функция randomColor вызывается каждый раз, когда мяч отскакивает, но в логике генерации цвета вы можете получить недопустимые значения, такие как #, #A или #AB, вы можете легко исправьте это изменение * 16 на * 15 и исправьте это.

Но также обратите внимание, что иногда ваш случайный цвет очень и очень близок к предыдущему, так что, похоже, он не изменился, но на самом деле он изменился. Это то, что я считаю, что мы видим большую часть времени.

Вы могли бы придумать функцию «умного случайного выбора», которая запоминает последние 2 или 3 цвета и предотвращает схожесть следующих цветов, для более подробной информации о том, как сравнивать цвета, смотрите ответы на этот вопрос:
Как сравнить два цвета по сходству / разнице


Здесь я изменил логику вашего 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...