tags:

views:

3297

answers:

3

Hi,

I am trying to make an android game.

I have a game class that extends activity and handles all the user input. Then I have a missionView class that extends view and it draws the level on the screen.

When the user clicks on a door I want to add some animation.

What happens is: The game calls door.open. Changes the state so the view.onDraw function will draw the door half open. The game calls view.invalidate, which should redraw the screen. Then the game sleeps for half a second. Then it calls door.open again. The second time the function is called it changes the state so the view.onDraw function draws the door completely open. Then the game calls view.invalidate again.

The problem is that it does not redraw the screen when it gets to view.invalidate. If I set a break point on the line and run the debugger and click step into it does not step into my view.onDraw function. It can't even show me the code it is executing.

What I have is: Door class:

public boolean open()
{
   if (doorState == DoorState.Closed)
   {
       doorState = DoorState.Opening;

       return true;
   }
   else if (doorState == DoorState.Opening)
   {
        doorState = doorState.Open;
        return true;
   }
   else
   {
      return false;
   }
}

Game class:

if (tile instanceof DoorTile)
{
    DoorTile doorTile = (DoorTile) tile;
    Door door = doorTile.getDoor();

    if (door.isClosed())
    {
        door.open();
        selectedEntity.openDoor();
        view.invalidate();    // This line does not work

        try 
        {
            Thread.sleep(500);
        } 
        catch (InterruptedException e1) 
        {
             // TODO Auto-generated catch block
             e1.printStackTrace();
        }
        door.open();

        // Handled touch event so break switch statement
        break;
     }
}
+5  A: 

View#invalidate tells the system to redraw (via onDraw) the view as soon as the main thread goes idle. That is, calling invalidate schedules your view to be redrawn after all other immediate work has finished. If the code in your Game class is being called from the main thread and it puts that thread to sleep, you aren't just pausing rendering, you are pausing input processing all together (usually a bad idea). As a rule of thumb, never sleep a thread that you didn't spawn yourself unless you know what you are doing.

If you'd like to have your game logic periodically delay using Thread#sleep then run it in a separate thread and use view.postInvalidate() to signal the main thread to wake up and call onDraw.

rndmcnlly
Just to add...unless you make your own threads all your code executes in the UI thread. If you sleep or do a lot of computation in this thread the will experience a less responsive UI and eventually you'll get an Application Not Responding (ANR) box.
Will
+3  A: 

For games I would actually use a lower level access to graphics. The LunarLander from Google is an excellent example for that. Basically You need to do two things:

  • instead of View use SurfaceView
  • get handler from the SurfaceView
  • replace view.invalidate() with custom method repaint() that would contain

    private void repaint() {
      Canvas c = null;
      try {
        c = surfaceHolder.lockCanvas();
        paint(c);
      } finally {
        if (c != null) {
          surfaceHolder.unlockCanvasAndPost(c);
        }
      }
    }
    

Paint method will contain what You have in View.onDraw at the moment

JaanusSiim
I have done what you said. It works... sort of. The doors animate now but now the graphics glitch when I scroll around the screen. I have a gesturelistener in my game class which redraws the screen when the user scrolls with their finger. It allows you to scroll around the map. It use to draw fine. But now I get half the screen drawn and the other half has not updated for half a second before it corrects its self.
Using different view class does not solve this "issue". It is necessary to understand to NEVER EVER call sleep in the main thread and that invalidation does not trigger drawing immediately but rather "remembers" the regions that need redrawing the next time the UI thread gets a chance to do so.
Zordid
A: 

You may want to have a look at related discussion at http://stackoverflow.com/questions/2801877/android-why-wont-invalidate-update-my-buttons-immediately

MasterGaurav