Why is my mouse pressed (or key pressed) code executed several times?

edited November 2014 in Common Questions

Why is my mouse pressed (or key pressed) code executed several times?

Imagine you have a task to display, over a cross, a circle with a color: when you click on it, you have to display another color (from a list) and so on.

Lot of beginners will do code like:

color[] colors = { #FF0000, #00FF00, #0000FF };
int currentColor;

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

void draw()
{
  background(255);
  stroke(0);
  strokeWeight(20);
  line(0, 0, width, height);
  line(0, height, width, 0);

  if (mousePressed && dist(mouseX, mouseY, width / 2, height / 2) < 2 * width / 3)
  {
    currentColor++;
    if (currentColor >= colors.length)
    {
      currentColor = 0;
    }
  }

  noStroke();
  fill(colors[currentColor]);
  ellipse(width / 2, height / 2, 2 * width / 3, 2 * height / 3);
}

Then, they come to the forum, asking why the colors aren't displayed in the defined order...

The problem is simple: when the user clicks, the click duration spawns over several frames: by default, the frame rate is of 60 frames per second, so if the user clicks for a 10th of second, the mousePressed state will be detected on 6 draw() calls, resulting in displaying six colors in sequence!

Fortunately, the solution is simple too: for such case, it is better to use an event callback, like mousePressed(). This function is called only once, whatever the duration of the click. So, they move code to this function:

color[] colors = { #FF0000, #00FF00, #0000FF };
int currentColor;

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

void draw()
{
  background(255);
  stroke(0);
  strokeWeight(20);
  line(0, 0, width, height);
  line(0, height, width, 0);
}

void mousePressed()
{
  if (dist(mouseX, mouseY, width / 2, height / 2) < 2 * width / 3)
  {
    currentColor++;
    if (currentColor >= colors.length)
    {
      currentColor = 0;
    }
  }

  noStroke();
  fill(colors[currentColor]);
  ellipse(width / 2, height / 2, 2 * width / 3, 2 * height / 3);
}

But now, they complain they see the circle only briefly and only when clicking. That's because it is rarely a good idea to do drawing in these events. It is better to set up state variables, and to handle all drawings in draw():

color[] colors = { #FF0000, #00FF00, #0000FF };
int currentColor;

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

void draw()
{
  background(255);
  stroke(0);
  strokeWeight(20);
  line(0, 0, width, height);
  line(0, height, width, 0);

  noStroke();
  fill(colors[currentColor]);
  ellipse(width / 2, height / 2, 2 * width / 3, 2 * height / 3);
}

void mousePressed()
{
  if (dist(mouseX, mouseY, width / 2, height / 2) < 2 * width / 3)
  {
    currentColor++;
    if (currentColor >= colors.length)
    {
      currentColor = 0;
    }
  }
}

See How to manage the steps of a game: increasing levels, displaying messages, etc.? for more details on state handling.

Sign In or Register to comment.