Having problems with making explosions on Canvas with javascript - javascript

I am new here and a student in an informatics degree program. I am having trouble with some parts of one of my projects due next week. We were asked to do a project that contained all of these requirements.
fullscreen and webapp enabled
touch and mouse events
appropriately use arrays and functions
use event locations (pageX & pageY) to impact the x and y behavior of your canvas elements
must continually generate visuals -- no 'end of animation' permitted
So i chose to do some sort of fireworks show in which a certain amount of generated balls of different sizes were going to come in from the bottom of the canvas page and fly up towards around 1/3 from the top then they would get spliced out and an explosion would go on at the same time. While the circle would explode a new one would be generated at the bottom of the canvas and it would continue and so forth.
So i need help doing the explosion(creating tiny circles that shoot away from the center of the circle which disappear(exploded)) when they get to 1/3 of the top as well as adding mouse events / touch events to prematurely make the circles explode. Any help would be great thanks.
<html>
<head>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<title>basic_canvas</title>
<style>
#mycanvas {
margin: 0 auto;
background-color: black;
}
body {
margin: 0
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script>
//global variables
var mycanvas;
var ctx;
//make an array of balls shooting from the bottom of the page to the middle of the page
var Balls = [];
var fireworks = [];
//make a ready handler for our page to tirgger my javascript
$(document).ready(function () {
mycanvas = document.getElementById('mycanvas');
// mycanvas = $('#mycanvas');
ctx = mycanvas.getContext('2d');
mycanvas.width = window.innerWidth;
mycanvas.height = window.innerHeight;
setInterval(draw, 33);
//make the balls here
for (var i = 0; i < 30; i++) {
Balls[i] = new Ball(getRandomFloat(0, mycanvas.width), mycanvas.height, getRandomFloat(20, 70), getRandomFloat(0.1, 1));
}
// event listeners here
});
function draw() {
ctx.clearRect(0, 0, mycanvas.width, mycanvas.height);
for (var i = 0; i < Balls.length; i++) {
Balls[i].makeCirc();
Balls[i].moveCirc();
}
}
function degToRad(deg) {
radians = (deg * Math.PI / 180) - Math.PI / 2;
return radians;
}
function getRandomFloat(min, max) {
return Math.random() * (max - min) + min;
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
//make my flying balls here
//ball(x start value, y start value, radius, speed)
function Ball(xin, yin, radin, spin) {
//make all the variables for the Ball
var x = xin;
var y = yin;
var r = radin;
var sp = spin;
//generating random colors for the circles
var c = 'rgb(' +
getRandomInt(0, 255) +
',' +
getRandomInt(0, 255) +
',' +
getRandomInt(0, 255) +
')';
//draw the circle
this.makeCirc = function () {
ctx.fillStyle = c;
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fill();
}
this.moveCirc = function () {
y -= sp;
if (y + r < mycanvas.height / 3) {
// fireworks[fireworks.length] = new Fireworks(x,y,2);
Balls.splice(Balls.indexOf(this), 1);
}
}
}
// function Firework(xin,yin,rin){
// var x = xin;
// var y = yin;
// var r = rin;
//
// }
</script>
</head>
<body>
<canvas id="mycanvas"></canvas>
</body>
</html>

So i was able to fix my project. Just in case someone else ever needs something similar i am posting the fixed code.
<html>
<head>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<title>Balloon_Fireworks</title>
<style>
#mycanvas {
margin: 0 auto;
background-color: black;
}
body {
margin: 0
}
#score_card {
position:absolute;
top:25px;
left:25px;
padding-top:25px;
padding-left:25px;
width:100px;
height:75px;
background-color: rgb(112,200,112);
color:rgba(50,50,50,0.5);
font-size:50px;
font-family: sans-serif;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script>
//global variables
var mycanvas;
var ctx;
//make an array of balls shooting from the bottom of the page to the middle of the page
var Balls = [];
var Fireworks = [];
//global keep track of where i click
var mouseX;
var mouseY;
//Counts the number of fireworks popped
var point_counter = 0;
//make a ready handler for our page to tirgger my javascript
$(document).ready(function () {
mycanvas = document.getElementById('mycanvas');
// mycanvas = $('#mycanvas');
ctx = mycanvas.getContext('2d');
mycanvas.width = window.innerWidth;
mycanvas.height = window.innerHeight;
mycanvas.addEventListener('mousedown', explodeThis);
mycanvas.addEventListener('touchstart', explodeThis);
setInterval(draw, 33);
//make the balls here
//new Ball( x, y, rad, speedx, speedy);
for (var i = 0; i < 30; i++) {
Balls[i] = new Ball(getRandomFloat(0, mycanvas.width), mycanvas.height, getRandomFloat(50, 70), getRandomFloat(-3, -1));
}
// event listeners here
});
function draw() {
ctx.clearRect(0, 0, mycanvas.width, mycanvas.height);
for (var i = 0; i < Balls.length; i++) {
Balls[i].makeCirc();
Balls[i].moveCirc();
}
for (var i = 0; i< Fireworks.length; i++){
Fireworks[i].drawFire();
Fireworks[i].moveFire();
}
}
function explodeThis(e){
e.preventDefault();
mouseX = e.pageX || e.targetTouches[0].pageX;
mouseY = e.pageY || e.targetTouches[0].pageY;
for (var i = 0; i< Balls.length; i++){
Balls[i].hit();
}
}
function degToRad(deg) {
radians = (deg * Math.PI / 180) - Math.PI / 2;
return radians;
}
function getRandomFloat(min, max) {
return Math.random() * (max - min) + min;
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
//make my flying balls here
//ball(x start value, y start value, radius, speed)
function Ball(xin, yin, radin, spyin, spxin, cin){
//make all the variables for the Ball
var x = xin;
var y = yin;
var r = radin;
var spy = spyin;
var spx = spxin || 0;
//make a gravity for me
var g = getRandomFloat(.0001,.05);
//generating random colors for the circles
var c = cin || 'rgb(' +
getRandomInt(0, 255) +
',' +
getRandomInt(0, 255) +
',' +
getRandomInt(0, 255) +
')';
//draw the circle
this.makeCirc = function () {
ctx.fillStyle = c;
ctx.beginPath();
ctx.arc(x,y,r,0,Math.PI * 2);
ctx.fill();
};
this.moveCirc = function () {
y += spy;
x += spx;
// At 1/3 from the top the balls will explode
if (y+r < mycanvas.height/3) {
}
};
this.gravityMe = function () {
spy += g;
};
this.hit = function () {
var d = Math.sqrt( (x-mouseX)*(x-mouseX) + (y-mouseY)*(y-mouseY) );
if (d < r){
//when it hits
spy = 0;
//make a new set of fireworks using the last place
Fireworks[Fireworks.length] = new Firework (x, y, r, c);
//access that last one you just made, and add in particles
Fireworks[Fireworks.length-1].makeFire();
c = 'rgba(255,255,255,0)';
r = 0;
point_counter ++;
// console.log(point_counter);
document.getElementById('score_card').innerHTML = point_counter;
//make a new one
Balls[Balls.length] = new Ball(getRandomFloat(0, mycanvas.width), mycanvas.height+70, getRandomFloat(50, 70), getRandomFloat(-5, -2));
}
};
}
// make the circles that explode out
//firework(x value, y value, radius)
function Firework(xin,yin,rin, cin){
var x = xin;
var y = yin;
var r = rin;
var color = cin;
//make an array
var particles = new Array(getRandomInt(10,30));
this.makeFire = function () {
for ( var i = 0; i < particles.length; i++){
particles[i] = new Ball(getRandomFloat(x-r,x+r), getRandomFloat(y-r, y+r), getRandomInt(2,10), getRandomFloat(-1,1), getRandomFloat(-3, 3), color);
}
};
this.drawFire = function () {
for ( var i = 0; i < particles.length; i++){
particles[i].makeCirc();
}
};
this.moveFire = function () {
for ( var i = 0; i < particles.length; i++){
particles[i].moveCirc();
particles[i].gravityMe();
}
};
}
</script>
</head>
<body>
<canvas id="mycanvas"></canvas>
<div id = "score_card"></div>
</body>
</html>

Related

I have an issue in my canvas. I want to change the color of particles. currently they are in red color. How can I change...?

I have a issue in my canvas. i want to change the color of particles. currently they are in black color. How i can change..? here is my code please let me know if u have any solution. I have a issue in my canvas. i want to change the color of particles. currently they are in red color. How i can change..?
Here my source code:
`
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<style>
html, body {
height: 100%;
padding: 0;
margin: 0;
background: rgba(0, 0, 0, 0.879);
}
canvas {
position: absolute;
width: 100%;
height: 100%;
}
</style>
</HEAD>
<BODY>
<canvas id="pinkboard"></canvas>
<script>
/*
* Settings
*/
var settings = {
particles: {
length: 300, // maximum amount of particles
duration: 2, // particle duration in sec
velocity: 100, // particle velocity in pixels/sec
effect: -0.75, // play with this for a nice effect
size: 30, // particle size in pixels
},
};
/*
* RequestAnimationFrame polyfill by Erik Möller
*/
(function(){var b=0;var c=["ms","moz","webkit","o"];for(var a=0;a<c.length&&!window.requestAnimationFrame;++a){window.requestAnimationFrame=window[c[a]+"RequestAnimationFrame"];window.cancelAnimationFrame=window[c[a]+"CancelAnimationFrame"]||window[c[a]+"CancelRequestAnimationFrame"]}if(!window.requestAnimationFrame){window.requestAnimationFrame=function(h,e){var d=new Date().getTime();var f=Math.max(0,16-(d-b));var g=window.setTimeout(function(){h(d+f)},f);b=d+f;return g}}if(!window.cancelAnimationFrame){window.cancelAnimationFrame=function(d){clearTimeout(d)}}}());
/*
* Point class
*/
var Point = (function() {
function Point(x, y) {
this.x = (typeof x !== 'undefined') ? x : 0;
this.y = (typeof y !== 'undefined') ? y : 0;
}
Point.prototype.clone = function() {
return new Point(this.x, this.y);
};
Point.prototype.length = function(length) {
if (typeof length == 'undefined')
return Math.sqrt(this.x * this.x + this.y * this.y);
this.normalize();
this.x *= length;
this.y *= length;
return this;
};
Point.prototype.normalize = function() {
var length = this.length();
this.x /= length;
this.y /= length;
return this;
};
return Point;
})();
/*
* Particle class
*/
var Particle = (function() {
function Particle() {
this.position = new Point();
this.velocity = new Point();
this.acceleration = new Point();
this.age = 0;
}
Particle.prototype.initialize = function(x, y, dx, dy) {
this.position.x = x;
this.position.y = y;
this.velocity.x = dx;
this.velocity.y = dy;
this.acceleration.x = dx * settings.particles.effect;
this.acceleration.y = dy * settings.particles.effect;
this.age = 0;
};
Particle.prototype.update = function(deltaTime) {
this.position.x += this.velocity.x * deltaTime;
this.position.y += this.velocity.y * deltaTime;
this.velocity.x += this.acceleration.x * deltaTime;
this.velocity.y += this.acceleration.y * deltaTime;
this.age += deltaTime;
};
Particle.prototype.draw = function(context, image) {
function ease(t) {
return (--t) * t * t + 1;
}
var size = image.width * ease(this.age / settings.particles.duration);
context.globalAlpha = 1 - this.age / settings.particles.duration;
context.drawImage(image, this.position.x - size / 2, this.position.y - size / 2, size, size);
};
return Particle;
})();
/*
* ParticlePool class
*/
var ParticlePool = (function() {
var particles,
firstActive = 0,
firstFree = 0,
duration = settings.particles.duration;
function ParticlePool(length) {
// create and populate particle pool
particles = new Array(length);
for (var i = 0; i < particles.length; i++)
particles[i] = new Particle();
}
ParticlePool.prototype.add = function(x, y, dx, dy) {
particles[firstFree].initialize(x, y, dx, dy);
// handle circular queue
firstFree++;
if (firstFree == particles.length) firstFree = 0;
if (firstActive == firstFree ) firstActive++;
if (firstActive == particles.length) firstActive = 0;
};
ParticlePool.prototype.update = function(deltaTime) {
var i;
// update active particles
if (firstActive < firstFree) {
for (i = firstActive; i < firstFree; i++)
particles[i].update(deltaTime);
}
if (firstFree < firstActive) {
for (i = firstActive; i < particles.length; i++)
particles[i].update(deltaTime);
for (i = 0; i < firstFree; i++)
particles[i].update(deltaTime);
}
// remove inactive particles
while (particles[firstActive].age >= duration && firstActive != firstFree) {
firstActive++;
if (firstActive == particles.length) firstActive = 0;
}
};
ParticlePool.prototype.draw = function(context, image) {
// draw active particles
if (firstActive < firstFree) {
for (i = firstActive; i < firstFree; i++)
particles[i].draw(context, image);
}
if (firstFree < firstActive) {
for (i = firstActive; i < particles.length; i++)
particles[i].draw(context, image);
for (i = 0; i < firstFree; i++)
particles[i].draw(context, image);
}
};
return ParticlePool;
})();
/*
* Putting it all together
*/
(function(canvas) {
var context = canvas.getContext('2d'),
particles = new ParticlePool(settings.particles.length),
particleRate = settings.particles.length / settings.particles.duration, // particles/sec
time;
// get point on heart with -PI <= t <= PI
function pointOnHeart(t) {
return new Point(
160 * Math.pow(Math.sin(t), 3),
130 * Math.cos(t) - 50 * Math.cos(2 * t) - 20 * Math.cos(3 * t) - 10 * Math.cos(4 * t) + 25
);
}
// creating the particle image using a dummy canvas
var image = (function() {
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d');
canvas.width = settings.particles.size;
canvas.height = settings.particles.size;
// helper function to create the path
function to(t) {
var point = pointOnHeart(t);
point.x = settings.particles.size / 2 + point.x * settings.particles.size / 350;
point.y = settings.particles.size / 2 - point.y * settings.particles.size / 350;
return point;
}
// create the path
context.beginPath();
var t = -Math.PI;
var point = to(t);
context.moveTo(point.x, point.y);
while (t < Math.PI) {
t += 0.01; // baby steps!
point = to(t);
context.lineTo(point.x, point.y);
}
context.closePath();
// create the fill
context.fillStyle = '#ea80b0';
context.fill();
// create the image
var image = new Image();
image.src = canvas.toDataURL();
return image;
})();
// render that thing!
function render() {
// next animation frame
requestAnimationFrame(render);
// update time
var newTime = new Date().getTime() / 1000,
deltaTime = newTime - (time || newTime);
time = newTime;
// clear canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// create new particles
var amount = particleRate * deltaTime;
for (var i = 0; i < amount; i++) {
var pos = pointOnHeart(Math.PI - 2 * Math.PI * Math.random());
var dir = pos.clone().length(settings.particles.velocity);
particles.add(canvas.width / 2 + pos.x, canvas.height / 2 - pos.y, dir.x, -dir.y);
}
// update and draw particles
particles.update(deltaTime);
particles.draw(context, image);
}
// handle (re-)sizing of the canvas
function onResize() {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
}
window.onresize = onResize;
// delay rendering bootstrap
setTimeout(function() {
onResize();
render();
}, 10);
})(document.getElementById('pinkboard'));
</script>
</BODY>
</HTML>
`
I ended up with a red heart effect, how do I change it to blue

Code crashes because object's .rad property becomes undefined

I am creating an ecosystem with my code consisting of plants, herbivores, and carnivores being represented through circles. For some reason, my code has been crashing after a certain amount of time ranging from 30 seconds to 8 minutes but no more than that.
After doing some digging I have found out that the crash is a result of my object's .rad property becoming undefined for some reason. It's probably a result of me improperly setting up my functions but I haven't been able to find a solution.
var plantSpawn = 5;
var herbSpawn = 3;
var carnSpawn = 2;
var myPlants = new Array();
var myCarns = new Array();
var myHerbs = new Array();
//////////////PLANTS//////////////////
function createPlants() {
reproducePlants();
setInterval(reproducePlants, 5000);
}
function reproducePlants() {
for(var p=0; p<plantSpawn; p++){
var rr = Math.round(Math.random() * 150);
var gg = Math.round(Math.random() * 255);
var bb = Math.round(Math.random() * 150);
var plant = new Object();
plant.x = Math.random() * canvas.width;
plant.y = Math.random() * canvas.height;
plant.rad = 2 + Math.random()*2;
plant.skin = 'rgba('+rr+','+gg+','+bb+', 1)';
myPlants.push(plant);
}
}
function drawPlants(){
var plantAmt = myPlants.length;
for(var j=0; j<plantAmt; j++) {
if (myPlants[j].x + myPlants[j].rad >= canvas.width) {
myPlants[j].x -= 10;
}
if (myPlants[j].y + myPlants[j].rad >= canvas.height) {
myPlants[j].y -= 10;
}
context.beginPath();
context.arc(myPlants[j].x, myPlants[j].y, myPlants[j].rad, 0, Math.PI*2, false);
context.closePath();
context.fillStyle = myPlants[j].skin;
context.fill();
}
}
function killPlants() {
plantDeath();
setInterval(plantDeath, 30000); //play with inc
}
function plantDeath() {
myPlants.splice(0,5);
}
//////////////HERBS//////////////////
function herbsLife(){
reproduceHerbs();
setInterval(reproduceHerbs, 10000);
herbsDeath();
setInterval(herbsDeath, 90000); //1.5 minutes
setInterval(herbsStarve, 10000); //10 seconds
}
function reproduceHerbs() {
for (var h=0; h<herbSpawn; h++){
var gg = Math.round(Math.random() * 100);
var bb = Math.round(Math.random() * 255);
var herbivore = new Object();
herbivore.x = Math.random() * canvas.width;
herbivore.y = Math.random() * canvas.height;
herbivore.rad = 5 + Math.random()*3;
herbivore.skin = 'rgba(0,'+gg+','+bb+', 1)';
herbivore.speedH = -3 + Math.random()*1.2;
herbivore.speedV = -3 + Math.random()*1.2;
herbivore.dirH = 1;
herbivore.dirV = 1;
myHerbs.push(herbivore);
}
}
function drawHerbs() {
var herbAmt = myHerbs.length;
for(var j=0; j<herbAmt; j++) {
var hX = myHerbs[j].x;
var hY = myHerbs[j].y;
//HERB MOVEMENT//
myHerbs[j].x += myHerbs[j].dirH * myHerbs[j].speedH;
if (myHerbs[j].x > canvas.width + myHerbs[j].rad || myHerbs[j].x < 0){
myHerbs[j].dirH *= -1;
}
myHerbs[j].y += myHerbs[j].dirV * myHerbs[j].speedV;
if (myHerbs[j].y > canvas.height + myHerbs[j].rad || myHerbs[j].y < 0){
myHerbs[j].dirV *= -1;
}
context.beginPath();
context.arc(myHerbs[j].x, myHerbs[j].y, myHerbs[j].rad, 0, Math.PI*2, false);
context.closePath();
context.fillStyle = myHerbs[j].skin;
context.fill();
}
}
function herbsDeath() {
myHerbs.splice(0,3);
}
function herbsEat() {
for (var k=0; k<myPlants.length; k++){
var pX = myPlants[k].x;
var pY = myPlants[k].y;
for (var h=0; h<myHerbs.length; h++){
var hX = myHerbs[h].x;
var hY = myHerbs[h].y;
var eX = hX - pX;
var eY = hY - pY;
var dist = Math.sqrt(Math.pow(eX,2) + Math.pow(eY,2));
if (dist < myPlants[k].rad*2) {
myPlants.splice(k,1);
myHerbs[h].rad += 1;
}
}
}
}
function herbsStarve() {
for (var s=0; s<myPlants.length; s++){
myHerbs[s].rad -= 1;
if (myHerbs[s].rad <= 2) {
myHerbs.splice(s,1);
}
}
}
//////////////CARNS//////////////////
function carnsLife() {
reproduceCarns();
setInterval(reproduceCarns, 20000); //20 seconds
carnsDeath();
setInterval(carnsDeath, 60000); //50 seconds
setInterval(carnsStarve, 7500); //10 seconds
}
function reproduceCarns() {
for (var c=0; c<carnSpawn; c++){
var rr = Math.round(Math.random() * 255);
var gg = Math.round(Math.random() * 100);
var carnivore = new Object();
carnivore.x = Math.random() * canvas.width;
carnivore.y = Math.random() * canvas.height;
carnivore.rad = 7 + Math.random()*3;
carnivore.skin = 'rgba('+rr+','+gg+',0, 1)';
//bigger random = slower//
carnivore.speedH = -3 + Math.random()*2;
carnivore.speedV = -3 + Math.random()*2;
carnivore.dirH = 1;
carnivore.dirV = 1;
myCarns.push(carnivore);
}
}
function drawCarns() {
var carnAmt = myCarns.length;
for(var j=0; j<carnAmt; j++) {
//CARN MOVEMENT//
myCarns[j].x += myCarns[j].dirH * myCarns[j].speedH;
if (myCarns[j].x > canvas.width + myCarns[j].rad || myCarns[j].x < 0){
myCarns[j].dirH *= -1;
}
myCarns[j].y += myCarns[j].dirV * myCarns[j].speedV;
if (myCarns[j].y > canvas.height + myCarns[j].rad || myCarns[j].y < 0){
myCarns[j].dirV *= -1;
}
context.beginPath();
context.arc(myCarns[j].x, myCarns[j].y, myCarns[j].rad, 0, Math.PI*2, false);
context.closePath();
context.fillStyle = myCarns[j].skin;
context.fill();
}
}
function carnsDeath() {
myCarns.splice(0,2);
}
function carnsEat() {
for (var k=0; k<myCarns.length; k++){
var cX = myCarns[k].x;
var cY = myCarns[k].y;
for (var h=0; h<myHerbs.length; h++){
var hX = myHerbs[h].x;
var hY = myHerbs[h].y;
var eX = cX - hX;
var eY = cY - hY;
var dist = Math.sqrt(Math.pow(eX,2) + Math.pow(eY,2));
if (dist < myCarns[k].rad*1.2 && myCarns[k].rad > myHerbs[h].rad) {
myHerbs.splice(h,1);
myCarns[k].rad += 1;
}
}
}
}
function carnsStarve() {
for (var q=0; q<myPlants.length; q++){
myCarns[q].rad = myCarns[q].rad - 1;
if (myCarns[q].rad <= 5) {
myCarns.splice(q,1);
}
}
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title> Ecosystem </title>
<!-- import external .js scripts here -->
<script type="text/javascript" src="Creatures.js" ></script>
<!-- modify CSS properties here -->
<style type="text/css">
body,td,th {
font-family: Monaco, "Courier New", "monospace";
font-size: 14px;
color: rgba(255,255,255,1);
}
body {
background-color: rgba(0,0,0,1);
}
#container {
position: relative;
text-align: left;
width: 95%;
height: 800px;
}
#fmxCanvas {
position: relative;
background-color:rgba(255,255,255,1);
border: rgba(255,255,255,1) thin dashed;
cursor: crosshair;
display: inline-block;
}
</style>
</head>
<body>
<div id="container">
<!-- START HTML CODE HERE -->
<canvas id="fmxCanvas" width="800" height="800"></canvas>
<div id="display"></div>
<!-- FINISH HTML CODE HERE -->
</div>
<script>
///////////////////////////////////////////////////////////////////////
// DECLARE requestAnimFrame
var rAF = window.requestAnimFrame ||
window.mozRequestAnimFrame ||
window.webkitRequestAnimFrame ||
window.msRequestAnimFrame;
var fps = 30;
window.requestAnimFrame = (
function(callback) {
return rAF ||
function(callback) {
window.setTimeout(callback, 1000 / fps);
};
})();
///////////////////////////////////////////////////////////////////////
// DEFINE GLOBAL VARIABLES HERE
var canvas;
var context;
canvas = document.getElementById("fmxCanvas");
context = canvas.getContext("2d");
var canvas1;
var context1;
canvas1 = document.createElement("canvas");
context1 = canvas1.getContext("2d");
canvas1.width = canvas.width;
canvas1.height = canvas.height;
var display;
display = document.getElementById('display');
var counter;
///////////////////////////////////////////////////////////////////////
// DEFINE YOUR GLOBAL VARIABLES HERE
///////////////////////////////////////////////////////////////////////
// CALL THE EVENT LISTENERS
window.addEventListener("load", setup, false);
//////////////////////////////////////////////////////////////////////
// ADD EVENT LISTENERS
canvas.addEventListener("mousemove", mousePos, false);
//////////////////////////////////////////////////////////////////////
// MOUSE COORDINATES
var stage, mouseX, mouseY;
function mousePos(event) {
stage = canvas.getBoundingClientRect();
mouseX = event.clientX - stage.left;
mouseY = event.clientY - stage.top;
}
/////////////////////////////////////////////////////////////////////
// INITIALIZE THE STARTING FUNCTION
function setup() {
/////////////////////////////////////////////////////////////////////
// DECLARE STARTING VALUES OF GLOBAL VARIABLES
counter = 0;
mouseX = canvas.width/2;
mouseY = canvas.height/2;
/////////////////////////////////////////////////////////////////////
// CALL SUBSEQUENT FUNCTIONS, as many as you need
createPlants();
killPlants();
herbsLife();
carnsLife();
clear(); // COVER TRANSPARENT CANVAS OR CLEAR CANVAS
draw(); // THIS IS WHERE EVERYTHING HAPPENS
}
////////////////////////////////////////////////////////////////////
// CLEAR THE CANVAS FOR ANIMATION
// USE THIS AREA TO MODIFY BKGD
function clear() {
context.clearRect(0,0,canvas.width, canvas.height);
context1.clearRect(0,0,canvas.width, canvas.height);
// clear additional contexts here if you have more than canvas1
}
////////////////////////////////////////////////////////////////////
// THIS IS WHERE EVERYTHING HAPPENS
function draw() {
counter += 0.1; // EASIER FOR SINE COSINE FUNCTIONS
//if (counter > Math.PI*200) { counter = 0; } // RESET COUNTER
clear(); // USE THIS TO REFRESH THE FRAME AND CLEAR CANVAS
////////////////////////////////////////////////////////////////////
// >>>START HERE>>>START HERE>>>START HERE>>>START HERE>>>START HERE
drawPlants();
drawHerbs();
drawCarns();
herbsEat();
carnsEat();
// <<<END HERE<<<END HERE<<<END HERE<<<END HERE<<<END HERE<<<END HERE
///////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// HTML DISPLAY FIELD FOR TESTING PURPOSES
display.innerHTML =
// mouseX + " || " + mouseY +
" || Minutes = " + Math.trunc(counter/180) +
" || Seconds = " + Math.round(counter/3) +
"<br><br>" +
"Plants = " + myPlants.length +
"<br>" +
"Herbivores = " + myHerbs.length +
"<br>" +
"Carnivores = " + myCarns.length;
/////////////////////////////////////////////////////////////////
// LAST LINE CREATES THE ANIMATION
requestAnimFrame(draw); // CALLS draw() every nth of a second
}
</script>
</body>
</html>

HTML5 Canvas | Bouncing Balls | Looping through an image array and placing different background images on each ball, centered

I am having a bit of a nightmare applying different background images onto balls that bounce around in the canvas under the effect of gravity and the bounds of my canvas, eventually settling down and stacking at the bottom.
I have created an image array, that I am trying to loop through and create a ball for each image, where the image becomes a centred background.
I can centre the image, but this makes the balls appear to leave the bounds of my canvas. So have reverted that change.
I am unable to get the background image to be different from the previous ball. Where the image shown on all balls is the last image in the array. However the number of balls created does reflect the number of images in the array.
Here is a link to a codepen:
https://codepen.io/jason-is-my-name/pen/BbNRXB
html, body{
width:100%;
height:100%;
margin: 0;
padding: 0;
background: #333333;
}
*{
margin: 0;
padding: 0;
}
.container {
width: 410px;
height: 540px;
}
#ball-stage{
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<canvas id="ball-stage" ></canvas>
</div>
<script>
/*
/*
* Created by frontside.com.au
* Amended by Jason
*/
$(document).ready(function () {
$.ajaxSetup({
cache: true
});
var url1 = "https://code.createjs.com/easeljs-0.6.0.min.js";
$.getScript(url1, function () {
new App();
})
});
function App() {
var self = this;
self.running = false;
self.initialized = false;
var stageClicked = false;
var stage, canvas;
var canvasWidth = 410;
var canvasHeight = 540;
var bounce = -0.75;
var balls = [];
var _gravityY = 1;
var _gravityX = 0;
var FPS = 30;
var infoText, detailsText;
var ballsInitalized = false;
var iOS = navigator.userAgent.match(/(iPod|iPhone|iPad)/);
self.initialize = function () {
toggleListeners(true);
self.initCanvas();
self.initGame();
};
var toggleListeners = function (enable) {
if (!enable) return;
};
self.refresh = function () {}
self.initCanvas = function () {
canvas = $("#ball-stage").get(0);
stage = new createjs.Stage(canvas);
window.addEventListener('resize', onStageResize, false);
onStageResize();
createjs.Touch.enable(stage);
createjs.Ticker.addListener(tick);
createjs.Ticker.setFPS(FPS);
self.initialized = true;
}
self.initGame = function () {
initBalls(canvasWidth, canvasHeight);
}
var onStageResize = function () {
stage.canvas.width = canvasWidth;
stage.canvas.height = canvasHeight;
}
var initBalls = function (stageX, stageY) {
var imagesArray = ["img-1.png","img-2.png","img-3.png","img-4.png","img-5.png","img-6.png","img-7.png","img-8.png"];
for (var i = 0; i < imagesArray.length; i++) {
console.log(i);
var imageArray = imagesArray[i];
console.log(imageArray);
setTimeout(function () {
var arrayImage = new Image();
console.log(arrayImage);
arrayImage.onload = function(){
addBall(arrayImage, stageX / 2, 0);
}
arrayImage.src = imageArray;
}, i * 1000);
}
}
var addBall = function (img, x, y) {
console.log(img);
var shape = new createjs.Shape();
shape.id = balls.length;
shape.radius = 51.25;
shape.mass = shape.radius;
shape.x = x;
shape.y = y;
shape.vx = rand(-3, 3);
shape.vy = rand(-3, 3);
var image = new Image();
image.src = img;
shape.graphics.beginBitmapFill(img,'repeat').drawCircle(0, 0, shape.radius);
stage.addChild(shape);
balls.push(shape);
}
var numBalls = function () {
return balls.length;
}
var tick = function () {
balls.forEach(move);
for (var ballA, i = 0, len = numBalls() - 1; i < len; i++) {
ballA = balls[i];
for (var ballB, j = i + 1; j < numBalls(); j++) {
ballB = balls[j];
checkCollision(ballA, ballB);
}
}
stage.update();
}
var rotate = function (x, y, sin, cos, reverse) {
return {
x: (reverse) ? (x * cos + y * sin) : (x * cos - y * sin),
y: (reverse) ? (y * cos - x * sin) : (y * cos + x * sin)
};
}
var checkCollision = function (ball0, ball1) {
var dx = ball1.x - ball0.x,
dy = ball1.y - ball0.y,
dist = Math.sqrt(dx * dx + dy * dy);
//collision handling code here
if (dist < ball0.radius + ball1.radius) {
//calculate angle, sine, and cosine
var angle = Math.atan2(dy, dx),
sin = Math.sin(angle),
cos = Math.cos(angle),
//rotate ball0's position
pos0 = {
x: 0,
y: 0
}, //point
//rotate ball1's position
pos1 = rotate(dx, dy, sin, cos, true),
//rotate ball0's velocity
vel0 = rotate(ball0.vx, ball0.vy, sin, cos, true),
//rotate ball1's velocity
vel1 = rotate(ball1.vx, ball1.vy, sin, cos, true),
//collision reaction
vxTotal = vel0.x - vel1.x;
vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) /
(ball0.mass + ball1.mass);
vel1.x = vxTotal + vel0.x;
//update position - to avoid objects becoming stuck together
var absV = Math.abs(vel0.x) + Math.abs(vel1.x),
overlap = (ball0.radius + ball1.radius) - Math.abs(pos0.x - pos1.x);
pos0.x += vel0.x / absV * overlap;
pos1.x += vel1.x / absV * overlap;
//rotate positions back
var pos0F = rotate(pos0.x, pos0.y, sin, cos, false),
pos1F = rotate(pos1.x, pos1.y, sin, cos, false);
//adjust positions to actual screen positions
// ball1.x = ball0.x + pos1F.x;
setBallX(ball1, ball0.x + pos1F.x)
//ball1.y = ball0.y + pos1F.y;
setBallY(ball1, ball0.y + pos1F.y)
// ball0.x = ball0.x + pos0F.x;
setBallX(ball0, ball0.x + pos0F.x)
// ball0.y = ball0.y + pos0F.y;
setBallY(ball0, ball0.y + pos0F.y)
//rotate velocities back
var vel0F = rotate(vel0.x, vel0.y, sin, cos, false),
vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
ball0.vx = vel0F.x;
ball0.vy = vel0F.y;
ball1.vx = vel1F.x;
ball1.vy = vel1F.y;
}
}
var checkWalls = function (ball) {
if (ball.x + ball.radius > canvas.width) {
// ball.x = canvas.width - ball.radius;
setBallX(ball, canvas.width - ball.radius)
ball.vx *= bounce;
} else
if (ball.x - ball.radius < 0) {
// ball.x = ball.radius;
setBallX(ball, ball.radius)
ball.vx *= bounce;
}
if (ball.y + ball.radius > canvas.height) {
// ball.y = canvas.height - ball.radius;
setBallY(ball, canvas.height - ball.radius)
ball.vy *= bounce;
} else
if (ball.y - ball.radius < 0) {
//ball.y = ball.radius;
setBallY(ball, ball.radius)
ball.vy *= bounce;
}
}
var move = function (ball) {
ball.vy += _gravityY;
ball.vx += _gravityX;
setBallX(ball, ball.x + ball.vx)
setBallY(ball, ball.y + ball.vy)
checkWalls(ball);
}
var setBallX = function (ball, x) {
if (isNaN(ball.pointerID)) {
ball.x = x
}
}
var setBallY = function (ball, y) {
if (isNaN(ball.pointerID)) {
ball.y = y
}
}
var rand = function (min, max) {
return Math.random() * (max - min) + min;
return (Math.random() * max) + min;
}
self.initialize();
return self;
}
window.log = function f() {
log.history = log.history || [];
log.history.push(arguments);
if (this.console) {
var args = arguments,
newarr;
args.callee = args.callee.caller;
newarr = [].slice.call(args);
if (typeof console.log === 'object') log.apply.call(console.log, console, newarr);
else console.log.apply(console, newarr);
}
};
(function (a) {
function b() {}
for (var c = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","), d; !!(d = c.pop());) {
a[d] = a[d] || b;
}
})
(function () {
try {
console.log();
return window.console;
} catch (a) {
return (window.console = {});
}
}());
</script>
I have been trapped at this point in the code for about a week now and could really do with some genius' help!
Aims:
Add balls equivalent to the length of the image array.
Each ball with have its respective image as a centred background.
The balls will not leave the bounds of the canvas.
Relevant code:
initBalls()
addBall()
Thanks, Jason.
https://codepen.io/prtjohanson/pen/vPKQBg
What needed to be changed:
for (let i = 0; i < imagesArray.length; i++) {
console.log(i);
const imageArray = imagesArray[i];
setTimeout(function() {
var arrayImage = new Image();
arrayImage.onload = function() {
addBall(arrayImage, stageX / 2, 0);
};
arrayImage.src = imageArray;
}, i * 1000);
}
By the time the setTimeout callback fired, your for loop had already finished and with a var declaration, the for loop iteration has no scope of its own, with a let, each iteration has its own scope like a function does.
If it must run on browsers that don't have let or const keywords, let me know, I can provide a solution for them as well
This will work in IE11 and other browsers that don't support ES6
for (var i = 0; i < imagesArray.length; i++) {
(function(imageArray) {
setTimeout(function() {
var arrayImage = new Image();
arrayImage.onload = function() {
console.log('Add'+i);
addBall(arrayImage, stageX / 2, 0);
};
arrayImage.src = imageArray;
}, i * 1000);
})(imagesArray[i]);
}
To get the images centered, without them going out of the bounds of canvas, use a 2D transform on the beginBitmapFill operation:
var transform = new createjs.Matrix2D();
transform.appendTransform(-shape.radius, -shape.radius, 1, 1, 0);
shape.graphics.beginBitmapFill(img, "repeat", transform).drawCircle(0, 0, shape.radius);
As for there being not as many balls as there are URLs in the array, it seems that sometimes the image source URL prompts "I am not a robot" captcha. If replaced with URL-s under your control, the issue should go away.

use recursive function to draw multicolored dots on canvas using javascript

I have created a small application to create dots on an HTML canvas element. Here I have written code to draw multicolored dots in canvas.
I have created one button to change the color of the dots, And another button to sort the dots in a single line.
All are working perfectly.
"use strict";
//Canvas and context
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
//Buttons
randColBtn = document.getElementById('randColBtn'),
randPosBtn = document.getElementById('randPosBtn'),
sortDotsBtn = document.getElementById('sortDotsBtn'),
//Globals
dots = [],
color = '#AAAAAA';
//Constants
const DOT_RADIUS = 20;
//Dot constructor
var Dot = function(x, y, c) {
this.x = x;
this.y = y;
this.color = c;
this.draw = function() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x-DOT_RADIUS/2, this.y-DOT_RADIUS/2, DOT_RADIUS, 0, 2 * Math.PI);
ctx.fill();
}
}
//Checks if the mouse has clicked within the boundaries of an existing dot
var isOverlap = function(d) {
for (var i = dots.length - 1; i >= 0; i--) {
let normalizedX = d.x - dots[i].x,
normalizedY = d.y - dots[i].y;
if (-DOT_RADIUS < normalizedX && normalizedX < DOT_RADIUS && -DOT_RADIUS < normalizedY && normalizedY < DOT_RADIUS) {
dots.splice(i,1);
return true;
}
}
return false;
}
//Event listeners
canvas.addEventListener("click", function(e) {
var dot = new Dot(e.clientX,e.clientY,color);
if (!isOverlap(dot)) {
dot.draw();
dots.push(dot);
} else {
ctx.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0; i < dots.length; i++) {
dots[i].draw();
}
}
});
randColBtn.addEventListener("click", function(e) {
color = "rgb(" + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + ")";
});
randPosBtn.addEventListener("click", function(e) {
ctx.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0; i < dots.length; i++) {
dots[i].x = Math.random()*canvas.width;
dots[i].y = Math.random()*canvas.height;
dots[i].draw();
}
});
sortDotsBtn.addEventListener("click", function(e) {
ctx.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0; i < dots.length; i++) {
dots[i].x = 2*DOT_RADIUS*i%canvas.width + 3/2*DOT_RADIUS;
dots[i].y = Math.floor(2*DOT_RADIUS * i/canvas.width) * 2*DOT_RADIUS + 3/2*DOT_RADIUS;
dots[i].draw();
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DOT CLICKER</title>
<style>
#canvas {
border: thin solid black;
}
</style>
</head>
<body>
<canvas id="canvas" width=600 height=400></canvas>
<div>
<button id="randColBtn" type="button">Randomize Colour</button>
<button id="randPosBtn" type="button">Randomize Position</button>
<button id="sortDotsBtn" type="button">Sort Dots</button>
</div>
<script src="dots.js"></script>
</body>
</html>
Now I want to create a recursive function to draw the dots 10 times with a different color.
So what should I have to change in this code?
Here, Check this out:
I reorganized your code and created a new function to generate 10 random dots with random colors.
//Canvas and context
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
//Buttons
randColBtn = document.getElementById('randColBtn'),
randPosBtn = document.getElementById('randPosBtn'),
sortDotsBtn = document.getElementById('sortDotsBtn'),
//Globals
dots = [],
color = '#AAAAAA';
//Constants
const DOT_RADIUS = 20;
//Dot constructor
var Dot = function(x, y, c) {
this.x = x;
this.y = y;
this.color = c;
this.draw = function() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x-DOT_RADIUS/2, this.y-DOT_RADIUS/2, DOT_RADIUS, 0, 2 * Math.PI);
ctx.fill();
}
}
//Checks if the mouse has clicked within the boundaries of an existing dot
var isOverlap = function(d) {
for (var i = dots.length - 1; i >= 0; i--) {
let normalizedX = d.x - dots[i].x,
normalizedY = d.y - dots[i].y;
if (-DOT_RADIUS < normalizedX && normalizedX < DOT_RADIUS && -DOT_RADIUS < normalizedY && normalizedY < DOT_RADIUS) {
dots.splice(i,1);
return true;
}
}
return false;
}
//Event listeners
function canvasClick(e) {
var dot = new Dot(e.clientX,e.clientY,color);
if (!isOverlap(dot)) {
dot.draw();
dots.push(dot);
} else {
ctx.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0; i < dots.length; i++) {
dots[i].draw();
}
}
}
canvas.addEventListener("click", canvasClick,event);
function rndColor() {
color = "rgb(" + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + ")";
}
randColBtn.addEventListener("click", rndColor);
function rndPosition() {
ctx.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0; i < dots.length; i++) {
dots[i].x = Math.random()*canvas.width;
dots[i].y = Math.random()*canvas.height;
dots[i].draw();
}
}
randPosBtn.addEventListener("click", rndPosition);
function sortDots() {
ctx.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0; i < dots.length; i++) {
dots[i].x = 2*DOT_RADIUS*i%canvas.width + 3/2*DOT_RADIUS;
dots[i].y = Math.floor(2*DOT_RADIUS * i/canvas.width) * 2*DOT_RADIUS + 3/2*DOT_RADIUS;
dots[i].draw();
}
}
sortDotsBtn.addEventListener("click", sortDots);
function randDots(i) {
debugger;
rndColor();
canvasClick(0,0);
if (i==0){
rndPosition();
return;
}
randDots(--i);
}
randDotsBtn.addEventListener("click", function () {
randDots(10);
});
#canvas {
border: thin solid black;
}
<canvas id="canvas" width=600 height=400></canvas>
<div>
<button id="randColBtn" type="button">Randomize Colour</button>
<button id="randPosBtn" type="button">Randomize Position</button>
<button id="sortDotsBtn" type="button">Sort Dots</button>
<button id="randDotsBtn" type="button">Rand Dots</button>
</div>
I tried to implement your idea HERE in JSBin. You can adjust quantity of your dots and bouncing value
// dots qty
var limit = 10;
// random bouncing value
var bouncing = [-100, 100];
var rand = (min, max) => ~~(Math.random() * (max - min + 1)) + min;
// randomize you color
var randColor = ()=> "rgb(" + ~~(Math.random()*256) + "," + ~~(Math.random()*256) + "," + ~~(Math.random()*256) + ")";
// generate list of random dots
var newDots = [...Array(limit||0)]
.map((v,i) => new Dot(
e.clientX + rand.apply(null, bouncing),
e.clientY + rand.apply(null, bouncing),
randColor()
))
// draw new dots
newDots.forEach(dot=>dot.draw());
//extend global dots
dots = [...dots, ...newDots];

(Javascript) Bouncing balls clip into wall

document.addEventListener("DOMContentLoaded", function(event){
var context,
width = window.screen.availWidth - 120,
height = window.screen.availHeight - 120,
xTemp,
yTemp,
x = [],
y = [],
dx = [0],
dy = [5],
gravity = [1],
bounceTime = [1],
canvas = document.getElementById("bouncingField"),
isSpawned = 0,
image = new Image();
document.getElementById("bouncingField").width = width;
document.getElementById("bouncingField").height = height;
//Image to use as ball texture
image.src = "http://www.freeiconspng.com/uploads/soccer-ball-icon-14.png";
//Run func init on page load
window.onload = init;
//Get 2d context and repaint every 10 milliseconds
context = bouncingField.getContext('2d');
setInterval(repaint, 10);
canvas.onclick = function setSpawnTrue(){
if(!isSpawned){
x[0] = xTemp;
y[0] = yTemp;
} else{
x.push(xTemp);
y.push(yTemp);
dx.push(0);
dy.push(5);
gravity.push(1);
bounceTime.push(1);
}
isSpawned = 1;
}
//Draws the various entities
function draw(){
context = bouncingField.getContext('2d');
for(var i = 0; i < x.length; i++){
//context.beginPath();
//context.fillStyle = "#00ccff";
//Draw circles of r = 25 at coordinates x and y
//context.arc(x[i], y[i], 25, 0, Math.PI*2, true);
context.drawImage(image, x[i], y[i], 50, 50);
//context.closePath();
//context.fill();
}
}
//Repaints entities, essentially animating them
function repaint(){
for(var i = 0; i < x.length; i++){
context.clearRect(0, 0, 2000, 2000);
if(x[i] < 20 || x[i] > width) dx[i] *= -1;
if(y[i] < 20 || y[i] > height) {
dy[i] *= -1;
//We add bounceTime to dy so that it gradually loses speed
dy[i] += bounceTime[i];
//Inverting graviy to slow down on rise
gravity[i] *= -1;
}
x[i] += dx[i];
//Gravity affects the ball bounce speed, that gradually slows down.
y[i] += dy[i] + gravity[i];
//bounceTime gradually reduces the amount of speed the ball has
gravity[i] += 0.2 * bounceTime[i];
bounceTime[i] += 0.01;
if(isSpawned){
draw();
}
}
}
//Initializes Event.MOUSEMOVE to capture cursor coordinates
function init(){
if(window.Event){
document.captureEvents(Event.MOUSEMOVE);
}
document.onmousemove = getCoordinates;
}
//Gets mouse coordinates and puts them into xTemp and yTemp
function getCoordinates(e){
xTemp = (window.Event) ? e.pageX : event.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
yTemp = (window.Event) ? e.pageY : event.clientY + (document.documentElement.scrollRight ? document.documentElement.scrollRight : document.body.scrollRight);
xTemp -= 14;
yTemp -= 14;
}
});
body{
background-color: #555555;
}
#bouncingField{
border-style: solid;
border-width: 10px;
border-color: white;
}
<HTML>
<HEAD>
<TITLE>
Wingin' it
</TITLE>
<script type="text/javascript" src="script.js"></script>
<link href="style.css" rel="stylesheet" type="text/css">
</HEAD>
<BODY>
<CANVAS id="bouncingField" width="0" height="0"></CANVAS>
</BODY>
</HTML>
I'm working on a simple JavaScript project to create bouncing balls that simulate gravity and that bounce off of the floor or the walls. The problem is that sometimes they clip into the floor and "spaz out" until they disappear from the screen. Any clue why? I've been trying to figure it out by adding a tiny time-out every time it collides but JS doesn't have sleep so I'm just confused now.
Thank you in advance :)
I hope this helps. the tricky part is making a convincing "stop".
function getCoordinates(event) { return { x: event.offsetX, y: event.offsetY }; }
function spawnBall(coords, x, y, dx, dy){
x.push(coords.x);
y.push(coords.y);
dx.push(0);
dy.push(2);
}
// =========================
// Draws the various entities
// =========================
function draw(canvas, image, x, y, width, height) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
for(var i = 0; i < x.length; i++){ context.drawImage(image, x[i], y[i], width, height); }
}
// =========================
// =========================
// At the moment all this is concerned with is the "floor"
// =========================
function move(x, y, dx, dy, gravity, bounciness, floor){
for(var i = 0; i < x.length; i++){
// =========================
// Ball is close to the floor and not moving very fast, set it to rest
// otherwise it bounces forever.
// =========================
if (y[i] >= floor - 10 && Math.abs(dy[i]) <= 2 * gravity) {
dy[i] = 0;
y[i] = floor;
continue;
}
// =========================
// =========================
// Update the speed and position
// =========================
dy[i] += gravity;
y[i] += dy[i];
// =========================
// =========================
// Simulate a bounce if we "hit" the floor
// =========================
if(y[i] > floor) {
y[i] = floor - (y[i] - floor);
dy[i] = -1.0 * bounciness * dy[i];
}
// =========================
}
}
// =========================
document.addEventListener("DOMContentLoaded", function(event){
var canvas = document.getElementById("bouncingField");
canvas.width = window.innerWidth - 50;
canvas.height = window.innerHeight - 50;
//Image to use as ball texture
var image = new Image();
image.src = "http://www.freeiconspng.com/uploads/soccer-ball-icon-14.png";
var gravity = 1;
var ballSize = 50;
var ballBounciness = 0.8;
var floor = canvas.height - ballSize;
var x = [];
var y = [];
var dx = [];
var dy = [];
// =========================
// This can be done via requestAnimationFrame()
// https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
// =========================
var isSpawned = false;
setInterval(function(){
if(!isSpawned){ return; }
move(x, y, dx, dy, gravity, ballBounciness, floor)
draw(canvas, image, x, y, ballSize, ballSize);
}, 10);
// =========================
// =========================
// Add a ball
// =========================
canvas.onclick = function(event) {
isSpawned = true;
var coords = getCoordinates(event);
spawnBall(coords, x, y, dx, dy);
}
// =========================
});
body {
background-color: #555555;
}
#bouncingField {
border-style: solid;
border-width: 10px;
border-color: white;
}
<canvas id="bouncingField"></canvas>

Categories

Resources