Multithreading with built in functions for PONG

edited October 2014 in Questions about Code

I am creating a PONG game, where one of the modes is a player vs. player game. One player uses the mouse to control the paddle, and the other uses the arrow keys.

My code is like this:

void mousePressed() { if(mouseX >= sized/2-75 && mouseX <= sized/2+125 && mouseY >= sized/2-20 && mouseY <= sized/2+30) { play = 1; playmode = 0; } else { play = 0; } if(mouseX >= sized/2-75 && mouseX <= sized/2+125 && mouseY >= sized/2+50 && mouseY <= sized/2+100) { playm2 = 1; playmode = 1; println("BOX:2"); } else { playm2 = 0; } } void keyPressed() { switch(keyCode) { case 66 : rlength +=10; break; case 38 : arrow = 1; break; case 40 : arrow = 2; break; }

}

The problem here is that when one player is using the arrow keys, the mouse cannot be used. Am I right in thinking that since this isn't threaded, when the key is pressed and the function is called, the mouse function never runs because the program is stuck on the keyPressed function? If so, how would I thread this program? I have almost no experience in threading. Help would be graciously accepted.

Answers

  • You should take a look at my replies in this very recent forum thread:
    http://forum.processing.org/two/discussion/7450/event-handling

  • Without seeing an MCVE it's a little hard to tell what's going on in your program, but the short answer is that no, using multiple threads isn't the solution to this problem.

    Instead of doing the game logic (moving the paddles) directly from your event handlers, keep track of which key is pressed using booleans. Set those booleans in the event handler, and then refer to those booleans from your draw() function. More info here: http://staticvoidgames.com/tutorials/intermediateConcepts/keyboardInput

    If that doesn't work, please post an MCVE (note: not your whole project, just enough for us to copy and paste to see the problem in our own editors), and we'll go from there.

  • MCVE - (not so m, sorry)

         PFont font;
       PFont fontsm;
    
    
         int rlength = 150;
         int arrow = 0;
          int fill = 123;
          int fill2 = 123;
            int play = 0;
         int playmode;
       int playm2 = 0;
       int ballspeedx = 4;
        int ballspeedy = 4;
        int bx = 300;
        int by = 340;
         int y=357;
        int cy = 357;
       int move = 7;
       int cmove = 35;
        int mouseYrounded;
         int speed = 10;
         int sized = 700;
          int steps = 30;
        int pscore = 0;
         int cscore = 0;
        boolean upPressed = false;
         boolean downPressed = false;
          void setup(){
    
         background(0);
         size(sized, sized);
         font = loadFont("CourierNewPSMT-60.vlw");
         fontsm = loadFont("CourierNewPSMT-24.vlw");
         textFont(font);
    
        }
        void draw(){
    
        if(millis() < 100000 && (play==0 && playm2==0)){
        background(123,176,170);
        fill(176,123,129);
        text("PONG", sized/2-50, sized/2-50);
        if (overRect(sized/2-75, sized/2-20, 200,50)) {
          fill  = 50;
        }
        else {
          fill = 123;
        }
        if (overRect(sized/2-75, sized/2+50, 200, 50)) {
          fill2 = 50;
    
        }
        else {
          fill2 = 123;
        }
        fill(176, fill, 129);
        rect(sized/2-75, sized/2-20, 200,50,7);
        fill(176,fill2,129);
        rect(sized/2-75, sized/2+50, 200,50,7);
        fill(123,176,170);
    
        textFont(fontsm);
        text("Play Yourself", sized/2-60, sized/2+13);
        text("2 Players", sized/2-60, sized/2+83);
        textFont(font);
        }
      else {
    background(0);
    //The dotted line... using our friend the loop.
    for(int i=0; i<=35; i++) {
       int x = 349;
       int y = i*40;
       noStroke();
    
       fill(155,204,0);
       rect(x, y,2, sized/35);
    

    } //Shcores... also known as drunkards... text(pscore, sized/2-100, 630); text(cscore, sized/2+50, 630);

    //let's go and have a ball...
    fill(255);
    rect(bx, by, 20,20);
    ball();
    
    
    //1. The player (1) racket
    move = (mouseY>y+50) ? speed : -speed;
    mouseYrounded = mouseY - (mouseY%speed);
    
    if(y==mouseYrounded) {move = 0;}
    
    y += move;
    
    
    
    fill(255);
    rect(10,y,20,rlength);
    //2. The comp racket
     println("PLAYMD:"+playmode);
     if(playmode == 0) {
         rect(sized-30,y,20,150);
     }
     if(playmode == 1) {
         rect(sized-30, cy, 20, 150); 
        if(cy>0 && cy<sized-150) { 
         if(downPressed){
         cy+=cmove;
         }
          else if(upPressed) {
         cy-=cmove;
         }
         else {
           cy+=0;
         }
    
        }
        else {
          if(cy<sized-150){
           cy+=35;}
           else {cy-=35; println(cy);}
    
        }
     }
    

    } }

            void ball() {
    
    
    
    ballspeedy = (by<0 || by>height-20) ? -ballspeedy : ballspeedy;
    if ((by>y+75 && by<y+150) && (bx<30 || bx>sized-30)) {
       ballspeedy=-ballspeedy;
       ballspeedx=-ballspeedx;
    }
    if ((by>y && by<y+75) && (bx<30 || bx>sized-30)) {
    
       ballspeedx=-ballspeedx;
    }
    if ((by>cy+75 && by<cy+150) && (bx<30 || bx>sized-30)) {
       ballspeedy=-ballspeedy;
       ballspeedx=-ballspeedx;
    }
    if ((by>cy && by<cy+75) && (bx<30 || bx>sized-30)) {
    
       ballspeedx=-ballspeedx;
    }
    bx -= ballspeedx;
    by -= ballspeedy;
    
    if(bx<0) { 
    
      cscore++;
      bx = 310;
      by = 340;
     }
    if(bx>width-20) { 
      pscore++;
      bx = 310;
      by= 340;
      }
     }
    
        void mousePressed() {
     if(mouseX >= sized/2-75 && mouseX <= sized/2+125 && 
      mouseY >= sized/2-20 && mouseY <= sized/2+30) {
        play = 1;
        playmode = 0;
      }
     else {
       play = 0;
     }
     if(mouseX >= sized/2-75 && mouseX <= sized/2+125 && 
      mouseY >=  sized/2+50 && mouseY <= sized/2+100) {
        playm2 = 1;
        playmode = 1;
        println("BOX:2");
      }
     else {
       playm2 = 0;
     }
      }
    
          boolean overRect(int x, int y, int width, int height) {
         if (mouseX >= x && mouseX <= x+width && 
      mouseY >= y && mouseY <= y+height) {
    return true;
     } else {
    return false;
     }
     }
    
             void keyPressed() {
       switch(keyCode) {
      case 66 :
        rlength +=10; 
        break;
      case 38 :
         upPressed = true;
         break;
      case 40 :
         downPressed = true;
         break;
       }
    
    
     }
    
      void keyReleased() {
    
       switch(keyCode) {
      case 38 :
         upPressed = false;
         break;
      case 40 :
         downPressed = false;
         break;
    

    }

    }

    Again, the problem is that both the mouse input and the keyed inputs cannot be used at the same time in the two player game.

  • My code is almost barebones already, there is not much I could take off.

  • That's quite a bit of code just to demonstrate the problem, and I'm not sure what's going on with your formatting.

    I've put together my own MCVE that handles both keyboard and mouse input. If this doesn't work, please modify this program to show the problem:

    float keyBallX = 250;
    float keyBallY = 250;
    
    float mouseBallX = 100;
    float mouseBallY = 100;
    
    float speed = 5;
    
    boolean upPressed = false;
    boolean downPressed = false;
    boolean leftPressed = false;
    boolean rightPressed = false;
    
    void setup() {
      size(500, 500);
    }
    
    void draw() {
    
      if (upPressed) {
        keyBallY -= speed;
      }
      if (downPressed) {
        keyBallY += speed;
      }
      if (leftPressed) {
        keyBallX -= speed;
      }
      if (rightPressed) {
        keyBallX += speed;
      }
    
      mouseBallX = mouseX;
      mouseBallY = mouseY;
    
      background(0);
      ellipse(keyBallX, keyBallY, 25, 25);
    
      ellipse(mouseBallX, mouseBallY, 25, 25);
    } 
    
    void keyPressed(KeyEvent e) {
      if (key == CODED) {
        if (keyCode == UP) {
          upPressed = true;
        }
        else if (keyCode == DOWN) {
          downPressed = true;
        }
        else if (keyCode == LEFT) {
          leftPressed = true;
        }
        else if (keyCode == RIGHT) {
          rightPressed = true;
        }
      }
    }
    
    void keyReleased(KeyEvent e) {
      if (key == CODED) {
        if (keyCode == UP) {
          upPressed = false;
        }
        else if (keyCode == DOWN) {
          downPressed = false;
        }
        else if (keyCode == LEFT) {
          leftPressed = false;
        }
        else if (keyCode == RIGHT) {
          rightPressed = false;
        }
      }
    }
    
  • edited October 2014

    Tips: No need for a KeyEvent parameter if it's not gonna be used inside the callback:

    • keyPressed() {}
    • keyReleased() {}

    No need to check for CODED. Unless for a micro-optimization to return from the callback ASAP:

    if (key != CODED)  return;
    

    And since both keyPressed() & keyReleased() are almost the same but their boolean assignments,
    we can rather implement a separate function to be called by both. It's much neater: :P

    void keyPressed() {
      setDirection(keyCode, true);
    }
    
    void keyReleased() {
      setDirection(keyCode, false);
    }
    
    void setDirection(int k, boolean bool) {
      if      (k == 'W' | k == UP)     upPressed    = bool;
      else if (k == 'S' | k == DOWN)   downPressed  = bool;
      else if (k == 'A' | k == LEFT)   leftPressed  = bool;
      else if (k == 'D' | k == RIGHT)  rightPressed = bool;
    }
    
  • @KevinWorkman - You are right. Your code does work. But up to a fault, which is the same as my fault, which is the problem I am trying to solve: You cannot use both inputs at the same time. This makes my pong game impossible to play - both players need to be able to control their rackets at any given time - not just when the other player isn't giving input to the computer!

  • edited October 2014

    Both players need to be able to control their rackets at any given time...

    In @KevinWorkman's example, there are 2 circles: 1 is controlled by keyboard and the other by mouse.
    Independently and at the same time too! Dunno what else you're expecting from it! :-??

  • What exactly do you mean when you say you cannot use both inputs at the same time? My example uses both the mouse and the keyboard at the same time. Please modify the program to show exactly what you're talking about, as what you're saying doesn't make a lot of sense.

  • Are you on a Unix system? Which one? I recall some users of such system having issues with keyboard handling.

  • I am on a windows 8 system, and my problem is as follows @KevinWorkman : When the up and down arrows are used as an input, the mouse cannot be used as an input. I had assumed that this was since the keypad triggers the keyPressed event, this function was getting called and the mouseY function (yes, it is a function.) wasn't because java is not inherently multithreaded. No one seems to understand what I am trying to ask.

  • edited October 2014

    When the up and down arrows are used as an input, the mouse cannot be used as an input.

    Is it some hardware bug of yours? I'm pretty sure that I can hit the arrow keys to move 1 ellipse();
    and at the same time, move my mouse for the other ellipse() for the @KevinWorkman's example! >:/

    ... and the mouseY function (yes, it is a function.)...

    No, it isn't. All Java's functions are identified by a pair of parens suffixed to their name!
    Variable mouseY is 1 of PApplet's fields, which our sketches actually are:
    processing.org/reference/mouseY.html

    ... because Java is not inherently multi-threaded.

    Better take a look at Java's Thread class: docs.oracle.com/javase/8/docs/api/java/lang/Thread.html

    "A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently."

    No one seems to understand what I am trying to ask.

    Perhaps b/c when we run the program we got a behavior which doesn't match your description! >-)

  • @GoToLoop: Firstly: mouseY is a function that returns a variable called mouseY. It doesn't seem to be a function because of the absence of parens. However, it is a function that gets called every single time a frame is drawn and returns it's value in a variable called mouseY.

    Secondly: I didn't mean that Java doesn't have the capability to be multithreaded, I just meant that built in functions do not work concurrently, and that was my original question: Can you thread two built in functions.

    Finally, I guess my computer's hardware doesn't allow for it. But it is strange, since I saw the same behavior on a different brand of laptop running Win 8.1.

  • edited October 2014

    It doesn't seem to be a function because of the absence of parens.

    In Java, functions, or their more specific name methods, are always recognized by their parens ()!
    That's why we can have a variable & a function share the same name!

    In JavaScript, variables are also responsible to store references for functions.
    That's why in JS either a variable name refer to a function or something else!

    I wonder why are you acting so like a troll, to say the least, w/ such basic knowledge!
    "mouseY is a function that returns a variable called mouseY" - seriously? :-q

    Are you telling us that Processing got a function called mouseY()?
    Please read its description below. It says clearly it's a "system" VARIABLE:
    http://processing.org/reference/mouseY.html

    I just meant that built in functions do not work concurrently,...

    Most functions aren't written w/ concurrency in mind. Which btW it's an expert domain in any programing language, not just Java!
    But the good part is that Processing's framework already takes care of capturing input events transparently!
    We just need to tell what to do when those events happen, inside callbacks like keyPressed(), mousePressed(), etc.!
    I'm sorry it's not working in your hardware, but it's the 1st time I've seen such report! :-@

    Can you thread two built in functions.

    In Processing, all drawings happen in the canvas. We shouldn't modify it concurrently!
    But I can't understand why you'd need that in order to have 2 ellipses moving at the same time! ^#(^

  • No, this doesn't make any sense. What hardware are you using that you think your mouse completely shuts down when you have a key on the keyboard pressed?

    Did you really run the code I posted? Did you try moving the mouse in the window while pressing the keyboard arrows? Which circle doesn't move?

    Does the window have focus?

  • The window had focus, for sure. When I pasted your code into the IDE and had it run, I then held down in of the.keyboard arrows to move the vertically moving circle. However, when I moved the mouse, the mouse icon onscreen moved but the other circle didn't follow it.

    That was my experience with your code.

  • Was the mouse inside of the window?

Sign In or Register to comment.