Javascript unwanted lines connecting moving arcs - javascript

So i have this basic script which makes 4 circles move around a centre, and I have put in two circles which are the route which the circles follow.. The problem is that there's odd unwanted lines joining the circles to the stationary one's. I think it may be because the line for the circles ctx.arc(cx, cy, 200, 200, 0, 2 * Math.PI); is within the draw function. Does anyone know how to solve this? (Placing the stationary circles outside the draw function causes them to disappear when the canvas is cleared.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
var dd = 3;
var dd2 = 3;
var dd3 = 3;
var dd4 = 3;
var angle = 0;
var angle2 = 0;
var angle3 = 0;
var angle4 = 0;
var cx = 1000;
var cy = 1000;
var radius = 200;
var radius2 = 300;
var radius3 = 400;
var radius4 = 500;
var fps = 100;
ctx.fillStyle = "yellow";
ctx.strokeStyle = "skyblue";
(function () {
"use strict";
function draw(x, y) {
ctx.save();
ctx.clearRect(0, 0, w, h);
ctx.beginPath();
ctx.arc(cx, cy, 75, 75, 0, 2 * Math.PI);
ctx.fillStyle = "lightgray";
ctx.arc((x - 50 / 2) + 25, (y - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.arc(cx, cy, 200, 200, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.restore();
}
function draw1(x1, y1) {
ctx.save();
ctx.beginPath();
ctx.fillStyle = "orange";
ctx.arc((x1 - 50 / 2) + 25, (y1 - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.arc(cx, cy, 300, 300, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.restore();
}
function draw2(x2, y2) {
ctx.save();
ctx.beginPath();
ctx.fillStyle = "blue";
ctx.arc((x2 - 50 / 2) + 25, (y2 - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.arc(cx, cy, 400, 400, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.restore();
}
function draw3(x3, y3) {
ctx.save();
ctx.beginPath();
ctx.fillStyle = "red";
ctx.arc((x3 - 50 / 2) + 25, (y3 - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.arc(cx, cy, 500, 500, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.restore();
}
window.requestAnimFrame = (function (callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / fps);
};
}());
function animate() {
setTimeout(function () {
requestAnimFrame(animate);
ctx.beginPath();
angle += Math.acos(1 - Math.pow(dd / radius, 2) / 2);
var newX = cx + radius * Math.cos(angle),
newY = cy + radius * Math.sin(angle),
newX1 = cx + radius2 * Math.cos(angle2),
newY1 = cy + radius2 * Math.sin(angle2),
newX2 = cx + radius3 * Math.cos(angle3),
newY2 = cy + radius3 * Math.sin(angle3),
newX3 = cx + radius4 * Math.cos(angle4),
newY3 = cy + radius4 * Math.sin(angle4);
draw(newX, newY);
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.beginPath();
angle2 += Math.acos(1 - Math.pow(dd2 / radius2, 2) / 2);
draw1(newX1, newY1);
ctx.arc(cx, cy, radius2, 0, 2 * Math.PI);
ctx.closePath();
ctx.beginPath();
angle3 += Math.acos(1 - Math.pow(dd3 / radius3, 2) / 2);
draw2(newX2, newY2);
ctx.arc(cx, cy, radius3, 0, 2 * Math.PI);
ctx.closePath();
ctx.beginPath();
angle4 += Math.acos(1 - Math.pow(dd4 / radius4, 2) / 2);
draw3(newX3, newY3);
ctx.arc(cx, cy, radius4, 0, 2 * Math.PI);
ctx.closePath();
}, 1000 / fps);
}
animate();
}());

You have to use ctx.beginPath(), ctx.closePath() and ctx.stroke() for EVERY arc you create, else it will connect them with lines (as you yourself also would have to, if you were drawing and were not allowed to take the pencil off the paper):
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
var dd = 3;
var dd2 = 3;
var dd3 = 3;
var dd4 = 3;
var angle = 0;
var angle2 = 0;
var angle3 = 0;
var angle4 = 0;
var cx = 1000;
var cy = 1000;
var radius = 200;
var radius2 = 300;
var radius3 = 400;
var radius4 = 500;
var fps = 100;
ctx.fillStyle = "yellow";
ctx.strokeStyle = "skyblue";
(function () {
"use strict";
function draw(x, y) {
ctx.save();
ctx.clearRect(0, 0, w, h);
ctx.beginPath();
ctx.arc(cx, cy, 75, 75, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.fillStyle = "lightgray";
ctx.beginPath();
ctx.arc((x - 50 / 2) + 25, (y - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.arc(cx, cy, 200, 200, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
function draw1(x1, y1) {
ctx.save();
ctx.fillStyle = "orange";
ctx.beginPath();
ctx.arc((x1 - 50 / 2) + 25, (y1 - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.arc(cx, cy, 300, 300, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
function draw2(x2, y2) {
ctx.save();
ctx.fillStyle = "blue";
ctx.beginPath();
ctx.arc((x2 - 50 / 2) + 25, (y2 - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.arc(cx, cy, 400, 400, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
function draw3(x3, y3) {
ctx.save();
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc((x3 - 50 / 2) + 25, (y3 - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.arc(cx, cy, 500, 500, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
window.requestAnimFrame = (function (callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / fps);
};
}());
function animate() {
setTimeout(function () {
requestAnimFrame(animate);
angle += Math.acos(1 - Math.pow(dd / radius, 2) / 2);
var newX = cx + radius * Math.cos(angle),
newY = cy + radius * Math.sin(angle),
newX1 = cx + radius2 * Math.cos(angle2),
newY1 = cy + radius2 * Math.sin(angle2),
newX2 = cx + radius3 * Math.cos(angle3),
newY2 = cy + radius3 * Math.sin(angle3),
newX3 = cx + radius4 * Math.cos(angle4),
newY3 = cy + radius4 * Math.sin(angle4);
draw(newX, newY);
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
angle2 += Math.acos(1 - Math.pow(dd2 / radius2, 2) / 2);
draw1(newX1, newY1);
ctx.arc(cx, cy, radius2, 0, 2 * Math.PI);
angle3 += Math.acos(1 - Math.pow(dd3 / radius3, 2) / 2);
draw2(newX2, newY2);
ctx.arc(cx, cy, radius3, 0, 2 * Math.PI);
angle4 += Math.acos(1 - Math.pow(dd4 / radius4, 2) / 2);
draw3(newX3, newY3);
ctx.arc(cx, cy, radius4, 0, 2 * Math.PI);
}, 1000 / fps);
}
animate();
}());
<canvas id="canvas" width="2000" height="2000"></canvas>
E.g. I changed the following:
ctx.beginPath();
ctx.arc(cx, cy, 75, 75, 0, 2 * Math.PI);
ctx.fillStyle = "lightgray";
ctx.arc((x - 50 / 2) + 25, (y - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.arc(cx, cy, 200, 200, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
Into this:
ctx.beginPath();
ctx.arc(cx, cy, 75, 75, 0, 2 * Math.PI);
ctx.closePath(); //Added
ctx.stroke(); //Added
ctx.fillStyle = "lightgray";
ctx.beginPath(); //Added
ctx.arc((x - 50 / 2) + 25, (y - 30 / 2) + 15, 25, 25, 0, 2 * Math.PI);
ctx.closePath(); //Added
ctx.stroke(); //Added
ctx.beginPath(); //Added
ctx.arc(cx, cy, 200, 200, 0, 2 * Math.PI);
ctx.closePath(); //Reversed order (doesn't really matter, but looks better IMO)
ctx.stroke(); //Reversed order (doesn't really matter, but looks better IMO)

Related

adding animation to canvas wheel using javascript, spinning wheel animation

I'm trying to make a simple animation for a wheel, and I'm not sure how to define the animation function of it.
index.html, can be found below, trying to keep the body clean... (no real reson).
<!DOCTYPE html>
<html>
<head>
</head>
<body>
</body>
</html>
javascript, can be found below or using the jsfiddle link.
I have compose the wheel from 2 main canvas, one is the outterWheel and the other one is the innerWheel which is filled to cover the lines of outterWheel, give the impression of a mechanical wheel.
let buttonDOM = document.createElement('canvas');
buttonDOM.id = 'outterWheel';
buttonDOM.width = 80;
buttonDOM.height = 60;
document.body.appendChild(buttonDOM);
ctx = document.getElementById('outterWheel').getContext('2d');
ctx.lineWidth = 2;
ctx.beginPath();
const smallLines = [ 0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5, 180, 202.5, 225, 247.5, 270, 292.5, 315, 337.5 ];
ctx.fillStyle = "#76D7C4";
ctx.fillRect(0, 0, 80, 60);
ctx.arc(40, 30, 15, 0, 2 * Math.PI);
for (var angle of smallLines){
ctx.moveTo(40, 30);
ctx.lineTo(40 + 17 * Math.cos(angle * Math.PI * 2 / 360), 30 + 17 * Math.sin(angle * Math.PI * 2 / 360));
}
ctx.stroke();
buttonDOM = document.createElement('canvas');
buttonDOM.id = 'innerWheel';
buttonDOM.width = 80;
buttonDOM.height = 60;
document.body.appendChild(buttonDOM);
ctx = document.getElementById('innerWheel').getContext('2d');
ctx.lineWidth = 2;
ctx.beginPath();
ctx.fillStyle = "#76D7C4";
ctx.clearRect(0, 0, 80, 60);
ctx.arc(40, 30, 15, 0, 2 * Math.PI);
ctx.fillStyle = "#76D7C4";
ctx.fill();
for (var angle of smallLines){
ctx.moveTo(40, 30);
ctx.lineTo(40 + 18 * Math.cos((angle + 11.25) * Math.PI * 2 / 360), 30 + 18 * Math.sin((angle + 11.25) * Math.PI * 2 / 360));
}
ctx.stroke();
https://jsfiddle.net/nh63c28w/2/
At the moment you're using two <canvas> elements to draw your wheels. I'd recommend using a single instance for creating each wheel initially. With the help of the canvas.toDataURL() you can store a snapshot of your canvas' content to a element and re-use the two images to compose your final animation on the canvas.
To actually draw the animation we can utilize a combination of the translate(), rotate() and drawImage() methods. translate will move the context to a specific x & y position, rotate will rotate the canvas by a certain amount given in radians and drawImage will finally draw the given image at the context's current position.
To change the animation over time - like rotating the wheels - we need to re-trigger the animation function. This is done by the requestAnimationFrame() function which calls a given callBack function at the refreshrate of your monitor e.g. 60 times per second on a 60hz display.
For example:
let buttonDOM = document.createElement('canvas');
buttonDOM.id = 'outerWheel';
buttonDOM.width = 80;
buttonDOM.height = 60;
document.body.appendChild(buttonDOM);
ctx = document.getElementById('outerWheel').getContext('2d');
ctx.lineWidth = 2;
ctx.beginPath();
const smallLines = [0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5, 180, 202.5, 225, 247.5, 270, 292.5, 315, 337.5];
ctx.fillStyle = "#76D7C4";
ctx.fillRect(0, 0, 80, 60);
ctx.arc(40, 30, 15, 0, 2 * Math.PI);
for (var angle of smallLines) {
ctx.moveTo(40, 30);
ctx.lineTo(40 + 17 * Math.cos(angle * Math.PI * 2 / 360), 30 + 17 * Math.sin(angle * Math.PI * 2 / 360));
}
ctx.stroke();
ctx.closePath();
let outerWheel = new Image();
outerWheel.src = buttonDOM.toDataURL();
ctx.lineWidth = 2;
ctx.beginPath();
ctx.clearRect(0, 0, 80, 60);
ctx.arc(40, 30, 15, 0, 2 * Math.PI);
ctx.fill();
for (var angle of smallLines) {
ctx.moveTo(40, 30);
ctx.lineTo(40 + 18 * Math.cos((angle + 11.25) * Math.PI * 2 / 360), 30 + 18 * Math.sin((angle + 11.25) * Math.PI * 2 / 360));
}
ctx.stroke();
ctx.closePath();
let innerWheel = new Image();
innerWheel.src = buttonDOM.toDataURL();
let innerWheelProperties = {
x: 75,
y: 100,
rotation: 0
};
let outerWheelProperties = {
x: 250,
y: 100,
rotation: 0
};
buttonDOM.width = 300;
buttonDOM.height = 200;
function animation() {
ctx.clearRect(0, 0, buttonDOM.width, buttonDOM.height);
ctx.save();
ctx.translate(innerWheelProperties.x, innerWheelProperties.y);
ctx.rotate(innerWheelProperties.rotation * Math.PI / 180);
ctx.drawImage(innerWheel, 0 - innerWheel.width / 2, 0 - innerWheel.height / 2);
ctx.restore();
ctx.save();
ctx.translate(outerWheelProperties.x, outerWheelProperties.y);
ctx.rotate(outerWheelProperties.rotation * Math.PI / 180);
ctx.drawImage(outerWheel, 0 - outerWheel.width / 2, 0 - outerWheel.height / 2);
ctx.restore();
outerWheelProperties.rotation++;
innerWheelProperties.rotation -= 0.5;
requestAnimationFrame(animation);
}
requestAnimationFrame(animation);

Animation assistance with a circle using JavaScript in a Canvas--what am I missing?

I'm trying to create simple animation to take the moon that I have drawn behind the clouds and allow users to move it across the x axis in the canvas. I have seen where others have done this with rectangles, and I have seen where their code seems basic enough for my inexperience to follow... but I'm struggling a bit with my code.
Every time I put code in that I think will work, it wipes out the canvas... which means I have placement and structural issues... but I'm having trouble figuring out where and how.
Can someone help me figure out how to animate my drawMoon so that it will move across the x axis when the left and right arrow keys are used?
NOTE I have tried using event listeners for keydown and keyup, but I'm sure I'm doing it wrong.
Attaching code that has nothing included so that you all have the base code without the animation attempt.
Any help is appreciated.
UPDATE I think I broke it more..... thoughts?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Howling at the Moon</title>
</head>
<body onload="init();">
<canvas id="myCanvas" width="900" height="900">Your browser does not support the canvas tag.</canvas>
<script type="text/javascript">
var canvas, ctx;
var moonx = 0;
var moony = 0;
var moonAngle = 0;
var incrementX = 0;
function init() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
window.addEventListener("keydown", handleKeydown, false);
window.addEventListener("keyup", handleKeyup, false);
drawMonster(260, 260);
drawMoon(100, 100);
drawCloud(150, 175);
requestId = requestAnimationFrame(animationLoop);
function handleKeydown(evt) {
if (evt.keyCode === 37) {
incrementX = -1;
} else if (evt.keyCode === 39) {
incrementX = 1;
}
}
function handleKeyup(evt) {
incrementX = 0;
}
function animationLoop() {
context.globalCompositeOperation = 'destination-out'
}
drawMoon(moonx, moony, moonAngle, "green", "yellow");
moonx += incrementX;
requestId = requestAnimationFrame(animationLoop);
}
function drawMonster(x, y) {
ctx.save();
ctx.beginPath();
ctx.arc(740, 750, 175, 0, Math.PI / 0.5);
ctx.fillStyle = "lightgrey";
ctx.fill();
ctx.lineWidth = 3;
ctx.stroke();
//mouth1
ctx.fillStyle = "black";
ctx.fillRect(x + 350, y + 550, 200, 20);
//mouth2
ctx.fillStyle = "black";
ctx.fillRect(x + 375, y + 540, 150, 20);
//mouth3
ctx.fillStyle = "black";
ctx.fillRect(x + 375, y + 560, 150, 20);
ctx.restore();
//eyes
addShadows2();
ctx.fillStyle = "lightslategrey";
ctx.fillRect(x + 350, y + 400, 40, 40);
ctx.fillRect(x + 450, y + 400, 40, 40);
//pupil
ctx.fillStyle = "black";
ctx.fillRect(x + 350, y + 400, 20, 20);
ctx.fillRect(x + 450, y + 400, 20, 20);
}
//moon
function drawMoon(moonx, moony) {
ctx.beginPath();
ctx.arc(100, 75, 150, 0, Math.PI / 0.5);
ctx.fillStyle = "lightgrey";
addShadows();
ctx.fill();
ctx.lineWidth = 3;
ctx.stroke();
}
//cloud
function drawCloud(x, y) {
ctx.beginPath();
ctx.arc(x, y, 60, Math.PI * 0.5, Math.PI * 1.5);
ctx.arc(x + 70, y - 60, 70, Math.PI * 1, Math.PI * 1.85);
ctx.arc(x + 152, y - 45, 50, Math.PI * 1.37, Math.PI * 1.91);
ctx.arc(x + 200, y, 60, Math.PI * 1.5, Math.PI * 0.5);
ctx.moveTo(x + 200, y + 60);
ctx.lineTo(x, y + 60);
ctx.strokeStyle = "#797874";
ctx.stroke();
ctx.fillStyle = "lightslategrey";
ctx.fill();
}
function addShadows() {
ctx.shadowColor = "beige"; // color
ctx.shadowBlur = 160; // blur level
ctx.shadowOffsetX = 15; // horizontal offset
ctx.shadowOffsetY = 15; // vertical offset
}
function addShadows2() {
ctx.shadowColor = "black";
ctx.shadowBlur = 40;
ctx.shadowOffsetX = 15;
ctx.shadowOffsetY = 10;
}
function addShadows3() {
ctx.shadowColor = "beige";
ctx.shadowBlur = 160;
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Howling at the Moon</title>
</head>
<body onload="init();">
<canvas id="myCanvas" width="900" height="900">Your browser does not support the canvas tag.</canvas>
<script type="text/javascript">
var canvas, ctx;
function init() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
window.addEventListener('keydown', handleKeydown, false);
window.addEventListener('keyup', handleKeyup, false);
drawMonster(260, 260);
drawMoon(100, 100);
drawCloud(150, 175);
function handleKeydown(evt) {
if (evt.keyCode === 37) {
//left key
incrementX = -1;
} else if (evt.keyCode === 39) {
// right key
incrementX = 1;
}
}
function drawMonster(x, y) {
ctx.save();
ctx.beginPath();
ctx.arc(740, 750, 175, 0, Math.PI / .5);
ctx.fillStyle = "lightgrey";
ctx.fill();
ctx.lineWidth = 3;
ctx.stroke();
//mouth1
ctx.fillStyle = 'black'
ctx.fillRect(x + 350, y + 550, 200, 20);
//mouth2
ctx.fillStyle = 'black'
ctx.fillRect(x + 375, y + 540, 150, 20);
//mouth3
ctx.fillStyle = 'black'
ctx.fillRect(x + 375, y + 560, 150, 20);
ctx.restore();
//eyes
addShadows2();
ctx.fillStyle = 'lightslategrey'
ctx.fillRect(x + 350, y + 400, 40, 40);
ctx.fillRect(x + 450, y + 400, 40, 40);
//pupil
ctx.fillStyle = 'black'
ctx.fillRect(x + 350, y + 400, 20, 20);
ctx.fillRect(x + 450, y + 400, 20, 20);
}
function animateMoon()
{
ctx.clearArc(0,0,canvas.width,canvas.height);
drawMoon(x,y);
requestId = requestAnimationFrame(animateMoon);
}
//moon
function drawMoon(x, y) {
ctx.beginPath();
ctx.arc(100, 75, 150, 0, Math.PI / .5);
ctx.fillStyle = "lightgrey";
addShadows();
ctx.fill();
ctx.lineWidth = 3;
ctx.stroke();
}
//cloud
function drawCloud(x, y) {
ctx.beginPath();
ctx.arc(x, y, 60, Math.PI * 0.5, Math.PI * 1.5);
ctx.arc(x + 70, y - 60, 70, Math.PI * 1, Math.PI * 1.85);
ctx.arc(x + 152, y - 45, 50, Math.PI * 1.37, Math.PI * 1.91);
ctx.arc(x + 200, y, 60, Math.PI * 1.5, Math.PI * 0.5);
ctx.moveTo(x + 200, y + 60);
ctx.lineTo(x, y + 60);
ctx.strokeStyle = "#797874";
ctx.stroke();
ctx.fillStyle = "lightslategrey";
ctx.fill();
}
function addShadows() {
ctx.shadowColor = "beige"; // color
ctx.shadowBlur = 160; // blur level
ctx.shadowOffsetX = 15; // horizontal offset
ctx.shadowOffsetY = 15; // vertical offset
}
function addShadows2() {
ctx.shadowColor = "black";
ctx.shadowBlur = 40;
ctx.shadowOffsetX = 15;
ctx.shadowOffsetY = 10;
}
function addShadows3() {
ctx.shadowColor = "beige";
ctx.shadowBlur = 160;
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
}
function start() {
// Start the animation loop, targets 60 frames/s
requestId = requestAnimationFrame(animationLoop);
}
function stop() {
if (requestId) {
cancelAnimationFrame(requestId);
}
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Howling at the Moon</title>
</head>
<body onload="init();">
<canvas id="myCanvas" width="900" height="900">Your browser does not support the canvas tag.</canvas>
<script type="text/javascript">
var canvas, ctx;
function init() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
window.addEventListener('keydown', handleKeydown, false);
window.addEventListener('keyup', handleKeyup, false);
drawMonster(260, 260);
drawMoon(100, 100);
drawCloud(150, 175);
function handleKeydown(evt) {
if (evt.keyCode === 37) {
//left key
incrementX = -1;
} else if (evt.keyCode === 39) {
// right key
incrementX = 1;
}
}
function drawMonster(x, y) {
ctx.save();
ctx.beginPath();
ctx.arc(740, 750, 175, 0, Math.PI / .5);
ctx.fillStyle = "lightgrey";
ctx.fill();
ctx.lineWidth = 3;
ctx.stroke();
//mouth1
ctx.fillStyle = 'black'
ctx.fillRect(x + 350, y + 550, 200, 20);
//mouth2
ctx.fillStyle = 'black'
ctx.fillRect(x + 375, y + 540, 150, 20);
//mouth3
ctx.fillStyle = 'black'
ctx.fillRect(x + 375, y + 560, 150, 20);
ctx.restore();
//eyes
addShadows2();
ctx.fillStyle = 'lightslategrey'
ctx.fillRect(x + 350, y + 400, 40, 40);
ctx.fillRect(x + 450, y + 400, 40, 40);
//pupil
ctx.fillStyle = 'black'
ctx.fillRect(x + 350, y + 400, 20, 20);
ctx.fillRect(x + 450, y + 400, 20, 20);
}
function animateMoon() {
ctx.clearArc(0, 0, canvas.width, canvas.height);
drawMoon(x, y);
requestId = requestAnimationFrame(animateMoon);
}
//moon
function drawMoon(x, y) {
ctx.beginPath();
ctx.arc(100, 75, 150, 0, Math.PI / .5);
ctx.fillStyle = "lightgrey";
addShadows();
ctx.fill();
ctx.lineWidth = 3;
ctx.stroke();
}
//cloud
function drawCloud(x, y) {
ctx.beginPath();
ctx.arc(x, y, 60, Math.PI * 0.5, Math.PI * 1.5);
ctx.arc(x + 70, y - 60, 70, Math.PI * 1, Math.PI * 1.85);
ctx.arc(x + 152, y - 45, 50, Math.PI * 1.37, Math.PI * 1.91);
ctx.arc(x + 200, y, 60, Math.PI * 1.5, Math.PI * 0.5);
ctx.moveTo(x + 200, y + 60);
ctx.lineTo(x, y + 60);
ctx.strokeStyle = "#797874";
ctx.stroke();
ctx.fillStyle = "lightslategrey";
ctx.fill();
}
function addShadows() {
ctx.shadowColor = "beige"; // color
ctx.shadowBlur = 160; // blur level
ctx.shadowOffsetX = 15; // horizontal offset
ctx.shadowOffsetY = 15; // vertical offset
}
function addShadows2() {
ctx.shadowColor = "black";
ctx.shadowBlur = 40;
ctx.shadowOffsetX = 15;
ctx.shadowOffsetY = 10;
}
function addShadows3() {
ctx.shadowColor = "beige";
ctx.shadowBlur = 160;
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
}
function start() {
// Start the animation loop, targets 60 frames/s
requestId = requestAnimationFrame(animationLoop);
}
function stop() {
if (requestId) {
cancelAnimationFrame(requestId);
}
}
</script>
</body>
</html>
There were several issues in your code and I'll share the changes I made to get the animation to work.
Errors
In your animationLoop, you referenced a variable named context which I believe you meant to reference ctx instead.
context.globalCompositeOperation = 'destination-out'
I can't say I've used this property of the CanvasRenderingContext2D, but I didn't notice any positive effects it produced for your code and the resulting animation. I first changed it to ctx.globalCompositeOperation and eventually removed it.
Another error was that you were declaring ctx and canvas in your init function even though you had variables declared outside the function. I opted to remove the declaration and just make it an assignment instead:
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
With these changes, the initial errors were resolved.
Issues
In init the shapes are drawn on the canvas and we have two identical lines using requestAnimationFrame:
requestId = requestAnimationFrame(animationLoop);
drawMoon(moonx, moony, moonAngle, "green", "yellow");
moonx += incrementX;
requestId = requestAnimationFrame(animationLoop);
I removed the first one (also removing the requestId assignment as it didn't seem necessary). Then, in order for the animationLoop to continue to animate, we need to call requestAnimationFrame(animationLoop) inside of the animationLoop function.
function animationLoop() {
// ...
requestAnimationFrame(animationLoop);
}
Then, in order to actually draw the shapes in each call of animationLoop, I moved the draw<shape> function calls inside of animationLoop. Also, we want to clear the canvas each time we draw on it to properly animate our shapes, so we'll need to use .clearRect. Now the animationLoop looks like this:
function animationLoop() {
moonx += incrementX;
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawMonster(260, 260);
drawCloud(150, 175);
drawMoon(moonx, moony, moonAngle, "green", "yellow");
requestAnimationFrame(animationLoop);
}
But the final reason the moon won't move when we press the left or right arrows is that we're not actually using the moonx and moony variables when drawing the moon. So, in drawMoon, instead of
ctx.arc(100, 75, 150, 0, Math.PI / .5);
this should be changed to the following
ctx.arc(moonx, moony, 150, 0, Math.PI / 0.5);
I believe I covered all of the major issues with your code to be able to draw all the shapes and move the moon with the left and right arrows. See the full code example below.
var canvas, ctx;
var moonx = 0;
var moony = 0;
var moonAngle = 0;
var incrementX = 0;
function init() {
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
window.addEventListener("keydown", handleKeydown, false);
window.addEventListener("keyup", handleKeyup, false);
requestAnimationFrame(animationLoop);
function handleKeydown(evt) {
if (evt.keyCode === 37) {
incrementX = -1;
} else if (evt.keyCode === 39) {
incrementX = 1;
}
}
function handleKeyup(evt) {
incrementX = 0;
}
function animationLoop() {
moonx += incrementX;
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawMonster(260, 260);
drawCloud(150, 175);
drawMoon(moonx, moony, moonAngle, "green", "yellow");
requestAnimationFrame(animationLoop);
}
}
function drawMonster(x, y) {
ctx.save();
ctx.beginPath();
ctx.arc(740, 750, 175, 0, Math.PI / 0.5);
ctx.fillStyle = "lightgrey";
ctx.fill();
ctx.lineWidth = 3;
ctx.stroke();
//mouth1
ctx.fillStyle = "black";
ctx.fillRect(x + 350, y + 550, 200, 20);
//mouth2
ctx.fillStyle = "black";
ctx.fillRect(x + 375, y + 540, 150, 20);
//mouth3
ctx.fillStyle = "black";
ctx.fillRect(x + 375, y + 560, 150, 20);
ctx.restore();
//eyes
addShadows2();
ctx.fillStyle = "lightslategrey";
ctx.fillRect(x + 350, y + 400, 40, 40);
ctx.fillRect(x + 450, y + 400, 40, 40);
//pupil
ctx.fillStyle = "black";
ctx.fillRect(x + 350, y + 400, 20, 20);
ctx.fillRect(x + 450, y + 400, 20, 20);
}
//moon
function drawMoon(moonx, moony) {
ctx.beginPath();
ctx.arc(moonx, moony, 150, 0, Math.PI / 0.5);
ctx.fillStyle = "lightgrey";
addShadows();
ctx.fill();
ctx.lineWidth = 3;
ctx.stroke();
}
//cloud
function drawCloud(x, y) {
ctx.beginPath();
ctx.arc(x, y, 60, Math.PI * 0.5, Math.PI * 1.5);
ctx.arc(x + 70, y - 60, 70, Math.PI * 1, Math.PI * 1.85);
ctx.arc(x + 152, y - 45, 50, Math.PI * 1.37, Math.PI * 1.91);
ctx.arc(x + 200, y, 60, Math.PI * 1.5, Math.PI * 0.5);
ctx.moveTo(x + 200, y + 60);
ctx.lineTo(x, y + 60);
ctx.strokeStyle = "#797874";
ctx.stroke();
ctx.fillStyle = "lightslategrey";
ctx.fill();
}
function addShadows() {
ctx.shadowColor = "beige"; // color
ctx.shadowBlur = 160; // blur level
ctx.shadowOffsetX = 15; // horizontal offset
ctx.shadowOffsetY = 15; // vertical offset
}
function addShadows2() {
ctx.shadowColor = "black";
ctx.shadowBlur = 40;
ctx.shadowOffsetX = 15;
ctx.shadowOffsetY = 10;
}
function addShadows3() {
ctx.shadowColor = "beige";
ctx.shadowBlur = 160;
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
}
init();
<canvas id="myCanvas" width="900" height="900">Your browser does not support the canvas tag.</canvas>

How to rotate only a line around it's middle point?

I want to display a windmill on js canvas. For now, I display a green line on a cube. I have a problem with rotating the line around it's middle point. Also, I don't want my cube to move. Save() doesn't seem to work? I don't know what I'm doing wrong. I tried looking the answer online but they don't seem to work or I don't understand them. Elements in my canvas somehow disappear.
var x = 600;
function init()
{
window.requestAnimationFrame(draw);
}
function draw()
{
var ctx = document.getElementById('canvas').getContext('2d');
ctx.clearRect(0, 0, 600, 600);
// sciana przednia
ctx.lineWidth = 1;
ctx.strokeStyle = "#000000";
ctx.strokeRect(x/2,x/2,x/4,x/4);
//sciana gorna
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = "#000000";
ctx.moveTo(x/2,x/2);
ctx.lineTo(x-x/3,x/4+x/6);
ctx.lineTo(x-x/8,x/4+x/6);
ctx.lineTo(x/2+x/4,x/2);
ctx.closePath();
ctx.stroke();
//sciana prawa
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = "#000000";
ctx.moveTo(x/2+x/4,x/2+x/4);
ctx.lineTo(x-x/8,x/2+x/7);
ctx.lineTo(x-x/8,x/4+x/6);
ctx.stroke();
ctx.closePath();
//raczka
ctx.beginPath();
ctx.lineWidth = 5;
ctx.strokeStyle = "#808080";
ctx.moveTo(x/2+x/5,x/2-x/5);
ctx.lineTo(x/2+x/5,x/2-x/8+50);
ctx.stroke();
ctx.closePath();
ctx.save();
//smiglo
ctx.beginPath();
ctx.translate(x/2, x/2);
ctx.rotate( (Math.PI / 180) * 25);
ctx.translate(-x/2, -x/2);
ctx.fillStyle = "#00cc00";
ctx.fillRect(x/2+x/5-100,x/2-x/5,200,10);
ctx.closePath();
ctx.restore();
window.requestAnimationFrame(draw);
}
init();
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');
var x = 600;
function init() {
window.requestAnimationFrame(draw);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// sciana przednia
ctx.lineWidth = 1;
ctx.strokeStyle = "#000000";
ctx.strokeRect(x / 2, x / 2, x / 4, x / 4);
//sciana gorna
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = "#000000";
ctx.moveTo(x / 2, x / 2);
ctx.lineTo(x - x / 3, x / 4 + x / 6);
ctx.lineTo(x - x / 8, x / 4 + x / 6);
ctx.lineTo(x / 2 + x / 4, x / 2);
ctx.closePath();
ctx.stroke();
//sciana prawa
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = "#000000";
ctx.moveTo(x / 2 + x / 4, x / 2 + x / 4);
ctx.lineTo(x - x / 8, x / 2 + x / 7);
ctx.lineTo(x - x / 8, x / 4 + x / 6);
ctx.stroke();
ctx.closePath();
//raczka
ctx.beginPath();
ctx.lineWidth = 5;
ctx.strokeStyle = "#808080";
ctx.moveTo(x / 2 + x / 5, x / 2 - x / 5);
ctx.lineTo(x / 2 + x / 5, x / 2 - x / 8 + 50);
ctx.stroke();
ctx.closePath();
ctx.save();
//smiglo
ctx.beginPath();
ctx.translate(x / 2, x / 2);
ctx.rotate((Math.PI / 180) * 25);
ctx.translate(-x / 2, -x / 2);
ctx.fillStyle = "#00cc00";
ctx.fillRect(x / 2 + x / 5 - 100, x / 2 - x / 5, 200, 10);
ctx.closePath();
ctx.restore();
window.requestAnimationFrame(draw);
}
init();
<canvas id="canvas" width=600 height=600></canvas>
Edit: I understand now how to rotate around a certain point. I still don't know how to rotate only the line not the whole thing.
Talking about the rotation, I think that you did well: the green line is rotated by 25 degrees in your example. You just need to rotate its middle point.
But to do so, I think it's better if you make other changes in your code: the part that draws the cube is difficult to handle, whenever you want to edit your code, this part will cause issues. I suggest to isolate it in a drawCube() function and to use proper (x,y) coordinates.
According to me, it should look like this:
function draw() {
angle += 5;
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(Math.PI / 180 * angle);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
// It rotates
drawLine();
ctx.restore();
// It doesn't rotate
drawCube();
}
Then, your code will work. All you will have to do is to make the line rotate around its middle point, but you said that you know how to do it.
Good luck!
EDIT: I added a snippet with an working example, and with a cube like yours as well, may help.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var btnExample = document.getElementById('btnExample');
var btnCube = document.getElementById('btnCube');
var angle = 0;
var fps = 1000 / 60;
var propellerWidth = 100;
var propellerHeight = 10;
var towerWidth = 2;
var towerHeight = 100;
var mode = {
CUBE: 'CUBE',
EXAMPLE: 'EXAMPLE'
}
var currentMode = mode.EXAMPLE;
btnExample.onclick = function() {
currentMode = mode.EXAMPLE;
}
btnCube.onclick = function() {
currentMode = mode.CUBE;
}
setInterval(function() {
angle += 3;
draw(canvas, ctx, (canvas.width - propellerWidth) / 2, (canvas.height - propellerWidth) / 2, angle);
}, fps);
function draw(canvas, ctx, cx, cy, angle) {
var towerX = cx + propellerWidth / 2 - towerWidth / 2;
var towerY = cy + propellerWidth / 2;
var propellerX = (canvas.width - propellerWidth) / 2;
var propellerY = (canvas.height - propellerHeight) / 2;
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw other things that don't rotate
if (currentMode === mode.EXAMPLE) {
drawHelp(canvas, ctx);
}
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(Math.PI / 180 * angle);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
// Draw things that rotate
drawPropeller(ctx, propellerX, propellerY, propellerWidth, propellerHeight);
ctx.restore();
// Draw other things that don't rotate
if (currentMode === mode.EXAMPLE) {
drawTower(ctx, towerX, towerY, towerWidth, towerHeight);
} else if (currentMode === mode.CUBE) {
drawCube(ctx, towerX, towerY, 30);
}
}
function drawPropeller(ctx, propellerX, propellerY, propellerWidth, propellerHeight) {
ctx.fillStyle = 'black';
ctx.fillRect(propellerX, propellerY, propellerWidth, propellerHeight);
}
function drawTower(ctx, towerX, towerY, towerWidth, towerHeight) {
ctx.fillStyle = 'red';
ctx.fillRect(towerX, towerY, towerWidth, towerHeight);
}
function drawCube(ctx, x, y, size) {
ctx.strokeStyle = 'black';
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x, y + size);
ctx.closePath();
ctx.stroke();
var x1 = x - size + (size / 4) + (size / 16);
var y1 = y + (size * 1.25);
var x2 = x1 + (size / 3);
var y2 = y1 - (size * 2 / 3);
var x3 = x2 + size;
var y3 = y2;
var x4 = x3 - (size / 3);
var y4 = y1;
var x5 = x4;
var y5 = y4 + size;
var x6 = x3;
var y6 = y3 + size;
ctx.strokeRect(x1, y1, size, size);
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x3, y3);
ctx.lineTo(x4, y4);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x3, y3);
ctx.lineTo(x6, y6);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x5, y5);
ctx.lineTo(x6, y6);
ctx.closePath();
ctx.stroke();
}
function drawHelp(canvas, ctx) {
ctx.globalAlpha = 0.2;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(canvas.width, canvas.height);
ctx.moveTo(canvas.width, 0);
ctx.lineTo(0, canvas.height);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, propellerWidth / 2, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, propellerWidth / 2, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.globalAlpha = 1;
}
canvas {
border: 1px solid black;
}
<canvas id="canvas" width=200 height=200></canvas>
<br>
<button id="btnExample">Example</button>
<button id="btnCube">Cube</button>

How to make a small triangle in a rectangle shape in canvas?

I want to add a small triangle similar to this example:
As you can see from the image there is a triangle in the middle of the side, I would like to have that in canvas.
This is what I have so far
// JavaScript for drawing on canvas
// applying colors + three triangles
function draw() {
// canvas with id="myCanvas"
var canvas = document.getElementById('myCanvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
roundRect(ctx, 100, 100, 180, 60, 10, true);
}
}
function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
if (typeof stroke == "undefined") {
stroke = true;
}
if (typeof radius === "undefined") {
radius = 5;
}
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
if (stroke) {
ctx.stroke();
}
if (fill) {
ctx.fill();
}
}
draw();
<canvas id="myCanvas" width="700" height="410">
<p>Some default content can appear here.</p>
</canvas>
<p>Triangles!</p>
4 arcs for a rounded box plus a triangle to fit..
You can create a rounded box with just the rounded corners. Adding the triangle is just a matter of setting out the 3 points between drawing two corners.
The example draws two types of quote boxes, left and right.
The size, corner radius, triangle size and position are all set as arguments.
The animation is just to show the variations possible.
const ctx = canvas.getContext("2d");
// r is radius of corners in pixels
// quoteSize in pixels
// quotePos as fraction of avalible space 0-1
function roundedQuoteBoxLeft(x, y, w, h, r, quoteSize, quotePos) {
// draw 4 corners of box from top, left, top right , bottom right, bottom left
ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);
ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2);
ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5);
ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI);
// make sure trianle fits
if (quoteSize > h - r * 2) { quoteSize = h - r * 2 }
// get triangle position
var qy = (h - (r * 2 + quoteSize)) * quotePos + r + y;
// draw triangle
ctx.lineTo(x, qy + quoteSize);
ctx.lineTo(x - quoteSize, qy + quoteSize / 2);
ctx.lineTo(x, qy);
// and add the last line back to start
ctx.closePath();
}
function roundedQuoteBoxRight(x, y, w, h, r, quoteSize, quotePos) {
// draw top arcs from left to right
ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);
ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2);
// make sure trianle fits
if (quoteSize > h - r * 2) { quoteSize = h - r * 2 }
// get pos of triangle
var qy = (h - (r * 2 + quoteSize)) * quotePos + r + y;
// draw triangle
ctx.lineTo(x + w, qy);
ctx.lineTo(x + w + quoteSize, qy + quoteSize / 2);
ctx.lineTo(x + w, qy + quoteSize);
// draw remaining arcs
ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5);
ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI);
// and add the last line back to start
ctx.closePath();
}
function sin(time) {
return Math.sin(time) * 0.5 + 0.5;
}
requestAnimationFrame(drawIt)
function drawIt(time) {
ctx.clearRect(0, 0, 500, 250);
// get some sizes
var width = sin(time / 1000) * 100 + 100;
var height = sin(time / 1300) * 50 + 100;
var radius = sin(time / 900) * 20 + 5;
var x = sin(time / 1900) * 20 + 20;
var y = sin(time / 1400) * 50 + 10;
var quotePos = sin(time / 700)
var quoteSize = x - 10;
// set up box render
ctx.lineJoin = "round";
ctx.strokeStyle = "#8D4";
ctx.lineWidth = 4;
ctx.fillStyle = "#482";
// draw left quote box
ctx.beginPath();
roundedQuoteBoxLeft(x, y, width, height, radius, quoteSize, quotePos);
ctx.fill();
ctx.stroke()
x += width + 10;
width = 500 - x - quoteSize;
// draw right quote box
ctx.beginPath();
roundedQuoteBoxRight(x, y, width, height, radius, quoteSize, quotePos);
ctx.fill();
ctx.stroke()
/// animate
requestAnimationFrame(drawIt)
}
<canvas id="canvas" width="500" height="250"></canvas>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Your Canvas</title>
<style type="text/css"><!--
#container { position: relative; }
#imageTemp { position: absolute; top: 1px; left: 1px; }
--></style>
</head>
<body>
<canvas id="imageView" width="600" height="500"></canvas>
<script type="text/javascript">
var canvas, context, canvaso, contexto;
canvaso = document.getElementById('imageView');
context = canvaso.getContext('2d');
context.lineWidth = 5;
context.strokeStyle = '#000000';
context.beginPath();
context.moveTo(143, 224);
context.lineTo(168, 191);
context.stroke();
context.closePath();
context.strokeStyle = '#000000';
context.beginPath();
context.moveTo(143, 221);
context.lineTo(169, 247);
context.stroke();
context.closePath();
context.strokeStyle = '#000000';
context.strokeRect(168, 124, 242, 182);
</script>
</body>
</html>

Basketball Physics Collision Detection and Bounce Physics

I am making a basketball physics simulator. I am am using a parametric equation to calculate the path of the ball. I am having a hard time with collision detection with the front of the rim, backboard, pole, and the court floor (bottom of canvas). Additionally I want to make the ball bounce when hitting these objects but I am having a hard time. Can anyone offer some help with this problem?
Here is the code snippet:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.transform(1, 0, 0, -1, 0, canvas.height)
ctx.translate(canvas.width / 2, canvas.height / 2);
var speed = 5;
var gravity = 16;
var bounce = 10;
var mouseX = 0;
var mouseY = 0;
var stage = 1;
var x = 0;
var y = 0;
var xOrgn = 0;
var yOrgn = 0;
var xClk = 175;
var yClk = 100;
var mag = 0;
var ang = 0;
var xVel = 0;
var yVel = 0;
var time = 0;
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, 12, 0, Math.PI * 2);
ctx.fillStyle = "#FF8C00";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x, y + 12);
ctx.lineTo(x, y - 12);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x - 12, y);
ctx.lineTo(x + 12, y);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x - 8, y - 8);
ctx.bezierCurveTo(x - 2, y - 4, x - 2, y + 4, x - 8, y + 8);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x + 8, y - 8);
ctx.bezierCurveTo(x + 2, y - 4, x + 2, y + 4, x + 8, y + 8);
ctx.strokeStyle = 'black';
ctx.stroke();
}
function drawHoop() {
ctx.beginPath();
ctx.rect(228, -160, 12, 172);
ctx.fillStyle = "#191919";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(222, -12, 6, 80);
ctx.fillStyle = "#666666";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(171, -6, 51, 6);
ctx.fillStyle = "#e50000";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(171, -3, 3, 0, Math.PI * 2);
ctx.fillStyle = "#e50000";
ctx.fill();
ctx.closePath();
}
function drawCursor() {
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(mouseX - 12, mouseY);
ctx.lineTo(mouseX + 12, mouseY);
ctx.strokeStyle = '#00cd00';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(mouseX, mouseY - 12);
ctx.lineTo(mouseX, mouseY + 12);
ctx.strokeStyle = '#00cd00';
ctx.stroke();
ctx.closePath();
}
function calcVel() {
mag = Math.sqrt((Math.pow(xClk - xOrgn, 2) + Math.pow(yClk - yOrgn, 2)) / 4);
ang = Math.atan((yClk - yOrgn) / (xClk - xOrgn));
xVel = mag * Math.cos(ang);
yVel = mag * Math.sin(ang);
}
function draw() {
ctx.clearRect(-(canvas.width / 2), -(canvas.height / 2), canvas.width, canvas.height);
ctx.canvas.addEventListener('mousemove', function(event) {
mouseX = event.clientX - ctx.canvas.offsetLeft - canvas.width / 2;
mouseY = -event.clientY + ctx.canvas.offsetTop + canvas.height / 2;
});
drawBall();
drawHoop();
if (stage === 1) {
x = mouseX;
y = mouseY;
ctx.canvas.addEventListener('click', function(event) {
xOrgn = x;
yOrgn = y;
stage = 2;
});
} else if (stage === 2) {
drawCursor();
ctx.canvas.addEventListener('click', function(event) {
xClk = mouseX;
yclk = mouseY;
calcVel();
time = 0;
stage = 3;
});
} else if (stage === 3) {
x = xVel * time + xOrgn;
y = -gravity * Math.pow(time, 2) + yVel * time + yOrgn;
time = time + speed * 0.01;
}
}
setInterval(draw, 10);
canvas {
background: white;
}
<canvas id="myCanvas" width="480" height="320"></canvas>
Here is the code in jsfiddle: JSfiddle
You have to add collision detection in "Stage 3" only. Since the locations and sizes of everything are hardcoded, it's pretty simple to add in collision detection item by item. (but if you make this much more complicated, I would add in some variables or objects that make it easy to get the positions of things as variables, etc).
I added in a horizontal bounce when the ball hits the backboard, and a vertical bounce off the floor. Any others are similar.
(Note, what made these possible were updating x and y (and xVel, yVel) iteratively rather than from a determined equation. The results are the same, but the calculation and dynamic behaviour are easier).
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.transform(1, 0, 0, -1, 0, canvas.height)
ctx.translate(canvas.width / 2, canvas.height / 2);
var speed = 5;
var gravity = 16;
var bounce = 10;
var mouseX = 0;
var mouseY = 0;
var stage = 1;
var x = 0;
var y = 0;
var xOrgn = 0;
var yOrgn = 0;
var xClk = 175;
var yClk = 100;
var mag = 0;
var ang = 0;
var xVel = 0;
var yVel = 0;
var time = 0;
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, 12, 0, Math.PI * 2);
ctx.fillStyle = "#FF8C00";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x, y + 12);
ctx.lineTo(x, y - 12);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x - 12, y);
ctx.lineTo(x + 12, y);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x - 8, y - 8);
ctx.bezierCurveTo(x - 2, y - 4, x - 2, y + 4, x - 8, y + 8);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x + 8, y - 8);
ctx.bezierCurveTo(x + 2, y - 4, x + 2, y + 4, x + 8, y + 8);
ctx.strokeStyle = 'black';
ctx.stroke();
}
function drawHoop() {
ctx.beginPath();
ctx.rect(228, -160, 12, 172);
ctx.fillStyle = "#191919";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(222, -12, 6, 80);
ctx.fillStyle = "#666666";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(171, -6, 51, 6);
ctx.fillStyle = "#e50000";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(171, -3, 3, 0, Math.PI * 2);
ctx.fillStyle = "#e50000";
ctx.fill();
ctx.closePath();
}
function drawCursor() {
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(mouseX - 12, mouseY);
ctx.lineTo(mouseX + 12, mouseY);
ctx.strokeStyle = '#00cd00';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(mouseX, mouseY - 12);
ctx.lineTo(mouseX, mouseY + 12);
ctx.strokeStyle = '#00cd00';
ctx.stroke();
ctx.closePath();
}
function calcVel() {
mag = Math.sqrt((Math.pow(xClk - xOrgn, 2) + Math.pow(yClk - yOrgn, 2)) / 4);
ang = Math.atan((yClk - yOrgn) / (xClk - xOrgn));
xVel = mag * Math.cos(ang);
yVel = mag * Math.sin(ang);
}
function draw() {
ctx.clearRect(-(canvas.width / 2), -(canvas.height / 2), canvas.width, canvas.height);
ctx.canvas.addEventListener('mousemove', function(event) {
mouseX = event.clientX - ctx.canvas.offsetLeft - canvas.width / 2;
mouseY = -event.clientY + ctx.canvas.offsetTop + canvas.height / 2;
});
drawBall();
drawHoop();
if (stage === 1) {
x = mouseX;
y = mouseY;
ctx.canvas.addEventListener('click', function(event) {
xOrgn = x;
yOrgn = y;
stage = 2;
});
} else if (stage === 2) {
drawCursor();
ctx.canvas.addEventListener('click', function(event) {
xClk = mouseX;
yclk = mouseY;
calcVel();
time = 0;
stage = 3;
});
} else if (stage === 3) {
//x = xVel * time + xOrgn;
// update x from it's own value so we can vary the xVel.
x += xVel * speed * 0.01;
//y = -gravity * Math.pow(time, 2) + yVel * time + yOrgn;
// update yVel and y iteratively instead of this determined calculation
//y = -gravity * Math.pow(time, 2) + yVel * time + yOrgn;
yVel -= gravity * 0.1;
y += yVel * speed * 0.01;
// do a collision check: the backboard.
if (x > 222 - 12 && y > -12 && y < 62) {
xVel *= -1;
}
// with floor
if(y <= -142) {
y = -142;
yVel *= -1;
}
time = time + speed * 0.01;
}
}
setInterval(draw, 10);
canvas {
background: white;
}
<canvas id="myCanvas" width="480" height="320"></canvas>
You can handle any other collisions you want similarly

Categories