Javascript animation infinite loop - javascript

I am writing a simple animation in javascript (I can't use css) and I don't seem to make it infinite. this is what I have so far:
myMove(ball , i, size) {
var id = setInterval(frame, 3* i);
function frame() {
if (size == 100) {
size = 0;
} else {
size++;
ball.style.width = size/10 + 'px';
ball.style.height = size/10 + 'px';
}
}
}
the ball would be the element, the i is the iterated element in a for loop in which the function is called for each element.
for (var i = 0; i < numberOfBalls; i++{
myMove(document.getElementByClassName[i]('ball'), i, 10)
}
and size is the max size I wish my element expands to.
I wish to have a smooth transition, where the 5 balls will expand in succession (so first ball after 300ms, the second, after 300ms the third and so on) and when the last ball has expanded, repeat the process. I'm really struggling to get a decent result.
Thanks for your help

Related

JavaScript canvas + requestAnimationFrame stuttering

I'm currently trying to make a sparkle effect that happens within the canvas. However, as I was testing out the animation, I noticed that some circles would be erased for a frame, and then reappear again.
This seems to be caused when a sparkle of a higher index is removed by splicing. You can notice the flash whenever a sparkle shrinks to a radius of 0. If this is the actual reason why it causes the issue, I really don't understand why splicing would cause such an issue.
https://jsfiddle.net/sketti21/2gfarp74/82/
// Handles the animation of the sparkles.
function animate(timestamp)
{
// Observe the timestamp gives by requestAnimationFrame in console.
// console.log(timestamp);
// Clears the previous frame;
draw.clearRect(0, 0, canvas.width, canvas.height);
// Loop through each index of sparkles. Doing this lets us draw multiple
// sparkles at once.
for (i = 0; i < sparkles.length; i++)
{
if (sparkles[i] != null)
{
// If the sparkle's delay is not set, then set it.
// This is necessary to do here since the timestamp that requestAnimationFrame
// puts in as a parameter is always growing.
if (sparkles[i].delay == null)
{
sparkles[i].delay = Math.floor(Math.random()*config.maxDelay) + timestamp;
}
// Handles whether to animate the next frame or to remove this sparkle from array.
// If timestamp is larger than sparkle's delay, this means it's time to
// animate this sparkle.
if (timestamp > sparkles[i].delay)
{
// Increment the input variable and calculate the radius of circle.
sparkles[i].inputX += config.increment;
var radius = getRadius(sparkles[i].inputX, sparkles[i].multiplier);
console.log("Radius of index " + i + ": " + radius);
console.log("Multiplier of index " + i + ": " + sparkles[i].multiplier);
if (radius < 0)
{
radius = 0;
}
// Drawing the circle.
draw.beginPath();
draw.arc(sparkles[i].x,
sparkles[i].y,
radius, 0, 360);
draw.fill();
draw.closePath();
// If the sparkle's radius drops below 0, then remove it from the array.
if (radius == 0)
{
sparkles.splice(i, 1);
console.log("spliced indexes " + i + " to " + (i + 1));
}
}
}
}
if (sparkles.length > 0)
{
animControl = window.requestAnimationFrame(animate);
}
else
{
console.log("Refilled the array.");
for (i = 0; i < config.maxSparkles; i++)
{
sparkles[i] = new Sparkle();
}
animControl = window.requestAnimationFrame(animate);
}
}
Let me summarize the logic of my code to make reading through it quicker and easier:
Create the sparkles array.
Start the animation. (animate())
Clear the canvas.
Fill sparkles array up to config.maxSparkles.
requestAnimationFrame(animate)
Clear the canvas.
If a random delay hasn't been assigned to the Sparkle object, then calculate a delay that's below config.maxDelay and add the timestamp.
If the current timestamp is greater than the Sparkle's delay..
8a. Calculate and draw each sparkle individually for this frame.
8b. If the Sparkle radius = 0, then splice that sparkle out of the sparkles array.
If there are elements in the sparkles array, then requestAnimationFrame(animate)
9a. Else, refill the array up to config.maxSparkles.
... So on and so forth.
Any help is greatly appreciated!
When you splice something from an array, an element gets removed, and thus the length is shortened by one.
So if you loop through an array and remove something, that means that the index for the item you are removing has now become the index for the next item. So on the next loop, that item is skipped.
To solve your problem, you need to decrement i when you splice something from the array, so it isn't skipped on the next iteration.
That should hopefully solve the issue!

Svg object modified with setAttributeNS not updating until after while loop

I'm creating a small game in javascript and I'm using svg for the graphics. Right now I'm having a problem with updating the game in the middle of a game tick. If I exit my loop directly after I update the fill attribute with "setAttributeNS", it's redrawn, but if I don't do that, it isn't updated until after "game_tick" is over. Even worse, if I call "game_tick" multiple times in a row, the svg objects aren't updated until after I've run all of the "game_tick"s instead of being updated after each one.
function game_tick(){
num_grid_copy = num_grid.slice();
for (var x = 0; x < num_squares_x; x += 1) {
for (var y = 0; y < num_squares_x; y += 1) {
var n = get_neighbors(x,y);
var isAliveInNextGen = next_gen(n, num_grid[x*num_squares_x+y]);
num_grid_copy[x*num_squares_x+y] = isAliveInNextGen;
if (isAliveInNextGen == 1){
rect_grid[x*num_squares_x+y].setAttributeNS(null, 'fill', '#0099ff');
}
else {
rect_grid[x*num_squares_x+y].setAttributeNS(null, 'fill', '#fff');
}
}
}
num_grid = num_grid_copy;
}
Thanks to valuable input from Robert I realized that javascript execution and page rendering are done in the same thread. I changed the function to the following:
function start() {
var inc = 0,
max = 25;
delay = 100; // 100 milliseconds
var repeat = setInterval(function() {
game_tick();
if (++inc >= max)
clearInterval(repeat);
},
delay);
}
This works fine. I can set the delay and the number of times it repeats.

JS swapping an image smoothly

I already have a function to swap the images, but they swap without any animation. Now I want a function witch swaps the images with a fading. Here is my written code for the swap function:
var header = new Array();
header[0] = "images/lan/IMG_2799.jpg";
header[1] = "images/lan/IMG_2816.jpg";
var x = 0;
function swapHeader() {
document.getElementById("header").style.backgroundImage = "url(" + header[x] + ")";
if (x < header.length - 1) x++; else x = 0;
setTimeout("swapHeader()", 5000);
}
window.onload=swapHeader;
You may want to use two elements, one per image. Then, slowly increase and decrease the opacity (a CSS property) of the one on top. The rest of your content should go above those two elements, and have a transparent background.

Can't detect collision in 3D JavaScript

I am using three.js to make a simulation of the Brownian Motion and I'm stuck on a part where I need to get the little molecules to collide against each other. This is what I have so far:
function intersects(sphere, other){ //check if the distance between one sphere and the other is less than radius of both (4)
var distance = Math.sqrt((sphere.position.x - other.position.x) * (sphere.position.x - other.position.x) +
(sphere.position.y - other.position.y) * (sphere.position.y - other.position.y) +
(sphere.position.z - other.position.z) * (sphere.position.z - other.position.z));
if(distance < (4)){
return true;
} else {
return false;
}
}
function checkCollision(current){
for(var i = 0; i < balls.length; i++) {
if(intersects(balls[current], balls[i]) == true){
// balls[current].velocity.negate();
alert('hey');
}
}
}
When I run the code, I know for certain that the balls don't collide/intersect with each other, however I continuously get an alert box. I've tried to check if it's less than (sphere.radius + other.radius) but I don't think that's correct since it didn't seem to work. Also when I do keep it '< 4', it messes up the performance and it starts to run slowly at around 5 fps or less. checkCollision gets used here during the animation, so basically it checks it every time.
function animate(){
for(var i = 0; i < balls.length; i++){
balls[i].position.add(balls[i].velocity);
checkWallBoundaries(i);
checkCollision(i);
}
THREEx.WindowResize(renderer, camera);
requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
stats.update();
}
I don't know why I can't get this to work. If someone could help me, that'd be greatly appreciated.
edit: Here's a picture of what happens when I uncomment the balls[current].velocity.negate() line https://puu.sh/uG1eS.png. The balls keep going back and forth but they're not even remotely close to each other, so I don't know why collision is being detected
Every ball collides with itself. You need to exclude i === current
for(var i = 0; i < balls.length; i++) {
if(current === i) continue;
if(intersects(balls[current], balls[i]) == true){
alert('hey');
}
}

Animation changes the position of div's

Well I've implementes some divs and when I start the page I want them animate, they do, but the problem is that sometimes one div overlaps another one then I see a blank space... How could I avoid this? I'm doing this :
This is how I change the divs :
function swap(d1, d2){
var topaux, leftaux;
topaux = d1.css("top");
leftaux = d1.css("left");
d1.animate({
top: d2.css("top"),
left: d2.css("left"),
}, { duration: 1000, queue: false });
d2.animate({
top: topaux,
left: leftaux,
}, { duration: 1000, queue: false });
}
This is how I'm trying to do it now, but after try this, I didn't have any animation so I had this code and it worked I mean no overlaps between div's....
d1.css("top", d2.css("top"));
d1.css("left", d2.css("left"));
d2.css("top", topaux);
d2.css("left", leftaux);
I call this function (swap) when I'm shuffling the divs as follows :
function swapdivs(){
var i,r, c, d1, d2;
for (i = 1; i < 100; i++) {
r = Math.floor((Math.random() * rows) + 1);
c = Math.floor((Math.random() * columns) + 1);
d1= $("#r"+r+"c"+c);
r = Math.floor((Math.random() * rows) + 1);
c=Math.floor((Math.random() * columns) + 1);
d2 = $("#r"+r+"c"+c);
swap(d1,d2);
}
}
This is the jfiddle
What I'm missing?
Ok, now i see the problem.
In your barrejarPeces function you're scrambling randomly all elements multiple times (100)
for (i = 1; i < 100; i++) {
In the interanvipeces function you try to switch the position of 2 different elements with an animation of 1000ms, calculating their css attributes top and left
Well, the problem is when one (or both) elements are already switching position (since the barrejarPeces function will scramble 100 times without waiting any animation to finish), top and left values won't be correct.
So there are 2 possible solutions:
Don't use animation delay (try to set to 0 instead of 1000 in your fiddle and you'll see it works)
Scramble all elements just once (see my example here, where i changed some logic)

Categories

Resources