Animating simple motion of line with clean fade not overwriting with background(0)


#1

I am a newbie learning nested loops, for, while, if, else, etc.
My intention is to create a series of horizontal white lines that are animated moving downwards. The number and distance should be variables I can later output to other programs.

But am completely stuck regarding nested loops (while, for, etc). The clear background technique to make most of the examples work seems like a shortcut, but regardless I can’t get anything to work.

Basically these lines should be moving down on repeat:
image

I’ve tried tons of different things, using these tutorials https://www.youtube.com/watch?v=LaarVR1AOvs, https://www.youtube.com/watch?v=H7frvcAHXps&t=28s

Basically I want to do a while loop to make the series of lines and then a for loop to rewrite them so it looks like they are moving downwards. It’s important I can output global variables when I am down to use in programs like VDMX with OSC output.

Here’s my code (one of many):

float ii;

void setup() {
  background(0);
  size(500, 500);
  stroke(255);
  strokeWeight(1);
}

void draw() {
  for (int i = 0; i < height; i=i+10) {
//       background (20);
//    for (int ii=0; ii < 10; ii++) {
      line (0, i+ii, width, i+ii);
    }
//  }
}


#2

It is not a shortcut, this is how almost every animation works.

You start by cleaning everything you have on your screen at the begining of draw() with

background(color);

Then you update the position of your objects.
Then you draw your objects (at their new position).

I remember there was a thread quite similar to what you are asking. I’ll have a look and paste it here.

Edit:
This is the thread: Draw lines that go from bottom to top?


#3

You’re really close, you just need a few tweaks. :slight_smile:

To make the lines move down together (I assume you want the distance apart to be the same), you need to make ii increment every frame with ii+=<speed>, but make sure it’s outside the for() loop so it doesn’t increment too many times each frame.

Also, you only need to erase the canvas once every frame, do add background(0); to the start of draw().

If you want the lines to keep moving downwards, you can add an if statement that checks if ii is more than the distance of space between the lines, and set it to 0 if it is, as we don’t need actual motion, just the illusion.


#4

The are 2 things in your code that contradict what you are trying to do. First thing is that you are clearing the whole background within a loop. This is not neccessary (almost never, because you can’t see what happens inside a loop on the screen if it resets itself afterwards). And second, you have a nested loop, which is also not neccessary if you just want a continuous drawing in one direction (drawing one line under the other). Note that i’m talking about the commented parts. And Sarah just said how to solve the motion downwards :sweat_smile:


#5

Thank you @jb4x, the example you posted is a version on steroids of what I am trying to do. I look forward to learning the meaning/purpose of things from Draw lines that go from bottom to top? like:
final int
void createLines
class
private

And I look forward to that.
But do I need to understand those things to achieve my goal?

As you say, start be clearing at the beginning of draw with:

background(color);

And I get what you mean by update position and draw new, but there are two steps I am doing that are nested (is that the proper use of “nested”?)

  1. Draw white lines every (10?) pixels to fill screen equidistant from eachother
    (that’s a for loop right? I also tried while loop)

  2. clear

  3. move location down one pixel and then redraw all the lines

clear and loop so lines all appear to move smoothly down the screen.


#6

Thats not how nested loops work. Lets say a nested loop like this :

for (int i = 0; i < 10; i++) {
  for (int j = 0; j < 10; j++) {
    println(i*10+j);
  }
}

This will count up to 99, including 0. But it will not do it slowly. It will do it within one frame. And same goes for the lines you draw. If you do so, it will draw all lines in the j loop, and that 10 times (maybe moving them down a bit each time) which will cause either maaaany lines to be drawn, or if the lines have the same distance to each other as they get pushed down, then it will overlap the lines.

What you need to do, is to reset the background with background(255), then create a for loop that draws all the lines you need. Or :

for (int i = 0; i < 10; i++) {
  line(x, i*10 + j, x+100, i*10 + j);
}

And then you need to (after the loop is done) increment the offset j by 1, or do j++;.

To do many calculations within one frame you will want to use loops, while to make changes at a visible rate (like movement) you want to increment an external variable each frame.


#7

@Sarah You get my confusion exactly. If I put the background(0) at the start of draw() I just see a single line moving down.

And regarding your suggestion of using if statement, I can’t find examples that help me use for with if (with else with while) etc.


#8

you already have a good for loop for all the lines
and a variable to shift the position,
so just use it:

int ii=0, di = 20, lstroke=3;

void setup() {
  size(500, 500);
  stroke(0,0,200);
  strokeWeight(lstroke);
}

void draw() {
  background(200, 200, 0);
  for (int i = 0; i < height; i=i+di)  line (0, i+ii, width, i+ii);
  ii++;  if ( ii >= di ) ii = 0;             // @Sarah
}


#9

thank you @kll
that’s exactly what I am trying to achieve

ahem
now forgive me a few while I try to figure out how you made that work :slight_smile:


#10

Short explanation : a for loop does things within one frame, so if you move something down, it will be at the end position after the frame is done and you wont see it move smoothly (though you might see the path it took, if you have drawn something in the for loop). While you need to use external variables to make slow changes over time, like movement.

Long explanation in the post 4 up.


#11

For smoother motion, instead of if ( ii > 10 ) ii = 0; you should use if ( ii >= 10 ) ii = 0;.


#12

sounds absolutely right, but i not see it and got dizzy already,
anyhow changed upstairs

p.s. happy loy krathong


#13

but did i ignore your title / question?
you say

not overwriting with background(0)

so you need to clear each old line and make a new line a pix down

int ii=0, di = 20, lstroke=3;

void setup() {
  size(500, 500);
  stroke(0,0,200);
  strokeWeight(lstroke);
}

void draw() {
//  background(200, 200, 0);
  stroke(200, 200, 0);
  for (int i = 0; i < height; i=i+di)  line (0, i+ii, width, i+ii);
  ii++;  if ( ii >= di ) ii = 0;             // @Sarah
  stroke(0,0,200);
  for (int i = 0; i < height; i=i+di)  line (0, i+ii, width, i+ii);
}


#14

The keyword final is used to declare a constant. So the following line is saying: I’m creating a constant called nbOfLines that is an integer value of 50. You won’t be able to change it in the future.

final int nbOfLines = 50;

void createLines() is a function. The basic structure of a function is as followed:

type functionName(type arg1, type arg2, ...) { return result }

The fist type before the function name is the type of the value returned by the function.
Inside the brackets, you can declare some arguments with their own types.
And finally in between the curly brackets, this is where you put all of your logic.
The return keyword is used to return the value of the following variable (in this case return).

For example, the following code will display in the console the square of the variable val.

void setup() {
  int val, result;
  
  val = 10;
  result = squareOf(val);
  
  println(result);
}

// A function that return an integer and that take an integer as an argument.
int squareOf(int a) {  
  return a * a;
}

The keyword class is used in OOP. This is the blueprint of an object. You can think of it as a fancy variable that can contain several value and do operation on them. It is a bit complicated to explain quickly here, but I advise you to have a look at it as it can really simplify your life in bigger projects :slight_smile:


The keyword private is used inside a class to tell the computer that you can’t read or change the value outside of the class. So only the method that are inside of your class can deal with them. That is the core principle of OOP.


Now, of course, you don’t need to understand all that to create your project and the others gave you nice examples.
Nonetheless, it would be interesting for you to dig into OOP.