Hold noLoop() for certain amount of time - p5.js

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);
}
}

Related

How to control how many times something is shown in Processing?

void setup() {
background(0);
fullScreen();
}
void draw() {
int g = 0;
float cCount = map(mouseY, 0, height, 1, 20);
for (int i = 0; i < width; i+=50) {
while(g < cCount) {
circle(i, mouseY, 20);
}
}
}
So what I'm trying to do is change the number of times circles are shown on the screen as I move the mouse. When the mouse moves down, more circles are shown on the screen all with the same Y coordinate but the distance between each circle is 50. As I move the mouse up, less circles are shown. Max circles is 20 and min is 1. I don't know how to set up a way for the number of circles to change as I move the mouse?
I think your approach is correct, but your code has some bugs that are not related to the problem itself.
In your while (g < cCount) loop, neither g nor cCount is updated, resulting in an infinite loop, but you don't really need that while loop anyway.
The following should work (but I haven't checked running the code myself, so it might have some bugs.
void draw() {
int circleCount = round(map(mouseY, 0, height, 1, 20));
for (int i = 0; i < circleCount; i+=1) {
circle(i*50, mouseY, 20);
}
}

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 interpolate between two consecutive points with a smooth curve in p5.js

I intend to have an ellipse move smoothly between the stop points while keep rotating. It'll rotate for 1sec at point (20,50), transition to (40,70) on a smooth curve (bezier or random polynomial) and rotate till 3sec and move on to (160,190)
The current issue is that it jumps between stop points rather than move smoothly.
var angle=0;
var x=[20,40,160] // x coordinates for stop points
var y=[50,70,190] // y coordinates for stop points
var t=[1000,2000,4000] // time for stop points
var i=0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
frameRate(30);
translate(x[i],y[i]);
rotate(angle);
if (millis() >= t[i] & millis() < t[i+1]){
i+=1
}
fill(0);
ellipse(0,0, 20, 80);
angle++
}
There are a lot of different ways to do this, and which approach you take depends on exactly how you want your code to behave.
Similar to the answer to your last question, you need to show the movement between the points.
Right now you're moving directly from one point to another. You need to show the intermediate steps.
Here are a few things to look into:
The frameCount variable holds the current frame number. This is useful for exact timing of behaviors that you want to trigger on specific frames.
The millis() function returns the number of milliseconds the sketch has been running. This is useful for duration-based logic, where you want to do something after a certain number of seconds.
The lerp() function allows you to calculate values that change over time.
You could also use delta values, where you move the X and Y values by some amount each frame.
Here's an example of that last approach:
var circleX = 20;
var circleY = 20;
var mode = 'move right';
function setup() {
createCanvas(400, 400);
}
function draw() {
background(200);
ellipse(circleX, circleY, 20, 20);
if (mode == 'move right') {
circleX++;
if (dist(circleX, circleY, 380, 20) < 1) {
mode = 'move down';
}
} else if (mode == 'move down') {
circleY++;
if (dist(circleX, circleY, 380, 380) < 1) {
mode = 'move left';
}
} else if (mode == 'move left') {
circleX--;
if (dist(circleX, circleY, 20, 380) < 1) {
mode = 'move up';
}
} else if (mode == 'move up') {
circleY--;
if (dist(circleX, circleY, 20, 20) < 1) {
mode = 'move right';
}
}
}
But please note that this code is just an example, and there's a ton of room for improvement here. The important thing is that you need to move the scene a little bit each frame, instead of going directly from one point to another.

Processing: Increment a counter when midpoint of ellipses are passed

I've got some code that displays 10 ellipses in random locations on the screen, and a square that descends from the top of the screen to the bottom, at which point it resets back at the top. What I'm trying to do is get a counter to increment when that square passes any of the ellipses (by comparing their y-positions). However, the counter increases rapidly instead of steadily and just doesn't behave desirably in general.
Here's my draw() function. barriers[i][0] stores the x-pos, barriers[i][1] the y-pos obviously.
void draw()
{
background(255);
fill(0);
for(int i = 0; i < barriers.length; i++) {
// Draw barriers
ellipse(barriers[i][0], barriers[i][1], 50, 50);
// Did we pass a barrier? (doesn't work!)
if(y >= barriers[i][0] - 1 && y <= barriers[i][1] + 1) {
counter++;
}
}
// Draw the square
rect(x, y, 25, 25);
// Draw counter alongside square
fill(255, 0, 0);
text(counter, x + 25, y - 5);
// Reset
if(y < height) {
y+=5;
} else {
y = -25;
counter = 0;
}
}
Apologies if the solution is blindingly obvious, but I'm just not seeing the problem here...
Looking forward to some assistance.
Look at this section of code:
if(y >= barriers[i][0] - 1 && y <= barriers[i][1] + 1) {
counter++;
}
The draw() function fires 60 times a second, so this code will be fired 60 times per second. That means that while you're passing a barrier, the counter variable will increment 60 times per second!
Presumably you only want the counter to increase once for each barrier. There are a number of ways to do this. You could have another data structure that keeps track of whether each barrier has already been passed, and then only check barriers that haven't been passed yet. Or you could keep track of the previous positions of the square, and then use that to determine when the square starts passing a barrier.
Think about how you would do this in your head, without a computer. How do you know when the square is passing a circle? How do you, in your head, only count one for each barrier?
Following Kevin's advice, I was able to get it working using an array of booleans which I used to ensure I wasn't incrementing counter more than once:
Full code:
float barriers[][] = new float[10][2];
float x = 400;
float y = -25;
int counter = 0;
boolean barriersChecked[] = {false, false, false, false, false, false, false, false, false, false};
void setup()
{
size(800, 600);
genBarriers();
}
void genBarriers()
{
for (int i = 0; i < barriers.length; i++) {
barriers[i][0] = random(width);
barriers[i][1] = random(height);
}
}
void draw()
{
background(255);
fill(0);
for (int i = 0; i < barriers.length; i++) {
// Draw barriers
ellipse(barriers[i][0], barriers[i][1], 50, 50);
// Did we pass a barrier?
if (barriers[i][1] < y && !barriersChecked[i]) {
counter++;
barriersChecked[i] = true;
}
}
// Draw the square
rect(x, y, 25, 25);
// Draw counter alongside square
fill(255, 0, 0);
text(counter, x + 25, y - 5);
// Reset
if (y < height) {
y+=2;
} else {
y = -25;
genBarriers();
// Reset barriersChecked
for(int i = 0; i < barriersChecked.length; i++) {
barriersChecked[i] = false;
}
}
}
Out of curiosity, is there a more elegant (loopless) way of resetting every element in barriersChecked back to false?
Suggestions of additional improvements would also be greatly appreciated.

Resources