Galaxy Defender: 2D Space Shooter

This is my first game.

This game is not entirely finished, Still have a few bugs here and there to fix and polish up the graphics a tad bit.

Would like feedback if at all possible, If you have suggestions please leave them in a comment and if anything is confusing please explain to me what it is and what I may be able to do to make it not so confusing.

Anyways hope you like what I have so far.

Download link
Galaxy Defender.msi

Screens:

http://img339.imageshack.us/img339/1015/gdscreen1.png

http://img243.imageshack.us/img243/3559/gdscreen2.png

The backgrounds are gorgeous and the ships are pretty too (although if they were slightly more photorealistic I think that would look better overall). But you should never distribute Java as MSI, for several reasons - 1 people don’t want to risk running an MSI, 2 you ruin the whole main purpose of Java (portability), 3 you are forcing a download and install, which is inherently a pain.

Please package this as an Applet (preferred) or Webstart.

Thanks, The backgrounds I got from google.

I have absolutely no clue on how to do webstart, I have looked at tutorials and what not but there are none that make any sense to me. mainly the accessing of resources from within jar files. I am also not fammiliar with HTML which i read in one of the tuts that you needed to make an HTML file or somethin.

the IDE that I use is eclipse though.

This is indeed non-obvious, so here we go:


public static InputStream getStream(String path)
{
   return Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
}

InputStream stream = getStream("some/directory/beautiful.png");

InputStream stream = getStream("some/directory/beautiful.png");

Do I need to put that line in wherever im getting an image at within my program?

this is how I am currently getting my background and using them.

Object  back1 = Toolkit.getDefaultToolkit().getImage("space.png");
	 Object back2 = Toolkit.getDefaultToolkit().getImage("space2.png");

I guess what im asking is, how can I set them to an Object so that I can later use them within my program using your code?

BufferedImage image = ImageIO.read(thatStream);

public static InputStream getStream(String path)
{
   return Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
}

Lastly do i need to make a new thread for this? or do I just put this method in my class and call it?

Sorry for being such a noob to this =P

It’s up to you, but… as you call yourself a n00b: don’t make a new thread

Ok then Ill make the Method and call it and see how that goes.
Gonna have to wait until im feeling better and can think straight. I believe I have the flu.

Thanks for all the help!

I’m surprised nobody said this yet, but it’s a good idea to put all that stuff in a resource manager class. Here is a very simple example:


import java.util.HashMap;
import java.awt.image.BufferedImage;
import java.awt.imageio.ImageIO;

public class ResourceManager
{
    private HashMap<String,BufferedImage> images;

    public void initialize()
    {
        images = new HashMap<String,BufferedImage>();
    }

    public BufferedImage getImage(String url)
    {
        BufferedImage image = images.get(url);

        if (image == null)
        {
            try
            {
                image = ImageIO.read(Thread.currentThread().getContextClassLoader().getResourceAsStream(url));
                images.put(url, image);
            }
            catch(Exception e)
            {
                System.err.println("Couldn't load resource: " + url);
                e.printStackTrace();
            }
        }

        return image;
    }
}

That way each image only gets loaded once. Probably you’d want some sort of preloading in there and all that, but the idea is that generally you don’t want to directly load resources from within your code. Let some kind of manager deal with that. By the way, I make no guarantee that my syntax is right or anything else in that code, I have been coding in NotJava™ so much lately that my head isn’t really in that space at the moment. Also you need to decide what you want your code to do when it gets a null resource (couldn’t be loaded), which obviously depends greatly on where your resource is coming from (a local JAR, the web, a server, the filesystem, etc.), as well as personal taste. Typically I will preload a very small “ERROR” image in the initialize() function and then return that if no resource could be loaded.

Ah thanks, I think Ill try this out if I run into any issues ill leave a post. hopefully I wont =)

Okay. so say I have an image called Craft.png. How would I load that image using your ResourceManager code? or does it load all of my images? im just sorta confused on how I am supposed to use it. Could you maybe post an example?

Sure. This first snippet is a case when you are creating a new BufferedImage for every single object you make. Each object has their own image, and the image is loaded upon construction. This is the most obvious way to do things and is pretty much how you seem to be doing it.


public class Ship
{
    private int x, y, width, height;
    private BufferedImage image;

    public Ship(int xPos, int yPos, int wid, int hi, String imageLoc)
    {
        x = xPos;
        y = yPos;
        width = wi;
        height = hi;
        try {image = ImageIO.read(imageLoc); } catch (Exception e) {e.printStackTrace();}
    }

    public void draw(Graphics  g)
    {
        g.drawImage(image, x, y, width, height, null);
    }
}

The second snippet is almost exactly the same but uses the ResourceManager. Every object has a key that points to an image loaded within the ResourceManager, which will only be loaded the first time you call it. In addition, having only one instance of that image is much much easier on your memory.


public class Ship
{
    private int x, y, width, height;
    private String image;

    public Ship(int xPos, int yPos, int wid, int hi, String imageLoc)
    {
        x = xPos;
        y = yPos;
        width = wi;
        height = hi;
        image = imageLoc;
    }

    public void draw(Graphics  g)
    {
        g.drawImage(ResourceManager.getImage(image), x, y, width, height, null);
    }
}

See the difference? Typically you want to preload every image, by the way, I just didn’t include it in the code because it’s simple to do and would be up to you when you want to do it.

Yes I think I understand now. Thanks for the help.

Ok so I tried to implement your resource manager code in and I seem to get an error.

this is how im using it from what I understand after reading your posts


BufferedImage back1 = ResourceManager.getImage("space.png");

and then I get this error here.


Exception in thread "main" java.lang.NullPointerException
	at ResourceManager.getImage(ResourceManager.java:17)
	at Board.<init>(Board.java:160)
	at ExecuteGame.<init>(ExecuteGame.java:22)
	at ExecuteGame.main(ExecuteGame.java:39)

That points to the code I got from you here

import java.util.HashMap;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;

public class ResourceManager
{
    private static HashMap<String,BufferedImage> images;

    public void initialize()
    {
        images = new HashMap<String,BufferedImage>();
    }

    public static BufferedImage getImage(String url)
    {
        BufferedImage image = images.get(url);

        if (image == null)
        {
            try
            {
                image = ImageIO.read(Thread.currentThread().getContextClassLoader().getResourceAsStream(url));
                images.put(url, image);
            }
            catch(Exception e)
            {
                System.err.println("Couldn't load resource: " + url);
                e.printStackTrace();
            }
        }

        return image;
    }
}

What I was trying to do was set my BufferedImage object to an Image from within my Jar file but I seem to be grasping this concept wrong yet again =(

Change

    public void initialize()
    {
        images = new HashMap<String,BufferedImage>();
    }

To:

    static
    {
        images = new HashMap<String,BufferedImage>();
    }

Ty so much it works now like a charm. May I ask though what changing that to just static does exactly?

Also how could I change this line of code so that it can get a sound file from my jar? my sound files are in .wav format if it matters.

image = ImageIO.read(Thread.currentThread().getContextClassLoader().getResourceAsStream(url));

It should have been public static void intialize() for one thing. What Riven’s code does is initialize the images map once the class ResourceManager loads, automatically. What I put into the initialize() function creates the images map when you tell the ResourceManager to initialize. So typically somewhere in your program (before you try to use the ResouceManager) and in some logical place (somewhere you want to be loading things) you would call ResourceManager.initialize();.

Basically Riven’s is automatic but you have no control over when it happens, whereas doing it in initialize() happens when you want it to.

The reason you got a NullPointerException before is because you never created the images map in the first place. Any time you try to call an Object that hasn’t been instantiated (i.e. “new” hasn’t been called on it) you’ll get that exception. Because the images map was never instantiated, (it gets instantiated in initialize) it’s null. Therefore, NullPointerException.

To make it a sound file is a whole other can of worms. There are a lot of possible ways to load sounds, all with different advantages. I’d make a separate post in the sound forum asking for advice. Then once you know how you’re going to store/load sounds, you can use the same basic idea (a HashMap) to have your sounds working.

Ok, I’ll post a new topic sometime in the future if when I get to that point if one isn’t already posted over it.
Thanks again for clearing that up. :slight_smile:

Ok so I seemed to have run into a problem, When using the resource manager to pull the images out of the jar it just freezes the game up. But when I put that same jar using the resource manager into a folder that has all the images in it. (So that the jar is next to all my image files) it works just fine.

Any hint to what could be wrong?

This is an example of how Im getting the images and storing them to buffered images in my code.

	private void LoadResources()
	{
		// TODO Auto-generated method stub
		
		 ResourceManager.initialize();
		 //Create Objects of all my images. 
		 bubShield = ResourceManager.getImage("bubbledrop.gif");
		 back1 = ResourceManager.getImage("space.png");
		 back2 = ResourceManager.getImage("space2.png");
		 back3 = ResourceManager.getImage("space3.png");
		 back4 = ResourceManager.getImage("space4.jpg");
		 back5 = ResourceManager.getImage("space5.jpg");
		 back6 = ResourceManager.getImage("space6.jpg");
		 back7 = ResourceManager.getImage("space7.png");
		 back8 = ResourceManager.getImage("space8.png");
		 back9 = ResourceManager.getImage("space9.png");
		 back10 = ResourceManager.getImage("space10.png");
	}