Making your mouse drop a shape

edited October 12 in Questions about Code

Hello there! Alright, to get right down to it, i am having a problem. I am working on making a small game that follows the user's mouse, and fires a shape when the mouse is clicked. The problem that i am having, put dumbly is:

void setup() { size(500,500); background(0); }

void draw() { background(0);

}

void mouseClicked() { rect(mouseX,mouseY,50,50);

}

Without the background, it works great, but none of my other animations work without it. The plan after this is to make the shape shoot away from the ship and to the enemy.

How do i work around that?

Thanks!

Answers

  • Answer ✓

    The solution is simple: Do all your drawing in draw().

    "But wait," you ask, "how do I know where to draw a shape based on a mouse click if the mouse click happened in mouseClicked(), not draw()?"

    That's a good question. The answer is that you have to remember the fact that a mouse click happened (and do this when the mouse was clicked), and then check (when drawing in draw()) if a shape should be drawn because the mouse was clicked.

    "Okay. That sounds good. But how do I remember that fact?" you ask.

    Well, you have to store the knowledge of that fact somewhere, and the best place to do that would be in some variables. Global variables, specifically, because then that same variable can be accessed in both mouseClicked() and draw().

    Let's add some variables to record information about our "the mouse was clicked" facts:

    int clicked_at_x;
    int clicked_at_y;
    boolean was_clicked = false;
    

    Next, we want to remember things about our mouse click when a click occurs:

    void mouseClicked(){
      was_clicked = true;
      clicked_at_x = mouseX;
      clicked_at_y = mouseY;
    }
    

    And finally, we want to use this information in draw():

    void draw(){
      background(0);
      if(was_clicked){
        rect(clicked_at_x, clicked_at_y,50,50);
      }
    }
    

    If you put it all together, you get this:

    int clicked_at_x;
    int clicked_at_y;
    boolean was_clicked = false;
    
    void setup() { 
      size(500, 500);
    }
    
    void draw() {
      background(0);
      if (was_clicked) {
        rect(clicked_at_x, clicked_at_y, 50, 50);
      }
    }
    
    void mouseClicked() {
      was_clicked = true;
      clicked_at_x = mouseX;
      clicked_at_y = mouseY;
    }
    

    And as you can see, the square now only appears when the mouse is clicked, and stays where the mouse was clicked, and moves to a new position every time the mouse is clicked.

  • Answer ✓

    "Great!", you exclaim,"But wait - before, I could click many times and have many squares appear. And now only one appears. How do I get many squares to appear again?"

    Ah, well, you need to remember EVERY click, not just the LAST click.

    "Okay, so how do I record more than one click?"

    First, you will need variables to remember the information about the clicks. Then you will need to update that information - add the fact that a click occurred - every time a click occurs. And you will need to redraw ALL the squares for ALL the clicks EVERY frame!

    "Wait, I have to redraw EVERY SQUARE EVERY SINGLE TIME I REDRAW MY SKETCH?!? Isn't that going to SLOW my sketch WAY DOWN?"

    Yes, you have to. And no, it won't.

    "Okay. So what sort of data structure do you suggest I use to store the information about all my mouse clicks?"

    I suggest an ArrayList of PVectors:

    ArrayList<PVector> clicks = new ArrayList();
    
    void setup() { 
      size(500, 500);
    }
    
    void draw() {
      background(0);
      for( int i = 0; i < clicks.size(); i++){
        rect(clicks.get(i).x, clicks.get(i).y, 50, 50);
      }
    }
    
    void mouseClicked() {
      clicks.add( new PVector( mouseX, mouseY, millis() ) );
    }
    

    "Whoa. that's even LESS code than before!"

    Amazing, right?

  • "Whoa. that's even LESS code than before!"

    Just a little adjustment for even less code: :ar!
    for (PVector p : clicks) rect(p.x, p.y, 50, 50);

  • Wow, that is beautiful! Thank you so much, TFGuy44 XD There is still a lot for me to learn, but this is a great start for what i need.

  • Don't applaud, just throw (beer) money (via paypal) (to tfguy44 at gmail dot com). :D

    The next step is to not draw rectangles, but to actually draw bullets. What you really want to be storing is not a position for a rectangle, but a object that represents your bullet. Then you can draw those objects instead of rectangles:

    class Shot {
      PVector p;
      PVector v;
      Shot(float px, float py, float vx, float vy){
        p = new PVector(px, py, 0);
        v = new PVector(vx, vy, 0);
      }
      void draw(){
        simulate();
        render();
      }
      void simulate(){
        p.x += v.x;
        p.y += v.y;
      }
      void render(){
        pushMatrix();
        pushStyle();
        translate(p.x,p.y);
        fill(255,255,0);
        noStroke();
        ellipseMode(CENTER);
        ellipse(0,0,5,5);
        popStyle();
        popMatrix();
      }
    }
    
    ArrayList<Shot> shots = new ArrayList();
    
    void setup() { 
      size(500, 500);
    }
    
    void draw() {
      background(0);
      for (Shot shot : shots) shot.draw();
    }
    
    void mousePressed() {
      shots.add( new Shot( mouseX, mouseY, 0, -5 ) );
      shots.add( new Shot( mouseX, mouseY, -.5, -5 ) );
      shots.add( new Shot( mouseX, mouseY, .5, -5 ) );
    }   
    
  • So I am trying to be able to shoot an object per click pretty much like you did, but horizontally, and so it deletes after it goes off screen to prevent lag. After I made my edit though, how did you make it shoot more than once? This only seems to want to shoot once then be done. ._.

    //Test for Dropping Blocks and shooting.

    ArrayList clicks = new ArrayList(); float sl = 0.0; float x = 0.0; float y = 0.0;

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

    void draw() { background(0);

    //These control the movement of the object sl = sl-10.0; //This sets up where the stars restart when they pass a certain point. if (-2000.0>sl){sl=2000.0;}

    if(x> 0 || x<width){ for( int i = 0; i < clicks.size(); i++) { rect(clicks.get(i).x-sl-600, clicks.get(i).y, 50, 50); } } }

    void mouseClicked() { clicks.add( new PVector( mouseX, mouseY, millis() ) ); }

    P.S. Noob question, how do you make the coding box like you have been doing? Thanks~

Sign In or Register to comment.