Processing - lines get bigger progressively - time

so I have in a file the coordinates and the seconds I want to make a line get bigger progressively. In the file, I have x1, x2 (regarding the first point coordinates), x2, y2 (2nd point coordinates), and the time (in seconds) I want to start growing the line, in the second point direction.
This is my code:
//TO READ LINES
import processing.video.*;
Movie myMovie;
Table table;
float duration, time;
int row_no=1;
int clickcount = 0;
void setup() {
size(640,480);
myMovie = new Movie(this, "draft.mov");
myMovie.loop();
table = loadTable("data/new.csv");
}
void draw() {
duration = myMovie.duration();
time = myMovie.time();
image(myMovie, 0, 0);
if(time>= table.getFloat(row_no, 4)){
strokeWeight(15);
stroke(255,14,255);
float a = table.getFloat(row_no, 0);
float b = table.getFloat(row_no,1);
line(table.getFloat(row_no,0),table.getFloat(row_no, 1), a, b);
a = a + 2;
b = b + 2;
}
}
// Called every time a new frame is available to read
void movieEvent(Movie m) {
m.read();
} `

As Niccolo advises, break your problem down first, take out anything you don't need and go one step at a time.
In terms or taking stuff out, based on the description of your goals, it doesn't sound like code has anything to do with playing back a movie, so take that code out to simplify. (The only reason I could think of for using a movie is to use it's current time to control the lines, but unless you want a movie background you shouldn't need that)
In the draw() loop there are a few things that look odd:
if(time>= table.getFloat(row_no, 4)){ assuming the 5th column in the .csv file holds the cue time for the current row in seconds, this condition will trigger only once potentially as there's nothing incrementing row_no
line(table.getFloat(row_no,0),table.getFloat(row_no, 1), a, b); isn't probably what you're after and might be a typo because a and b have retrieved from the same .csv columns (0 and 1), which means you're line's start and end position are in the exact position (therefore not rendering a line). perhaps you meant line(table.getFloat(row_no,2),table.getFloat(row_no, 3), a, b); ?
a = a + 2; and b = b + 2;: the x,y positions for one of the points may be offset by 2, but the new positions are never used past this point. In the next draw() iteration a and b are redefined, and therefore the offset is lost.
Let's go through breaking the problem down:
I have in a file the coordinates and the seconds I want to make a line get bigger progressively. In the file, I have x1, x2 (regarding the first point coordinates), x2, y2 (2nd point coordinates), and the time (in seconds) I want to start growing the line, in the second point direction.
load and parse the data (rows containing line coordinates (x1,y1,x2,y2) and time(in seconds))
"make a line get bigger progressively" - animate (interpolate) between the current line (.csv row coordinates) and the next line based on the specified time in seconds)
and even further, if starting from scratch, more as a "how to":
interpolate between one value an another (ignoring time for now, keeping task independent and as simple as possible)
keep track of time as a parameter for interpolating between values
parsing .csv rows
interpolating between 4 four values
incrementing .csv rows based on animation time
Luckily, Processing provides a built-in function for linearly interpolating between values lerp()(lerp = linear interpolation for short).
It takes three parameters:
a value to animate from (start)
a value to animate to (stop)
an interpolation amount (between 0.0 and 1.0)
and it returns one value: the value in between the start and stop values.
Think of the interpolation amount as a percentage (0 = 0%, 0.5 = 50%, 1.0 = 100%).
Here's a basic sketch to illustrate the concept:
void draw(){
background(255);
//map time to an interpolation normalized value
float t = map(mouseX,0,width,0.0,1.0);
//interpolate the values
float size = lerp(10,90,constrain(t,0.0,1.0));
ellipse(50,50,size,size);
}
the snippet a p5.js demo you can run bellow:
function setup() {
createCanvas(100,100);
}
function draw(){
background(255);
//map time to an interpolation normalized value
var t = map(mouseX,0,width,0.0,1.0);
//interpolate the values
var size = lerp(10,90,constrain(t,0.0,1.0));
ellipse(50,50,size,size);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script>
if you move your mouse on the x axis you'll notice the size goes between 10 and 90 pixels in diameter based on the mouse position.
Step 1 done!
Next up, you can use millis() to keep track of time and simply map() between time in millis (mapping the current time between the start and end time to the 0.0 - 1.0 range):
float seconds = 3.5;
//the time in millis since the last update
int previousMillis;
//the current time in millis
int currentMillis;
//the time in millis until the next event
int nextMillis;
void setup(){
previousMillis = millis();
currentMillis = millis();
nextMillis = currentMillis + (int)(seconds * 1000);
}
void draw(){
background(255);
//update the current timer continously
currentMillis = millis();
//map the current time from the previous to the next time as a normalized value (0,0 to 1.0) range
float t = map(currentMillis,previousMillis,nextMillis,0.0,1.0);
//interpolate the values
float size = lerp(10,90,constrain(t,0.0,1.0));
ellipse(50,50,size,size);
}
and as a p5.js runnable demo:
var seconds = 3.5;
//the time in millis since the last update
var previousMillis;
//the current time in millis
var currentMillis;
//the time in millis until the next event
var nextMillis;
function setup(){
previousMillis = millis();
currentMillis = millis();
nextMillis = currentMillis + (int)(seconds * 1000);
}
function draw(){
background(255);
//update the current timer continously
currentMillis = millis();
//map the current time from the previous to the next time as a normalized value (0,0 to 1.0) range
var t = map(currentMillis,previousMillis,nextMillis,0.0,1.0);
//interpolate the values
var size = lerp(10,90,constrain(t,0.0,1.0));
ellipse(50,50,size,size);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script>
That's step2 done and it looks like you've got a hand of step 3 (parsing the .csv values) already :)
Step 4 should be trivial once you understand how to interpolate one value: just do it 4 times for different variables!
Step 5 is simple as you simply need to check if row_no goes beyond the table's row count.
row_no = row_no + 1;
if(row_no > table.getRowCount()) row_no = 0;
One neat thing you could do is use the modulo operator(%) to do the same as a mathematical expression:
row_no = (row_no + 1) % table.getRowCount();
In conclusion, let's assume you're .csv file looks a little like this:
x1,y1,x2,y2,seconds
5,5,95,5,4
95,5,95,95,3
95,95,5,95,2
5,95,5,5,1
One way to put it all together would be something like this:
Table table;
int row_no = 0;
//the time in millis since the last update
int previousMillis;
//the current time in millis
int currentMillis;
//the time in millis until the next event
int nextMillis;
//where to animate the line from
float x1Start,y1Start,x2Start,y2Start;
//where to animate the line to
float x1Stop,y1Stop,x2Stop,y2Stop;
//currently interpolated line positions
float x1Lerp,y1Lerp,x2Lerp,y2Lerp;
void setup(){
size(100,100);
strokeWeight(3);
fill(0);
table = loadTable("data/new.csv","header, csv");
//printing the table in console, handy just for debugging/double checking values
println("data");
for(int i = 0 ; i <= table.getRowCount(); i++){
print(table.getColumnTitle(i)+"\t");
}
println();
for(int i = 0 ; i < table.getRowCount(); i++){
TableRow row = table.getRow(i);
for(int j = 0; j < row.getColumnCount(); j++){
print(row.getFloat(j) + "\t");
}
println();
}
//fetch lines and seconds from the current and next rows
updateFromRow();
}
void updateFromRow(){
//update times
previousMillis = millis();
currentMillis = millis();
//get the current row and it's line coordinates
TableRow currentRow = table.getRow(row_no);
x1Start = currentRow.getFloat("x1");
y1Start = currentRow.getFloat("y1");
x2Start = currentRow.getFloat("x2");
y2Start = currentRow.getFloat("y2");
//get the next row and it's line coordinates - notice % module is used to easily loop back to 0 once row_no goes beyond the number of table rows
TableRow nextRow = table.getRow((row_no + 1) % table.getRowCount());
x1Stop = nextRow.getFloat("x1");
y1Stop = nextRow.getFloat("y1");
x2Stop = nextRow.getFloat("x2");
y2Stop = nextRow.getFloat("y2");
//get the duration in seconds, convert it to millis( * 1000) and add it to the current millis
nextMillis = currentMillis + (int)(currentRow.getFloat("seconds") * 1000);
println("updated from row: " + row_no);
}
void draw(){
background(255);
//update the current timer continously
currentMillis = millis();
//map the current time from the previous to the next time as a normalized value (0,0 to 1.0) range
float t = map(currentMillis,previousMillis,nextMillis,0.0,1.0);
//if the current interpolation value is above 1.0
if(t > 1.0){
t = 0;
//increment the row
row_no++;
//if the current row counter is above the total number of rows, reset back 0
if(row_no >= table.getRowCount()){
row_no = 0;
}
//update values from incremented row (lines and their coordinates + time)
updateFromRow();
}
text("t:"+t,15,20);
//constrain interpolated value between 0.0 and 1.0
float interpolationAmount = constrain(t,0.0,1.0);
//linearly interpolate (lerp) between the current and next line coordinates
x1Lerp = lerp(x1Start,x1Stop,interpolationAmount);
y1Lerp = lerp(y1Start,y1Stop,interpolationAmount);
x2Lerp = lerp(x2Start,x2Stop,interpolationAmount);
y2Lerp = lerp(y2Start,y2Stop,interpolationAmount);
//finally, render the interpolated line
line(x1Lerp,y1Lerp,x2Lerp,y2Lerp);
}
In terms of keeping track of the data, the line coordinates can be stored using PVector instances (...the x,y components set() from .csv data and the line points can be interpolated in pairs via PVector's lerp()).
So far we've only been using linear interpolation, but you might also want to look into easing and tweening.

Related

How to make this pattern to expand and shrink back

i have a task to make a pattern of circles and squares as described on photo, and i need to animate it so that all objects smoothly increase to four times the size and then shrink back to their original size and this is repeated. i tried but i cant understand problem
{
size(500,500);
background(#A5A3A3);
noFill();
rectMode(CENTER);
ellipseMode(CENTER);
}
void pattern(int a, int b)
{
boolean isShrinking = false;
for(int x = 0; x <= width; x += a){
for(int y = 0; y <= height; y += a){
stroke(#1B08FF);
ellipse(x,y,a,a);
stroke(#FF0000);
rect(x,y,a,a);
stroke(#0BFF00);
ellipse(x+25,y+25,a/2,a/2);
if (isShrinking){a -= b;}
else {a += b;}
if (a == 50 || a == 200){
isShrinking = !isShrinking ; }
}
}
}
void draw()
{
pattern(50,1);
}
this is what pattern need to look like
Great that you've posted your attempt.
From what you presented I can't understand the problem either. If this is an assignment, perhaps try to get more clarifications ?
If you comment you the isShrinking part of the code indeed you have an drawing similar to image you posted.
animate it so that all objects smoothly increase to four times the size and then shrink back to their original size and this is repeated
Does that simply mean scaling the whole pattern ?
If so, you can make use of the sine function (sin()) and the map() function to achieve that:
sin(), as the reference mentions, returns a value between -1 and 1 when you pass it an angle between 0 and 2 * PI (because in Processing trig. functions use radians not degrees for angles)
You can use frameCount divided by a fractional value to mimic an even increasing angle. (Even if you go around the circle multiple times (angle > 2 * PI), sin() will still return a value between -1 and 1)
map() takes a single value from one number range and maps it to another. (In your case from sin()'s result (-1,1) to the scale range (1,4)
Here's a tweaked version of your code with the above notes:
void setup()
{
size(500, 500, FX2D);
background(#A5A3A3);
noFill();
rectMode(CENTER);
ellipseMode(CENTER);
}
void pattern(int a)
{
for (int x = 0; x <= width; x += a) {
for (int y = 0; y <= height; y += a) {
stroke(#1B08FF);
ellipse(x, y, a, a);
stroke(#FF0000);
rect(x, y, a, a);
stroke(#0BFF00);
ellipse(x+25, y+25, a/2, a/2);
}
}
}
void draw()
{
// clear frame (previous drawings)
background(255);
// use the frame number as if it's an angle
float angleInRadians = frameCount * .01;
// map the sin of the frame based angle to the scale range
float sinAsScale = map(sin(angleInRadians), -1, 1, 1, 4);
// apply the scale
scale(sinAsScale);
// render the pattern (at current scale)
pattern(50);
}
(I've chosen the FX2D renderer because it's smoother in this case.
Additionally I advise in the future formatting the code. It makes it so much easier to read and it barely takes any effort (press Ctrl+T). On the long run you'll read code more than you'll write it, especially on large programs and heaving code that's easy to read will save you plenty of time and potentially headaches.)

How to make something "instantaneously" in Processing

So, i'm sorry if this is a weird or stupid question but I genuinely couldn't find an answer. So, the thing is I'm trying to do a visual representation of the multiplication tables, so i divide a circle in a certain number of "slices", for example I divide it in 10. Then I join each point with its product, for example for the 2 times table i make a line between 1 and 2, another one between 2 and 4, 3 and 6 and so on...
The thing is, if i surpass a certain amount of "slices" i can clearly see Processing drawing each one of the lines one by one. I wanted to progressively change the number of slices so you can see how does it evolve, but then the lines would just have to "appear" or change instantaneously since the "animation" makes no sense if you see it drawing every line. Is there a way I can improve the speed of the program, or just make it show all lines at once?
For reference, this is how i kinda want it to look like:
YouTube video
This is the code i'm using (with the ControlP5 library and soooo poorly optimized):
import controlP5.*;
ControlP5 cp5;
Knob myKnobA;
Knob myKnobB;
int ncosas = 30;
float sumangle = (2*PI)/ncosas;
float angle = HALF_PI + PI + sumangle;
int radius = 100;
int counter = 1;
int sumar = 15;
int tablade = 2;
int prueba = 30;
void setup(){
size(400,400);
background(255);
textAlign(CENTER,CENTER);
fill(0);
stroke(0);
textSize(8);
cp5 = new ControlP5(this);
myKnobA = cp5.addKnob("Servo")
.setRange(1,120)
.setValue(1)
.setPosition(20,20)
.setRadius(30)
.setDragDirection(Knob.HORIZONTAL)
.setCaptionLabel("N")
.setColorCaptionLabel(0)
;
myKnobB = cp5.addKnob("TablaD")
.setRange(1,50)
.setValue(1)
.setPosition(20,120)
.setRadius(30)
.setDragDirection(Knob.HORIZONTAL)
.setCaptionLabel("Tabla de")
.setColorCaptionLabel(0)
;
//translate(height/2,width/2);
//line(0,0,radius*sin(radians(prueba)),radius*cos(radians(prueba)));
}
void draw(){
if(counter <= ncosas){
dibujar();
}
}
void Servo(int theValue){
background(255);
counter = 1;
ncosas = theValue;
sumangle = (2*PI)/ncosas;
angle = HALF_PI + PI + sumangle;
}
void TablaD(int theValue){
background(255);
counter = 1;
tablade = theValue;
angle = HALF_PI + PI + sumangle;
}
void dibujar(){
pushMatrix();
translate(width*2.5/4,height/2);
circle(radius*sin(angle),radius*cos(angle),2);
//if(counter*tablade<=ncosas){
line(radius*sin(angle),radius*cos(angle),radius*sin((counter*tablade*sumangle)+(angle-counter*sumangle)),radius*cos((counter*tablade*sumangle)+(angle-counter*sumangle)));
//}
println(counter*tablade + " -> " + counter*tablade*degrees(sumangle));
text(counter,(radius+sumar)*sin(angle),(radius+sumar)*cos(angle));
angle += sumangle;
counter++;
popMatrix();
}
void keyPressed(){
if (key == 'D' || key == 'd'){
Servo(int(myKnobA.getValue())+1);
myKnobA.setValue(int(myKnobA.getValue())+1);
}
if (key == 'A' || key == 'a'){
Servo(int(myKnobA.getValue())-1);
myKnobA.setValue(int(myKnobA.getValue())-1);
}
if (key == 'W' || key == 'w'){
TablaD(int(myKnobB.getValue())+1);
myKnobB.setValue(int(myKnobB.getValue())+1);
}
if (key == 'S' || key == 's'){
TablaD(int(myKnobB.getValue())-1);
myKnobB.setValue(int(myKnobB.getValue())-1);
}
}
Thank you in advance
To expand on what John Coleman said, you need to execute the dibujar() command multiple times in draw(). In Processing, the canvas is rendered at the end of the draw() loop, so if you draw multiple lines in draw(), they will all appear at the same time.
This will involve some kind of loop. If you want to draw the entire multiplication circle at once, you could replace if with while in the draw() loop:
void draw(){
while (counter <= ncosas){
dibujar();
}
}
I believe this will draw the entire multiplication circle in a single frame. You can then adjust the knobs to change the parameters of the multiplication circle, and the multiplication circle will change as you adjust the knobs.

How to create a sinusoidal wave of a line so that the start of the wave returns to being flat

I know how to create a sinusoidal movement with particles as per the code below. What I would like to do however is to create an effect which is more of a ripple along a string. The idea is that a wave moves along a string but the section that is not currently in a wave returns to the zero position and doesn't undergo a further wave- ie just one wave passing down the line.
How do I amend the sinusoidal movement below to achieve this?
int xspacing = 16; // How far apart should each horizontal location be spaced
int w; // Width of entire wave
float theta = 0.0; // Start angle at 0
float amplitude = 75.0; // Height of wave
float period = 500.0; // How many pixels before the wave repeats
float dx; // Value for incrementing X, a function of period and xspacing
float[] yvalues; // Using an array to store height values for the wave
void setup() {
size(640, 360);
w = width+16;
dx = (TWO_PI / period) * xspacing;
yvalues = new float[w/xspacing];
}
void draw() {
background(0);
calcWave();
renderWave();
}
void calcWave() {
// Increment theta (try different values for 'angular velocity' here
theta += 0.02;
// For every x value, calculate a y value with sine function
float x = theta;
for (int i = 0; i < yvalues.length; i++) {
yvalues[i] = sin(x)*amplitude;
x+=dx;
}
}
void renderWave() {
noStroke();
fill(255);
// A simple way to draw the wave with an ellipse at each location
for (int x = 0; x < yvalues.length; x++) {
ellipse(x*xspacing, height/2+yvalues[x], 16, 16);
}
}
I'm not totally sure exactly what you're going for. Drawing out some examples might help explain it better.
But the short answer to your question is: you'd change the height of the sin wave by modifying this line:
yvalues[i] = sin(x)*amplitude;
Right now every particle has the same amplitude, so it your wave has a uniform height. Instead, what you want to do is give each particle a different amplitude. Here's a very simple example:
yvalues[i] = sin(x) * x * 10;
This causes particles towards the left of the screen to have a smaller amplitude, and particles at the right of the screen to have a larger amplitude. In other words, the wave starts out flat and gets larger as it moves to the right.
What I would probably do is create a Particle class that encapsulates each particle's position, movement, and amplitude. Then I'd decrease the amplitude of each particle over time, maybe increasing it when the user clicks (or whatever event you want to spawn your waves).
Shameless self-promotion: I've written a tutorial on creating classes in Processing available here.

animating sine waves in processing

how do I animate the sin lines in the following code to move along the y-axis, to somehow look more like moving water waves?
-if you take out the velocity and acceleration codes you will see what I was trying to work with
float scaleVal = 6.0;
float angleInc = 0.19;
float velocity=0.0;
float acceleration=0.01;
void setup(){
size(750,750);
stroke(255);
}
void draw(){
background (0);
float angle=0.0;
for (int offset = -10; offset < width+10; offset += 10) {
for (int y = 1; y <= height; y += 3) {
float x = offset + (sin(angle) * scaleVal);
line(x, y, x, y+2);
angle += angleInc;
velocity += acceleration;
y += velocity;
}
angle += PI;
}
}
Try using sin() to change the y position instead of x.
The x position can simply increment.
The math may be daunting, but it gets fun once you get the hang of it.
Imagine going around a circle with the radius of 1.0 in a cartesian coordinate system (0 is centre , x and y increase to the right and down and decrease towards left and top):
Let's say you start at the top, the highest value, the length radius of your circle (1.0).
As you decrease the angle, the x move to the left, but the y will go towards the centre( 0.0 )
then x will increase as it gets close to the centre and y will drop to bottom of the circle (-1.0)
then x will keep increasing until it reaches the right edge of the circle and the y value will increase and reach the vertical centre (0.0)
finally the x will decrease until it reaches the horizontal centre and y will increase and reach back to the top of the circle (1.0)
This image explains it pretty well:
Essentially it's like a converter: you plug in an angle from 0 to 360 degrees or TWO_PI radians (as sin works with angles in radians) and you get back a value between -1.0 and 1.0.
If you want to draw a sine wave, you have to draw multiple points:
the x position will increase value directly
the y position will increase the angle, but use the result of the sin() function to obtain a value that goes up and down.
The last thing to do is multiple the result of the sin() function by a larger number to essentially scale the sine wave (from -1.0 to 1.0) to a size more appropate for the screen.
Here's a quick commented demo you can use the mouse position to play with:
function setup(){
createCanvas(640,100);
}
function draw(){
background(255);
var numberOfPoints = 1+(mouseX/2);
//how often apart will the points be
var widthPerPoint = width / numberOfPoints;
//how much will the angle change from one point to another
var anglePerPoint = TWO_PI/numberOfPoints;
var waveHeight = 25;
for(var i = 0; i < numberOfPoints; i++){
var x = i * widthPerPoint;
var y = sin(anglePerPoint * i) * waveHeight;
ellipse(x,50 + y,5,5);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
The gist of it is this line:
var y = sin(anglePerPoint * i) * waveHeight;
which can be broken down to:
//increment the angle
var incrementedAngle = anglePerPoint * i;
//compute sine (-1.0,1.0)
var sine = sin(incrementedAngle);
//scale sine result
var waveY = sine * waveHeight;
Once you can draw a static sine wave, it's pretty easy to animate: to the angle increment at each point you add an increasing value. This increases the angle and essentially goes around the circle (TWO_PI) for you.
You can create your own variable to increase at your own rate or you
can easily use an increasing value based on time(millis()) or frame(frameCount) which you can scale down (divide by a large number...or better yet multiple by a small fractional number):
function setup(){
createCanvas(640,100);
}
function draw(){
background(255);
var numberOfPoints = 1+(mouseX/2);
//how often apart will the points be
var widthPerPoint = width / numberOfPoints;
//how much will the angle change from one point to another
var anglePerPoint = TWO_PI/numberOfPoints;
var waveHeight = 25;
for(var i = 0; i < numberOfPoints; i++){
var x = i * widthPerPoint;
var y = sin(anglePerPoint * i + frameCount * 0.01) * waveHeight;
ellipse(x,50 + y,5,5);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
Hopefully the animation and simple demos above help illustrate the point.
In even simpler terms, it's a bit of an illustion: you draw points that only move up and down, but each point use an increasing angle along the circle.
Have a look at Reuben Margolin's kinectic sculpture system demo:
(I recommend checking out the whole PopTech talk: it's inspiring)
You should have a look at the Processing SineWave example as well.
Here's a more complex encapsulating the notions in a resuable function to draw multiple waves to hint at an atmospheric perspective:
int numWaves = 5;
void setup(){
size(400,400);
noStroke();
}
void draw(){
background(255);
for(int i = 0 ; i < numWaves; i++){
fill(30,120,180,map(i,0,numWaves-1,192,32));
drawSineWave(HALF_PI,0.00025 * (i+1),50 + (10 * i),8,width,mouseY);
}
fill(255);
text("drag mouse x to change number of waves",10,height-10);
}
/*
* radians - how often does the wave cycle (larges values = more peaks)
* speed - how fast is the wave moving
* amplitude - how high is the wave (from centre point)
* detail - how many points are used to draw the wave (small=angled, many = smooth)
* y - y centre of the wave
*/
void drawSineWave(float radians,float speed,float amplitude,int detail,float size,float y){
beginShape();
vertex(0,height);//fix to bottom
//compute the distance between each point
float xoffset = size / detail;
//compute angle offset between each point
float angleIncrement = radians / detail;
//for each point
for(int i = 0 ; i <= detail; i++){
//compute x position
float px = xoffset * i;
//use sine function compute y
//millis() * speed is like an ever increasing angle
//to which we add the angle increment for each point (so the the angle changes as we traverse x
//the result of sine is a value between -1.0 and 1.0 which we multiply to the amplitude (height of the wave)
//finally add the y offset
float py = y + (sin((millis() * speed) + angleIncrement * i) * amplitude);
//add the point
vertex(px,py);
}
vertex(size,height);//fix to bottom
endShape();
}
void mouseDragged(){
numWaves = 1+(int)mouseX/40;
}
Which you can also run bellow:
var numWaves = 5;
function setup(){
createCanvas(400,400);
noStroke();
}
function draw(){
background(255);
for(var i = 0 ; i < numWaves; i++){
fill(30,120,180,map(i,0,numWaves-1,192,32));
drawSineWave(HALF_PI,0.00025 * (i+1),50 + (10 * i),8,width,mouseY);
}
fill(255);
text("drag mouse x to change number of waves",10,height-10);
}
/*
* radians - how often does the wave cycle (larges values = more peaks)
* speed - how fast is the wave moving
* amplitude - how high is the wave (from centre point)
* detail - how many points are used to draw the wave (small=angled, many = smooth)
* y - y centre of the wave
*/
function drawSineWave(radians,speed,amplitude,detail,size,y){
beginShape();
vertex(0,height);//fix to bottom
//compute the distance between each point
var xoffset = size / detail;
var angleIncrement = radians / detail;
for(var i = 0 ; i <= detail; i++){
var px = xoffset * i;
var py = y + (sin((millis() * speed) + angleIncrement * i) * amplitude);
vertex(px,py);
}
vertex(size,height);//fix to bottom
endShape();
}
function mouseDragged(){
numWaves = ceil(mouseX/40);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
The only other suggestion I have, in terms of rendering, it to have play with beginShape(). Rather than having to worry about where to draw each line, simply pass a bunch of points(via vertex(x,y)) in between beginShape()/endShape() calls and let Processing connect the dots for you.
Stack Overflow isn't really designed for general "how do I do this" type questions. It's for more specific "I tried X, expected Y, but got Z instead" type questions. That being said, I'll try to help in a general sense.
If you want to animate something going up and down, you have to modify its Y position over time.
One approach is to use the sin() or cos() functions to come up with a value that alternates between -1 and 1, which you can then multiply by a height and add to a center:
void setup() {
size(100, 200);
}
void draw() {
background (0);
float centerY = height/2;
float waveHeight = 75;
float input = frameCount/10.0;
float ballY = centerY+sin(input)*waveHeight;
ellipse(width/2, ballY, 10, 10);
}
Another approach is to keep track of the position and speed yourself. When the position reaches a min or max, just reverse the speed. Something like this:
float ballY = 100;
float ySpeed = 1;
void setup() {
size(100, 200);
}
void draw() {
background (0);
ballY += ySpeed;
if(ballY < 0 || ballY > height){
ySpeed *= -1;
}
ellipse(width/2, ballY, 10, 10);
}
You could also use the lerp() function. The point is that there are a million different ways to do this. The best thing you can do is to try something and post an MCVE if you get stuck. Good luck.

Hold noLoop() for certain amount of time

I'm attempting to create a very simple "whack-a-mole" type game, designed for students new to p5.js, and Processing in general.
Currently, I've created an array, and a random search within that array that randomly picks a square and makes it brown (a "mole", for now).
How do I make it so that after selecting a square, it stays there for a couple seconds, and then jumps to the next one, using basic p5?
I've managed to implement noLoop(), which can stop the search, but after a certain time I want it to resume.
Here's the code I have so far:
function setup() {
createCanvas(610,610)
}
function draw() {
var grid = []
for (var x = 0; x < 6; x += 1){
grid[x]=0;
for (var y = 0; y < 6; y += 1){
rand=round(random(360))
grid[x][y]=0
if (rand==0){
grid[x]=1
grid[y]=1
noLoop()
}
if (grid[x]==0 || grid[y]==0){
fill(76,153,0)
rect((x*100+10),(y*100+10),90,90)
}
if (grid[x]>0 && grid[y]>0){
fill(102,51,0)
rect((x*100+10),(y*100+10),90,90)
}
}
}
}
Instead of using noLoop(), you could keep looping at 60 frames per second, but then use the millis() function to keep track of the elapsed time.
Here's an example that shows a circle for 1 second whenever the user clicks:
var clickTime;
function mousePressed(){
clickTime = millis();
}
function draw() {
background(0);
if(millis() < clickTime + 1000){
ellipse(width/2, height/2, width/4, height/4);
}
}
Edit: Another approach is to use the % operator along with the frameCount variable in order to do something every X frames. This examples draws a circle in a random position every 60 frames:
function draw() {
if (frameCount % 60 == 0) {
background(0);
ellipse(random(width), random(height), width / 4, height / 4);
}
}

Resources