Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pacman in Java questions

For my university assignment I have to make a networkable version of pacman. I thought I would best approach this problem with making a local copy of pacman first and then extend this functionality for network play.

I would have to say that I am relatively new to java GUI development and utilizing such features within java.

  • http://www.planetalia.com/cursos/Java-Invaders/
  • http://javaboutique.internet.com/PacMan/source.html

I have started following the above links with regards to game development within java and an example of the pacman game.

I decided to represent the maze as an int array with different values meaning different things. However when the paint method inside the main game loop is run i am redrawing the whole maze with this method.

    for (int i : theGame.getMaze())
    {
        if (i == 4)
        {
            g.setColor(mazeWallColour);
            g.fillRect(curX, curY, cellSize, cellSize);
            curX += 25;
        }
        else
        {
            curX += cellSize;
        }

        index++;


        // Move to new row
        if (index == 25)
        {
            index = 0;
            curX = 10;
            curY += cellSize;
        }
    }

However this is providing me with less then 1fps. Although i've noticed the example linked above uses a similar way of redrawing each time the paint method is called and i believe does this on a image that is not viewable (kinda like double buffering [I've used a BufferStrategy like the first link explains]) What would be a better way to redraw the maze?

Any pointers/advice with this would be useful.

Thank you for your time.

http://pastebin.com/m25052d5a - for the main game class.

Edit: I have just noticed something very weird happening after trying to see what code was taking so long to execute.

In the paintClear(Graphics g) method i have added

ocean = sprites.getSprite("oceano.gif");
g.setPaint(new TexturePaint(ocean, new Rectangle(0,t,ocean.getWidth(),ocean.getHeight())));
g.fillRect(10, 10,getWidth() - 20,getHeight() - 110);

which made the whole thing run smoothly - however when i removed these lines the whole thing slowed down? What could have caused this?

Updated code

like image 794
Malachi Avatar asked Jan 14 '09 23:01

Malachi


4 Answers

First off, I'd recommend that you use named constants rather than having random magic numbers in your code and consider using enums for your cell types. While it won't make your code run any faster, it certainly will make it easier to understand. Also, 'i' is normally used as a counter, not for a return value. You should probably call it cellType or something similar. I'd also recommend that you use a 2D array for your stage map since it makes a number of things easier, both logistically and conceptually.

That said, here are a few things to try:

Pull the setColor() out of the loop and do it once. The compiler might be able to do loop-invariant hoisting and thus do this for you (and probably will), but conceptually, you should probably do this anyway since it appears you want all of your walls to be one color anyway.

Try calling drawRect() instead of fillRect() and see if that draws faster. I don't think it will, but it is worth a shot, even if it looks uglier. Similarly, you can try creating an Image and then drawing that. This has the advantage that it is really easy to tell your Graphics object to implement a transform on your image. Also, consider taking this out completely and make sure that it is being a significant performance hit.

Also, normally you don't need to ask for the parent for its Graphics object and implement painting directly on it. Rather, you should override its paintComponent() method and just utilize the Graphics given to you (possibly calling helper methods as you do). Swing components are double-buffered by default, so you don't need to implement that yourself; just let the swing object do its job and let you know when to paint.

Also, you end up repainting the entire screen, which is something of overkill. If you call repaint(Rectangle), Swing can choose to redraw only the sections of your board that are explicitly marked dirty. When you update one of your sprites, call repaint(r) only on the area of the sprite's old and new locations. When you complete a level and need a new board, then you can call repaint() (without parameters) to redraw the entire map.

You should also look at Sun's tutorial to get some tips for efficiency in Swing.

like image 191
James Avatar answered Nov 20 '22 21:11

James


I still consider myself a beginner with Java, but I recently developed a Frogger-esque game with dynamic map and editor using some of the techniques you've mentioned, and I'm only too happy to provide some help.

As mentioned, enum's are the way to go. I set my map up as a 2-dimensional array and set an enum for each different type, writing a method inside my map class to take in one image and divide each square in the map to each value in my enum.

A tutorial that helped me with mapping can be found on Coke and Code. All the source code is there if you need a hand with any of it, although you do seem to have a decent grasp of what you're doing. If you still need help I could always drag out some source code.

like image 22
Mike B Avatar answered Nov 20 '22 20:11

Mike B


It looks like your call to Thread.sleep doesn't do what you intended, but I don't think it's the source of your trouble. You have:

Thread.sleep(Math.max(0, startTime - System.currentTimeMillis()));

startTime will always be less than System.currentTimeMillis(), so startTime - System.currentTimeMillis() will always be negative and thus your sleep will always be for 0 milliseconds. It's different from the example you showed because the example increments startTime by 40 milliseconds before doing the calculation. It is calculating how long to sleep for to pad out the drawing time to 40 milliseconds.

Anyway, back to your problem. I'd recommend measurement to figure out where your time is being spent. There's no point optimising until you know what's slow. You already know how to use System.currentTimeMillis(). Try using that to measure where all the time goes. Is it all spent drawing the walls?


EDIT - I see this got marked as accepted, so should I infer that the problem went away when you fixed the sleep time? I don't have a lot of Java GUI experience, but I can speculate that perhaps your code was starving out other important threads. By setting your thread to have maximum priority and only ever calling sleep(0), you pretty much guarantee that no other thread in your process can do anything. Here's a post from Raymond Chen's blog that explains why.

like image 3
Weeble Avatar answered Nov 20 '22 20:11

Weeble


The code you listed above can't be the source of the 1fps problem... I have code doing far more than this that runs far faster.

Can you benchmark that code and make sure it's the root of the problem?

like image 3
Allain Lalonde Avatar answered Nov 20 '22 19:11

Allain Lalonde