Java LibGDX drawing multiple shapes each with unique renderers - java

I'm creating a game with LibGDX using JAVA and I've hit a problem I can't solve even after a week's worth of trying. I have shapes being drawn with the ShapeRenderer class, and I have multiple classes and methods interacting with each other. A shape grows on the screen and when the user clicks the screen, the shape stops growing and the second shape begins to grow.
I have an array of ShapeRenderer's and Polygon's and I must draw each shape with a different ShapeRenderer and different Polygon. For example a triangle must be rendered using ShapeRenderer[1] and Polygon[1]. The next triangle on that level must be drawn with ShapeRenderer[2] and Polygon[2]. This is to avoid clashing values and rotations when drawing Polygons on the same ShapeRenderer.
My particular problem is one method I created, "DrawStar" is given a number (starts with 1 representing the first star) and draws that star using ShapeRenderer[1] and Polygon[1]. This means the first star is being drawn then when I click the screen, IDEALLY, the first star should stop growing and the second star should begin to be rendered with ShapeRenderer[2] and Polygon[2].
Here's the problem: Let's say this particular level has been written so that 2 stars are going to grow. The method "DrawStar" will be given the number "1" and draw the first star as it grows, then the method "DrawStar" is given the number "2" and it draws the second star (this isn't visually a problem yet since the star's polygon starts with values of 0 and doesn't increase until the second click so even if it is being drawn it's not visible) and it continues to draw the two stars simultaneously, it basically draws all the stars for that level one after the other i.e. DrawShape(1) then DrawShape(2) then DrawShape(1) then DrawShape(2) etc.
This is my code:
public void drawFiveStar(FiveStar star, int num) {
shapeRenderer[num].begin(ShapeType.Line);
shapeRenderer[num].setColor(Color.RED);
poly[num].setVertices(star.verticiesStar);
poly[num].rotate(1);
poly[num].setOrigin(star.originX, star.originY);
shapeRenderer[num].polygon(poly[num].getTransformedVertices());
shapeRenderer[num].end();
}
Star represents the star object passed through and num represents the shape number to draw, as explained in the above example with ShapeRenderer[1] and Polygon[1]. The problem is it will DrawFiveStar(Star1, 1), DrawFiveStar(Star1, 2), DrawFiveStar(Star1, 1), DrawFiveStar(Star1, 2).... UNTIL I click the mouse button and it moves onto the next star object DrawFiveStar(Star2, 1), DrawFiveStar(Star2, 2), DrawFiveStar(Star2, 1), DrawFiveStar(Star2, 2)....
The problem with the code above is that the whole point of using a ShapeRenderer array is so that for the second shape, a new, fresh ShapeRenderer is used. This code has it so that the first star object will use both ShapeRenderers and by the time I click to prompt the second star object to grow, both ShapeRenderers have been used to draw the first star object. Ideally it should be only the first ShapeRenderer used to draw the first star object and then when the second object begins to grow that is drawn with the second ShapeRenderer. I tried many solutions none of which produced the desired results of the ideal solution I just described.
It's a programming problem that I can't figure out because the code needs to be dynamic so that if it were 3 or 100 shapes the code would still use a different ShapeRenderer for each star object. Again, this is because drawing multiple shapes on one ShapeRenderer object and rotating them leads to really strange results with shapes flying everywhere, drawing multiple rotating shapes on separate ShapeRenderer objects solves this problem. That is what I'm trying to achieve here.
Read Level > See there are 2 shapes to be drawn > Use 2 shape renderers to draw these 2 shapes

It's kind of unclear what your issue is, but I'm guessing that you are conflating two different ideas into the num variable that is passed in, so it's not doing what you want.
Is num the shape renderer index you want to use, or is it the shape instance you want to draw? If these are distinct, you need to pass two different int values to your method, and use them appropriately.
That said, if you think you need more than one ShapeRenderer, you must be using it incorrectly. It is a very flexible class and should have no problems with drawing multiple types of shapes in the desired locations. Figure out what you're doing wrong and fix it, so you will only need one. A ShapeRenderer is kind of a heavy object. Each instance has a large backing array, has a mesh stored on the GPU, and loads a ShaderProgram. You definitely do not want to load 100 identical shaders to draw 100 shapes.

If using a single ShapeRenderer creates problems, maybe you are changing the transformation matrix, for example by using translations and rotations? In this case you need to save the original matrix first and restore it after the transformations.
Example
shapeRenderer.begin(ShapeType.Filled);
for(Shape shape: shapes)
{
Matrix4 tf = shapeRenderer.getTransformMatrix().cpy();
shapeRenderer.translate([...]);
shapeRenderer.rotate([...];
// ... create your shape ...
shapeRenderer.setTransformMatrix(tf);
}
shapeRenderer.end();

Related

How to draw the area around a shape

I worked on a very simple map editor phase for a game in java. The goal is to put some islands with different shape on the map. But there is some constraints:
islands must not be a specific distance far from another island (lets call it L)
islands must not be a specific distance close from another island (lets call it S)
In the game, the island is place with the mouse. The gamer can see areas where the island can be place or not as you can see.
My problem is that I realize my disalow area is not good. For example, the rectangle island have a rectangle disallow area (my first naive attempt) but in fact I must draw area of S around the rectangle ; that leads to a shape like this:
I'm able to draw these kind of areas as long as my shapes are just composed of lines. But my island can have cubic or quadratic curve (and even though i'll need this kind of area for other shapes later).
The closer I manage to do is that:
In this case, the disallow area around the circle must be ... a circle (simple geometry). But as you can see, I have a weird rounded rectangle.
I currently try to transform each segment of the pathiterator of a Shape to get the area. It's not as simple as scaling a shape (remember the rectangle case). I've allready try many ways to transform the shape and get the area.
Question:
Does someone have information, formula, clues, algorithms, libs to get this area from any java.awt.Shape (or PathIterator) and a distance?
http://www.java2s.com/example/java/java.lang/expand-or-shrink-a-shape-in-all-directions-by-a-defined-offset.html
This site describe how to use stroke to get the offset area.
There is just a single modification to solve my problem ; I have to use BasicStroke.JOIN_ROUND to get the good rectangular Shape.
Then I get:

defining regions in bitmap (java)

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.

Java: drawing nonoverlapping shapes randomly within area

I need to draw some graphics objects on a JPanel in a JApplet, they are Graphics2D objects.
Here is some visual help
1) I would like to draw circles near the boundaries of the panel at random coordinates so that every time the applet is started it looks different.
I would like in some way to say that exclude this part, don't draw there - blue circle in image.
2) Would be nice if I could evenly distribute them so that if there are 4 circles, then the distance between the circles is almost the same, but still random to some amount.
3) If the first 3 or 4 circles are drawn then draw the other smaller and random sized circles are drawn all over the panel that isn't used.
It seems like a strange idea but would it be possible to make an algorithm that gives you the centre coordinates based on some constraints like
(x-100)^2 + (y-100)^2 >200 && 0< x <400 && 0< y < 400
Now I do it like this:
divide the whole area into a grid where every slot in the gird is free or taken and inside that slot draw the circles at random coordinates, but still within that slot.
That idea doesn't look so good and I would like to do it better.
I'm implementing this in java but general ideas are also welcome.
If you have only circles, the "not overlapping" test is easy: Two circles are not overlapping if and only if the distance of there centers is bigger than the sum of their radiuses (for equality they are touching). For overlapping the border: the distance from the border must be bigger than the radius.
So, you could simply go on and generate random coordinates (either with fixed or random radiuses), then check if any are overlapping. If yes, either start again, or throw away only the overlapping ones and go on.
If you have not too many circles, this simple algorithm is enough. If it starts taking too long, you might think about using some spatial data structure, so you will only have to check the circles near to your new point.
You may want to create the list of circles to paint not inside of the paintComponent method, but instead in the init() or start() method (or some thread called from there), so the painting will not take too long, and the circles will not change for every (maybe even partial) repaint.

Painting Program

I'm writing a simple painting program. To simulate a pencil drawing, I've stored the drawn points in a set, so when the window is resized the points won't be gone, and whenever another point is added I call the repaint method (the paint method draws all paints in the array on screen). But when the number of points increases, the program runs slowly.
Is there a more efficient method to do this?
The fastest way to get constant-speed repainting is to store the entire image that's drawn as a bitmap, and of course update it when the user draws. This way, you can redraw the right thing, and even add scrollbars and the like if you want. You can keep the array of points for an "undo" feature, for example.
If instead you want to make a vector-drawing program, then you have to keep the individual primitive operations (such as line, rectangles, etc). In that case it still pays off to keep an image for fast repainting, and now the trick becomes how to efficiently update that image when the user modifies the drawing (e.g. by resizing a rectangle). One way to do that is to tile the drawing area into lots of smaller ones, so you only need to recompute the underlying image for the parts that intersect with the object being modified by the user.
In both techniques, you'd use double-buffering just so that the user doesn't perceive flicker. But with double-buffering alone, the "redraw the whole set of points" would still be slow.
Since you haven't give any code, I am guessing that you are using primitive drawing methods (like draw a line or point).
A good option would be to use the Double Buffering technique to do the painting.
Look up GeneralPath.
What you can do is create a Shape class, that'll vary according to what you are going to draw (Rectangle, Triangle, Point, Line, etc.). You should do this even though now you're only drawing points.
When you create your Shape have code that checks what Shape to create, something like a switch/case statement:
...
case PENCIL:
if (generalPath == null) {
generalPath = new GeneralPath();
generalPath.moveTo(p1.x, p1.y);
} else {
generalPath.lineTo(p2.x, p2.y);
}
shape = generalPath;
break;
...
In the code that draws, simply call repaint and the Shape will be drawn.

Pacman maze in Java

So I'm building the pacman game in Java to teach myself game programming.
I have the basic game window with the pacman sprite and the ghost sprites drawn, the pacman moves with the arrow keys, doesn't move beyond the walls of the window, etc. Now I'm trying to build the maze, as in this picture:
Without giving me the direct/complete solution to this, can someone guide me as to how this can be built? I'm talking only about the boundaries and the pipes('T' marks) here which you can't go through and you have to go around. Not the dots which the pacman eats yet.
Here are my questions:
1) What's the most efficient algorithm/method for creating this maze? Will it have to be drawn each time the paint() method is called or is there a way to draw it only at the start of the game and never again?
2) How will this actually be drawn to the screen? I assume the fillRect() will be used?
3) Any hints on collision detection (so the pacman/ghosts can't go through the walls) would be helpful.
4) Any hints on how the vacant space between the pipes will be calculated so the dots can be filled between them will also be very helpful.
Thanks
I wouldn't do it that way.
I'd draw the graphical map and then create a 2D data array which represents the map. The data map would be responsible for determining collisions, eating dots, where candy is and where the ghosts are. Once all the logic for everything is handled just use the 2D array to display everything in their proper pixel coordinates over the graphical map.
For example the user is pressing the left key. First you determine that pacman is at element 3, 3. Element 3, 2 contains information denoting a wall so you can implement the code to make him ignore the command.
EDIT:
Each element would represent about where a dot could be. For example:
No, looking at the board I would say the array would look something like this.
d,d,d,d,d,d,d,d,d,d,d,d,w,w,d,d,d,d,d,d,d,d,d,d,d,d
d,w,w,w,w,d,w,w,w,w,w,d,w,w,d,w,w,w,w,w,d,w,w,w,w,d
p,w,w,w,w,d,w,w,w,w,w,d,w,w,d,w,w,w,w,w,d,w,w,w,w,p
d,w,w,w,w,d,w,w,w,w,w,d,w,w,d,w,w,w,w,w,d,w,w,w,w,d
d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
And so on. You might want to pick a more flexible data structure than just characters however since some areas need to contain a bunch of different information. IE even though the ghost spawning area is blank, pacman isn't allowed in there. The movement of the ghosts and pacman is different for the side escapes, the candy spawn point is a blank spot but if you want to remain flexible you'll want to denote where this is on a per map basis.
Another thing you'll want to remember is that pacman and the ghosts are often inbetween points so containing information that represents a percentage of a space they're taking up between 1,2 and 1,3 is important for collision detection as well as determining when you want to remove dots, powerups and candy from the board.
You can paint the map into a BufferedImage and just drawImage that on every paint(). You'll get quite reasonable performance this way.
If you are happy with the walls being solid, you can draw each square wall block with fillRect. If you wish to get the same look as in the picture, you need to figure how to draw the lines in the right way and use arcs for corners.
The Pacman game map is made of squares and Pacman and the ghosts always move from one square to the neighbouring square in an animated step (i.e. you press right, the pacman moves one square to the right). That means that collision detection is easy: simply don't allow moves to squares that are not empty.
I do not understand what you are trying to ask here.
1) Just to give my advice on redrawing. Something that you can do if you find redrawing the entire image is slow, is determine only the elements that have changed on the screen and redraw those. An approach for this would be the following: Determine the sprites that have moved. Determine (approximate) a rectangle around those sprites. Redraw those rectangles only. This way you are only refreshing parts of the screen and not the whole screen. This should result in an increase in performance over redrawing the entire screen.
The other answers have been reasonable for the other questions you have asked.

Categories

Resources