views:

233

answers:

1

Hi

I'm working on a project for university which is essentially a re-working of the Space Invaders game with the rules changed a bit. So far I've got a main JFrame, containing a subclass of JPanel (for the background image) which contains another subclass of JPanel which I'm using for the sprites. However, when I run it the JFrame and the background JPanel work fine but then when I draw the sprite it just generates a grey square, for which I can't change the size or position. Here's the code I've got for my Sprite class:

import java.awt.*;
import java.io.File;
import javax.swing.*;


public class Sprite extends JPanel
{
Image spriteImage;
int speedX;
int speedY;
Point pos;
final boolean MV_LEFT = false;
final boolean MV_RIGHT = true;

public Sprite(File _imageFile)
{
 try {
  spriteImage = javax.imageio.ImageIO.read(_imageFile);
 } catch (Exception e) {
  /* handled in paintComponent() */
 }
 speedX = 1;
 speedY = 1;
 pos = new Point(100,100);
}

@Override
protected void paintComponent(Graphics g)
{
 super.paintComponent(g);
 if (spriteImage != null)
  g.drawImage(this.spriteImage, this.pos.x, this.pos.y, this.getWidth(), this.getHeight(), this);
}

public void move(boolean direction)
{
 if (direction == true)
 {
  this.pos = new Point((pos.x + speedX), pos.y);
  repaint();
 }
 else
 {
  this.pos = new Point((pos.x - speedX), pos.y);
  repaint();
 }
}
}

I'm sure there are a few things wrong in there, but for the paintComponent() method I just parroted all of the image handling tutorials I found around the internet and it still doesn't seem to work. Is there something huge I'm forgetting?

Thanks

Ben

+2  A: 

One problem I see with the paintComponent() method is the location where you're drawing the image. My understanding is that each sprite in your game is a separate JPanel. The Graphics object (g) being passed in the paintComponent method is, therefore, different for each Sprite. You can imagine a Graphics object as a painting canvas. If you only had 1 Graphics object for the entire game, and this graphics object represented the entire game window, then your logic would be correct and everything should work.

However, each Sprite here has its own graphics object, presumably with height and width relevant to the sprite. In this case, your paintComponent method would probably just look like:

public void paintComponent(Graphics g)
{
    if (spriteImage != null)
        g.drawImage(this.spriteImage, 0, 0, getWidth(), getHeight(); // always at (0,0)
}

Why? Because with your design, you're moving the Sprite, AND it's Graphics object, around the game window! The coordinates you pass to drawImage() are relative to the Graphics object; you always want to start painting in the upper-left hand corner, (0,0), of the Sprite. You're getting just a gray square because you're trying to draw the image way out of bounds of the Graphics object.

In the long run, I don't think this approach is going to work because it's not that easy to move JPanels around inside of their parent containers (unless you're using absolute positioning). It's not really scalable either because JPanels are pretty heavyweight and take a lot of resources to create and display.

You are probably better of having a single JPanel that represents the entire game area. Each Sprite wouldn't be a subclass of JPanel, so you don't have a paintComponent method. You could do something like this:

public class GameArea extends JPanel
{
    private final Collection<Sprite> sprites; // sprites to draw

    public void paintComponent(Graphics g)
    {
        for(Sprite sprite : sprites)
        {
            sprite.drawOnSurface(g);
        }
    }
}

public class Sprite // no need to extend anything
{
    /* Your other code looks OK */

    public void drawOnSurface(Graphics surface)
    {
        surface.drawImage(image, x, y, getWidth(), getHeight());
    }
}
Outlaw Programmer