Program in Infinite Loop Unable to Handle User Input


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 11 of 11

Thread: Program in Infinite Loop Unable to Handle User Input

  1. #1
    Join Date
    May 2006
    Posts
    10

    Program in Infinite Loop Unable to Handle User Input

    Hi all,

    I am working on a simple game in which the player moves a paddle up and down to keep a bouncing ball from going out of bounds. The user moves the paddle by the pressing and dragging on the paddle (graphically shown as a rectangle) with the mouse. To keep the ball in constant motion, I created an Alarm class which notifies the top-level class in the program when the ball needs to be moved.

    public void setEndlessAlarm(Alarmed alarmed, double delay)
    {
    while (true)
    {
    this.setAlarm(alarmed, delay);
    }
    }

    public void setAlarm(Alarmed alarmed, double delay)
    //delay is in milliseconds
    {
    timer.start();
    while (timer.stop() < delay)
    {

    }
    alarmed.alarmAction();
    }

    The problem is that when the method setEndlessAlarm() is called, the paddle can no longer be moved. In fact, no user input is handled. The window cannot even be closed; to end the program, I must use Eclipse's Terminate button.
    To deal with the problem, I tried to use threading, since I hear that multithreading allows several events to run simultaneously. So, I set up a thread to initialize the listener, and a thread to keep the ball moving. The output was the same. I also tried using yield(), wait(), sleep(), and other Thread methods to give an opportunity for the user input to be handled. It could just be that I do not know how to properly implement threading.
    So, the bottom line is, how can I receive and handle user input while still having the ball moving?

    Thanks,
    David

  2. #2
    Join Date
    Feb 2006
    Location
    Cologne - Germany
    Posts
    271
    the code above is an endless loop, which will eat up the full processor time and thus not allow anyone to do anything.
    try sthg like this. it will set your actual thread to sleep for a while
    allowing user interactions etc.

    Code:
    public void setAlarm(Alarmed alarmed, double delay)
    //delay is in milliseconds
    {
      try{
        Thread.sleep(delay);
      }
      catch(InterruptedException e){
        // nothin serious here
      }
    
      alarmed.alarmAction();
    }

  3. #3
    Join Date
    May 2006
    Posts
    10
    Thanks, graviton. I have tried this, and I just tried it again; however, it is not working.

    David

  4. #4
    Join Date
    Feb 2006
    Location
    Cologne - Germany
    Posts
    271
    hmm, i think i need a broader sight on your application.
    what about that class timer? could you post it?

  5. #5
    Join Date
    May 2006
    Posts
    10
    OK, here is my Timer class:

    Code:
    package paddle;
    /**A general-purpose timer, written originally for timing different sorting
     * methods. The class has start and stop methods for starting and stopping
     * the timing. It also has a method which returns the time elapsed during the
     * last timing. Time is returned in milliseconds, but is stored in the class as
     * nanoseconds.*/
    public class Timer
        {
        
        /**Points to the value of the time of the System in nanoseconds when the
         * start() method was called, or to the value of the static constant
         * NO_START_TIME.*/
        private long startTime;
        
        /**Points to the value of the time of the System in nanoseconds when the
         * stop() method was called.*/
        private long stopTime;
        
        /**This is the value assigned to the data member startTime in the
         * constructor.*/
        private static final byte NO_START_TIME = -1;
        
        /**This is the value assigned to the data member stopTime in the
         * constructor.*/
        private static final byte NO_STOP_TIME = -1;
    
        /**Constructor*/
        public Timer()
            {
            super();
            startTime = NO_START_TIME;
            stopTime = NO_STOP_TIME;
            }
        
        /**Starts the timing.*/
        public void start()
            {
            startTime = System.nanoTime();
            }
        
        /**Stops the timing, if timing has been initiated with the start() method;
         * if no such timing has been started, an exception is thrown.
         * @return The difference between the starting time and the ending time,
         * or the time elapsed.*/
        public double stop() throws TimerNotStartedException
            {
            if (startTime == NO_START_TIME)
                {
                String message = "The timer cannot be stopped because it has not" +
                      "been started";
                throw new TimerNotStartedException(message);
                }
            else
                {
                stopTime = System.nanoTime();
                double timeElapsed = (stopTime - startTime) / 1E6;
                return timeElapsed;
                }
            }
        
        /**Returns the reading of the last timing, if timer has been previously
         * set and stopped.*/
        public double getLastTime()
            {
            if (startTime == NO_START_TIME)
                {
                String message = "No time can be given because the timer was" +
                      "never started.";
                throw new TimerNotStartedException(message);
                }
            else if (stopTime == NO_STOP_TIME)
                {
                String message = "No time can be given because the timer was" +
                "never stopped.";
                throw new TimerNotStartedException(message);
                }
            else
                {
                double timeElapsed = (stopTime - startTime) / 1E6;
                return timeElapsed;
                }
            }
        }
    Btw, I have tried using the Timer class that comes with the java.util package; with that class, I was able to move the paddle, but there was a very long delay before the paddle moved, making the game very impractical. Additionally, the paddle moved more than it is supposed to; this problem also occurs when I call the setAlarm() method once, not the setEndlessAlarm() method. Once the ball has moved at all, the paddle cannot be moved properly.

    Thanks for helping, graviton.

    David

  6. #6
    Join Date
    Feb 2006
    Location
    Cologne - Germany
    Posts
    271
    your timer should implement runnable or extend thread an run as a seperate thread.
    if not, as you did, it will use the same thread as the main application and thus block the main application when it waits.
    when the timer is a seperate thread, it can wait for it's own while the main thread works on.
    but that's just a guess, since i'm not shure how the rest of your app works.
    let me resume: you have a class with a gui, where the user can press buttons or keys to do interaction.
    how is the interaction of the user evaluated? usually, you should have some kind of mvc pattern. the interaction should modify the model. the model should notify the view and the view should be updated.
    as you say, the ball keeps bouncing without userinteraction.
    this means, that there should be a seperate thread, that modifies the model automatically at his own. i guess that's the timer.
    for this purpose you will have to use at least:
    1 thread for the automatic manipulation of the model (ball keeps bouncing)
    1 thread for the userinteraction
    as multiple threads will access your model synchronously, the model has to be synchronized, eg the methods will have to be synchronized.

  7. #7
    Join Date
    May 2006
    Posts
    10
    OK, I tried to implement your suggestions. but I wasn't sure how to make the user interface have its own thread. I made my UserInterface class extend Thread; was there more that you meant about that?
    I haven't tried to follow the mvc pattern. Basically, UserInterface (which implements the appropriate listener interfaces) notifies the GameFrame (which is a subclass of JFrame and has the main() method and the paint() method) what to do based on user actions. GameFrame often modifies other classes which come under the category of Model. Perhaps, my bad design is causing problems? Should the controller (i.e. UserInterface) have the main method, so that the main thread sticks with user input? Or should the main method be in a separate class that is neither Model nor View nor Controller?

    David

  8. #8
    Join Date
    Feb 2006
    Location
    Cologne - Germany
    Posts
    271
    well, the view usually has it's own thread, since visual updates to swing are handled by a seperate thread the jvm automatically creates. you will have to create a seperate thread for the bouncing.

    lets try a simple mvc like pattern to refactor your application:

    the datamodel

    the datamodel should have some methods to manipulate the balls state as [CODE]well as the variables for the state themself:

    Code:
    public BallModel{
      private int speed; // the speed of the ball
      private double direction; // the direction of the ball
      private Point location; // however, you can use
    
      public synchronized void setSpeed(....)
      public synchronized int getSpeed(....)
      public synchronized void setDirection(....)
      public synchronized double getDirection(....)
    
      // the method should be synchronized, since multiple threads will access it
      public synchronized void moveBall(){
        // sets the location of the ball corresponding 
        // to the variables, eg speed and direction.
        // also checks, if the bounds have been reached, eg position.x<0 and so on
      }
      
      // the new point is returned to avoid that the coordinates of this object
      // are changed outside of the class
      public Point getPosition(){
        return new Point(position.x, position.y);
      }
    }
    that's the ballmodel. now we make a view for that ball:

    Code:
    // can be any jcomponent
    public class BallView extends JPanel{
      private BallModel model;
    
      public BallView(BallModel model){
        this.model = model;
      }
    
      public void paintComponent(Graphics g){
        super.paintComponent(g); // to keep border and insets etc. for this jpanel
        // paint circle at model.getPosition()
      }
    }
    now we need another pattern,through which the model can notify the view (or any other listener) about changes. that's the observer pattern. the model is the observable and the view is the observer that observes. for this purpose the observable needs to know the observer to notify him about changes that occured. in the java classes this are usualy the fireEvent and listeners (actionlistener).
    to make it not too compicated, we give the model a reference to the view.
    Code:
    public BallModel{
    ...
      private BallView view;
    
      public void setView(BallView view){
        this.view = view;
      }
    
      private void notifyView(){
        view.notifyBallChange();
      }
    
      public synchronized void moveBall(){
        ...
        notifyView(); // after some changes were made to the position of the ball,
       // the view has to be notified
      }
    }
    the notifyballchange method has to be included in the view:

    Code:
    public class BallView extends JButton{
      ...
      public void notifyBallChange(){
        repaint();
      }
    }
    the construction for all of that would look like this:

    Code:
    BallModel model = new BallModel();
    BallView view = new BallView(model);
    model.setView(view);
    // swing stuff
    frame.add(view);
    now we need a seperate thread, that will update the movement of the ball. in the model i assumed, that the userinteraction only will change the speed and direction. the movement will be triggered by the seperate thread:

    Code:
    public BallMover extends Thread{
      private BallModel model;
    
      public BallMover(BallModel model){
        this.model = model;
      }
    
      public void run(){
        while(true){
          model.moveBall();
          Thread.sleep(500);
        }
      }
    }
    so our construction becomes:
    Code:
    BallModel model = new BallModel();
    BallView view = new BallView(model);
    model.setView(view);
    // swing stuff
    frame.add(view);
    BallMover mover = new BallMover(model); 
    mover.start(); // start the thread
    at this point, the ball should start to move, and the view should start painting it.

    if you ask where the controller of mvc is:
    that is the keylistener of your BallView, or any buttons you add to the same frame as the view. on action, you invoke the setSpeed/direction methods of the model.
    since i don't have the time to test all of my examplecode, i'm not shure, if there is still a blocking issue.
    let me know and we can trace it.

  9. #9
    Join Date
    May 2006
    Posts
    10
    graviton, thanks for your help. I restructured my program from scratch in the way you suggested, and I am now able to move the paddle while the ball is moving! Thanks a lot!
    However, there are a couple of smaller problems:
    1) the paddle movement is somewhat choppy (i.e., there are brief delays)
    2) when the paddle is moved, the ball slows down

    I was wondering if you know of a way to deal with these.

    Thanks again,
    David

  10. #10
    Join Date
    Feb 2006
    Location
    Cologne - Germany
    Posts
    271
    i guess you used the same structure for the paddle as for the ball, with some model, view and the mvc.
    the delays on the paddle movement can come from different sources:
    repainting the view can be too slow.
    some speed gaining can be achieved, when you draw your views per hand and don't extend the jpanel or jbutton.
    feg you have a view panel for both, ball and paddle. let's call it gameview. then you can draw your objects within the paintComponent method by hand, eg drawing images for the objects or drawing them by graphics primitives (circles, lines, rectangles etc).
    this can speed up the reaction of the view, since jpanels and jbuttons are quite complex and big.
    also you can include some clipping support. when you're within the paintComponent method, you get the actual graphics object. on this object, you can invoke the getClip() method. this is a rectangle which tells you which part of the display has to be redrawn. usually, when some other window overlaps your gamewindow, the clip contains the intersection of both windows and thus the are, which has to be redrawn. if you only repaint the clipping area instead of the full display area this will speed up the display and the reactiontime at all. you also can set the clipping area by yourself.
    when the view is beeing notified by the model, you don't invoke repaint() but repaint(rectangle(cliparea)). the cliparea you can determine by the bounds of the object that just moved, eg the balls previous and actual bounds merged.

    then the keylistener for the paddle can be an other problem:
    when the keylistener invokes the move method on the ball/paddle, it will only return after all the painting and processing within the moveBall/paddle method have been processed.
    for this purpose you should start a seperate thread on each keyaction, which then asynchronously can invoke and process the rest, which will "free" the swingthread, which usually works down the code in a listener.
    there are good explainations on this at http://spin.sourceforge.net/ which also has a simple api that takes care of this problem.

  11. #11
    Join Date
    May 2006
    Posts
    10
    What do you mean by drawing the images by hand? Like, using the Paint program in Windows?

Similar Threads

  1. processing additional data when program is running
    By Ervin Rodriguez in forum Database
    Replies: 1
    Last Post: 05-16-2003, 09:45 AM
  2. Unable to get the window handle for the 'AxMSFlexGrid' control
    By Miroslav St. Jeliaskoff in forum .NET
    Replies: 0
    Last Post: 10-01-2002, 03:37 PM
  3. validating input in java??
    By atif in forum Java
    Replies: 1
    Last Post: 05-22-2002, 08:48 AM
  4. User input
    By Metal Maniac in forum Java
    Replies: 2
    Last Post: 02-12-2001, 01:14 AM
  5. user input
    By Joseph in forum Java
    Replies: 0
    Last Post: 07-17-2000, 04:26 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center