views:

885

answers:

4

Hi all. I'm probably doing this wrong, so please be nice. I'm developing a java game, and I'm at the stage of testing character movement / animation.

The "person" can move up down left and right on a grid. The class the grid is drawn in the gamePanel class. The buttons are in the gameControlPanel class.

I have a button which spawns a person on the grid. I then have a button to move the person up down left and right.

When the move up button is pressed, it calls the move up method from the person person. (As I'm only allowing one person at current for testing) In that method is the following code...

int move = 10;
while(move!=0)
{
    setTopLeftPoint(new Point((int)getTopLeftPoint().getX(),
                              (int)getTopLeftPoint().getY() - 3));

    try
    {
        Thread.sleep(300);
    } catch (InterruptedException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }   
    move-=1;
}

The problem is, I cant seem to call the repaint method for the gamePanel class from within the Person class. To get round this, I created a time in the gamePanel class which repaints every 20ms.

When I press the up button after the person is sawned, the button remains pressed down until the cycles of the while loop has been completed, and then the circle representation of the person is displayed in the grid square above.

I will try to answer any questions regarding this. Please help.

Thanks in advance

Rel

A: 

I don't have much experience making games but having a loop to control all animation is a fundamental aspect of game programming. Most simple 2d games only have 1 loop to render most of its animation.

In my experience a good way to render a whole bunch of stuff is to have a collection of all the entities in your game in one place and just loop over this collection passing the Graphics object to each entity.

This will allow each entity to draw itself onto the graphics object. Although this is just one way to do it.

synchronized ( entities ) {
    for ( Entity e : entities ) {
     e.draw( g );
     e.doAction();
    }
}
Peter D
yes i do indeed do this, however when the up button i clicked, it is supposed to change the position by -3 upwards using a while loop. The painting doesn't change.I just think i may be doing it slightly wrong.
Relequestual
I think I see. It seems to me you are doing the movement of your person in the same thread that the game loop is in. Therefore yes your person does move, but during the movement (in the while loop) your main loop is not repainting because it's waiting for the person to move and sleep and move etc. It isn't good practice, but you might want to spawn a new thread to do the movement of your person.
Peter D
ok, I may be able to do this. If this isn't good practice, how should I be doing this?
Relequestual
Like I mention in my original post. You should have a loop that calls a method like doAction on your objects that require moving. So on each frame a method will be called on each object and that method will do the work of modifying the X and Y values of itself. Keep doing what you are doing though, you need to make mistakes before you can do things correctly. :)
Peter D
ok, thanks :)I think i understand, but my issue is, i dont see how i can implement this into my project. where would i put that loop? also how would the draw work? at current, i just have a really big paint method, which i know cant be the best way to do this.
Relequestual
A: 

Is the button press handled by the event-dispatch thread of your GUI?

If this is a case, then the repaint method on the GUI will not fire until the event dispatch thread ends (i.e. when the button is released and it breaks out of the loop). I had this problem recently, and the best solution I can suggest is to make the class with the movement algorithm threadable and fire off a thread when the keypress is detected. This allows the event-dispatch thread to finish and therefore allows the gui to repaint.

For more information on threading see Starting a thread.

Chris Clarke
I'm not sure I understand what you mean in your question. I have not dealt with threading as far as I'm aware. I'm still rather new to java. The previous answer has left some comments which seem helpful
Relequestual
I only asked to be sure, unless you've done something very esoteric the answer is almost certainly "yes". Creating your own threading is an alternative to the SwingWorker suggested above.
Chris Clarke
I think me using SwingWorker or another thread may be me over complicating things a bit. I am just about to ask a further question in relation to this matter. Thanks for your help
Relequestual
+2  A: 

repaint() does not immediately repaint the GUI. Rather, it posts a message to the AWT thread telling it to paint at the next convenient opportunity. When it gets the chance, it will repaint your app. However, if you do this in an event handler, then the AWT thread is already busy and you need to exit the handler to give control back to the AWT handler.

As a general rule of thumb, you don't want to do any long-running calculations on the AWT thread (including in event handlers) since these will stop the app from responding to other events until your calculations are done. This will often appear to the user as stuck buttons like you described. To get around this, use a SwingWorker which can do the calculations on a separate thread.

Finally, something to be aware (but not necessarily to change) is that timers and sleeps do not guarantee when they will awaken. Rather, they guarantee that they will not waken before the amount of time elapses, but can theoretically sleep indefinitely. Also, not all machines have 1 ms timer resolution. In particular, on many windows machines the timers only have 55 ms resolution, so a 20 ms timer may give weird results.

James
Thanks for this useful information. I'm still at very basic testing stages of the game, so who knows. I had a brief look at swingworker, but it looks really confusing to me :S
Relequestual
The SwingWorker is definitely what you want here. Like a lot of Java, it's got a steep learning curve, but once you figure it out, you probably won't need that timer any more.
Ian McLaird
A: 

If you want to repaint at a certain interval, javax.swing.Timer is probably the class for you. In the specific case of repaint you can call it from a non-EDT thread, but you may get yourself into difficulty as you are now dealing with multiple threads.

Tom Hawtin - tackline
I believe multiple threads are too complicated for me. I have another question which people should look at as a sort of answer to this issue. I decided on doing logic-repaint-sleep on each tick of a 100ms timer.
Relequestual