How do I draw a rectangular polygon without a triangular cutout? - java

I am creating a rectangular polygon that represents the box bounding the player sprite in a simple 2D game. This is the implementation I use:
float[] vertices = new float[] {player.getSprite().getX(), player.getSprite().getY(),
player.getSprite().getX() + player.getSprite().getWidth(),
player.getSprite().getY(), player.getSprite().getX(),
player.getSprite().getY() + player.getSprite().getHeight(),
player.getSprite().getX() + player.getSprite().getWidth(),
player.getSprite().getY() + player.getSprite().getHeight()};
Polygon rPoly = new Polygon(vertices);
polyBatch.draw(
new PolygonRegion(new TextureRegion(healthImage), rPoly.getTransformedVertices(),
new EarClippingTriangulator().computeTriangles(vertices).toArray()),
player.getSprite().getScaleX(), player.getSprite().getScaleY());
Where the "Sprite" is an actual LibGDX sprite object. When I try to use this implementation I get this as a result:
How do I get this polygon to be drawn without that triangular cut in it?

I will start this answer with a disclaimer: I have never used LibGDX before. Nonetheless I can see a potential problem with your code.
Let's number the corners of your rectangle as follows:
1 2
3 4
Your array of vertex coordinates includes these corners in the order 1, 2, 3, 4.
You are using a polygon object to represent this rectangle. Polygon objects will typically expect the vertex coordinates that they are given to go around the polygon in one direction or the other. For example, if you had a polygon with 10 points, how would the Polygon class know in which order to connect the points? Of course, order 1, 2, 3, 4 is not going around your rectangle in either direction.
Try swapping the order of the last two pairs of coordinates, so that your array of vertices includes the corners in the order 1, 2, 4, 3.
Bonus hint for readability: try to format your array of vertices so that it contains one pair of coordinates per line, perhaps something like the following:
Sprite sprite = player.getSprite();
float[] vertices = new float[] {
sprite.getX(), sprite.getY(),
sprite.getX() + sprite.getWidth(), sprite.getY(),
sprite.getX() + sprite.getWidth(), sprite.getY() + sprite.getHeight(),
sprite.getX(), sprite.getY() + sprite.getHeight()
};
To reduce the line length, I've created a local variable for the value of player.getSprite(). I've guessed the name of the class as Sprite: feel free to adjust this if necessary. You could potentially create further local variables for the values of sprite.getX(), sprite.getY() and so on.

Related

Efficient Way to Draw Lots of Triangles (OpenGL)

I am a little bit new to OpenGL. I am trying to draw 3D dynamic trail for aircraft using Java OpenGL and WorldWind Java I can draw it by using glDrawArrays. Since the trail of the aircraft increases in every frame(25fps) I put new vertice values to verticeBuffer. I also use rightFloatBuffer and leftFloatBuffer to draw GL_LINE_STRIP to the both sides of the trail as you may see in the attached firstpicture. Since the trail gets longer and longer as the aircraft flies I thought that I need to create a large FloatBuffer for the triangles (verticeBuffer) and 2 large FloatBuffers for the left and right lines.
My first question: What is the most efficient way to draw to many triangles? Based on my code I think after 5 hours of flight the FloatBuffers will be full. If I try to update values with for loop in each frame and if I have, say 50-75 aircraft at the same time, this will reduce the performance. And because of that, I update one triangle at each frame.
Second question: I want to draw a trail like in the second picture. As you see trail gets more transparent as it gets closer to aircraft. And when the aircraft turns color the bottom side of the trail seems different. How can I do it?
Third question: I use gl.DepthMask(false) and draw line_strip and gl.DepthMask(true) to draw smooth lines without a gap between the lines. But this time aircraft trail which is added to the scene first always seems on the top no matter if it is under another trail. What can I do to overcome this? Or what can I do to draw smooth lines without gaps considering the amount of the vertices?
My code to draw the trail is below:
private final FloatBuffer verticeBuffer = GLBuffers.newDirectFloatBuffer(3000000);
private final FloatBuffer rightFloatBuffer = GLBuffers.newDirectFloatBuffer(1500000);
private final FloatBuffer leftFloatBuffer = GLBuffers.newDirectFloatBuffer(1500000);
protected void drawTrail() {
gl.glPushAttrib(GL2.GL_CURRENT_BIT | GL2.GL_COLOR_BUFFER_BIT | GL2.GL_LINE_BIT | GL2.GL_ENABLE_BIT
| GL2.GL_DEPTH_BUFFER_BIT);
try {
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
doDrawTrail(dc);
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
gl.glDisable(GL.GL_BLEND);
} finally {
gl.glPopAttrib();
}
}
protected void doDrawTrail() {
updateTrailVertices();
float[] colors = new float[]{trailColor.getRed() / 255.f, trailColor.getGreen() / 255.f, trailColor.getBlue() / 255.f};
gl.glColor4f(colors[0], colors[1], colors[2], 0.6f);
gl.glEnable(GL2.GL_LINE_SMOOTH);
gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, verticeBuffer.rewind());
gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, verticeBuffer.limit() / 3);
gl.glColor3f(colors[0], colors[1], colors[2]);
gl.glLineWidth(3f);
//To draw smooth lines
gl.glDepthMask(false);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, rightFloatBuffer.rewind());
gl.glDrawArrays(GL.GL_LINE_STRIP, 0, rightFloatBuffer.limit() / 3);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, leftFloatBuffer.rewind());
gl.glDrawArrays(GL.GL_LINE_STRIP, 0, leftFloatBuffer.limit() / 3);
gl.glDepthMask(true);
}
protected void updateTrailVertices() {
// In each frame when the aircraft position changes this function updates the last vertices
if (positionChange) {
positionChange = false;
//I need to set the position and the limit of the buffers to draw only updated parts
verticeBuffer.position(lastIndex * 2);
rightFloatBuffer.position(lastIndex);
leftFloatBuffer.position(lastIndex);
verticeBuffer.limit((lastIndex * 2) + 6);
rightFloatBuffer.limit(lastIndex + 3);
leftFloatBuffer.limit(lastIndex + 3);
List<Vec4> pointEdges = computeVec4(this.currentPosition, this.currentHeading, this.currentRoll, this.span);
verticeBuffer.put((float) pointEdges.get(0).x).put((float) pointEdges.get(0).y).put((float) pointEdges.get(0).z);
verticeBuffer.put((float) pointEdges.get(1).x).put((float) pointEdges.get(1).y).put((float) pointEdges.get(1).z);
rightFloatBuffer.put((float) pointEdges.get(0).x).put((float) pointEdges.get(0).y).put((float) pointEdges.get(0).z);
leftFloatBuffer.put((float) pointEdges.get(1).x).put((float) pointEdges.get(1).y).put((float) pointEdges.get(1).z);
lastIndex = rightFloatBuffer.position();
}
}
If you can use geometry shaders, the most efficient way to display the flight track is to have one vertexbuffer and render it as a line strip. The vertexbuffer contains the earlier locations and a normal vector (plane up direction). With these two values the the geometry shader you can transform it into quads. These quads should contain texture coordinates, which can be used in the fragment shader to display the borders.
You need only one draw call and reduce the data stored on the gpu to the absolute minimum.
The fading of the flight track can be done by using a uniform with the plane coordinates. One of your shades can calculate the distance to the plane and with that a alpha value for the pixel.

JAVA drawPolygon() - Parameter Explanation

I'm currently looking into the drawPolygon(int[] xPoints, int[] yPoints, int nPoints) method in Java.
If I am not mistaken, the first two parameters are arrays, indicating the x-coordinates and y-coordinates of the polygon.
My question is, how are the polygon's coordinates interpreted from the two arrays?
For instance, I want to draw a line between the points (100, 300) and (200, 400). That is, a line increasing from left to right.
However, if I put these values into their respective arrays:
xPoints = {100, 200}; //x-coordinates
yPoints = {300, 400}; //y-coordinates
I get a line decreasing from left to right. As if the points are interpreted (100, 400) and (200, 300).
Thus, my question is: how are the array elements evaluated to make up the points of the polygon?
Thanks!
The default coordinate system has the origin in the upper left hand side corner of the canvas, and the y values increase from the top of the screen downwards. You can use an affine transform if you aren't happy with this orientation.
This is an example (!) from some code I have lying around - you may have to adapt it according to your situation:
// Polygon -> PathIterator -> Path2D, and then:
Path2D path = ...;
at.scale( 1, -1 );
path.transform( at );
bbox = path.getBounds2D();
at = new AffineTransform();
at.translate( -bbox.getMinX(), -bbox.getMinY() );
path.transform( at );
The coordinate system has origo in the top-left corner, and the y-axis increasing downwards.
This is why you get a downward slope when you increase the y-coordinate.

Collision detection in libgdx for triangles

I am making a simple game with libgdx and wanted to add some simple collision detection. I already managed to express my player by using a simple rectangle:
boundingBox = new Rectangle(x + 10, y + 10, 13, 21);
but my obstacles seem to be much more complicated.
They are supposed to be spikes over which the player can jump and have a triangle shape. They pretty much look like this:
http://kayin.pyoko.org/iwbtg/forums/Smileys/iwbtg/spikes.gif
As far as I noticed there is no triangle shape in libgdx. I already tried using polygons but they seem far too complicated for my purposes.
Is there an easy way to implement an accurate hitbox for them?
Thanks in advance for reading my post : )
EDIT:
Thanks everyone for your responses, everything works fine now, besides drawing my polygons for testing purposes. When I call
shapeRenderer.polygon(kid.getVertices());
it only draws my polygon in the top left corner, since it's defined as
boundingBox2.setVertices(new float[] { 10, 10, 10, 31, 23, 31, 23, 10 });
But I move it around in the update method of my kid class by using
boundingBox2.setPosition(position.x, position.y);
Is there a way to use that position change inside
shapeRenderer.polygon(kid.getVertices()); ?
Anyways I really appreciate your help and after sorting out this problem I will close this thread : )
Create a Polygon of your rectangle and your triangle.
You can even create a custom polygon if you want to add more advanced shapes.
To convert from rectangle to polygon is very easy, i made a method some months ago
public static float[] rectangleToVertices(float x, float y, float width,
float height) {
float[] result = new float[8];
result[0] = x;
result[1] = y;
result[2] = x + width;
result[3] = y;
result[4] = x + width;
result[5] = y + height;
result[6] = x;
result[7] = y + height;
return result;
}
The good thing about libGDX polygon class is that you can move your polygon or even rotate it, and get the transformed vertices!
Now you can use the Intersector class
public static boolean overlapConvexPolygons(Polygon p1,
Polygon p2)
Check whether specified convex polygons overlap.
Parameters:
p1 - The first polygon.
p2 - The second polygon.
Returns:
Whether polygons overlap.
For testing purposes, after you end your sprite batch do like this
batch.end(); // you end your spritebatch
renderer.setProjectionMatrix(camera.combined);
renderer.begin(ShapeType.Line)
renderer.polygon(polygonname.getVertices());
renderer.end();
Now you will be able to see your polygon.

Java LWJGL - Creating a Grid of Squares

(The colored squares are just positions that have been added to an array to be drawn)
I am having problems creating a grid of squares in Java. As you can see in the picture, it appears as if the squares are being placed in the right position, but they are progressively getting smaller in x and in y as x and y grows. I have been trying to find the right algorithm for this for a while now and I am having problems.
public void draw() {
setColor(material);
glBegin(GL_QUADS);
glVertex2i(x+(SIZE*(x-1)), y+(SIZE*(y-1))); //top-left vertex
glVertex2i(SIZEx, y+(SIZE(y-1))); //top-right vertex
glVertex2i(SIZEx, SIZEy); //bottom-left vertex
glVertex2i(x+(SIZE*(x-1)), SIZE*y); //bottom-right vertex
glEnd();
}
SIZE is set to 32.
The problem here is that you are adding "+x" and "+y" in several places this is why the squares are changing in their size as x and y progresses. If you wish to write to make squares with some small distance in between them, you could try something like this, say SIZE=32 and PADDING_HALF=1, then something like this should work (this way the squares should be 30x30 with a padding of 2 between each):
public void draw() {
setColor(material);
glBegin(GL_QUADS);
glVertex2i(SIZE*(x-1) + PADDING_HALF, SIZE*y - PADDING_HALF); //top-left vertex
glVertex2i(SIZE*x - PADDING_HALF, SIZE*y - PADDING_HALF); //top-right vertex
glVertex2i(SIZE*(x-1) + PADDING_HALF, SIZE*(y-1) + PADDING_HALF); //bottom-left vertex
glVertex2i(SIZE*x - PADDING_HALF, SIZE*(y-1) + PADDING_HALF); //bottom-right vertex
glEnd();
}
Also bear in mind that in OpenGL the y-coordinate isn't inverted.

How to have a "Camera" only show a portion of a loaded area

I'm having a little problem with figuring something out (Obviously).
I'm creating a 2D Top-down mmorpg, and in this game I wish the player to move around a tiled map similar to the way the game Pokemon worked, if anyone has ever played it.
If you have not, picture this: I need to load various areas, constructing them from tiles which contain an image and a location (x, y) and objects (players, items) but the player can only see a portion of it at a time, namely a 20 by 15 tile-wide area, which can be 100s of tiles tall/wide. I want the "camera" to follow the player, keeping him in the center, unless the player reaches the edge of the loaded area.
I don't need code necessarily, just a design plan. I have no idea how to go about this kind of thing.
I was thinking of possibly splitting up the entire loaded area into 10x10 tile pieces, called "Blocks" and loading them, but I'm still not sure how to load pieces off screen and only show them when the player is in range.
The picture should describe it:
Any ideas?
My solution:
The way I solved this problem was through the wonderful world of JScrollPanes and JPanels.
I added a 3x3 block of JPanels inside of a JScrollPane, added a couple scrolling and "goto" methods for centering/moving the JScrollPane around, and voila, I had my camera.
While the answer I chose was a little more generic to people wanting to do 2d camera stuff, the way I did it actually helped me visualize what I was doing a little better since I actually had a physical "Camera" (JScrollPane) to move around my "World" (3x3 Grid of JPanels)
Just thought I would post this here in case anyone was googling for an answer and this came up. :)
For a 2D game, it's quite easy to figure out which tiles fall within a view rectangle, if the tiles are rectangular. Basically, picture a "viewport" rectangle inside the larger world rectangle. By dividing the view offsets by the tile sizes you can easily determine the starting tile, and then just render the tiles in that fit inside the view.
First off, you're working in three coordinate systems: view, world, and map. The view coordinates are essentially mouse offsets from the upper left corner of the view. World coordinates are pixels distances from the upper left corner of tile 0, 0. I'm assuming your world starts in the upper left corner. And map cooridnates are x, y indices into the map array.
You'll need to convert between these in order to do "fancy" things like scrolling, figuring out which tile is under the mouse, and drawing world objects at the correct coordinates in the view. So, you'll need some functions to convert between these systems:
// I haven't touched Java in years, but JavaScript should be easy enough to convey the point
var TileWidth = 40,
TileHeight = 40;
function View() {
this.viewOrigin = [0, 0]; // scroll offset
this.viewSize = [600, 400];
this.map = null;
this.worldSize = [0, 0];
}
View.prototype.viewToWorld = function(v, w) {
w[0] = v[0] + this.viewOrigin[0];
w[1] = v[1] + this.viewOrigin[1];
};
View.prototype.worldToMap = function(w, m) {
m[0] = Math.floor(w[0] / TileWidth);
m[1] = Math.floor(w[1] / TileHeight);
}
View.prototype.mapToWorld = function(m, w) {
w[0] = m[0] * TileWidth;
w[1] = m[1] * TileHeight;
};
View.prototype.worldToView = function(w, v) {
v[0] = w[0] - this.viewOrigin[0];
v[1] = w[1] - this.viewOrigin[1];
}
Armed with these functions we can now render the visible portion of the map...
View.prototype.draw = function() {
var mapStartPos = [0, 0],
worldStartPos = [0, 0],
viewStartPos = [0, 0];
mx, my, // map coordinates of current tile
vx, vy; // view coordinates of current tile
this.worldToMap(this.viewOrigin, mapStartPos); // which tile is closest to the view origin?
this.mapToWorld(mapStartPos, worldStartPos); // round world position to tile corner...
this.worldToView(worldStartPos, viewStartPos); // ... and then convert to view coordinates. this allows per-pixel scrolling
mx = mapStartPos[0];
my = mapStartPos[y];
for (vy = viewStartPos[1]; vy < this.viewSize[1]; vy += TileHeight) {
for (vx = viewStartPos[0]; vx < this.viewSize[0]; vy += TileWidth) {
var tile = this.map.get(mx++, my);
this.drawTile(tile, vx, vy);
}
mx = mapStartPos[0];
my++;
vy += TileHeight;
}
};
That should work. I didn't have time to put together a working demo webpage, but I hope you get the idea.
By changing viewOrigin you can scroll around. To get the world, and map coordinates under the mouse, use the viewToWorld and worldToMap functions.
If you're planning on an isometric view i.e. Diablo, then things get considerably trickier.
Good luck!
The way I would do such a thing is to keep a variable called cameraPosition or something. Then, in the draw method of all objects, use cameraPosition to offset the locations of everything.
For example: A rock is at [100,50], while the camera is at [75,75]. This means the rock should be drawn at [25,-25] (the result of [100,50] - [75,75]).
You might have to tweak this a bit to make it work (for example maybe you have to compensate for window size). Note that you should also do a bit of culling - if something wants to be drawn at [2460,-830], you probably don't want to bother drawing it.
One approach is along the lines of double buffering ( Java Double Buffering ) and blitting ( http://download.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html ). There is even a design pattern associated with it ( http://www.javalobby.org/forums/thread.jspa?threadID=16867&tstart=0 ).

Categories