Scene management

Now that we know how to make sweet animated scenes, let's make sure we can handle the other sort of non-static scene: scenes that respond to user interaction. For example, we want to draw a scene where Winston has babies (after his rock star phase, of course) -- but we also want to let the user click to give Winston MORE babies. Because we can always use more little Winstonitos in the world, right?

Here's what that scene would look like as a standalone program. The program draws the static part of the scene, and then in mouseClicked, it draws Winston baby images at the clicked mouse location, layering them on top of whatever was already drawn.

How would we integrate that into our multi-scene program? Well, we'd start by just wrapping all the static drawing code into a scene drawing function drawScene5() and adding scene switching logic to mouseClicked:

var drawScene5 = function() {
currentScene = 5;
background(173, 239, 255);
fill(7, 14, 145);
textSize(39);
text("Winston has babies!", 10, 47);
...
};

mouseClicked = function() {
if (currentScene === 1) {
drawScene2();
} else if (currentScene === 2) {
drawScene3();
} else if (currentScene === 3) {
drawScene4();
}  else if (currentScene === 4) {
drawScene5();
} else if (currentScene === 5) {
drawScene1();
}
};

Here's what that looks like:

But how do we integrate the mouseClicked functionality? We've already defined a mouseClicked in our code, and we can't define it twice. In JavaScript, the last function definition "wins", it overrides any previous definitions. That means that we need to find a good place to put that baby drawing line inside our existing mouseClicked. Let's talk about a few options:

1. We could put the line at the top of the function:

mouseClicked = function() {
image(getImage("creatures/BabyWinston"), mouseX-20, mouseY-20);
...
};

Then it will get called EVERY time the user clicks the mouse, even if it's not the baby making scene (and it'd be weird if baby winston had a baby). No good.

2. We could put the line inside the currentScene === 4 if block:

mouseClicked = function() {
if (currentScene === 1) {
drawScene2();
} else if (currentScene === 2) {
drawScene3();
} else if (currentScene === 3) {
drawScene4();
}  else if (currentScene === 4) {
drawScene5();
image(getImage("creatures/BabyWinston"), mouseX-20, mouseY-20);
} else if (currentScene === 5) {
drawScene1();
}
};

After all, that's where we call drawScene5(), and the babies should be added to scene 5. But think about it: that'd mean that we'd always draw an extra baby, every time we drew the scene. It'd also mean that we'd never draw any more babies, because currentScene would get set to 5, and the code in that if block wouldn't get executed any more.

3. We could put the line inside the currentScene === 5 if block:

mouseClicked = function() {
if (currentScene === 1) {
drawScene2();
} else if (currentScene === 2) {
drawScene3();
} else if (currentScene === 3) {
drawScene4();
}  else if (currentScene === 4) {
drawScene5();
} else if (currentScene === 5) {
image(getImage("creatures/BabyWinston"), mouseX-20, mouseY-20);
drawScene1();
}
};

That would mean we wouldn't draw babies until the first click after the initial drawing of the scene. But, as you can see from the line after it, the baby would be instantly replaced with scene 1.

This is where we realize a fatal flaw in our idea of integrating this baby-clicking scene into our scenes: we're using the exact same interaction--a mouse click anywhere on the screen--to change scenes as well as to do within-scene interaction. Now we really have a conundrum on our hands, and we need to consider more radical options for integrating the scene.

4. We could stop re-drawing scene 1 at the end, and tell the user to restart in that case. Sure, that'd work, but that relies on the fact that our click-controlled screen happens to be in the last one. What if we wanted an earlier click-controlled scene? That solution would fail.

5. We could use a different sort of interaction - like mouseDragged. That will work, because dragging doesn't also cause a click event. We still need to check that currentScene === 5, to make sure dragging doesn't draw babies in any other scene:

mouseDragged = function() {
if (currentScene === 5) {
image(getImage("creatures/BabyWinston"), mouseX-20, mouseY-20);
}
drawButton();
};

Try it out below, making sure you drag on the final scene:

So, that kind of works, although I'm a bit worried about how many babies Winston might end up with. Generally, this is not an optimal solution, since it means we have to limit ourselves to designing scenes that don't respond to mouse clicks. We don't want to have to have that constraint, there must be a better way.

What if we instead differentiated mouse clicks by location, so that a click in one location would mean changing scenes, and clicks elsewhere could be used for in-scene interaction? You know, like a button! In fact, that's how most multi-scene programs approach this problem, and we'll talk through that next.