Scenes in Processing

Good afternoon, processing community, I would like to ask a question. How is it possible to implement “Scenes/Activities” on Processing?

Hello @OverLord

If I’m understanding your question correctly, the three threads below may be of interest:

:nerd_face:

1 Like

Thank you for the materials

1 Like

Your question is not very specific.

In the forum screens are often discussed as state (of a program)

here is another simple program

final int SPLASH    = 0;  // constants 
final int GAME      = 1; 
final int GAME_OVER = 2; 

int screen=SPLASH; 

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

void draw() {

  switch(screen) {

  case SPLASH: 
    background (0); 
    float x=width/2; // =mouseX; 
    float y=height/2; // =mouseY; 

    beginShape();
    vertex(x, y-80); // TOP
    vertex(x+40, y); // Right middle 
    vertex(x, y+80); // Bottom 
    vertex(x-40, y); // LEFT 
    endShape(CLOSE);

    text("Welcome to the game", 120, 120);

    break; 

  case GAME:
    background (0);
    text("Game", 120, 120); 
    break; 

  case GAME_OVER:
    background (0);
    text("You won", 220, 320); 
    break;

  default: 
    background (0);
    text("unknown screen number", 220, 320);
    break;
  }//switch
  //
}//func 

void keyPressed() {
  screen++;
}
//

After screen++; you need an if to check if screen is > 2. If so, reset to 1.

Since draw() runs 60 times per second and we use switch(), only the lines of the current screen are executed.

Chrisir

3 Likes

Write a Base class „Scene“ with a method void draw(). Have one instance gscene pointing onto the current scene. Derive specific scenes from that class. Every draw call in processing now delegates to gscene.draw(). That‘s it. Jens

1 Like

Can you please show this as an example as I did?

1 Like

Objects are deleted or simply hidden??

When you have this at start of draw() you just don’t draw the object anymore

When you have a ArrayList of Object Bullets, it’s better to remove() them (when they are finished, after collision or after leaving the screen), so that you don’t have so many dead objects in your ArrayList.

  • But you need to provide more context so we can understand your question.
1 Like

I made the same scene system as you showed, everything works fine, thank you. Do the objects disappear when switching to a new scene. Let’s say I have scene 1 and scene 2 at my mom, I have background and objects on both scenes (squares, circles, etc), if I change scene to 2, what happens to the objects on scene 1
Code:
final int START = 1; //scene
final int GAME = 2; //scene
final int GAME_OVER = 3; //scene
int scene = START; //sceneCurrent

void settings (){
fullScreen (OPENGL);
}

void setup () {
scene = 1;
}

void draw() {
background (0);
switch(scene) { //смена сцены

case START: //1 activity
background (200)
ellipse(random (0, width), random (0, height), 70,70);
rect(random (0, width), random (0, height), 70,70);
if(mousePressed){
scene = 2;
}
break; //end 1 atcivity

case GAME: //2 activity or scene 2
background (57,78,9);
break; //end 2 atcivity

case GAME_OVER: //3 activity

break; //end 3 activity

} // end switch
} //end draw

@Quertz can you please explain this to me?

Do you mean implement?

@Quertz
@quark

I worked further on this.

There is the classic approach I often used. With states and switches.

And the new approach using ONE class for each state. Using interface / implements.

  • This class contains a method showState, a method keyPressed and a method mousePressed. Therefore we just call it and don’t need switch. When we change the state, we just say currentState = new statePause(); for example.

I’d like to discuss which approach might be better.

What do you all think?

My thoughts:

  • It’s good to get rid of the switch (pro new approach)
  • we change the object inside the class (is this evil?) (in the new approach)
  • a variant of the new approach would be an array of the objects of each state and then use int state as index. Might be faster than currentState = new StateGame();

Thank you all!

Chrisir


// This is the classic approach

// Links:
// https://discourse.processing.org/t/beginner-new-pages/17774
// https://discourse.processing.org/t/scenes-in-processing/40386/5

//
// states
final int stateGame  = 0; // consts
final int statePause = 1;
int state = stateGame;    // current

// -------------------------------------------------

void setup() {
  // init (runs only once)
  size(800, 600);
} // func

void draw() {
  // runs on and on

  switch (state) {

  case stateGame:
    // Game
    handleStateGame();
    break;

  case statePause:
    // Pause
    handleStatePause();
    break;

  default:
    // error
    println("Error number 939; unknown state : "
      + state
      + ".");
    exit();
    break;
  } // switch
  //
} // func

// functions for states - called from draw()

void handleStateGame() {
  // Game
  background(11);
  fill(244, 3, 3); // red
  text ("This is the Game....\n Don't touch the red rectangle...", 210, 313);

  //
  noStroke();
  fill(255, 2, 2) ;
  rect(100, 100, 100, 100);
  fill(255, 2, 255) ;
  // rect(300, 100, 100, 100);

  if (mouseX > 100 &&
    mouseX < 100 + 100  &&
    mouseY > 100   &&
    mouseY < 100 + 100) {
    println ("collide");
    state = statePause;
  }
} // func

void handleStatePause() {
  // Pause
  background(255);
  fill(244, 3, 3); // red
  text ("You LOST....  "
    + "   ...   ", 210, 313);

  text ("Hit p to start Game", 210, 385);
} // func

// ----------------------------------------
// keyboard input

void keyPressed() {

  switch (state) {

  case stateGame:
    // Game
    keyPressedForStateGame();
    break;

  case statePause:
    // Pause
    keyPressedForStatePause();
    break;

  default:
    // error
    println("Error number 1039; unknown state : "
      + state
      + ".");
    exit();
    break;
  } // switch
} // func

// ----

void keyPressedForStateGame() {
  if (key == CODED)
  {
    if (keyCode == UP) {
      //
    } else if (keyCode == DOWN) {
      //
    }

    if (keyCode == LEFT) {
      //
    } else if (keyCode == RIGHT) {
      //
    } else {
      // do nothing
    } // else
  } //  if (key == CODED) {
  else
  {
    // not CODED ----------------------
    if (key == 'p') {
      // Pause
      state = statePause;
    } else {
      // do nothing
    } // else
  } // else not CODED
} // func

void keyPressedForStatePause() {
  if (key == CODED)
  {
    if (keyCode == UP) {
      //
    } else if (keyCode == DOWN) {
      // none
    }

    if (keyCode == LEFT) {
      //
    } else if (keyCode == RIGHT) {
      //
    } else {
      // do nothing
    } // else
  } //  if (key == CODED) {
  else
  {
    // not CODED ----------------------
    if (key == 'p') {
      //
      state = stateGame;
    } else {
      // do nothing
    } // else
  } // else not CODED
} // func

//----------------------------------------------------------------------

void mousePressed() {

  switch (state) {

  case stateGame:
    // Game
    println("mouse 1");
    break;

  case statePause:
    // Pause
    println("mouse 2");
    break;

  default:
    // error
    println("Error number 1046; unknown state : "
      + state
      + ".");
    exit();
    break;
  } // switch
} // func
// -------------------------------------------------------


New approach.




// This is the NEW approach

// Links:
// https://discourse.processing.org/t/beginner-new-pages/17774
// https://discourse.processing.org/t/scenes-in-processing/40386/5
// Interface example
// https://discourse.processing.org/t/classes-and-arraylist/9626/3

StateInterface currentState = new StateGame();

// -------------------------------------------------

void setup() {
  // init (runs only once)
  size(800, 600);
} // func

void draw() {
  // runs on and on
  currentState.showState();
}

// ----------------------------------------
// keyboard input

void keyPressed() {
  currentState.keyPressedState();
}

//----------------------------------------

void mousePressed() {
  currentState.mousePressedState();
}

// ===============================================================================================

class StateGame implements StateInterface {
  // Game
  void showState() {
    // Game
    background(11);
    fill(244, 3, 3); // red
    text ("This is the Game....\n Don't touch the red rectangle...", 210, 313);

    //
    noStroke();
    fill(255, 2, 2) ;
    rect(100, 100, 100, 100);
    fill(255, 2, 255) ;
    // rect(300, 100, 100, 100);

    if (mouseX > 100 &&
      mouseX < 100 + 100  &&
      mouseY > 100   &&
      mouseY < 100 + 100) {
      println ("collide");
      currentState = new statePause();
    }
  } // func

  void keyPressedState() {
    if (key == CODED)
    {
      if (keyCode == UP) {
        //
      } else if (keyCode == DOWN) {
        //
      }

      if (keyCode == LEFT) {
        //
      } else if (keyCode == RIGHT) {
        //
      } else {
        // do nothing
      } // else
    } //  if (key == CODED) {
    else
    {
      // not CODED ----------------------
      if (key == 'p') {
        // Pause
        currentState =  new statePause();
      } else {
        // do nothing
      } // else
    } // else not CODED
  } // func

  void mousePressedState() {
    // Game
    println("mouse 1");
  }//func
}//class

// ===========================================================================================

class statePause implements StateInterface {
  void showState() {
    // Pause
    background(255);
    fill(244, 3, 3); // red
    text ("You LOST....  "
      + "   ...   ", 210, 313);

    text ("Hit p to start Game", 210, 385);
  } // func

  void keyPressedState() {
    if (key == CODED)
    {
      if (keyCode == UP) {
        //
      } else if (keyCode == DOWN) {
        // none
      }

      if (keyCode == LEFT) {
        //
      } else if (keyCode == RIGHT) {
        //
      } else {
        // do nothing
      } // else
    } //  if (key == CODED) {
    else
    {
      // not CODED ----------------------
      if (key == 'p') {
        //
        currentState = new StateGame();
      } else {
        // do nothing
      } // else
    } // else not CODED
  } // func

  void mousePressedState() {
    // Pause
    println("mouse 2");
  }//func
}

// =====================================

interface StateInterface {

  // Let's abstract

  // Let's abstract display()
  void showState();
  void keyPressedState();
  void mousePressedState();
}
//

Thank you all.

Chrisir

2 Likes

@Chrisir The new approach is neat because it combines both rendering and user interaction in one class. Encapsulating this functionality into classes makes it easier to follow the program logic. Effectively you are creating and using a 'Finite State Machine` (FSM),

2 Likes

Thank you.

My thoughts:

  • It’s good to get rid of the switch (pro new approach)
  • we change the object inside the class (is this evil?) (in the new approach): currentState = new StateGame(); etc.
  • a variant of the new approach would be an array of the objects of each state and then use int state as index. Might be faster than currentState = new StateGame();. Would this be better?

What do you think about this?

1 Like

There is a lot of hype about the inefficiency of using new, in fact there is a lot of misconceptions related to Java efficiency in general.

It is true that using new is slower than other approaches but does it matter? Not really unless you are creating hundreds/thousands of new objects every frame or the operation is time critical (quite rare for most sketches). If it becomes a problem then one solution is to cache and reuse objects.

The biggest misconception in Java is using low level syntax ‘fixes’ to reduce the number of lines of code or the number of statements will make a significant difference. Again in most cases this makes little difference because the JVM optimises at runtime those parts of the code most heavily executed which is why you have to be careful timing functions because you can sometimes see a noticeable speed up after a few seconds. Of course you still have to write good code, you shouldn’t rely on the optimiser.

Personally when evaluating source code, including my own I aim for

  1. Algorithms that are appropriate for the tasks to be performed
  2. Correct selection of data structures
  3. Tight intergration between the data and the code using it (OO and avoiding global variables helps)

and perhaps most importantly (for me)

  1. Clear and unambiguous semantics so that I and others can clearly understand what the code is doing.

This last part is very important if the software is to have a long shelf life e.g. Processing, third party libraries etc.

So after a long preamble (sorry about that) the answer is that in this situation creating new states is not a problem in this scenario (FSM)

4 Likes

You could also use PGraphics, if you dont want to render always.
Example:

PGraphics scene1, scene2;
int scene = 1;

void setup() {
size(960,540,P2D);
scene1 = createGraphics(width,height,P2D);
scene2 = createGraphics(width,height,P2D);
}

void draw() {
if(scene == 1) {
image(scene1,0,0);
scene1update();
}
if(scene == 2) {
image(scene2,0,0);
scene2update();
}
}

void scene1update() {
scene1.beginDraw();
scene1.fill(#00FF00);
scene1.rect(10,10,100,100);
scene1.endDraw();
}

void scene2update() {
scene2.beginDraw();
scene2.fill(#FF00FF);
scene2.rect(10,10,100,100);
scene2.endDraw();
}

btw u could also change when the scenes are updating, and you need something like “if mousePressed() scene = 1;”

1 Like