В какой-то момент, отскакивающий от краёв канваса мяч, попадает в баг и ведет себя аномально

103
06 марта 2021, 19:40

Пишу небольшую програмку для отображения отскакивающего от краёв мяча. Некоторое время все работает хорошо, но в какой-то момент, по неизвестной причине, оно начинает "уползать" за края канваса:

Как видно на скрине, координата X пошла в минус, хотя не должна.

Предполагаю, что это связано с этим условием, которое внутри функции draw(), которая в свою очередь, выполняется большое количество раз, и значение направления мяча просто начинает бесконечно меняться между положительным и отрицательным значением:

if (xPos+ballSize>=cvs.width||xPos<=0) {
  xKof+=Math.random()/10;
  xKof= -xKof;
}

Весь код:

var cvs = document.getElementById("canvas");
var ctx = cvs.getContext("2d");
var speed = 5; // SPEED
var xPos = 150;
var yPos = 50;
var xKof = Math.random();
var yKof = Math.random();
var ballSize = 20;
var ball = new Image();
ball.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Soccerball.svg/1024px-Soccerball.svg.png";
function draw() {
 ctx.clearRect(0,0,cvs.width,cvs.height);
 ctx.drawImage(ball, xPos, yPos, ballSize, ballSize);
 xPos+=xKof*speed;
 yPos+=yKof*speed;
 if (xPos+ballSize>=cvs.width||xPos<=0) {
    xKof+=Math.random()/10;
    xKof= -xKof;
 }
 if (yPos+ballSize>=cvs.height||yPos<=0) {
    yKof+=Math.random()/10;
    yKof= -yKof;
 }
 ctx.fillStyle = "#000";
 ctx.font = "12px Verdana";
 ctx.fillText("X: " + Math.round(xPos*100)/100, 10, cvs.height - 20);
 ctx.fillText("Y: " + Math.round(yPos*100)/100, 10, cvs.height - 10);
 requestAnimationFrame(draw); 
}
ball.onload = draw;

JSFiddle: https://jsfiddle.net/sazdan/60pqsLxv/34/

Answer 1

В целом Ваше предположение верное, в какой то момент проверка происходит поздно или дельта становится маленькая и так как Вы просто инвертируете знак то шарик начинает осциллировать.

В качестве решения предлагаю выбирать знак направления а не просто инвертировать его:

 if (xPos+ballSize>cvs.width||xPos<0) {
    xKof += Math.random()/10;
    xKof =  Math.abs(xKof) * Math.sign(-xPos);
 }
 if (yPos+ballSize>cvs.height||yPos<0) {
    yKof += Math.random()/10;
    yKof =  Math.abs(yKof) * Math.sign(-yPos);
 }

var cvs = document.getElementById("canvas"); 
var ctx = cvs.getContext("2d"); 
 
var speed = 5; // SPEED 
 
var xPos = 150; 
var yPos = 50; 
var xKof = Math.random(); 
var yKof = Math.random(); 
 
var ballSize = 20; 
var ball = new Image(); 
 
ball.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Soccerball.svg/1024px-Soccerball.svg.png"; 
 
function draw() { 
 ctx.clearRect(0,0,cvs.width,cvs.height); 
  
 ctx.drawImage(ball, xPos, yPos, ballSize, ballSize); 
 xPos+=xKof*speed; 
 yPos+=yKof*speed; 
  
 if (xPos+ballSize>cvs.width||xPos<0) { 
 	xKof += Math.random()/10; 
 	xKof =  Math.abs(xKof) * Math.sign(-xPos); 
 } 
  
 if (yPos+ballSize>cvs.height||yPos<0) { 
 	yKof += Math.random()/10; 
 	yKof =  Math.abs(yKof) * Math.sign(-yPos); 
 } 
 
 ctx.fillStyle = "#000"; 
 ctx.font = "12px Verdana"; 
 ctx.fillText("X: " + Math.round(xPos*100)/100, 10, cvs.height - 20); 
 ctx.fillText("Y: " + Math.round(yPos*100)/100, 10, cvs.height - 10); 
  
 requestAnimationFrame(draw);  
} 
 
ball.onload = draw;
canvas { 
  background: #ccc; 
}
<canvas id="canvas" width="640" height="175"></canvas>

READ ALSO
Потеря данных при записи файла File.WriteAllLines

Потеря данных при записи файла File.WriteAllLines

Есть файл, в котором находятся данные data1, полное имя с адресом в переменной FullFileNameЯ записываю новые данные в данный файл File

143
Добавить в List&lt;Object&gt; экземпляр объекта

Добавить в List<Object> экземпляр объекта

Имеется один экземпляр Object, который каждый раз меняет свои значения свойств, при этом, после изменения свойства он добавляется в List через...

113
Как отобразить содержимое тега в HtmlDocument?

Как отобразить содержимое тега в HtmlDocument?

У меня проблема с парсингом HtmlDocument по какой то причине не могу войти в <td width="300px"> </td>

149
Как я могу заменить public GameObject из другого скрипта?

Как я могу заменить public GameObject из другого скрипта?

Как я могу заменить public GameObject из другого скрипта? Я должен сначала "найти скрипт" и потом передать ему другое значение или же есть более простой...

102