Enyak Stew
Enyak Stew

Reputation: 176

Random() happening only once

I have this for() loop where I am randomizing the selection of slices of a picture, to display 16 slices of an image in a random order.

I'm picking those slices from an array and I have a variable that picks up what slice is going to be selected in the array.

The problem being that I'd think that the random function would be triggered for every frame, but it's triggered only once.

Here's the code :

void setup() {

    size(720,720);

    slices = new PImage[16];

        slices[0] = loadImage("1.png");
        slices[1] = loadImage("2.png");
        slices[2] = loadImage("3.png");
        slices[3] = loadImage("4.png");
        slices[4] = loadImage("5.png");
        slices[5] = loadImage("6.png");
        slices[6] = loadImage("7.png");
        slices[7] = loadImage("8.png");
        slices[8] = loadImage("9.png");
        slices[9] = loadImage("10.png");
        slices[10] = loadImage("11.png");
        slices[11] = loadImage("12.png");
        slices[12] = loadImage("13.png");
        slices[13] = loadImage("14.png");
        slices[14] = loadImage("15.png");
        slices[15] = loadImage("16.png");
        
        frameRate(1);


    
}

void draw() {

        

        for (int a = 0; a < 16; a++){

        int rand = int(random(slices.length));
        
        image(slices[rand],x,y,size,size);
         x += size;

         if (a % 4 == 3){
            y += size;
            x = 0;
            }
            
        }

It's dispalying the randomized slices only once and then I end up with a fix image. What I'd like to have is random slices appearing at every frame.

Thanks for your help !

Upvotes: 0

Views: 871

Answers (2)

George Profenza
George Profenza

Reputation: 51867

Could it be because you've forgot to clear the screen (e.g. calling background()) (meaning once you've drawn an image it will stay rendered) ?

You could also make use of the for loop in setup to avoid repeating yourself:

int numSlices = 16;
PImage[] slices = new PImage[numSlices];
float x, y;
float size = 180;

void setup() {

  size(720, 720);

  
  for(int i = 0 ; i < numSlices; i++){
    slices[i] = loadImage((i+1) + ".png");
  }
  
  frameRate(1);
}

void draw() {
  background(255);
  
  for (int a = 0; a < numSlices; a++) {

    int rand = int(random(numSlices));

    image(slices[rand], x, y, size, size);
    x += size;

    if (a % 4 == 3) {
      y += size;
      x = 0;
    }
  }
  y = 0;
}

Additionally you could easily format your code (via CMD+T on OSX or Ctrl+T on Windows/Linux)

Update Kamakura (+1) correctly pointing out y not being reset to 0.

As a distraction I though't point you to IntList's shuffle() method:

int numSlices = 16;
PImage[] slices = new PImage[numSlices];
float x, y;
float size = 180;

IntList indices = new IntList();

void setup() {

  size(720, 720);


  for(int i = 0 ; i < numSlices; i++){
    slices[i] = loadImage((i+1) + ".png");
    indices.append(i);
  }

  frameRate(1);
}

void draw() {
  background(255);
  // shuffle list
  indices.shuffle();
  // reset y
  y = 0;
  
  for (int a = 0; a < numSlices; a++) {

    int rand = indices.get(a);

    image(slices[rand], x, y, size, size);
    x += size;

    if (a % 4 == 3) {
      y += size;
      x = 0;
    }
  }
  
}

Extra reason to play with it, other than a learning experience is that fact that it will be unlikely to get the same random index repeated.

Regarding splicing/shuffling, here's a modified version of the Load and Display example:

/**
 * Load and Display 
 * 
 * Images can be loaded and displayed to the screen at their actual size
 * or any other size. 
 */

PImage img;  // Declare variable "a" of type PImage
// shuffled image
PImage imgShuffled;
// list of indices to shuffle
IntList shuffleIndices = new IntList();
// configure image slicing rows/columns
int rows = 4;
int cols = 4;
// total sections
int numSections = rows * cols;
// image section dimensions
int sectionWidth;
int sectionHeight;

void setup() {
  size(640, 360);
  frameRate(1);
  // The image file must be in the data folder of the current sketch 
  // to load successfully
  img = loadImage("https://processing.org/examples/moonwalk.jpg");  // Load the image into the program
  // calculate section dimensions
  sectionWidth  = img.width / cols;
  sectionHeight = img.height / rows;
  // allocate a separate image to copy shuffled pixels into
  imgShuffled = createImage(img.width, img.height, RGB);
  // populate image section indices
  for(int i = 0 ; i < numSections; i++){
    shuffleIndices.append(i);
  }
}

void shuffleImage(){
  // shuffle the list
  shuffleIndices.shuffle();
  // Ta-da!
  println(shuffleIndices);
  // loop through each section
  for(int i = 0 ; i < numSections; i++){
    // index to row, col conversion
    int srcCol = i % cols;
    int srcRow = i / cols;
    // convert to pixel coordinates to copy from
    int srcX = srcCol * sectionWidth;
    int srcY = srcRow * sectionHeight;
    // get random / shuffled index
    int index = shuffleIndices.get(i);
    // same row, col, to pixel conversion to copy to
    int dstCol = index % cols;
    int dstRow = index / cols;
    int dstX = dstCol * sectionWidth;
    int dstY = dstRow * sectionHeight;
    // copy from original image to shuffled pixel coordinates
    imgShuffled.copy(img,srcX,srcY,sectionWidth,sectionHeight,dstX,dstY,sectionWidth,sectionHeight);
  }
}

void draw() {
  shuffleImage();
  // Displays the image at its actual size at point (0,0)
  image(imgShuffled, 0, 0);
}

Moonwalk image shuffled as a 4x4 grid

Upvotes: 1

Dietrich
Dietrich

Reputation: 681

You have 2 problems in your code. First, you may not want to choose a random index.

This is because the same image could be chosen twice. Instead, you could shuffle the array before drawing the images, like this:

for (int i = slices.length; i > 1; i--) {
  //choose a random index for the i-th element to be swapped with
  int j = (int)random(i);

  //swap them
  PImage temp = slices[j];
  slices[j] = slices[i-1];
  slices[i-1] = temp;
}

Second, the index is chosen on every frame, and the images are drawn, too, but you can't see it, because your code never resets y back to 0, meaning that they are below the screen.

You can fix this by adding

y = 0;

to the top or bottom of your draw().

Upvotes: 1

Related Questions