How do I reset the velocity variable of my object - javascript

How can I reset the velocity variable in my objects. I am making a canvas game, in which stars fall from the top of the Canvas. Problem is when I run the game in a setinterval() the velocity keeps getting greater and greater. What i want is the speed to stay the same unless i change it.
function Star(x, y, rad, velocity, fill){
this.x = Math.floor(Math.random() * 999);//this create a random number between 0 and 599 on the x axis
this.y = 0;
this.rad = Math.floor((Math.random() * 30) + 15);//this create a random number between 10 and 30 for the radius
this.velocity = 5;
this.fill = fill
this.draw = function(){
ctx.beginPath();
ctx.fillStyle = this.fill;
ctx.arc(this.x, this.y, this.rad, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
this.y += this.velocity;
}
}
function createMultipleStars(){
for (var i = 0; i <= numOfStars; i++)
stars[i] = new Star(i * 50, 10, i, i, "rgba(255,215,0,0.6)");
}
//createMultipleStars();
function step() {
ctx.clearRect(0,0,canvas.width, canvas.height);
for (var i = 0; i<= numOfStars; i++)
stars[i].draw();
requestAnimationFrame(step);
}
spaceShip.drawSpaceShip();
var myVar = setInterval(function(){ init() }, 4000);
function init(){
createMultipleStars();
step();
}

Your frames per second were increasing with each interval. Every four seconds another step function is added to the animation frame. To fix this I added an fps counter and singleton pattern. With the singleton pattern you shouldn't break the requestAnimationFrame max 60 fps. Without it you will see that the fps increases. Technically it can't go above 60 but the step function runs multiple times in the same frame increasing the velocity each time and making the stars run faster.
var canvas = document.getElementById('can');
var ctx = canvas.getContext('2d');
var stars = [];
var numOfStars = 10;
function Star(x, y, rad, velocity, fill) {
this.x = Math.floor(Math.random() * 999); //this create a random number between 0 and 599 on the x axis
this.y = 0;
this.rad = Math.floor((Math.random() * 30) + 15); //this create a random number between 10 and 30 for the radius
this.velocity = 5;
this.fill = fill
this.draw = function() {
ctx.beginPath();
ctx.fillStyle = this.fill;
ctx.arc(this.x, this.y, this.rad, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
this.y += this.velocity;
}
}
function createMultipleStars() {
for (var i = 0; i <= numOfStars; i++) {
stars[i] = new Star(i * 50, 10, i, i, "rgba(255,215,0,0.6)");
}
}
function fps() {
var now = (new Date()).getTime();
fps.frames++;
if ((now - fps.lastFps) >= 1000) {
fps.total = fps.frames;
fps.lastFps = now;
fps.frames = 0;
}
return fps.total;
}
fps.frames = 0;
fps.lastFps = (new Date()).getTime();
fps.total = 0;
// Step is a singleton. Only one instance can be created.
function Step() {
// comment out the line below to see what happens when not running
// singleton
if (Step.instance !== null) return Step.instance;
var self = this;
function frame() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i <= numOfStars; i++) {
stars[i].draw();
}
ctx.fillStyle = "red";
ctx.fillText("FPS: " + fps(), 10, 10);
requestAnimationFrame(frame);
}
frame();
Step.instance = this;
return this;
}
Step.instance = null;
//spaceShip.drawSpaceShip();
function init() {
var myVar = setInterval(function() {
createMultipleStars();
var step = new Step();
}, 4000);
createMultipleStars();
//
var step = new Step();
var step = new Step();
var step = new Step();
var step = new Step();
}
init();
#can {
border: 1px solid #FF0000;
}
<canvas id="can" width="400" height="200"></canvas>

Your issue is very simple : you are using both requestAnimationFrame and setInterval to drive the animation. More and more render loops get created and run at the same time, causing the issue
Separate the concerns :
have one render loop working for ever with RequestAnimationFrame
Have a setInterval-ed function inject some new stuff in your game.
So the only change you need to do is here :
var myVar = setInterval(createMultipleStars, 4000);

Related

Creating a checkered board with pieces in HTML5 canvas

I am experimenting with canvas in HTML and JS and attempting to draw a canvas of a chess board with 16 pieces on each side of it. I was able to create the chess board but am stuck on how I would draw just specifically the 16 pieces on each side (The pieces can just be circles so just one side with 16 red circles, one side with 16 blue circles).
I don't know why this is so confusing to me, I know you probably just need a for loop stopping at the specific coordinates but to get different colored pieces on each side as well as stopping at certain part is giving me trouble.
I would just like assistance on where in my code would I be placing the chess pieces in. If you could just modify my current code and place comments on where you made the changes so I could see then that would be very appreciated.
Here is what I have so far to make the checkers board:
<canvas id="canvas" width="300" height="300"></canvas>
function drawCheckeredBackground(can, nRow, nCol) {
var ctx = can.getContext("2d");
var w = can.width;
var h = can.height;
nRow = nRow || 8;
nCol = nCol || 8;
w /= nCol;
h /= nRow;
for (var i = 0; i < nRow; ++i) {
for (var j = 0, col = nCol / 2; j < col; ++j) {
ctx.rect(2 * j * w + (i % 2 ? 0 : w), i * h, w, h);
}
}
ctx.fill();
}
var canvas = document.getElementById("canvas");
drawCheckeredBackground(canvas);
Here is how I want the chess board to look like, with 16 pieces on each side like so. I just quickly made this example in paint:
https://i.imgur.com/BvbxzSZ.png
This isn't the most beautiful solution possible, but it should offer some basic ideas and is adjustable using your step variable idea. Chances are, you'll need to refactor when going for actual pieces.
const drawBoard = (ctx, step) => {
for (let i = 0; i < 8; i++) {
for (let j = 0; j < 8; j++) {
ctx.fillStyle = (i + j) & 1 ? "black" : "white";
ctx.fillRect(j * step, i * step, step, step);
}
}
};
const drawPieces = (ctx, y, color, step) => {
ctx.fillStyle = color;
for (let i = y; i < 2 * step + y; i += step) {
for (let j = step / 2; j < 8 * step; j += step) {
ctx.beginPath();
ctx.arc(j, i - step / 2, step / 3, 0, Math.PI * 2);
ctx.fill();
}
}
};
const step = 60;
const c = document.createElement("canvas");
c.height = c.width = step * 8;
document.body.appendChild(c);
const ctx = c.getContext("2d");
drawBoard(ctx, step);
drawPieces(ctx, step, "red", step);
drawPieces(ctx, step * 7, "blue", step);
Play with it at JSFiddle.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
display: block;
margin: auto;
border: solid 1px white;
border-radius: 10px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
// Self executing function
void function() {
// Turn on strict js rules for this scope
"use strict";
// Classes
function ChessPeice(x,y,radius) {
this.x = x || 0.0;
this.y = y || 0.0;
this.radius = radius || 1.0;
}
ChessPeice.prototype = {
tick: function() {
},
render: function(ctx) {
ctx.moveTo(
this.x + this.radius,
this.y
);
ctx.arc(
this.x,
this.y,
this.radius,
0.0,
2.0 * Math.PI,
false
);
}
};
// Constructor, when called with 'new' creates an object and puts it
// in the 'this' variable, new properties can then be added to it.
function Chessboard(width,height) {
this.boardWidth = width || 1;
this.boardHeight = height || 1;
this.tileWidth = this.boardWidth / this.H_TILE_COUNT;
this.tileHeight = this.boardHeight / this.V_TILE_COUNT;
this.whitePeices = [];
this.blackPeices = [];
for (var y = 0; y < 2; ++y) {
for (var x = 0; x < this.V_TILE_COUNT; ++x) {
this.whitePeices.push(
new ChessPeice(
x * this.tileWidth + (this.tileWidth >> 1),
y * this.tileHeight + (this.tileHeight >> 1),
this.CHESS_PIECE_RADIUS
)
);
this.blackPeices.push(
new ChessPeice(
x * this.tileWidth + (this.tileWidth >> 1),
(this.V_TILE_COUNT - 1 - y) * this.tileHeight + (this.tileHeight >> 1),
this.CHESS_PIECE_RADIUS
)
);
}
}
}
// Prototype object, all objects created with 'new Chessboard()'
// will share the properties in the prototype, use it for constant values
// & class functions
Chessboard.prototype = {
H_TILE_COUNT: 8, // How many white & black tiles per axis?
V_TILE_COUNT: 8,
EDGE_THICKNESS: 10.0,
EDGE_COLOUR: "#603E11FF",
WHITE_TILE_COLOUR: "#BBBBBBFF",
BLACK_TILE_COLOUR: "#555555FF",
CHESS_PIECE_RADIUS: 5.0,
WHITE_PIECE_COLOUR: "#EEEEEEFF",
BLACK_PIECE_COLOUR: "#333333FF",
tick: function() {
// You can add game logic here
},
render: function(ctx) {
// Draw white tiles
var x = 0;
var y = 0;
var totalTiles = this.H_TILE_COUNT * this.V_TILE_COUNT;
ctx.fillStyle = this.WHITE_TILE_COLOUR;
ctx.beginPath();
for (var i = 0; i < totalTiles; ++i) {
ctx.rect(
x * this.tileWidth,
y * this.tileHeight,
this.tileWidth,
this.tileHeight
);
x += 2;
if (x >= this.H_TILE_COUNT) {
x = this.H_TILE_COUNT - x + 1;
++y;
}
}
ctx.fill();
// Draw black tiles
x = 1;
y = 0;
ctx.fillStyle = this.BLACK_TILE_COLOUR;
ctx.beginPath();
for (var i = 0; i < totalTiles; ++i) {
ctx.rect(
x * this.tileWidth,
y * this.tileHeight,
this.tileWidth,
this.tileHeight
);
x += 2;
if (x >= this.H_TILE_COUNT) {
x = this.H_TILE_COUNT - x + 1;
++y;
}
}
ctx.fill();
// Draw edge
ctx.lineWidth = this.EDGE_THICKNESS >> 1;
ctx.strokeStyle = this.EDGE_COLOUR;
ctx.beginPath();
ctx.rect(0,0,this.boardWidth,this.boardHeight);
ctx.stroke();
// Draw white pieces
ctx.lineWidth = 2;
ctx.strokeStyle = "#000000FF";
ctx.fillStyle = this.WHITE_PIECE_COLOUR;
ctx.beginPath();
for (var i = 0; i < this.whitePeices.length; ++i) {
this.whitePeices[i].render(ctx);
}
ctx.fill();
ctx.stroke();
// Draw black pieces
ctx.lineWidth = 2;
ctx.strokeStyle = "#000000FF";
ctx.fillStyle = this.BLACK_PIECE_COLOUR;
ctx.beginPath();
for (var i = 0; i < this.blackPeices.length; ++i) {
this.blackPeices[i].render(ctx);
}
ctx.fill();
ctx.stroke();
}
};
// Variables
var canvasWidth = 160;
var canvasHeight = 160;
var canvas = null;
var ctx = null;
var board = null;
// Game Loop
function loop() {
// Tick (Update game logic)
board.tick();
// Render
ctx.fillStyle = "gray";
ctx.fillRect(0,0,canvasWidth,canvasHeight);
board.render(ctx);
//
requestAnimationFrame(loop);
}
// Entry Point (Runs when the page loads)
onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
ctx = canvas.getContext("2d");
board = new Chessboard(canvasWidth,canvasHeight);
loop();
}
}();
</script>
</body>
</html>

setInterval is slowing down over time [duplicate]

This question already has an answer here:
HTML5 Canvas slows down with each stroke and clear
(1 answer)
Closed 4 years ago.
I've just started learning javascript.
My problem is, that the website is slowing down after a few seconds. I'm using setinterval to "tick" the things on the screen and i feel like this might be the cause of the problem.
Here is my code:
var r = [];
var ctx;
function init() {
ctx = document.getElementById("canvas").getContext("2d");
for(var i = 0; i < 20; i++) {
var x = Math.floor(Math.random() * (ctx.canvas.width - 20)) + 10;
var y = Math.floor(Math.random() * (ctx.canvas.height - 20)) + 10;
r.push(new Rect(x,y, 10, 10, ctx));
}
window.setInterval(tick,10);
window.setInterval(draw,10);
}
function tick() {
for(var i = 0; i < r.length; i++) {
r[i].tick();
}
}
function draw() {
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
for(var i = 0; i < r.length; i++) {
r[i].draw();
}
ctx.lineWidth = 5;
ctx.rect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.stroke();
}
Here's another class:
class Rect {
constructor(x, y, width, height, ctx) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.cxt = ctx;
this.xVel = 2.5;
this.yVel = 2.5;
if (Math.random() < 0.5) {
this.xVel = -this.xVel;
}
if (Math.random() < 0.5) {
this.yVel = -this.yVel;
}
}
tick(){
this.x += this.xVel;
this.y += this.yVel;
if (this.x + this.width >= ctx.canvas.width | this.x <= 0){
this.xVel = -this.xVel;
}
if (this.y + this.height >= ctx.canvas.height | this.y <= 0){
this.yVel = -this.yVel;
}
}
draw() {
ctx.fillRect(this.x,this.y,this.width,this.height);
}
}
So what exactly is the cause of this issue and how can i fix it?
You can download the files here: https://drive.google.com/file/d/1pg4ASPvjbo2ua_7cCvQvzucLgbegtiw6/view?usp=sharing
This issue is in your draw function.
Canvas-es remember all the lines drawn, over time it slows down your animation.
The solution is to reset the lines drawn list by calling ctx.beginPath()
function draw() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
for (var i = 0; i < r.length; i++) {
r[i].draw();
}
ctx.beginPath()
ctx.lineWidth = 5;
ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.stroke();
}
First of all the screen only refreshes at a rate of 16 milliseconds (assuming 60 frames per second). So calling the two function at 10 milliseconds is a bit overkill. But in the modern browser, we now have a native support to do anything when the screen refreshes. Its called request animation frame: requestAnimationFrame(animationrDrawCallback).
You can read more about it here: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame. Now back to your code, it can be refactored like this:
const r = [];
const ctx;
function init() {
ctx = document.getElementById("canvas").getContext("2d");
for(let i = 0; i < 20; i++) {
const x = Math.floor(Math.random() * (ctx.canvas.width - 20)) + 10;
const y = Math.floor(Math.random() * (ctx.canvas.height - 20)) + 10;
r.push(new Rect(x,y, 10, 10, ctx));
}
// start our animation
window.requestAnimationFrame(render);
}
function render() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
r.forEach((item) => {
item.trick();
item.draw();
})
ctx.beginPath();
ctx.lineWidth = 5;
ctx.rect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.stroke();
// this will be called at next screen refresh
window.requestAnimationFrame(render);
}
The BIGGEST BONUS of using requestAnimationFrame is that it will stop executing when the tab is no longer in focus. Big boost for smartphones. Hope this helps.

Creating trail over an already made canvas

So I am trying to implement a concept of shooting star over an already drawn canvas of slowly moving stars. But I haven't found a way to do so. I tried implementing an array to make it look so but the trail isn't as efficient.
This code is as follows:
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var mouse = {
x : innerWidth/2,
y : innerHeight/2
};
var colors = [
'#3399CC',
'#67B8DE',
'#91C9E8',
'#B4DCED',
'#E8F8FF'
];
addEventListener('resize', function () {
canvas.width = innerWidth;
canvas.height = innerHeight;
init();
});
var isClicked = false;
addEventListener('click', function () {
mouse.x = event.clientX;
mouse.y = event.clientY;
isClicked = true;
});
function randomIntFromRange (min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function randomColor (colors) {
return colors[Math.floor(Math.random() * colors.length)];
}
function Stars (x, y, radius, dy, color) {
this.x = x;
this.y = y;
this.radius = radius;
this.dy = dy;
this.color = color;
this.draw = function () {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
c.shadowColor = this.color;
c.shadowBlur = 15;
c.shadowOffsetX = 0;
c.shadowOffsetY = 0;
c.fillStyle = this.color;
c.fill();
c.closePath();
}
this.update = function () {
if (this.y < -10) {
this.y = canvas.height + 10;
this.x = randomIntFromRange(this.radius, canvas.width);
}
this.y -= this.dy;
this.draw();
}
}
function ShootingStar (x, y, radius) {
this.x = x;
this.y = y;
this.radius = radius;
this.draw = function () {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
c.shadowColor = "red";
c.shadowBlur = 15;
c.shadowOffsetX = 0;
c.shadowOffsetY = 0;
c.fillStyle = "red";
c.fill();
c.closePath();
}
this.update = function () {
this.x += 10;
this.y += 10;
this.draw();
}
}
let stars = [];
let shooting_star = [];
function init () {
stars = [];
for (var i = 0; i < 300; i++) {
var stars_radius = randomIntFromRange(2, 3);
var stars_x = randomIntFromRange(stars_radius, canvas.width);
var stars_y = randomIntFromRange(stars_radius, canvas.height);
var stars_dy = Math.random() / 6;
var color = randomColor(colors);
stars.push(new Stars(stars_x, stars_y, stars_radius, stars_dy, color));
}
}
function Explode () {
shooting_star = [];
var shooting_star_radius = 3;
var shooting_star_x = mouse.x;
var shooting_star_y = mouse.y;
for (var i = 0; i < 50; i++) {
shooting_star.push(new ShootingStar(shooting_star_x, shooting_star_y, shooting_star_radius));
if (shooting_star_radius > 0.2) {
shooting_star_radius -= .2;
}
var initiator = randomIntFromRange(-1, 1);
console.log(initiator);
shooting_star_x -= 3;
shooting_star_y -= 3;
}
}
function animate () {
requestAnimationFrame(animate);
c.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < stars.length; i++)
stars[i].update();
for (var i = 0; i < shooting_star.length; i++)
shooting_star[i].update();
if (isClicked == true) {
Explode();
isClicked = false;
}
}
init();
animate();
Here is the jsfiddle to it
https://jsfiddle.net/qjug4qdz/
I basically want the shooting star to come from a random location to the point where my mouse is clicked, but the trail is difficult to work with using an array.
Basic particles
For the particular effect you are looking for you can use a basic particle system.
As the shooting star moves you will drop a particle that starts with the star velocity and then slows and fades out.
The particle
You first start with the particle. I like to use Object.assign when creating objects but you can use any method you like, class, new, factory...
// This defines a particle and is copied to create new particles
const starDust = {
x : 0, // the current position
y : 0,
dx : 0, // delta x,y (velocity)
dy : 0,
drag : 0, // the rate that the particle slows down.
life : 0, // count down till particle is removed
age : 0, // the starting value of life
draw(){ // function to update and draw the particle
this.x += this.dx; // move it
this.y += this.dy;
this.dx *= this.drag; // slow it down
this.dy *= this.drag;
const unitLife = (this.life / this.age); // get the life left as a value
// from 0 to 1 where 0 is end
ctx.globalAlpha = unitLife; // set the alpha
ctx.beginPath();
ctx.arc(this.x,this.y,4,0,Math.PI); // draw the particle
this.life -= 1; // count down
return this.life > 0; // return true if still alive
}
Be memory aware.
A common mistake when creating particle systems is that people forget that creating and destroying objects will add a lot of work to javascripts memory management. The worst of which is GC (Garbage Collection). GC is a major source of lag and if you are wasteful with memory it will impact the quality of the animation. For simple particles it may not be noticeable, but you may want hundreds of complex particles spawning each frame. This is when GC realy hurts the animation.
Most Game engines reduce the GC impact by reusing objects rather than dereferencing and recreating. A common method is an object pool, where a second array holds objects that are no longer used. When a new object is needed then the pool is first checked, if there is an unused object, it is used, else a new object is created.
This way you never delete any particles, greatly reducing the GC workload, and preventing your animation from dropping frames (if you use a lot of particles)
Particle needs initializer
But you need to provide a way to re-initialize the object. Thus add the function init to the particle that will set it up to be used again
init(x,y,vx,vy){ // where x,y and velocity vx,vy of shooting star
this.x = x;
this.y = y;
this.dx = vx;
this.dy = vy;
// give a random age
this.age = (Math.random() * 100 + 60) | 0; // in frames and | 0 floors the value
this.life = this.age; // and set the life countdown
this.drag = Math.random() * 0.01 + 0.99; // the drag that slows the particle down
}
} // end of starDust object.
The arrays
To manage all the particles we create object that has arrays and methods for adding, creating and rendering the particles. In this case I will call it dust
const dust = {
particles : [], // array of active particles
pool : [], // array of unused particels
createParticle(particleDesc){ // creates a new particle from particleDesc
return Object.assign({},particleDesc);
},
add(x,y,vx,vy){ // where x,y and velocity vx,vy
var dust;
if(this.pool.length){ // are there any particles in the pool
dust = this.pool.pop(); // get one
}else{ // else there are no spare particles so create a new one
dust = this.createParticle(starDust);
}
dust.init(x,y,vx,vy); // init the particle
this.items.push(dust); // put it in the active particle array
return dust; // return it (sometimes you want to do something with it)
},
draw(){ // updates and draws all active particles
var i = 0;
while(i < this.items.length){ // iterate each particle in items
if(this.items[i].draw() === false){ // is it dead??
this.pool.push(this.items.splice(i,1)[0]); // if dead put in the pool for later
}else{ i ++ } // if not dead get index of next particle
}
}
}//end of dust object
Using the particle system
The simplest way to create a particle is to use a random number and set the chance of a particle being created every frame.
In your main loop
// assuming that the falling star is called star and has an x,y and dx,dy (delta)
if(star) { // only if there is a start to spawn from
// add a particle once every 10 frame (on average
if(Math.random() < 0.1) {
dust.add(star.x, star.y, star.dx, star.dy); // add some dust at the shooting starts position and speed
}
}
dust.draw(); // draw all particles
And that is it.

requestAnimationFrame too fast

I am creating simple animation in canvas. I use requestanimationframe to control animation. There is 3 circle. But i can only see 3 circle and animation is too fast. My question is how can i slow my animation and how can show each frame. here is my live link.
const swing = (time) => {
for(var i = 0; i < 3; i++) {
circle[i] = new ball();
circle[i].draw(i, circle[i].color);
}
requestAnimationFrame(swing);
}
requestAnimationFrame(swing);
//swing();
function ball(i){
this.x = random(100, 150);
this.y = random(40, 60);
this.radius = 45;
this.color = getRandomColor(random(1, 30));
this.strokeText = "m"
ctx.clearRect(0, 0, el.width, el.height);
this.draw = function(i, color){
ctx.beginPath();
ctx.font="30px Verdana";
ctx.arc(i*this.x, this.y, this.radius, 0, 2*Math.PI, false);
ctx.fillStyle = color;
ctx.globalAlpha = 0.5;
ctx.strokeText(i,i*this.x,this.y);
ctx.fill();
ctx.closePath();
}
}
Thanks in advance.
Edited:- I am creating something similar like this:- http://codepen.io/jscottsmith/pen/oWyxjp?editors=1010
Just a simple example, let three balls doing some circular motion:
// refer below
// http://codepen.io/jscottsmith/pen/oWyxjp?editors=1010
const el = document.getElementById('canvas'),
ctx = el.getContext('2d');
let circle = [];
el.width = document.body.clientWidth;
el.height = document.body.clientHeight;
const getRandomColor = (i) => {
let count = 30,
color = 1,
hue = (i / count * color) * 360;
return `hsla(${hue}, 100%, 50%, 1)`
}
for (var i = 0; i < 3; i++) {
circle[i] = new ball();
}
let angle = 0;
let speed = 0.02;
const swing = (time) => {
ctx.clearRect(0, 0, el.width, el.height);
for (var i = 0; i < 3; i++) {
circle[i].x = circle[i].x + Math.cos(angle) * 1;
circle[i].y = circle[i].y + Math.sin(angle) * 2;
}
for (var i = 0; i < 3; i++) {
circle[i].draw(i, circle[i].color);
}
angle += speed;
requestAnimationFrame(swing);
}
requestAnimationFrame(swing);
//swing();
function ball(i){
this.x = random(100, 150);
this.y = random(40, 60);
this.radius = 45;
this.color = getRandomColor(random(1, 30));
this.strokeText = "m"
this.draw = function(i, color){
ctx.beginPath();
ctx.font="30px Verdana";
ctx.arc(i*this.x, this.y, this.radius, 0, 2*Math.PI, false);
ctx.fillStyle = color;
ctx.globalAlpha = 0.5;
ctx.strokeText(i,i*this.x,this.y);
ctx.fill();
ctx.closePath();
}
}
function random (num1, num2) {
var max = Math.max(num1, num2);
var min = Math.min(num1, num2);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
#canvas {
width: 600px;
height: 600px;
}
<canvas id="canvas"></canvas>

How to add random shapes on click using canvas animation

For this animation On click I need a different shapes to be made I need 5 different shapes in total. Also Ive had a hard time doing these things,
add a random motion vector to every circle
add an interval timer that redraws the background and each circle in its new position every 30 milliseconds
Check if any circle is outside the canvas width and height, and if so reverse its direction back onto the screen
also maybe If I can have some random text to fade in and fade out every couple of seconds too
The code...
var canvas;
var context;
var circles = [];
var timer;
function Circle(x, y, color) {
this.x = x;
this.y = y;
this.dx = Math.random() * 4 - 2;
this.dy = Math.random() * 4 - 2;
this.color = color;
}
function init() {
canvas = document.getElementById('canvas');
context = canvas.getContext("2d");
window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('orientationchange', resizeCanvas, false);
resizeCanvas();
canvas.onclick = function (event) {
handleClick(event.clientX, event.clientY);
};
timer = setInterval(resizeCanvas, 20);
}
function handleClick(x, y) {
var found = false;
for (var i = 0; i < circles.length; i++) {
d = Math.sqrt((circles[i].x - x) * (circles[i].x - x) + (circles[i].y - y) * (circles[i].y - y));
if (d <= 30) {
circles.splice(i, 1);
found = true;
}
}
fillBackgroundColor();
if (!found) {
var colors = ["red", "green", "blue", "orange", "purple", "yellow"];
var color = colors[Math.floor(Math.random() * colors.length)];
circles.push(new Circle(x, y, color));
}
for (var i = 0; i < circles.length; i++) {
drawCircle(circles[i]);
}
}
function drawCircle(circle) {
context.beginPath();
context.arc(circle.x, circle.y, 30, 0, degreesToRadians(360), true);
context.fillStyle = circle.color;
context.fill();
if (circle.x + circle.dx > canvas.width || circle.x + circle.dx < 0)
circle.dx = -circle.dx;
if (circle.y + circle.dy > canvas.height || circle.y + circle.dy < 0)
circle.dy = -circle.dy;
circle.x += circle.dx;
circle.y += circle.dy;
}
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
fillBackgroundColor();
for (var i = 0; i < circles.length; i++) {
drawCircle(circles[i]);
}
}
function fillBackgroundColor() {
//var colors = ["white", "yellow", "blue", "red"];
//var bgColor = colors[Math.floor(Math.random() * colors.length)];
context.fillStyle = 'black';
context.fillRect(0, 0, canvas.width, canvas.height);
}
function degreesToRadians(degrees) {
//converts from degrees to radians and returns
return (degrees * Math.PI) / 180;
}
window.onload = init;
<canvas id='canvas' width=500 height=500></canvas>

Categories

Resources