Im trying to make each square in my grid randomly rotated, so each one has a diffrent angle, but instead i rotate all of my squares. I dont understandt why, as both the rotate and the rect is drawn once at a time inside of the for loop?
int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
float rando = (random(55));
void setup() {
size(900, 900);
noStroke();
fill(40);
rectMode(CENTER);
}
void draw() {
background(255);
for (int x=marginX; x<width; x+=xStep) {
for (int y=marginY; y<height; y+=yStep) {
pushMatrix();
rotate(radians(rando));
rect(x, y, rectSize, rectSize, 10);
popMatrix();
}
}
}
You're on the right track using pushMatrix()
/popMatrix()
to isolate coordinates for each square.
The gotcha is with rect()
as it "hides" a translation.
This lines:
rotate(radians(rando));
rect(x, y, rectSize, rectSize, 10);
roughly works as:
rotate(radians(rando));
translate(x, y);
rect(0, 0, rectSize, rectSize, 10);
and (as you can see in the 2D Transformations tutorials) the order of operations is important.
In your case, you want to translate first, then rotate (from that translated position):
translate(x, y);
rotate(radians(rando));
rect(0, 0, rectSize, rectSize, 10);
In conclusion, your code would look like this:
int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
float rando = (random(55));
void setup() {
size(900, 900);
noStroke();
fill(40);
rectMode(CENTER);
}
void draw() {
background(255);
for (int x=marginX; x<width; x+=xStep) {
for (int y=marginY; y<height; y+=yStep) {
pushMatrix();
translate(x, y);
rotate(radians(rando));
rect(0, 0, rectSize, rectSize, 10);
popMatrix();
}
}
}
Update If you want to rotate each square with a different random value you need to calculate one for each square.
You could so something like this:
int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
float rando = (random(55));
void setup() {
size(900, 900);
noStroke();
fill(40);
rectMode(CENTER);
}
void draw() {
background(255);
for (int x=marginX; x<width; x+=xStep) {
for (int y=marginY; y<height; y+=yStep) {
rando = random(55);
pushMatrix();
translate(x, y);
rotate(radians(rando));
rect(0, 0, rectSize, rectSize, 10);
popMatrix();
}
}
}
Pretty easy, right ? Re-calculate the value! There's a catch here too :) If you do this, random is re-calculated not just once per square, but also per frame so you'll end up with very jittery squares.
That is you need to re-draw the same squares again and again (even though the content doesn't change). If you simply want a static image, you can skip draw()
and just use setup()
:
int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
void setup() {
size(900, 900);
noStroke();
fill(40);
rectMode(CENTER);
background(255);
for (int x=marginX; x<width; x+=xStep) {
for (int y=marginY; y<height; y+=yStep) {
pushMatrix();
translate(x, y);
rotate(radians(random(55)));
rect(0, 0, rectSize, rectSize, 10);
popMatrix();
}
}
}
Even "immediate mode", with no setup()
will result in the same image:
int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
size(900, 900);
noStroke();
fill(40);
rectMode(CENTER);
background(255);
for (int x=marginX; x<width; x+=xStep) {
for (int y=marginY; y<height; y+=yStep) {
pushMatrix();
translate(x, y);
rotate(radians(random(55)));
rect(0, 0, rectSize, rectSize, 10);
popMatrix();
}
}
Let's assume you do want draw()
because you might want to use a keyboard shortcut or a mouse click to re-randomise values.
To get around the limitation you'd need to calculate the random values for each square once, then simply retrieve these values when rendering.
That means you'd need a structure to store each random value per square to which you write values once in setup()
and read repeatedly in draw()
: an array can easily solve you problem.
Since you're using nested for loops you could use a 2D array. Just remember that x,y
counter in your loop are absolute pixel coordinates and you'd need separate indices for array access. That's easy enough to: simply divide x,y
by the pixel increment and it will the 'step' counter:
int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
// store random values for each square
float[][]randos;
void setup() {
size(900, 900);
// initialise random array
randos = new float[width / xStep][height / yStep];
for (int x=marginX; x<width; x+=xStep) {
for (int y=marginY; y<height; y+=yStep) {
// calculate array indices
int xIndex = x / xStep;
int yIndex = y / yStep;
// write random values
randos[yIndex][xIndex] = random(55);
}
}
noStroke();
fill(40);
rectMode(CENTER);
}
void draw() {
background(255);
for (int x=marginX; x<width; x+=xStep) {
for (int y=marginY; y<height; y+=yStep) {
// calculate array indices
int xIndex = x / xStep;
int yIndex = y / yStep;
pushMatrix();
translate(x, y);
// read random values
rotate(radians(randos[xIndex][yIndex]));
rect(0, 0, rectSize, rectSize, 10);
popMatrix();
}
}
}
The array can also be 1D, just need to count differently:
int xStep = 110;
int yStep = 110;
int rectSize = 100;
int marginX = 65;
int marginY = 65;
// store random values for each square
float[] randos;
void setup() {
size(900, 900);
// initialise random array
int numSquares = (width / xStep) * (height / yStep);
randos = new float[numSquares];
int index = 0;
for (int x=marginX; x<width; x+=xStep) {
for (int y=marginY; y<height; y+=yStep) {
randos[index++] = random(55);
}
}
noStroke();
fill(40);
rectMode(CENTER);
}
void draw() {
background(255);
int index = 0;
for (int x=marginX; x<width; x+=xStep) {
for (int y=marginY; y<height; y+=yStep) {
pushMatrix();
translate(x, y);
rotate(radians(randos[index++]));
rect(0, 0, rectSize, rectSize, 10);
popMatrix();
}
}
}
(As a next step you can encapsulate the part in setup which initialises the array with random values into a function: this would allow you reset/recalculate new random values whenever you call this function again (e.g. on mouse click/key press/etc.)