Reputation: 113
I am trying to create one website for monitoring kind of thing. Here i need to control the speed of the ball. How to do that? Then i need to change the color of the balls to red if it collide or overlay with other. If not, it should remain green . I have no idea how to do these thing. Can anyone please help with this?
function getBall(xVal, yVal, dxVal, dyVal, rVal, colorVal) {
var ball = {
x: xVal,
lastX: xVal,
y: yVal,
lastY: yVal,
dx: dxVal,
dy: dyVal,
r: rVal,
color: colorVal,
normX: 0,
normY: 0,
durationAverage: 0,
durationMin: Number.MAX_SAFE_INTEGER,
durationMax: 0,
bounceCount: 0
};
return ball;
}
var canvas = document.getElementById("Canvas");
var ctx = canvas.getContext("2d");
var containerR = 200;
canvas.width = containerR * 2;
canvas.height = containerR * 2;
canvas.style["border-radius"] = containerR + "px";
var balls = [
getBall(canvas.width / 2, canvas.height - 30, 2, -2, 8, "#32CD32"),
getBall(canvas.width / 3, canvas.height - 50, 3, -3, 8, "#32CD32"),
getBall(canvas.width / 4, canvas.height - 60, -3, 4, 8, "#32CD32"),
getBall(canvas.width / 2, canvas.height / 5, -1.5, 3, 8, "#32CD32")
];
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < balls.length; i++) {
var curBall = balls[i];
ctx.beginPath();
ctx.arc(curBall.x, curBall.y, curBall.r, 0, Math.PI * 2, false);
ctx.fillStyle = curBall.color;
ctx.fill();
ctx.closePath();
curBall.lastX = curBall.x;
curBall.lastY = curBall.y;
curBall.x += curBall.dx;
curBall.y += curBall.dy;
var dx = curBall.x - containerR;
var dy = curBall.y - containerR;
if (Math.sqrt(dx * dx + dy * dy) >= containerR - curBall.r) {
var start = performance.now();
// current speed
var v = Math.sqrt(curBall.dx * curBall.dx + curBall.dy * curBall.dy);
// Angle from center of large circle to center of small circle,
// which is the same as angle from center of large cercle
// to the collision point
var angleToCollisionPoint = Math.atan2(-dy, dx);
// Angle of the current movement
var oldAngle = Math.atan2(-curBall.dy, curBall.dx);
// New angle
var newAngle = 2 * angleToCollisionPoint - oldAngle;
// new x/y speeds, using current speed and new angle
curBall.dx = -v * Math.cos(newAngle);
curBall.dy = v * Math.sin(newAngle);
var end = performance.now();
var curDuration = end - start;
curBall.bounceCount++;
curBall.durationAverage = (((curBall.bounceCount - 1) * curBall.durationAverage) + curDuration) / curBall.bounceCount;
if (curDuration < curBall.durationMin) {
curBall.durationMin = curDuration
}
if (curDuration > curBall.durationMax) {
curBall.durationMax = curDuration
}
}
}
requestAnimationFrame(draw);
}
draw();
canvas {
background: #eee;
}
<canvas id="Canvas"></canvas>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
Upvotes: 3
Views: 64
Reputation: 17594
See if this is what you are looking for:
function getBall(xVal, yVal, dxVal, dyVal, rVal, colorVal) {
var ball = {x: xVal, y: yVal, dx: dxVal, dy: dyVal, r: rVal, color: colorVal
};
return ball;
}
var canvas = document.getElementById("Canvas");
var ctx = canvas.getContext("2d");
ctx.globalAlpha = 0.8
var containerR = 100;
canvas.width = canvas.height = containerR * 2;
var balls = [
getBall(canvas.width / 2, canvas.height - 30, 1, -0.5, 18, "#32CD32"),
getBall(canvas.width / 3, canvas.height - 50, 1.2, -1, 15, "#32CD32"),
getBall(canvas.width / 4, canvas.height - 60, -1.6, 1, 12, "#32CD32"),
getBall(canvas.width / 2, canvas.height / 5, -1.5, 1, 8, "#32CD32")
];
function drawBall(curBall) {
ctx.beginPath();
ctx.arc(curBall.x, curBall.y, curBall.r, 0, Math.PI * 2, false);
ctx.fillStyle = curBall.color;
ctx.fill();
ctx.stroke();
ctx.closePath();
}
function updateBallPos(curBall) {
curBall.x += curBall.dx;
curBall.y += curBall.dy;
var dx = curBall.x - containerR;
var dy = curBall.y - containerR;
if (Math.sqrt(dx * dx + dy * dy) >= containerR - curBall.r) {
var v = Math.sqrt(curBall.dx * curBall.dx + curBall.dy * curBall.dy);
var angleToCollisionPoint = Math.atan2(-dy, dx);
var oldAngle = Math.atan2(-curBall.dy, curBall.dx);
var newAngle = 2 * angleToCollisionPoint - oldAngle;
curBall.dx = -v * Math.cos(newAngle);
curBall.dy = v * Math.sin(newAngle);
}
}
function ballsMeet(b1, b2) {
return (Math.hypot(Math.abs(b1.x - b2.x), Math.abs(b1.y - b2.y)) < (b1.r + b2.r))
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < balls.length; i++) {
drawBall(balls[i])
updateBallPos(balls[i])
meet = false
for (var j = 0; j < balls.length; j++) {
if (ballsMeet(balls[i], balls[j]) && i != j) {
meet = true
balls[j].color = "red"
}
}
balls[i].color = (meet) ? "red" : "lime"
}
requestAnimationFrame(draw);
}
draw();
<canvas id="Canvas"></canvas>
I significantly stripped your code just to focus on the color change, the balls had a lot of properties that my guess you will use later for something else but not really relevant for the issue you are having at the moment.
Also I split your code into multiple smaller functions easier to read that way.
So the idea is to check every ball against all others see if they "meet" and if they do we change the color, I slow down the speed of your example to smooth the animation a little if not I was getting a lot of change from red to green this was it shows what is happening
Upvotes: 2
Reputation: 743
You can calculate the Euclidean distance between the two circles' centres. If it is less than the sum of the radii of the two circles, they are overlapping.
let euclideanDistance = Math.hypot(Math.abs(x1-x2), Math.abs(y1-y2));
let sumOfRadii = circle1radius + circle2radius;
if (euclideanDistance <= sumOfRadii) {
makeCirclesRed();
} else if (euclideanDistance > sumofRadii) {
makeCirclesGreen();
}
Explanation:
Math.hypot()
calculates the hypotenuse of a triangle given the two leg legnths, which happens to be the same as the formula for Euclidean distance
Math.abs()
just makes sure that the input to the hypot()
function is positive. It might not actually be necessary, so you can try experimenting without it.
You can fill in the makeCirclesRed()
and makeCirclesGreen()
functions to suit your needs.
Edit: if you want to make the circles red if they meet or come within x
pixels of each other, you can change sumOfRadii = circle1radius + circle2radius + x
for your desired value of x
.
Upvotes: -1