Archived

This topic is now archived and is closed to further replies.

[java] Java Star Map Help

This topic is 5158 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone, I didn''t realize that there was a special Java section of the forum! But I''m glad I finally found it Anyways, I am working on a rather ambitious and challenging (but hopefully, in the end, satisfying) space-strategy game. Unfortunately, I''m already having trouble with a major aspect of it - the star map. I was wondering if anyone here could be of any help. Here is what I want to implement: 1. The star map will (on the screen) be a 2-dimensional representation of a 3-dimensional virtual space. Right now, I''m thinking of using 2-d graphics with resizing (i.e. the "closer" they are, the bigger and brighter they appear on the screen). Is this a good path to follow, or is there a better way? 2. The map will be able to be rotated around the x and y axes. However, this poses two problems. First, how do I make all the stars stay visible if they are (in essence) rectangular components? Second, how do I ensure that the "closest" stars will overlap ones behind them, and not vice-versa? I''m thinking that maybe using the BufferedImage class will solve those problems, but I''m not sure. 3. The stars themselves will be components - that is, they will be able to respond to user-generated events (i.e. clicking the mouse). Does this mean I should have the Star class extend the (J)Component class? Or are BufferedImages components themselves? Any help on these issues will be greatly appreciated. Thanks, Rob

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Is this game real time? Using Swing/Java2D for a real time game is tough. AWT''s scaling mechanisms are not very fast and generate lots of dead objects. As an example I''m currently working on a paint program (a relatively lax program as far as requirements go), and getting it to scale an image beyond oh 300% in a way that was usable took a rather elaborate mechanism (but now I can scale to 5000% and paint away, I''m so happy )

Anyway, if this game is real time and you haven''t really started yet, you may want to stop and assess what your needs are and if AWT can handle them. There are other alternatives, almost all OpenGL based and significantly faster/more powerful.

BufferedImages are not components. If you want them to participate in Swing you need to create say a JPanel that paints the images onto themselves, and have the panel deal with the events and such.

As for problem two, what about giving all stars a z coordinate as well?

Share this post


Link to post
Share on other sites
Hey Tortoise,

Thanks for your reply. No, it''s not real-time; it''s going to be a turn-based space-strategy game. I agree that real-time would be much harder to implement, but I am actually more of a fan of turn-based games, so that is what I''m making Also, I have already given my Star class a variable for z-coordinate, but thanks for the suggestion.

In #2, I meant that if an instance of the Star class is represented graphically as a rectangular component with an image in it, other Stars could be hidden behind the Star''s corners (which is not realistic). Also, I would need to come up with a system whereby the program draws the Stars in closest-to-farthest order (in terms of z-coordinate/"depth").

Is there any way that I could make a Sprite class where things that are behind an object''s boundaries but not behind its painted area can still show up? Would this be a good idea to do for what I want?

What are the alternatives to AWT/Swing? I''m very interested in hearing about them.

Thanks,
Rob

Share this post


Link to post
Share on other sites
If you are using an image to represent the stars, then just use a gif with transparency enabled. If you are generating the star images yourself, then you have to look at ImageProducer and ColorModel to create an image with transparency.

If you are using JComponent for each star, then you need to use the method setOpaque() and set it to false.



First make it work,
then make it fast.

--Brian Kernighan

The problems of this world cannot possibly be solved by skeptics or cynics whose horizons are limited by the obvious realities. We need men and women who can dream of things that never were. - John Fitzgerald Kennedy(35th US President)

Do not interrupt your enemy when he is making a mistake. - Napolean Bonaparte

Share this post


Link to post
Share on other sites
Use BufferedImages, newer and better, one reason for their creation was to get rid of the producer/consumer model.


BufferedImage myImage = createBuffImage(width, height, transparent);

Graphics2D g2 = myImage.createGraphics();

Composite originalComp = g2.getComposite();

/*
* Normally transparent source does not overtake dest, with this
* composite set the src completely overtakes the destination
*/

AlphaComposite imageComposite = AlphaComposite.getInstance(AlphaComposite.SRC);

g2.setComposite(imageComposite);

// full transparency

g2.setColor(new Color(0,0,0,0));

g2.fillRect(0, 0, myImage.getWidth(), myImage.getHeight());

// myImage is now fully transparent


// restore standard method of drawing

g2.setComposite(originalComp);

// now fill in opaque areas as needed



I wouldn''t create a new composite each time, and all that, but just for demonstration.

If you want to create images that are compatible with your hardware and thus drawn as
quickly as possible, you need to get involved with the GraphicsConfiguration classes. Like...


BufferedImage createBuffImage(int w, int h, boolean transparent) {

// setup graphics config

GraphicsEnvironment genv =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = genv.getDefaultScreenDevice();

GraphicsConfiguration graphicsConfig = device.getDefaultConfiguration();

if (transparent) {
return graphicsConfig.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
} else {
return graphicsConfig.createCompatibleImage(w,h,Transparency.OPAQUE);
}
}


That will create what''s been dubbed a "managed" image, ie AWT will make it accelerated if possible, and it
will always be compatible with your hardware (like if your hardware expects BGR, this will give you BGR aligned
images and not RGB, which would mean the system would have to flip the bands around each time they are drawn,
really slowing things down).

Gifs work for premade images with transparency, but pngs offer full alpha possibilities. Both are easily loaded with one line
of code:

BufferedImage img = ImageIO.read(/* URL, File or InputStream to the image */);

Share this post


Link to post
Share on other sites
Thanks tortoise. I haven''t done much of the image stuff yet. It''s nice to know the better way of doing things.



First make it work,
then make it fast.

--Brian Kernighan

The problems of this world cannot possibly be solved by skeptics or cynics whose horizons are limited by the obvious realities. We need men and women who can dream of things that never were. - John Fitzgerald Kennedy(35th US President)

Do not interrupt your enemy when he is making a mistake. - Napolean Bonaparte

Share this post


Link to post
Share on other sites
Tortoise, CaptainJester, and Garazdawi, thanks for your replies. Right now what I''m thinking about doing is using gif images to represent my stars. How would I go about putting these images in the BufferedImages? Or would I?

Here is what I have so far:

Graphically speaking, each Star will be a transparent image loaded onto a JPanel.

Tortoise, would I include that image-loading line along with all the other BufferedImage code?

- Rob

Share this post


Link to post
Share on other sites
Unless the image on disks changes or something, you only want to load it once.

Somewhere in a constructor or some initialization code, load the image. ImageIO is a new class that was added to java 1.4 (you really want to be using 1.4+ if possible, a lot of these niceties are quite new). ImageIO does many things, but one thing it does easily is load gif, jpeg or png images. You can also register new image handlers with it that can load any kind of image you want.

Just do something like...


URL u = getClass().getClassLoader().getResource("images/mygif.gif");

try {
myImage = ImageIO.read(u);
} catch(IOException e) {
// handle error

}


By using the class loader, you can load images relative to the classpath, which means these images will be found in the same place no matter what the machine is.

read() is overloaded for URLs, Files and InputStreams, so you can get the image into ImageIO in just about any manner. You can just as easily write() images to disk too, ImageIO is awesome stuff.

That createBuffImage() method is a good thing to have. I always place it either in my main class or in the class that''s most logical (like if my program has a Renderer class), and make it static. Depending on the situation, using compatible/managed images can greatly increase performance, especially under Windows.

ImageIO does not return managed images. If performance is an issue, create blank managed images via createBuffImage() and then draw the image that ImageIO gave you into the blank image, flush() the ImageIO image, and use the new one, now it''s managed.

Share this post


Link to post
Share on other sites
Hey Tortoise,

Thanks again for your reply. Let''s say that I want to implement a system whereby the star image gets smaller as it moves away from the viewer (in terms of the virtual 3D space). Would it be faster to implement a transform or similar method on the BufferedImage than it would be to load multiple images at different times?

Also, I''ve been thinking about the best (i.e. fastest) way to make the stars respond to mouse clicks. Would loading the images onto JPanels be best, or is there a better alternative class?

Thanks,
Rob

Share this post


Link to post
Share on other sites
Since you will most likely have many stars at the same "depth" it will proabaly be a good idea to have a static number of pre-rendered images of stars at various depths. A concept of a "star" can just be a point in 3D space, when it comes time to render that 3D point, you can use the Z-Axis as a lookup to a static array (or vector) of images that contains the prerendered image for that size. Instead of one star image that gets referenced and trasnformed all the time by each star, you have 100 or so images of stars of various sizes that get passed to a paint function all the time. Cuts out a transform step. You can use your own program to-transform and render the images in all the various depths when your game starts.

Transparent JPanles are probably a bad way to just grab clicks. You can use the canvas you are painting on the grab the clicks, then use the current X,Y position of the player (camera) to find out if the x,y position of the mouse click instersects a "star". If you have a star at grid position 5,5 and the player or camera is still at 0,0, then a mouse click on the canvas at 5,5 means it hit a star. A basic loop through your stars sorted via the Z-Axis should determine if a click hit a star.

The only problem with that is foreshortening with 3D. As your mouse click travels into the canvas through 3D "space" it will gradully travel inwards until it hits the exact center of the canvas. Does that make sense? If your game is not going to deal with foreshortening (i.e. you can only click on starts that are above a certain z-axis) then this should matter too much. Then again, maybe you don''t have to do this sort of manipulation on your mouse clicks. I''d have to see a concept screen shot of something...

Share this post


Link to post
Share on other sites
Hey, Jim,

Have you ever seen/played the game Ascendancy? Its star map is pretty similar to the one I''d like to implement. Here''s a screen shot: http://www.logicfactory.com/games_ascendancy_screenshots.htm#.
Click on the picture at the bottom right.

- Rob

Share this post


Link to post
Share on other sites
I think you''re going about this the wrong way. Forget about JPanels and all of that stuff.

Have one image buffer that you write to, and handle mouse clicks on your own. It will make your code faster, and more portable if you do it this way.

To handle the foreground-background star issues, keep two buffers. Your regular image buffer, and a Z-buffer. Whenever you draw a planet / star to the video buffer, update the z-buffer by storing the depth (z coordinate) for each pixel in your sprite.

As far as scaling/zooming your stars, you can write a fast function to do this for you. you know how large your sprite is for a star/planet, so you can calculate a step-rate for drawing the scaled version.

ie:
float stepRate = spritWidth / drawWidth;

float spriteX = 0;
for ( i = 0 to drawWidth)
{
color = sprite.getpixel ( (int)spriteX, (int)spriteY);
screen.setPixel (x,y, color);
spriteX += steprate;
}

There are other tricks you could use to speed this up even more.

To handle mouse clicks of your stars / spaceships/ planets, and whatnot, you have many options.

You could calculate bounding boxes for each star, and check which box the mouse is in, OR, you could create a third buffer (like your Z buffer) where you will store and object ID instead of a depth or a color.

Whenever the user clicks on your image, check your object Buffer at the mouse X,Y to see what object ID is underneath of it. This is probably the most accurate way of handling clicking, although it does suck up a lot of memory.

If I were you I would avoid using as many Java classes as possible-- write as much as you can on your own. The end result will most likely be much cleaner and way more flexible. Remember that every time you instantiate a new object you''re throwing away speed.

Hope that this has been helpful,
Will

Share this post


Link to post
Share on other sites