I wanted to create Conway's Game of Life. I read the Java 2d API, but the Graphics class only provides methods to drawRect() and fillRect() on the paintComponent of a JPanel. I mean that the rectangles cannot be handled individually as objects i.e. so that i can check which one is on in relation to the ones in the vicinity.
So I wanted to ask how are squares to be made so that they can be handled individually and the grid be created dynamically?
Create a Sqaure class with all properties required.
Create a list of Square objects representing the board.
In the draw method for the JPanel, iterate over your list of Square objects, drawing each one out, based on its properties.
Keep your display code separate from your logic as much as possible - it's nearly always a good idea.
I'd like to propose a completely different solution. Normally have to treat the generated graphics as output-only, meaning, you don't want to read state from the graphics because that'd be too slow.
You'll have to keep the state of the cells elsewhere, like in a two-dimensional array.
boolean[][] or int[][] for example.
Then you'll need a "render" method of sorts, that takes the values of your cells, and draws it out.
But I'd like to propose an even cooler way of doing this. Instead of keeping a two dimensional array, use the (one dimensional) array that a BufferedImage is made up of.
Normally, each "pixel" is an element in that array. Then you use drawImage to draw that image, and scale that image up. This could perform really well. You might be able to have an entire screen draw in real time pretty much.
There are various methods on BufferedImage, it gets a little confusing at first. In the end you'll find a DataBuffer somewhere. You'll want access to the int[].
Then, to set a cell: data[y * width + x] = -1; (white cell)
to clear a cell: data[y * width + x] = 0; (black cell)
(for example - or vice versa - or any other color).
You can get really fancy with this. You could use various offset variables instead of having to calculate the y*width+x all the time, and optimize it really well.
In fact, I go as far as being able to make it so efficient, that you could actually outperform another guy making the exact same program in C++.
Related
I want to know what I should use for 2-dimensional positions for a Sprite.
I see Dimension objects referring to size, mainly around GUI components.
I was thinking about doing int[2], but it could easily be sabotaged by inserting in an empty array or one with the incorrect number of elements.
I only see Point objects around Mouse positions, so I don't know if it has the same purpose as what I'm looking for.
I have no idea what to choose for my purpose.
I'm having quite a bit of difficulty wrapping my head around the actual display side of things with libgdx. That is, it just seems fairly jumbled in terms of what needs to be done in order to actually put something up onto the screen. I guess my confusion can sort of be separated into two parts:
What exactly needs to be done in terms of creating an image? There's
Texture, TextureRegion, TextureAtlas, Sprite, Batch, and probably a
few other art related assets that I'm missing. How do these all
relate and tie into each other? What's the "production chain" among
these I guess would be a way of putting it.
In terms of putting
whatever is created from the stuff above onto the monitor or
display, how do the different coordinate and sizing measures relate
and translate to and from each other? Say there's some image X that
I want to put on the screen. IT's got it's own set of dimensions and
coordinates, but then there's also a viewport size (is there a
viewport position?) and a camera position (is there a camera size?).
On top of all that, there's also the overall dispaly size that's
from Gdx.graphics. A few examples of things I might want to do could
be as follow:
X is my "global map" that is bigger than my screen
size. I want to be able to scroll/pan across it. What are the
coordinates/positions I should use when displaying it?
Y is bigger
than my screen size. I want to scale it down and have it always be
in the center of the screen/display. What scaling factor do I use
here, and which coordinates/positions?
Z is smaller than my screen
size. I want to stick it in the upper left corner of my screen and
have it "stick" to the global map I mentioned earlier. Which
positioning system do I use?
Sorry if that was a bunch of stuff... I guess the tl;dr of that second part is just which set of positions/coordinates, sizes, and scales am I supposed to do everything in terms of?
I know this might be a lot to ask at once, and I also know that most of this stuff can be found online, but after sifting through tutorial after tutorial, I can't seem to get a straight answer as to how these things all relate to each other. Any help would be appreciated.
Texture is essentially the raw image data.
TextureRegion allows you to grab smaller areas from a larger texture. For example, it is common practice to pack all of the images for your game/app into a single large texture (the LibGDX “TexturePacker” is a separate program that does this) and then use regions of the larger texture for your individual graphics. This is done because switching textures is a heavy and slow operation and you want to minimize this process.
When you pack your images into a single large image with the TexturePacker it creates a “.atlas” file which stores the names and locations of your individual images. TextureAtlas allows you to load the .atlas file and then extract your original images to use in your program.
Sprite adds position and color capabilities to the texture. Notice that the Texture API has no methods for setting/getting position or color. Sprites will be your characters and other objects that you can actually move around and position on the screen.
Batch/SpriteBatch is an efficient way of drawing multiple sprites to the screen. Instead of making drawing calls for each sprite one at a time the Batch does multiple drawing calls at once.
And hopefully I’m not adding to the confusion, but another I option I really like is using the “Actor” and “Stage” classes over the “Sprite” and “SpriteBatch” classes. Actor is similar to Sprite but adds additional functionality for moving/animating, via the act method. The Stage replaces the SpriteBatch as it uses its own internal SpriteBatch so you do not need to use the SpriteBatch explicitly.
There is also an entire set of UI components (table, button, textfield, slider, progress bar, etc) which are all based off of Actor and work with the Stage.
I can’t really help with question 2. I stick to UI-based apps, so I don’t know the best practices for working with large game worlds. But hopefully someone more knowledgeable in that area can help you with that.
This was to long to reply as a comment so I’m responding as another answer...
I think both Sprite/SpriteBatch and Actor/Stage are equally powerful as you can still animate and move with Sprite/SpriteBatch, but Actor/Stage is easier to work with. The stage has two methods called “act” and “draw” which allows the stage to update and draw every actor it contains very easily. You override the act method for each of your actors to specify what kind of action you want it to do. Look up a few different tutorials for Stage/Actor with sample code and it should become clear how to use it.
Also, I was slightly incorrect before that “Actor” is equivalent to Sprite, because Sprite includes a texture, but Actor by itself does not have any kind of graphical component. There is an extension of Actor called “Image” that includes a Drawable, so the Image class is actually the equivalent to Sprite. Actor is the base class that provides the methods for acting (or “updating”), but it doesn’t have to be graphical. I've used Actors for other purposes such as triggering audio sounds at specific times.
Atlas creates the large Texture containing all of your png files and then allows you to get regions from it for individual png's. So the pipeline for getting a specific png graphic would be Atlas > Region > Sprite/Image. Both Image and Sprite classes have constructors that take a region.
I have a graphics application in JAVA, which is made up of many different shapes (lines, circles, arcs, etc, which are drawn via the Graphics.drawLine(), drawArc()... methods). I would like to create mouse-over events on many, if not all of the drawn objects.
What I was thinking was to store some sort of bitmap with metadata in it, and use that to figure out which object the mouse is over. Is there a way to do this in Java? (looping through all the objects per mouse move doesn't seem viable).
Thanks,
John
Key-color solution
(moved from comment)
Create an off-screen graphics buffer (like BufferedImage), same size as subject image.
Draw all objects into this buffer. Each object with one own color. Depending on object count you can optimize image buffer: For example use 8-bit graphics.
Read resulting image buffer by pixel (example Java - get pixel array from image). Determine pixel color at current mouse position, and map color index (or RGB value) to the source object.
Pros:
The solution is "pixel-accurate": Object boundaries are exact - pixel to pixel.
Easy to solve overlapping objects problem. Just draw them at the desired order.
Object complexity is not limited. Theoretically bitmaps are also possible.
Cons:
To move one object, the complete off-screen buffer must be repainted
Number of objects can be limited when using low-bit image buffer
It depends on your specifications. You do not mention if those shapes are allowed to overlap, to move, how many of them can exist etc.
Solution a) The easiest approach that comes to mind is to implement each shape as a JComponent descedant (e.g. JPanel). So you would have a CirclePanel, an ArcPanel etc that extend JPanel and each one of them paints itself in the same way it is being done now.
Having the shapes as a JComponent allows you to add a MouseListener to each panel that would then handle the mouseEntered(), mouseExited() events.
Solution b) If on the other hand you need to draw all the shapes on a single component's area (as I understand is the case now) then you still do not need to iterate over all the shapes. You just need to introduce an algorithm to categorize the shapes based on their position, to be able to exclude them fast inside your "isMouseOver(Shape s)" test procedure.
For example lets say you divide the area to 2 equal sub-areas left and right (let's call them tiles). When you create each shape you test which tile they intersect to, and you store this information both in the shape and in the corresponding tile.
Now when you need to test if the mouse is over a shape, you decide which tile the mouse is over. This way you only have to check shapes that intersect either the left or the right tile. Assuming that your shapes are distributed uniformly on the screen, you have just rejected 50% of the shapes with one test.
Depending on how many shapes you have, you could use 4 or 8 tiles, or you could even create/delete tiles dynamically (e.g. based on how many objects tend to gather in one area of the screen or not).
I would suggest to try the first solution because it is easier and a cleaner approach. If you decide that it does not fit your needs, you could then go for an approach similar to the second one.
I have an array that holds the names and then displays the appropriate graphics using:
public void paintComponent(Graphics g){
for(int i = 0; i<20; i++)
{
for(int j = 0; j<20; j++)
{
if(testMap.getData(i+(rowX-7), j+(columnY-7)).indexOf("rock") >= 0)
{
g.drawImage(image3, j*50 + 5*add, i*50 + 5*add2, 50, 50, this);
}
}
}
This works well displaying the actual graphics of my game. However, for my minimap, I do the same thing, with different values and increased numbers in the 'i' and 'j' in the for loop. This creates a smaller version of the map with a bigger scope, which leaves me with this. (Note, I only included one of the drawImage() methods, I removed the rest here to make the code more readable):
This is pretty much my desired effect (aside from the positioning, which I can change easily), however, this only shows a smaller version of what I already see on the screen. Any larger than about 20 x20, though, and the game begins to lag heavily -- probably something to do with the terrible way that I coded it.
I have tried replacing the images with squares using fillRect, but it does not help the issue.
Here is the code of my main class if anybody would like to take a look: http://pastebin.com/eEQWs2DS
The for loop within the paintComponent method begins at around line 3160, the loop for the main display is around 2678. I set up the Jframe at around 1260.
So, with all that said, basically my question is this:
Is there a better, more efficient way to create my minimap? My idea was to generate an image at the beginning of the program so that the game wouldn't have to recalculate every time the frame refreshes. I could create the map in advance, but I would have to manually update that every time I changed the map, which is definitely a hassle. I am having trouble researching how to do the former. My other idea is to slow the refresh rate of the minimap only, but I also do not know how to do that.
Other than that, if there are any simple fixes to the lag issue, please enlighten me. I apologize for the very, very messy code -- This is my first time programming anything with a display so I sort of just...hacked at it until it worked.
I don't know how easy this would be with your implementation, but instead of drawing an image, perhaps you could draw a square of a certain color based on what type of tile it should be?
For instance if you're looping through your list of tiles and you find a grass tile, you would first draw the grass tile at its proper location, then draw a smaller green square on the minimap.
The downside to this is that first you'd have to define what colors to use for the tiles, or perhaps when you load the tiles you can compute an average color for each one, and then just use that. Another issue is that the houses may not translate well on to the minimap, since the tiles have much more detail. You could draw some kind of house icon on the minimap instead of actually drawing any of the house tiles, though.
Basically, you want to use simpler representations of the objects in your map on the minimap, since it's smaller and less detail can be drawn anyway.
Have a look at how I do it in Tyrant (a Java roguelike):
https://github.com/mikera/tyrant/blob/master/src/main/java/mikera/tyrant/LevelMapPanel.java
Key tricks:
Use an offscreen BufferedImage. Cache this to avoid recreating it each time you paint.
Use an int[] array to setup up a single colour for each tile
Use setRGB with the array to draw all the map at once
Draw the mini-map at x2 zoom to get 2x2 pixel blocks for each tile.
If you want to be even more efficient, keep a changed flag and only update the mini-map BufferedImage when something visible on the mini-map changes. I didn't think it was worth it as the above is already very efficient, but YMMV.
For the sake of argument, let's say I want to place a wall object (for simplicity, let's pretend it's just a 1x1 square) on a 2d grid which is 20x20. Let's say I have the object modeled out in coordinates between 0 and 1.
So, my question is, using openGL in the correct manner (I realize there are plenty of ways I could change the coordinates manually, but that doesn't edify me for the future), how do I place this object on the grid in the location (5,5)? Would it be related to the model matrix?
Yes, I think you have the right idea.
If your wall exists in model space from (0,0) to (1,1), and you want to position a particular instance of this wall at (5,5) through (6,6), than an appropriate thing to do would be to draw this wall with a Model Matrix that is translated by 5 units in the x and y direction.
You should not use the transformation matrices to place single primitives. Everytime you change a uniform (aka matrix) it's very likely the rasterizer pipline must be flushed, which is a sure performance killer.
As a general rule, to be efficient, a given transformation matrix should be applied to at least 100 primitives within a scene. So if you have some grid of tiles, it's better to either duplicate-translate them into a larger Vertex Array, or use instancing (if available).