Имитация шаров, подпрыгивающих на границе холста - PullRequest
1 голос
/ 19 апреля 2020
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var h = canvas.height;
var w = canvas.width;
var sAngle = 0;
var numB = 10; 
var speed = 50;
var dt = 0.01;
const PI = Math.PI;
function resetCanvas () {
  canvas.width = canvas.width;
};
function createBalls (){
for(var i = 1; i <= numB; i++){ 
if (i % 2 == 0) {
  window['ball' + i] = 
  {r:10, color:"white", x:w*Math.random(), y:h*Math.random(), v:speed}} else {
   window['ball' + i] = 
  {r:10, color:"white", x:w*Math.random(), y:h*Math.random(), v:-1 *speed}};
      }
    }
  createBalls();
function drawBalls () {
for (var i = 1; i <= numB; i++) {
ctx.beginPath();
ctx.arc(window['ball' + i].x, window['ball' + i].y, window['ball' + i].r, sAngle, 2*PI);
ctx.fillStyle = window['ball' + i].color;
ctx.fill();
ctx.strokeStyle = window['ball' + i].color;
ctx.stroke();
    }
}
drawBalls();
function moveBalls () {
for (var i = 1; i <= numB; i++) {
if (0 < window['ball' + i].x < w && 0 < window['ball' + i].y < h) 
{window['ball' + i].x = window['ball' + i].x + window['ball' + i].v * dt; 
window['ball' + i].y = window['ball' + i].y + window['ball' + i].v * dt}
if (window['ball' + i].x < 0 || window['ball' + i].x > w) 
{window['ball' + i].x = window['ball' + i].x + ((-1) * window['ball' + i].v * dt); 
window['ball' + i].y = window['ball' + i].y + window['ball' + i].v * dt}
if (window['ball' + i].y < 0 || window['ball' + i].y > h) 
{window['ball' + i].y = window['ball' + i].y + ((-1) * window['ball' + i].v * dt);
window['ball' + i].x = window['ball' + i].x + window['ball' + i].v * dt}
    }
}
function animate () {
resetCanvas();
drawBalls();
moveBalls();
};
setInterval(animate, 100 * dt);

Я пытаюсь заставить шары отскочить от стен холста в противоположном направлении; однако прямо сейчас они просто ударяются о границы холста, скользят к углам и исчезают. Любые идеи о том, как я могу улучшить условия if в моей функции moveBall, чтобы шары отскакивали от стен холста?

Ответы [ 2 ]

1 голос
/ 19 апреля 2020

Не уверен, что это ваша единственная проблема, но ваши операторы if не выполняют то, что вы ожидаете. Например:

if (0 < window["ball" + i].x < w && 0 < window["ball" + i].y < h)

здесь вы, кажется, хотите сказать 0 < ball.x < w, что означает, что ball.x находится между нулем и шириной экрана. Проблема в том, что это не то, как работает сравнение. Вам нужно будет сказать:

if (0 < window["ball" + i].x && window["ball" + i].x < w && 
    0 < window["ball" + i].y && window["ball" + i].y < h)

Причина в том, что выражение 0 < x < w выполняется как (0 < x) < w, а первая часть (0 < x) возвращает либо true (1), либо false (0), и оба они, вероятно, меньше w, поэтому выражение всегда равно true.

Например, попробуйте этот фрагмент:

let x = 7;
console.log("Nope:",x,"is bewteen 0 and 6:",0 < x < 6);
console.log("Yep! ",x,"is between 0 and 6:",0 < x && x < 6); 

Итак, попробуйте написать moveBalls так:

function moveBalls() {
  for (var i = 1; i <= numB; i++) {
    // precompute values used multiple times for easier reading
    const ball = window["ball" + i];
    const offset = ball.v * dt;
    if (0 < ball.x && ball.x < w && 0 < ball.y && ball.y < h) {
      ball.x = ball.x + offset;
      ball.y = ball.y + offset;
    }
    if (ball.x < 0 || ball.x > w) {
      ball.x = ball.x - offset;
      ball.y = ball.y + offset;
    }
    if (ball.y < 0 || ball.y > h) {
      ball.y = ball.y - offset;
      ball.x = ball.x + offset;
    }
  }
}
0 голосов
/ 20 апреля 2020

В дополнение к тому, что Always Learning говорит , края обрабатываются неправильно. Я предполагаю, что вы хотите, чтобы они подпрыгивали?

Давайте посмотрим на код:

if (window['ball' + i].x < 0 || window['ball' + i].x > w) {
  window['ball' + i].x = window['ball' + i].x + ((-1) * window['ball' + i].v * dt);
  window['ball' + i].y = window['ball' + i].y + window['ball' + i].v * dt
}

Давайте избавимся от некоторого шума:

if (x < 0 || x > w) {
  x = x + ((-1) * v * dt);
  y = y + v * dt
}

Вы были правы с -1 * v, но это все еще только перемещает шар только в пределах границы холста снова. Затем l oop он будет внутри границы и будет действовать нормально, и его скорость будет добавлена ​​снова, снова выведя его за пределы границы, снова запустив этот код. Это эффективно "прилипает" шары к границе. Когда он попадает на одну границу, другая координата все еще перемещается, пока эта координата тоже не выходит за границу. Все шары заканчиваются около 0,0 или по диагонали напротив холста.

То, что вы хотите сделать здесь, это сделать скорость противоположной:

if (x < 0 || x > w || y < 0 || y > h) {
  v *= -1
}

Это приведет к мяч отскакивает в противоположном направлении.

Этот код все еще не вполне совершенен, потому что в действительности скорость имеет размерные компоненты, то есть скорость x и скорость yy.

Код гораздо более читабелен при использовании локальных переменных, особенно при использовании массива для шаров. Я могу вернуться позже и измерить скорость, но вот как выглядит код:

const canvas = document.getElementById("canvas");
const height = canvas.clientHeight;
const width = canvas.clientWidth;
canvas.height = height;
canvas.width = width;
const ctx = canvas.getContext("2d");
const h = canvas.height;
const w = canvas.width;
const sAngle = 0;
const numB = 10;
const speed = 50;
const dt = 0.01;
const PI = Math.PI;
const balls = createBalls();

function resetCanvas() {
  canvas.width = canvas.width;
}

function createBalls() {
  const balls = [];
  for (let i = 1; i <= numB; i++) {
    const ball = createBall();
    if (i % 2 == 0) {
      ball.v *= -1;
    }
    balls.push(ball);
  }
  return balls;
}

function createBall() {
  return { r: 10, color: "white", x: w * Math.random(), y: h * Math.random(), v: speed };
}

function drawBalls() {
  balls.forEach(ball => {
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, ball.r, sAngle, 2 * PI);
    ctx.fillStyle = ball.color;
    ctx.fill();
    ctx.strokeStyle = ball.color;
    ctx.stroke();
  });
}

function moveBalls() {
  balls.forEach(ball => {
    const { x, y } = ball;

    if (x < 0 || x > w || y < 0 || y > h) {
      ball.v *= -1
    }
    ball.x = x + ball.v * dt;
    ball.y = y + ball.v * dt
  });
}
function animate() {
  resetCanvas();
  drawBalls();
  moveBalls();
};
setInterval(animate, 100 * dt);

...