Why is my line not drawing over time? - javascript

I am trying to have a line draw to the canvas over a certain amount of time(ten seconds to be exact). I'm able to see that the script is counting to a certain time and then stopping, but I'm not seeing the line being drawn. Can anyone show me what I'm doing wrong?
$(document).ready(function(){
canvas = document.getElementById("test");
ctx = canvas.getContext("2d");
var count = 0;
var start_x = 0;
var start_y = 100;
var end_x = 50;
var end_y = 100;
var counter = setInterval(countNumbers, 1000);
ctx.beginPath();
ctx.moveTo(start_x, start_y);
console.log("Start");
function countNumbers(){
count += 1;
ctx.lineTo((start_x + count), start_y);
console.log(count);
if((start_x == end_x) || (count == 10)){
clearInterval(counter);
console.log("End");
}
}
ctx.lineWidth = 5;
ctx.strokeStyle = "white";
ctx.stroke();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="test"></canvas>

Try to move stroke inside the Interval. Because in your case stroke are called immediately without lineTo data. And after that lineTo are called in interval function and cannot be rendered without stroke.
$(document).ready(function(){
canvas = document.getElementById("test");
ctx = canvas.getContext("2d");
var count = 0;
var start_x = 0;
var start_y = 100;
var end_x = 50;
var end_y = 100;
var counter = setInterval(countNumbers, 1000);
ctx.beginPath();
ctx.moveTo(start_x, start_y);
console.log("Start");
function countNumbers(){
count += 1;
ctx.lineTo((start_x + count), start_y);
console.log(count);
if((start_x == end_x) || (count == 10)){
clearInterval(counter);
console.log("End");
ctx.lineWidth = 5; // <----- move here
ctx.strokeStyle = "white";
ctx.stroke();
}
}
})
Also ensure that you are not drawing white lines on white background

$(document).ready(function(){
canvas = document.getElementById("test");
ctx = canvas.getContext("2d");
var count = 0;
var start_x = 0;
var start_y = 100;
var end_x = 50;
var end_y = 100;
var counter = setInterval(countNumbers, 1000);
ctx.beginPath();
ctx.moveTo(start_x, start_y);
console.log("Start");
ctx.lineWidth = 5;
ctx.strokeStyle = "black";
function countNumbers(){
count += 1;
ctx.lineTo((start_x + count), start_y);
ctx.stroke();
console.log(count);
if((start_x == end_x) || (count == 10)){
clearInterval(counter);
console.log("End");
ctx.strokeStyle = "white";
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="test"></canvas>

I would count down for the step. This will allow you to figure out the step.
I modified your code to allow you to pass parameters into the interval function to minimize global scope variables. Since I passed a reference of the interval into itself, you no longer need to have global variables.
I created two function, the first will create a path and then stroke it. The second one will stroke a sub-line after each tick of the interval. I added a simple check for even-odd to swap between colors.
$(document).ready(function() {
var canvas = $('canvas#test')[0];
var ctx = canvas.getContext('2d');
var count = 10;
var start_x = 50, start_y = 50;
var end_x = 250, end_y = 150;
var delta_x = end_x - start_x, delta_y = end_y - start_y;
var step_x = delta_x / count, step_y = delta_y / count;
canvas.width = 300;
canvas.height = 200;
// Fill canvas with solid black.
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'black';
ctx.fill();
// Kick off the line stroke timer. No more global variables!
var counter = setInterval(function(opts) {
// Pass a reference to the timer into the interval.
strokeLineTimerLive(counter, opts);
}, 500, {
ctx : ctx,
n : count,
x1 : start_x,
y1 : start_y,
x2 : end_x,
y2 : end_y,
dx : step_x,
dy : step_y,
});
// After the interval has ended, the path is finally stroked.
function strokeLineTimer(timer, opts) {
if (!opts.init) {
console.log("Start");
opts.ctx.beginPath();
opts.ctx.moveTo(opts.x1, opts.y1);
opts.ctx.lineWidth = 5;
opts.ctx.strokeStyle = 'white';
opts.init = true;
}
opts.n -= 1;
opts.ctx.lineTo((opts.x1 += opts.dx), (opts.y1 += opts.dy));
console.log(opts.n);
if ((opts.x1 == opts.x2) || (opts.n == 0)){
clearInterval(timer);
opts.ctx.stroke();
console.log("End");
}
}
// After each tick of the interval, a line is stroked.
function strokeLineTimerLive(timer, opts) {
if (!opts.init) {
console.log("Start");
opts.ctx.beginPath();
opts.ctx.moveTo(opts.x1, opts.y1);
opts.ctx.lineWidth = 5;
opts.init = true;
}
opts.n -= 1;
opts.ctx.strokeStyle = opts.n % 2 == 0 ? 'white' : 'red';
opts.ctx.lineTo((opts.x1 += opts.dx), (opts.y1 += opts.dy));
opts.ctx.stroke();
console.log(opts.n);
if ((opts.x1 == opts.x2) || (opts.n == 0)){
clearInterval(timer);
console.log("End");
} else {
opts.ctx.beginPath();
opts.ctx.moveTo(opts.x1, opts.y1);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="test"></canvas>

Related

How to move the canvas backward in javascript?

I try to think how the box can move backward when it hit 1000px (canvas.width) ,but I don’t know how it solves after If condition, so there’s my script, anyone can help me ?
var canvas = document.querySelector("canvas");
var canvasCT = canvas.getContext("2d");
var x = 50;
function draw() {
canvas.width = canvas.width;
canvasCT.fillStyle = "blue";
canvasCT.fillRect(x, 50, 100, 100);
}
function run() {
draw();
x += 5 ;
if (x > 1000) {
......
}
}
setInterval(run, 10);
var canvas = document.querySelector("canvas");
var canvasCT = canvas.getContext("2d");
var x = 50;
var speed = 5;
function draw() {
canvas.width = canvas.width;
canvasCT.fillStyle = "blue";
canvasCT.fillRect(x, 50, 100, 100);
}
function run() {
draw();
x += speed;
if (x > 1000 || x < 0) {
speed = -speed;
}
}
setInterval(run, 10);
<canvas width=1000></canvas>

making a truck and buttons to increase speed, change direction using html/js via jQuery

this is the question for my assignment
You are required to create the same animation in Canvas. This can be any object: a truck, a car, a cycle an airplane, etc. Many example codes are provided in Blackboard for your help, and I have given you hints in the lecture as well.
The object should be at the left of the screen when you load the page.
There will be five buttons: start, stop, +, -, and change direction. You can show or hide whichever button you want. It is up to you.
The object should start moving when click on the start button.
The object should stop moving when you click on the stop button.
The object should change the direction when you click on “change direction” button.
When you click on the + button, the speed of the object should be increased and when you click on the - button, the speed should be decreased.
Below the buttons, there should be names of the students who did that question.
I've tried to solve it but it's seems not to work with me.
and this is the code for my page.
I want to make change direction button using html/js via jQuery please.
$(document).ready(function() {
var canvas = $("#myCanvas");
var ctx = canvas.get(0).getContext("2d");
var playAnimation = true;
var startButton = $("#startAnimation");
var stopButton = $("#stopAnimation");
var increaseButton = $("#increase");
var decreaseButton = $("#decrease")
var x = 0;
var b = 200;
var t = 200;
var w = 200;
var q = 255;
var cir = 240;
var cir2 = 90;
var ctx;
startButton.hide();
startButton.click(function() {
$(this).hide();
stopButton.show();
playAnimation = true;
animate();
});
stopButton.click(function() {
$(this).hide();
startButton.show();
playAnimation = false;
});
/*function increase() {
speed += 10;
};*/
increaseButton.click(function() {
var interval = 1000;
timer = function() {
interval--;
//do your thing here
interval = interval < 40 ? 40 : interval;
setTimeout(timer, interval);
};
timer();
});
/*stopButton.click.(function(){
if(mouseX >= 335 && mouseX <= 390 && mouseY >= 15 && mouseY <= 115){
x++;//Make faster
}
if(mouseX >= 335 && mouseX <= 390 && mouseY >= 295 && mouseY <= 395){
x--;//Make slower
if(speed < 0){
speed++;//Make faster, I said IT CAN'T GO TO 0 or less...
}
}
});*/
//var increase = x++;
//var decrease = x--;
function animate() {
x++;
b++;
t++;
w++;
q++;
cir++;
cir2++;
//y++; //update
//ctx.clearRect(0, 0, 800, 600); //clear
ctx.clearRect(0, 0, canvas.width(), canvas.height());
ctx.fillRect(x, 350, 190, 120);
ctx.fillRect(b, 410, 60, 60);
ctx.beginPath();
ctx.moveTo(t, 350);
ctx.lineTo(w, 400);
ctx.lineTo(q, 400);
ctx.closePath();
ctx.fillStyle = "#black";
ctx.fill();
//var c = document.getElementById("myCanvas");
//var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(cir, 490, 18, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = '#black';
ctx.stroke();
ctx.beginPath();
ctx.arc(cir2, 490, 18, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = '#black';
ctx.stroke();
//draw();
// removed for snippet: console.log(x);
if (playAnimation)
setTimeout(animate, 20);
//repeat
};
animate();
});
/* for snippet - a huge gap at the top makes it unviewable */
#myCanvas { margin-top: -340px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="myCanvas" width="800" height="600">
<!-- Insert fallback content here -->
</canvas>
<div>
<button id="startAnimation">Start</button>
<button id="stopAnimation">Stop</button>
<button id="increase"> Increase the speed</button>
<button id="decrease"> Decrease the speed</button>
</div>
It seems like you are calling animate() inside animate(), that is not a good idea.
Start and stop
I use this to run the function repeatedly
var speed = 10;
var animation = setInterval(function () {
animate();
}, speed);
Now, the animate() will run every speed ms, which in this case is 10ms. (Canvas will clear and update every 10ms)
To stop the animation, just stop the interval with clearInterval(animation), start again by assigning back it.
startButton.click(function () {
$(this).hide();
stopButton.show();
animation = setInterval(function () {
animate();
}, speed);
});
Change speed
increaseButton.click(function () {
changeSpeed(-10);
});
decreaseButton.click(function () {
changeSpeed(10);
});
function changeSpeed(changeValue) {
speed += changeValue;
clearInterval(animation)
animation = setInterval(function () {
animate();
}, speed);
}
Change direction
I have added in new variable named direction, which will let the animation move forward when it is in 1 and backward when -1.
I replace your code in animate()
x++;
b++;
t++;
w++;
q++;
cir++;
cir2++;
with:
x += direction;
b += direction;
t += direction;
w += direction;
q += direction;
cir += direction;
cir2 += direction;
and add button that allow it to change the value of direction
var changeDirection = $("#changeDirection");
changeDirection.click(function () {
direction *= -1;
})
All together:
$(document).ready(function () {
var canvas = $("#myCanvas");
var ctx = canvas.get(0).getContext("2d");
var playAnimation = true;
var startButton = $("#startAnimation");
var stopButton = $("#stopAnimation");
var increaseButton = $("#increase");
var decreaseButton = $("#decrease");
var changeDirection = $("#changeDirection");
var x = 0;
var b = 200;
var t = 200;
var w = 200;
var q = 255;
var cir = 240;
var cir2 = 90;
var ctx;
var direction = 1;
var speed = 10;
startButton.hide();
startButton.click(function () {
$(this).hide();
stopButton.show();
animation = setInterval(function () {
animate();
}, speed);
});
stopButton.click(function () {
$(this).hide();
startButton.show();
clearInterval(animation)
});
increaseButton.click(function () {
changeSpeed(-10);
});
decreaseButton.click(function () {
changeSpeed(10);
});
changeDirection.click(function () {
direction *= -1;
})
function changeSpeed(changeValue) {
speed += changeValue;
clearInterval(animation)
animation = setInterval(function () {
animate();
}, speed);
}
function animate() {
x += direction;
b += direction;
t += direction;
w += direction;
q += direction;
cir += direction;
cir2 += direction;
//update
ctx.clearRect(0, 0, canvas.width(), canvas.height());
ctx.fillRect(x, 350, 190, 120);
ctx.fillRect(b, 410, 60, 60);
ctx.beginPath();
ctx.moveTo(t, 350);
ctx.lineTo(w, 400);
ctx.lineTo(q, 400);
ctx.closePath();
ctx.fillStyle = "#black";
ctx.fill();
ctx.beginPath();
ctx.arc(cir, 490, 18, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = '#black';
ctx.stroke();
ctx.beginPath();
ctx.arc(cir2, 490, 18, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = '#black';
ctx.stroke();
};
var animation = setInterval(function () {
animate();
}, speed);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<canvas id="myCanvas" width="800" height="600">
<!-- Insert fallback content here -->
</canvas>
<div>
<button id="startAnimation">Start</button>
<button id="stopAnimation">Stop</button>
<button id="increase"> Increase the speed</button>
<button id="decrease"> Decrease the speed</button>
<button id="changeDirection"> Change direction</button>
</div>
</body>

How can I reverse the direction of this square after it reaches a certain value?

I'm trying to create an idle animation where the red rectangle moves back and forth slightly in a loop. For some reason once it reaches the specified threshhold instead of proceeding to move in the opposite direction, it just stops.
What did I do wrong?
<canvas id="myCanvas" width="1500" height="500" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
// Spaceship structure
var shipWidth = 250;
var shipHeight = 100;
// Canvas parameters
var cWidth = canvas.width;
var cHeight = canvas.height;
// Positioning variables
var centerWidthPosition = (cWidth / 2) - (shipWidth / 2);
var centerHeightPosition = (cHeight / 2) - (shipHeight / 2);
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
function drawShip(){
ctx.clearRect(0, 0, cWidth, cHeight);
ctx.fillStyle = "#FF0000";
ctx.fillRect(centerWidthPosition,centerHeightPosition,shipWidth,shipHeight);
centerWidthPosition--;
if (centerWidthPosition < 400){
++centerWidthPosition;
}
requestAnimationFrame(drawShip);
}
drawShip();
</script>
#TheAmberlamps explained why it's doing that. Here I offer you a solution to achieve what I believe you are trying to do.
Use a velocity variable that changes magnitude. X position always increases by velocity value. Velocity changes directions at screen edges.
// use a velocity variable
var xspeed = 1;
// always increase by velocity
centerWidthPosition += xspeed;
// screen edges are 0 and 400 in this example
if (centerWidthPosition > 400 || centerWidthPosition < 0){
xspeed *= -1; // change velocity direction
}
I added another condition in your if that causes the object to bounce back and forth. Remove the selection after || if you don't want it doing that.
Your function is caught in a loop; once centerWidthPosition reaches 399 your conditional makes it increment back up to 400, and then it decrements back to 399.
here is another one as a brain teaser - how would go by making this animation bounce in the loop - basically turn text into particles and then reverse back to text and reverse back to particles and back to text and so on and on and on infinitely:
var random = Math.random;
window.onresize = function () {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
window.onresize();
var ctx = canvas.getContext('2d');
ctx.font = 'bold 50px "somefont"';
ctx.textBaseline = 'center';
ctx.fillStyle = 'rgba(255,255,255,1)';
var _particles = [];
var particlesLength = 0;
var currentText = "SOMETEXT";
var createParticle = function createParticle(x, y) {_particles.push(new Particle(x, y));};
var checkAlpha = function checkAlpha(pixels, i) {return pixels[i * 4 + 3] > 0;};
var createParticles = function createParticles() {
var textSize = ctx.measureText(currentText);
ctx.fillText(currentText,Math.round((canvas.width / 2) - (textSize.width / 2)),Math.round(canvas.height / 2));
var imageData = ctx.getImageData(1, 1, canvas.width, canvas.height);
var pixels = imageData.data;
var dataLength = imageData.width * imageData.height;
for (var i = 0; i < dataLength; i++) {
var currentRow = Math.floor(i / imageData.width);
var currentColumn = i - Math.floor(i / imageData.height);
if (currentRow % 2 || currentColumn % 2) continue;
if (checkAlpha(pixels, i)) {
var cy = ~~(i / imageData.width);
var cx = ~~(i - (cy * imageData.width));
createParticle(cx, cy);
}}
particlesLength = _particles.length;
};
var Point = function Point(x, y) {
this.set(x, y);
};
Point.prototype = {
set: function (x, y) {
x = x || 0;
y = y || x || 0;
this._sX = x;
this._sY = y;
this.reset();
},
add: function (point) {
this.x += point.x;
this.y += point.y;
},
multiply: function (point) {
this.x *= point.x;
this.y *= point.y;
},
reset: function () {
this.x = this._sX;
this.y = this._sY;
return this;
},
};
var FRICT = new Point(0.98);//set to 0 if no flying needed
var Particle = function Particle(x, y) {
this.startPos = new Point(x, y);
this.v = new Point();
this.a = new Point();
this.reset();
};
Particle.prototype = {
reset: function () {
this.x = this.startPos.x;
this.y = this.startPos.y;
this.life = Math.round(random() * 300);
this.isActive = true;
this.v.reset();
this.a.reset();
},
tick: function () {
if (!this.isActive) return;
this.physics();
this.checkLife();
this.draw();
return this.isActive;
},
checkLife: function () {
this.life -= 1;
this.isActive = !(this.life < 1);
},
draw: function () {
ctx.fillRect(this.x, this.y, 1, 1);
},
physics: function () {
if (performance.now()<nextTime) return;
this.a.x = (random() - 0.5) * 0.8;
this.a.y = (random() - 0.5) * 0.8;
this.v.add(this.a);
this.v.multiply(FRICT);
this.x += this.v.x;
this.y += this.v.y;
this.x = Math.round(this.x * 10) / 10;
this.y = Math.round(this.y * 10) / 10;
}
};
var nextTime = performance.now()+3000;
createParticles();
function clearCanvas() {
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
(function clearLoop() {
clearCanvas();
requestAnimationFrame(clearLoop);
})();
(function animLoop(time) {
ctx.fillStyle = 'rgba(255,255,255,1)';
var isAlive = true;
for (var i = 0; i < particlesLength; i++) {
if (_particles[i].tick()) isAlive = true;
}
requestAnimationFrame(animLoop);
})();
function resetParticles() {
for (var i = 0; i < particlesLength; i++) {
_particles[i].reset();
}}

HTML5 canvas particle explosion

I'm trying to get this particle explosion working. It's working but it looks like some frames does not get rendered. If I click many times to call several explosions it starts to uhm.. "lag/stutter". Is there something I have forgotten to do? It may look like the browser hangs when I click many times. Is it too much to have 2 for loops inside each other?
Attached my code so you can see.
Just try to click many times, and you will see the problem visually.
// Request animation frame
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
// Canvas
var c = document.getElementById('canvas');
var ctx = c.getContext('2d');
// Set full-screen
c.width = window.innerWidth;
c.height = window.innerHeight;
// Options
var background = '#333'; // Background color
var particlesPerExplosion = 20;
var particlesMinSpeed = 3;
var particlesMaxSpeed = 6;
var particlesMinSize = 1;
var particlesMaxSize = 3;
var explosions = [];
var fps = 60;
var now, delta;
var then = Date.now();
var interval = 1000 / fps;
// Optimization for mobile devices
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
fps = 29;
}
// Draw
function draw() {
// Loop
requestAnimationFrame(draw);
// Set NOW and DELTA
now = Date.now();
delta = now - then;
// New frame
if (delta > interval) {
// Update THEN
then = now - (delta % interval);
// Our animation
drawBackground();
drawExplosion();
}
}
// Draw explosion(s)
function drawExplosion() {
if (explosions.length == 0) {
return;
}
for (var i = 0; i < explosions.length; i++) {
var explosion = explosions[i];
var particles = explosion.particles;
if (particles.length == 0) {
explosions.splice(i, 1);
return;
}
for (var ii = 0; ii < particles.length; ii++) {
var particle = particles[ii];
// Check particle size
// If 0, remove
if (particle.size < 0) {
particles.splice(ii, 1);
return;
}
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.size, Math.PI * 2, 0, false);
ctx.closePath();
ctx.fillStyle = 'rgb(' + particle.r + ',' + particle.g + ',' + particle.b + ')';
ctx.fill();
// Update
particle.x += particle.xv;
particle.y += particle.yv;
particle.size -= .1;
}
}
}
// Draw the background
function drawBackground() {
ctx.fillStyle = background;
ctx.fillRect(0, 0, c.width, c.height);
}
// Clicked
function clicked(e) {
var xPos, yPos;
if (e.offsetX) {
xPos = e.offsetX;
yPos = e.offsetY;
} else if (e.layerX) {
xPos = e.layerX;
yPos = e.layerY;
}
explosions.push(new explosion(xPos, yPos));
}
// Explosion
function explosion(x, y) {
this.particles = [];
for (var i = 0; i < particlesPerExplosion; i++) {
this.particles.push(new particle(x, y));
}
}
// Particle
function particle(x, y) {
this.x = x;
this.y = y;
this.xv = randInt(particlesMinSpeed, particlesMaxSpeed, false);
this.yv = randInt(particlesMinSpeed, particlesMaxSpeed, false);
this.size = randInt(particlesMinSize, particlesMaxSize, true);
this.r = randInt(113, 222);
this.g = '00';
this.b = randInt(105, 255);
}
// Returns an random integer, positive or negative
// between the given value
function randInt(min, max, positive) {
if (positive == false) {
var num = Math.floor(Math.random() * max) - min;
num *= Math.floor(Math.random() * 2) == 1 ? 1 : -1;
} else {
var num = Math.floor(Math.random() * max) + min;
}
return num;
}
// On-click
$('canvas').on('click', function(e) {
clicked(e);
});
draw();
<!DOCTYPE html>
<html>
<head>
<style>
* {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</html>
You are returning from iterating over the particles if one is too small. This causes the other particles of that explosion to render only in the next frame.
I have a working version:
// Request animation frame
const requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
// Canvas
const c = document.getElementById('canvas');
const ctx = c.getContext('2d');
// Set full-screen
c.width = window.innerWidth;
c.height = window.innerHeight;
// Options
const background = '#333'; // Background color
const particlesPerExplosion = 20;
const particlesMinSpeed = 3;
const particlesMaxSpeed = 6;
const particlesMinSize = 1;
const particlesMaxSize = 3;
const explosions = [];
let fps = 60;
const interval = 1000 / fps;
let now, delta;
let then = Date.now();
// Optimization for mobile devices
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
fps = 29;
}
// Draw
function draw() {
// Loop
requestAnimationFrame(draw);
// Set NOW and DELTA
now = Date.now();
delta = now - then;
// New frame
if (delta > interval) {
// Update THEN
then = now - (delta % interval);
// Our animation
drawBackground();
drawExplosion();
}
}
// Draw explosion(s)
function drawExplosion() {
if (explosions.length === 0) {
return;
}
for (let i = 0; i < explosions.length; i++) {
const explosion = explosions[i];
const particles = explosion.particles;
if (particles.length === 0) {
explosions.splice(i, 1);
return;
}
const particlesAfterRemoval = particles.slice();
for (let ii = 0; ii < particles.length; ii++) {
const particle = particles[ii];
// Check particle size
// If 0, remove
if (particle.size <= 0) {
particlesAfterRemoval.splice(ii, 1);
continue;
}
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.size, Math.PI * 2, 0, false);
ctx.closePath();
ctx.fillStyle = 'rgb(' + particle.r + ',' + particle.g + ',' + particle.b + ')';
ctx.fill();
// Update
particle.x += particle.xv;
particle.y += particle.yv;
particle.size -= .1;
}
explosion.particles = particlesAfterRemoval;
}
}
// Draw the background
function drawBackground() {
ctx.fillStyle = background;
ctx.fillRect(0, 0, c.width, c.height);
}
// Clicked
function clicked(e) {
let xPos, yPos;
if (e.offsetX) {
xPos = e.offsetX;
yPos = e.offsetY;
} else if (e.layerX) {
xPos = e.layerX;
yPos = e.layerY;
}
explosions.push(
new explosion(xPos, yPos)
);
}
// Explosion
function explosion(x, y) {
this.particles = [];
for (let i = 0; i < particlesPerExplosion; i++) {
this.particles.push(
new particle(x, y)
);
}
}
// Particle
function particle(x, y) {
this.x = x;
this.y = y;
this.xv = randInt(particlesMinSpeed, particlesMaxSpeed, false);
this.yv = randInt(particlesMinSpeed, particlesMaxSpeed, false);
this.size = randInt(particlesMinSize, particlesMaxSize, true);
this.r = randInt(113, 222);
this.g = '00';
this.b = randInt(105, 255);
}
// Returns an random integer, positive or negative
// between the given value
function randInt(min, max, positive) {
let num;
if (positive === false) {
num = Math.floor(Math.random() * max) - min;
num *= Math.floor(Math.random() * 2) === 1 ? 1 : -1;
} else {
num = Math.floor(Math.random() * max) + min;
}
return num;
}
// On-click
$('canvas').on('click', function (e) {
clicked(e);
});
draw();
<!DOCTYPE html>
<html>
<head>
<style>* {margin:0;padding:0;overflow:hidden;}</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</html>
Loops, break and continue.
The problem was caused when you checked for empty particle arrays and when you found a particle to remove.
The bugs
The following two statements and blocks caused the problem
if (particles.length == 0) {
explosions.splice(i, 1);
return;
}
and
if (particles.size < 0) {
explosions.splice(ii, 1);
return;
}
The returns stopped the rendering of particles, so you would sometimes return before drawing a single particle was rendered just because the first explosion was empty or first particle was too small.
Continue and break
You can use the continue token in javascript to skip the rest of a for, while, do loop
for(i = 0; i < 100; i++){
if(test(i)){
// need to skip this iteration
continue;
}
// more code
// more code
// continue skips all the code upto the closing }
} << continues to here and if i < 100 the loop continues on.
Or you can completely break out of the loop with break
for(i = 0; i < 100; i++){
if(test(i)){
// need to exit the for loop
break;
}
// more code
// more code
// break skips all the code to the first line after the closing }
}
<< breaks to here and if i remains the value it was when break was encountered
The fix
if (particles.length == 0) {
explosions.splice(i, 1);
continue;
}
and
if (particles.size < 0) {
explosions.splice(ii, 1);
continue;
}
Your example with the fix
Your code with the fix. Befor I found it I started changing stuff.
Minor stuff.
requestAnimationFrame passes a time in milliseconds so to an accuracy of micro seconds.
You were setting then incorrectly and would have been losing frames. I changed the timing to use the argument time and then is just set to the time when a frame is drawn.
There are some other issues, nothing major and more of a coding style thing. You should capitalise objects created with new
function Particle(...
not
function particle(...
and your random is a overly complex
function randInt(min, max = min - (min = 0)) {
return Math.floor(Math.random() * (max - min) + min);
}
or
function randInt(min,max){
max = max === undefined ? min - (min = 0) : max;
return Math.floor(Math.random() * (max - min) + min);
}
randInt(100); // int 0 - 100
randInt(10,20); // int 10-20
randInt(-100); // int -100 to 0
randInt(-10,20); // int -10 to 20
this.xv = randInt(-particlesMinSpeed, particlesMaxSpeed);
this.yv = randInt(-particlesMinSpeed, particlesMaxSpeed);
this.size = randInt(particlesMinSize, particlesMaxSize);
And if you are using the same name in variables a good sign to create an object
var particlesPerExplosion = 20;
var particlesMinSpeed = 3;
var particlesMaxSpeed = 6;
var particlesMinSize = 1;
var particlesMaxSize = 3;
Could be
const settings = {
particles : {
speed : {min : 3, max : 6 },
size : {min : 1 : max : 3 },
explosionCount : 20,
},
background : "#000",
}
Anyways your code.
var c = canvas;
var ctx = c.getContext('2d');
// Set full-screen
c.width = innerWidth;
c.height = innerHeight;
// Options
var background = '#333'; // Background color
var particlesPerExplosion = 20;
var particlesMinSpeed = 3;
var particlesMaxSpeed = 6;
var particlesMinSize = 1;
var particlesMaxSize = 3;
var explosions = [];
var fps = 60;
var now, delta;
var then = 0; // Zero start time
var interval = 1000 / fps;
// Optimization for mobile devices
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
fps = 29;
}
// Draw
// as time is passed you need to start with requestAnimationFrame
requestAnimationFrame(draw);
function draw(time) { //requestAnimationFrame frame passes the time
requestAnimationFrame(draw);
delta = time - then;
if (delta > interval) {
then = time
drawBackground();
drawExplosion();
}
}
// Draw explosion(s)
function drawExplosion() {
if (explosions.length == 0) {
return;
}
for (var i = 0; i < explosions.length; i++) {
var explosion = explosions[i];
var particles = explosion.particles;
if (particles.length == 0) {
explosions.splice(i, 1);
//return;
continue;
}
for (var ii = 0; ii < particles.length; ii++) {
var particle = particles[ii];
// Check particle size
// If 0, remove
if (particle.size < 0) {
particles.splice(ii, 1);
// return;
continue;
}
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.size, Math.PI * 2, 0, false);
ctx.closePath();
ctx.fillStyle = 'rgb(' + particle.r + ',' + particle.g + ',' + particle.b + ')';
ctx.fill();
// Update
particle.x += particle.xv;
particle.y += particle.yv;
particle.size -= .1;
}
}
}
// Draw the background
function drawBackground() {
ctx.fillStyle = background;
ctx.fillRect(0, 0, c.width, c.height);
}
// Clicked
function clicked(e) {
var xPos, yPos;
if (e.offsetX) {
xPos = e.offsetX;
yPos = e.offsetY;
} else if (e.layerX) {
xPos = e.layerX;
yPos = e.layerY;
}
explosions.push(new explosion(xPos, yPos));
}
// Explosion
function explosion(x, y) {
this.particles = [];
for (var i = 0; i < particlesPerExplosion; i++) {
this.particles.push(new particle(x, y));
}
}
// Particle
function particle(x, y) {
this.x = x;
this.y = y;
this.xv = randInt(particlesMinSpeed, particlesMaxSpeed, false);
this.yv = randInt(particlesMinSpeed, particlesMaxSpeed, false);
this.size = randInt(particlesMinSize, particlesMaxSize, true);
this.r = randInt(113, 222);
this.g = '00';
this.b = randInt(105, 255);
}
// Returns an random integer, positive or negative
// between the given value
function randInt(min, max, positive) {
if (positive == false) {
var num = Math.floor(Math.random() * max) - min;
num *= Math.floor(Math.random() * 2) == 1 ? 1 : -1;
} else {
var num = Math.floor(Math.random() * max) + min;
}
return num;
}
// On-click
$('canvas').on('click', function(e) {
clicked(e);
});
<!DOCTYPE html>
<html>
<head>
<style>
* {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</html>

How to make the objects fall in javascript?

I am trying to make this game, you should not collide the falling object. I have the objects falling and I have my black square, but it flashes when I run it and Im not sure how to make the code stop when the two objects collide together.
here is the code that I have so far!
<html>
<body>
<canvas id="canvasRegn" width="600" height="450"style="margin:100px;"></canvas>
<script>
var ctx;
var imgBg;
var imgDrops;
var noOfDrops = 50;
var fallingDrops = [];
function drawBackground(){
ctx.drawImage(imgBg, 0, 0); //Background
}
function draw() {
drawBackground();
for (var i=0; i< noOfDrops; i++)
{
ctx.drawImage (fallingDrops[i].image, fallingDrops[i].x, fallingDrops[i].y); //The rain drop
fallingDrops[i].y += fallingDrops[i].speed; //Set the falling speed
if (fallingDrops[i].y > 480) { //Repeat the raindrop when it falls out of view
fallingDrops[i].y = -25 //Account for the image size
fallingDrops[i].x = Math.random() * 800; //Make it appear randomly along the width
}
}
}
function setup() {
var canvas = document.getElementById('canvasRegn');
if (canvas.getContext) {
ctx = canvas.getContext('2d');
imgBg = new Image();
imgBg.src = "http://www.hamdancommunications.com/HComm/img/wite%20square.png";
setInterval(draw, 36);
for (var i = 0; i < noOfDrops; i++) {
var fallingDr = new Object();
fallingDr["image"] = new Image();
fallingDr.image.src = 'http://s18.postimg.org/o6jpmdf9x/Line1.jpg';
fallingDr["x"] = Math.random() * 800;
fallingDr["y"] = Math.random() * 5;
fallingDr["speed"] = 3 + Math.random() * 5;
fallingDrops.push(fallingDr);
anotherGame();
}
}
}
setup();
function anotherGame(){
var canvas = document.getElementById("canvasRegn");
var ctx = canvas.getContext('2d');
canvas.addEventListener("mousedown", clicked);
canvas.addEventListener("mousemove", moved);
canvas.addEventListener("mouseup", released);
var isclicked = 0;
var square = new Object();
square.color = "black";
square.x = 100;
square.y = 100;
square.w = 50;
square.h = 50;
var offX = 0;
var offY = 0;
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = square.color;
ctx.fillRect(square.x,square.y,square.w,square.h);
}
function game(){
}
function clicked(e){
var x = e.offsetX;
var y = e.offsetY;
if(x >= square.x && x <= square.x + square.w &&
y >= square.y && y <= square.y + square.h){
isclicked = 1;
offX = x - square.x;
offY = y - square.y;
}
}
function moved(e){
if(isclicked == 1){
var x = e.offsetX;
var y = e.offsetY;
square.x = x - offX;
square.y = y - offY;
}
}
function released(e){
var x = e.offsetX;
var y = e.offsetY;
isclicked = 0;
}
var drawtimer = setInterval(draw, 1000/30);
var gametimer = setInterval(game, 1000/10);
}
</script>
</body>
</html>

Categories

Resources