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:
Thank you for the materials
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
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
Can you please show this as an example as I did?
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.
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?
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
@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),
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?
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
- Algorithms that are appropriate for the tasks to be performed
- Correct selection of data structures
- Tight intergration between the data and the code using it (OO and avoiding global variables helps)
and perhaps most importantly (for me)
- 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)
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;”