Having trouble with a code and its structure

Hi everyone, I’ve been struggling with my art project due to my lack of experience and knowledge of Processing. My problem concerns coding, which then lead to a project guidance problem. I will try my best to explain clearly my project, the problems I am facing and the results I have so far. Here is the link to a drive where I added visual explanations, along with all the data files if necessary :

The project
The idea, is to show a randomly selected portrait, then out of three possible events (Call or Email or Kill) randomly select one of them and show its text, finally show a new randomly selected portrait, and repeat. An example is illustrated in the drive (fig.1). One of the possible event being “Kill”, the program should run until everyone dies.

The rules that I am trying to apply are :

  • The “CALLS” event CAN link to person that appeared before the “CALLS” image (a person can call herself)
  • The “CALLS” event CAN link the same duo of persons multiple times
  • The two rules above also applies to the “EMAILS” event
  • The “KILLS” event CAN link to person that appeared before the “KILLS” image (a person can kill herself)
  • Once a person appears AFTER the “KILLS” event, the person CANNOT appear ever again to the screen (if a person is killed, it must disappear from the randomly selected persons)

For the moment I’ve decided to work on different sketches for the different parts of the code, it’s easier to me.

This is the sketch that shows a random image picked from a library of 155 portraits. The code works.

PImage portrait;
int rand;

void setup() {
size(640, 640);
rand = int(random(1, 155));
takerandomimage(“portrait” + nf(rand, 3) + “.jpg”);
}

void takerandomimage(String fn) {
portrait = loadImage(fn);
image(portrait, 0, 0);
}

This is the sketch that treats the “event” part. Based on a random number, one out of the three events is chosen. The first one represents the action of calling, the second one represents the action of sending a mail, the last one represents the action of killing. The code works, appart from the sound, I don’t hear anything.

import processing.sound.*;
SoundFile Son;
int rand;
int event;

void setup() {
size(640, 640);
event = int (random (1, 4));

if (event == 1) {
PImage telephone;
telephone = loadImage(“Calls.jpg”);
image (telephone, 0, 0);
Son = new SoundFile(this, “Son_calls.mp3”);
Son.play();
} else if (event == 2) {
PImage mail;
mail = loadImage(“Emails.jpg”);
image (mail, 0, 0);
Son = new SoundFile(this, “Son_emails.mp3”);
Son.play();
} else if (event == 3) {
PImage arme;
arme = loadImage(“Kills.jpg”);
image (arme, 0, 0);
Son = new SoundFile(this, “Son_kills.mp3”);
Son.play();
}
}

With this two codes working, I am trying to put them together, but the main problem that I am facing is: how can I prevent the dead persons from showing up again ?

I found this sketch that generates random numbers without repetitions.

void setup() {
size(640, 640);
final int NUM = 155;
final IntList nums = new IntList(NUM);
for (int i = 0; i != NUM; nums.append(++i));
nums.shuffle();
println(nums);
final int[] arr = nums.array();
println();
println(arr);
exit();
}

I was thinking that I could implement the variable [0] inside the loadImage “name”+".jpg", followed by a command to add 1 to his value. This way I would have list of random numbers that won’t repeat, from which I could pick from [0] to [154].
The structure would be like shown in (fig.2).
The problem is that a dead person could appear when going through the first random portait selection node (the top one). i.e. after going through a “CALLS” or “EMAILS” event.

A solution could be to communicate a “blacklist” of the dead persons to the first random portrait selection node, but I don’t even know if it’s possible to do so. I think I am thinking about the structure in a wrong way, but my lack of knowledge doesn’t allow me to find an alternative. I have tried to find sketches that could help me but I can’t find the appropriate command that would suit my project.

I am aware that this a lot to ask for, and that my request is quite complex, but honestly anything would help. Thank you and have a nice day :slight_smile:

Hi @Spomch
Why is all your code in setup() that executes only once at startup?
If it’s only to work once you need to keep track of the number list by saving it and removing the ‘killed’ from the list every time your app runs.

1 Like

Hi @noel
Thanks for the reply !
I see, well first of all, I don’t know what void type I should put before the code if it’s not in setup().

Correct me if I’m wrong but from what I understand from your reply, you suggested to:

  • Run the code
  • Remove the ‘killed’ portrait from the list of portraits
  • Run the code again
  • And so on …
    If this is what you meant, I think that I haven’t explained correctly the idea that I have in mind. The goal would be to run the code once, and let it run in a loop until everyone is killed. I assume that this would imply to have the ‘killed’ removed from the list whilst the code is still running. Unfortunately I have no idea on how to do so.

This you can do in void draw() {}
wich is a loop that keeps your program running.
Just exit() the program when all are “killed” (not literally I hope :hot_face:).

1 Like

Great, thank you !
I came across void draw() a lot when I did my research, but I couldn’t remember its purpose.
I will try to work around that and see what I end up with.
Haha no worries this is pure fiction, the only ones killed are the pixels :wink:

Hello,

Checkout out the references, tutorials and examples here:

For example:

:)

Perfect, will do !
Thank you !

Alright, I’ve made some adjustments and ended up with this :

import processing.sound.*;
SoundFile Son;
int rand;
int event;

void setup() {
size(640, 640);
}

void draw(){
event = int (random (1, 4));
if (event == 1) {
PImage telephone;
telephone = loadImage(“Calls.jpg”);
image (telephone, 0, 0);
Son = new SoundFile(this, “Son_calls.mp3”);
Son.play();
delay(500);
Son.stop();
delay(500);
} else if (event == 2) {
PImage mail;
mail = loadImage(“Emails.jpg”);
image (mail, 0, 0);
Son = new SoundFile(this, “Son_emails.mp3”);
Son.play();
delay(500);
Son.stop();
delay(500);
} else if (event == 3) {
PImage arme;
arme = loadImage(“Kills.jpg”);
image (arme, 0, 0);
Son = new SoundFile(this, “Son_kills.mp3”);
Son.play();
delay(500);
Son.stop();
delay(500);
}
}

The events follow one another nicely, but I have a problem with the sound, it can hear it now, but it seems like sound de-syncs from its respective event image. The sounds should be played simultaneously to the appearance of the text, but here I have a slight latency.
I would guess that it has to do with my delay() system. I decided to put a delay() between the play() and the stop() to avoid sound glitches where the sound repeats and gets distorted.

Now, putting the sound aspect aside, I tried to implement the random portrait selection sketch inside the sketch I built, but I can’t put void takerandomimage(String fn){} inside void draw(){}
All I can do is to put it before, but I would want it to be inside the void draw(){}

import processing.sound.*;
SoundFile Son;
PImage portrait;
int rand;
int event;

void setup() {
size(640, 640);
rand = int(random(1, 155));
takerandomimage(“portrait” + nf(rand, 3) + “.jpg”);
}

void takerandomimage(String fn) {
portrait = loadImage(fn);
image(portrait, 0, 0);
}

void draw(){
event = int (random (1, 4));
if (event == 1) {
PImage telephone;
telephone = loadImage(“Calls.jpg”);
image (telephone, 0, 0);
//Son = new SoundFile(this, “Son_calls.mp3”);
//Son.play();
//delay(500);
//Son.stop();
delay(500);
} else if (event == 2) {
PImage mail;
mail = loadImage(“Emails.jpg”);
image (mail, 0, 0);
//Son = new SoundFile(this, “Son_emails.mp3”);
//Son.play();
//delay(500);
//Son.stop();
delay(500);
} else if (event == 3) {
PImage arme;
arme = loadImage(“Kills.jpg”);
image (arme, 0, 0);
//Son = new SoundFile(this, “Son_kills.mp3”);
//Son.play();
//delay(500);
//Son.stop();
delay(500);
}
}

So I’m pretty much stuck at this point. Does anyone know how this could be done ?

1 Like

Don’t use delay please.
Instead check the song‘s isPlaying property whether it has ended or make a timer.

That doesn’t make sense. You don’t want to put your function inside another function; instead you put it after the draw function and call it from draw(). Like takerandomimage();

Update, this is what I used to replace delay(), I read a little about it and now I understand why it wasn’t suited for my needs. I think that this millis() technique could work.
(I’m posting only a reduced version of the sketch for a better clarity)

import processing.sound.*;
SoundFile Son;
PImage portrait;
int rand;
int event;
int savedTimeSon;
int savedTimeImage;
int soundTime = 500;
int imageTime = 500;

void setup() {
size(640, 640);
rand = int(random(1, 155));
takerandomimage(“portrait” + nf(rand, 3) + “.jpg”);
}

void takerandomimage(String fn) {
portrait = loadImage(fn);
image(portrait, 0, 0);
}

void draw() {
PImage telephone;
telephone = loadImage(“Calls.jpg”);
image (telephone, 0, 0);
savedTimeImage = millis();
Son = new SoundFile(this, “Son_calls.mp3”);
savedTimeSon = millis();
Son.play();
int passedSonTime = millis() - savedTimeSon;
if (passedSonTime > soundTime) {
Son.stop();
savedTimeSon = millis();
}
int passedImageTime = millis() - savedTimeImage;
if (passedImageTime > imageTime) {
takerandomimage();
portrait = loadImage(fn);
image(portrait, 0, 0);
savedTimeImage = millis();
}
}

But as you will be able to tell, I didn’t really understand how to implement takerandomimage();
The console indicates :

The function “takerandomimage()” expects parameters like: “takerandomimage(String)”
and
The variable “fn” does not exist

Obviously I’m not using it right but I don’t understand the mechanism of takerandomimage();
I’m sorry to ask so much questions, I’m really struggling with Processing…

You call it correctly from setup and incorrectly from draw. Please correct it and in draw do it the same way as you do in setup: takerandomimage(“portrait” + nf(rand, 3) + “.jpg”);

Remark

This:

PImage telephone;
telephone = loadImage(“Calls.jpg”);

please don’t use loadImage() in draw because you would load 60 times per second which is time consuming.

Instead

  • load in setup telephone = loadImage(“Calls.jpg”); and
  • have this before setup: PImage telephone;

What to do

We all struggle with the logic in these cases.
The timers help us.
But at the moment the structure of your draw is not clear.

You described your goal:

The idea, is to show a randomly selected portrait, then out of three possible events (Call or Email or Kill) randomly select one of them and show its text, finally show a new randomly selected portrait, and repeat. An example is illustrated in the drive (fig.1). One of the possible event being “Kill”, the program should run until everyone dies.

Do you mean the entire process runs automatically?

Then you have random events that decide what happens, CALL Email, KILL?

And do you want to have an animation where for example the image of the face and the text KILL appears?

My idea

To make the structure of your draw() clearer:

I think you should work with states.

before setup say int state=0;

state indicates which state or phase the program is in. E.g. play a sound or show an image

so in draw() say :

if (state ==0) {
...
}
else if (state == 1) {
...
}

else if (state == 2) {
...
}

nothing outside this long if... else if... else if.... is allowed in draw().

for example selecting a new image and a new action like Kill/Email/call should be a state. After it say state++;

I think, to detect whether the song / sound is over, you can say say if( ! Son.isPlaying()) state ++;

When process is over, say state=0; so we start selecting/showing the next image

I hope this helps.

Warm regards,

Chrisir

Wow, thank you so much for taking the time to help me out, this helps a ton !!!
I’ll take the time to read carefully and understand properly what you explained here so that I can go further.
To answer the questions that you have asked :

Do you mean the entire process runs automatically?

  • Yes the idea would be to launch the program and let it run until everyone “dies”. That implies having multiple persons engaging multiple “events” in a row.

Then you have random events that decide what happens, CALL Email, KILL?

  • Yes, an event is randomly selected out of those three possibilities.

And do you want to have an animation where for example the image of the face and the text KILL appears?

And when I will have a sketch that works and displays what I described, I will try to implement the part where I remove the portraits of the persons that followed a “KILL” event. But I’m far from that I believe haha.

Again, thank you very much !

1 Like

Here is the new code with the new structure

import processing.sound.*;
SoundFile Son;
PImage portrait;
PImage telephone;
PImage mail;
PImage arme;
int rand;
int savedTimeSon;
int savedTimeImage;
int soundTime = 500;
int imageTime = 500;
int state = 0;

void setup() {
size(640, 640);
telephone = loadImage(“Calls.jpg”);
mail = loadImage(“Emails.jpg”);
arme = loadImage(“Kills.jpg”);
rand = int(random(1, 155));
}

void draw() {

if (state == 0) {
takerandomimage(“portrait” + nf(rand, 3) + “.jpg”);
state = int (random (1, 4));
state ++;
}

else if (state == 1) {
image (telephone, 0, 0);
Son = new SoundFile(this, “Son_calls.mp3”);
Son.play();
if (!Son.isPlaying()){
state ++;
}
state = 0;
}

else if (state == 2) {
image (mail, 0, 0);
Son = new SoundFile(this, “Son_emails.mp3”);
Son.play();
if (!Son.isPlaying()){
state ++;
}
state = 0;
}

else if (state == 3) {
image (arme, 0, 0);
Son = new SoundFile(this, “Son_kills.mp3”);
Son.play();
if (!Son.isPlaying()){
state ++;
}
state = 0;
}
}

void takerandomimage(String fn) {
portrait = loadImage(fn);
image(portrait, 0, 0);
}

Here are the issues that I’m having :

  • The portrait appears, then the event image appears, but the images glitch, going back and forth

  • Sometimes only a portrait appears

  • The program only runs once
    I thought that, by adding “state=0” at the end of (state==1), (state==2) and (state==3), it would redirect the commands to (state==0), thus beginning a new cycle.

  • The images are going way too fast, I need to find a way to add a constant frame rate (like 0.5 seconds for each image)

You are doing it wrong.

Remember to hit ctrl-t in processing to get auto-format for indents

Remember that draw runs 60 times per second. So when state is 1 this code section is run 60 times per second for several seconds. So the image is displayed a few seconds. Good. No need to slow things down! And don’t reset to state=0!!! Wrong approach. Leave the state as it is.

When your timer is up or the song ended playing then increase the state by 1

Only when the process of image and song and action actually has ended restart with state=0.

Here you say Son.play(); again and again while state == 3

instead

else if (state == 3) {
    image (arme, 0, 0);
    Son = new SoundFile(this, “Son_kills.mp3”);
    Son.play();
    state=4;
}

else if  (state == 4) {
    // wait for song to end ! 
    image (arme, 0, 0);
    if (!Son.isPlaying()){
        state = 5;
    }
}

Remark

This

    state = int (random (1, 4));
    state ++;

No state++ here in my opinion

Example

Here is an example of a timer within a if state clause


int state=0; 
int timer; 

void setup() {
  size(640, 640);

  timer = millis();
  background(0);
}

void draw() {
  background(0); 
  if (state == 0) {
    text("state is 0", 111, 111);
    if (millis()- timer > 3000) {
      state = 1;
    }
  } else if (state == 1) {
    text("state is 1", 111, 111);
  }
}

Thank you for your reply, I’m trying to understand what you’ve explained.
I will keep in mind to auto-format next time I post, sorry for that.

When you say :

Does “state=4” means that the next step the program will be executing is (state == 4) ?

must be state=4; with a semi, I corrected it

but yeah, the next step the program will be executing is (state == 4).

(I mean, first, it will go to the end of draw, then restart draw and THEN execute our (state == 4) code section. It doesn’t go to the state==4 section immediately, because it is in a long if…else if… clause it has to finish first.)

I see but this is causing a problem.
The next step after each of the three possible “events” should be to come back to (state==0).
Here is a simplified example :

(state==0) then (state==2) then (state==0) then (state==3) then (state==0) …

That is why I previously implemented state=0; at the end of (state==1), (state==2) and (state==3).
But it doesn’t seem to work.

the different states are NOT there to distinguish between the 3 different actions

Rather, they are there to help you organize the timer, how long you play the song or show the image.

to distinguish between the 3 different actions


if (state == 0) {
    takerandomimage(“portrait” + nf(rand, 3) + “.jpg”);
    action = int (random (1, 4));
    if(action==1) {
        image (telephone, 0, 0);
        Son = new SoundFile(this, “Son_calls.mp3”);
        Son.play();
    } else if(action==2) {
        image (mail, 0, 0);
        Son = new SoundFile(this, “Son_emails.mp3”);
        Son.play();
    }
    state ++;
}