Determining draw order for isometric games and irregular shapes (Java) - java

I'm having some unique trouble determining the order in which objects should be rendered, particularly in the case of when a player is behind a wall. I'll try and explain thoroughly, so prepare for a lot of information.
I render things back to front (as recommended here: Drawing Isometric game worlds) and that is, for the most part, simple enough.
I determine what is in the back using a simple comparator:
private Comparator<Entity> spriteSorter = new Comparator<Entity>(){
public int compare(Entity e1, Entity e2){
if(e1.getPhysics().getY() > e2.getPhysics().getY()) return 1;
if(e1.getPhysics().getY() < e2.getPhysics().getY())return -1;
return 0;
}
};
This uses the hitbox of an entity to determine its render order, and it works flawlessly for entities with a rectangular hitbox (as almost all my characters do). The actual draw call looks like this:
ArrayList<Entity> spriteList = new ArrayList<>();
spriteList.add(player);
for(int i = 0; i < walls.size(); i++){
spriteList.add(walls.get(i));
}
Collections.sort(spriteList, spriteSorter);
for(int i = 0; i < spriteList.size(); i++){
spriteList.get(i).render(g);
}
Here's where things get tricky though, all my characters use an instance of Rectangle, and their ordering works with no problem at all, but my walls (due to the nature of an isometric game) cannot use a rectangle, and thus use a Polygon that fits their size.
See picture:
I have to use a Polygon because if I use a rectangle, I get a stupid unpassable space near the wall like so:
Unfortunately, due to the nature of polygons, there is no immediately apparent test to see if the player is in front or behind the wall. Line 3 seems to be a likely candidate as a test, but there are two triangles on either side of the wall that would pass the player.getPhysics.getY() > wall.getPhysics.getY() test and mark him as in front, when he could be both in front and behind the wall.
So, how can I devise a test to tell me when he is behind the diagonal lines? The nature of Shapes and Polygons in Java seems to be limiting me a lot, but I'm sure there's a way to do it. I've played with points a lot, and getCenterY() has gotten fairly close, but it's still not perfect. The problem cases that arise with all of the methods I've tried look like this:
Actually behind, rendered in front
or this:
Actually in front, rendered behind.
Any one got any ideas?

Suppose your character is located at (x, y) and the wall has a central line which leads from (a, b) to (c, d). Then you can use the sign of the determinant
| x a c |
| y b d | = ab + ad + cy - ay - cb - xd
| 1 1 1 |
to decide whether the triangle formed by these three points is oriented clockwise or counter-clockwise. You can compute a similar determinant for the camera instead of the character, and multiply the results. If the product is positive, then camera and character are on the same side of the wall, and you want to draw the character after the wall. If the product is negative, then camera and character are on opposite sides and you want to draw the character before the wall.
This simplification assumes your walls are lines or line segments, not rotated rectangles, but unless your player can actually move inside the wall, the difference should not matter unless the camera looks pretty much head-on onto the short side of the wall. So perhaps you want a big rectangular bounding box for the wall after all, to do rough ordering, and only use the above if the player is inside this (still passable) bounding box.

It's not so easy!!!. Why? Because you have others sprites involucred in the scene (Not only 2. By example, you need have 2 players + 1 wall). How do you order them for rendering?
You must always work using x, y, z which determinate respectevely "front, back, behind of" position.
NOTE: After 2 (hard) months of analysis of the problem I finally found and implemented a "correct render drawing" for my new cocos2d-js game. Solution consists in mapping, for each tile (susceptible), which sprites are "front, back and behind".
Once doing that you can draw them following a "recursive logic".

Related

Checking depth/z when rendering triangular faces in 3d space

My question can be simplified to the following: If a 3d triangle is being projected and rendered to a 2d viewing plane, how can the z value of each pixel being rendered be calculated in order to be stored to a buffer?
I currently have a working Java program that is capable of rendering 3d triangles to the 2d view as a solid color, and the camera can be moved, rotated, etc. with no problem, working exactly how one would expect it to, but if I try to render two triangles over each other, the one closer to the camera being expected to obscure the farther one, this isn't always the case. A Z buffer seems like the best idea as to how to remedy this issue, storing the z value of each pixel I render to the screen, and then if there's another pixel trying to be rendered to the same coordinate, I compare it to the z value of the current pixel when deciding which one to render. The issue I'm now facing is as follows:
How do I determine the z value of each pixel I render? I've thought about it, and there seem to be a few possibilities. One option involves finding the equation of the plane(ax + by + cz + d = 0) on which the face lies, then some sort of interpolation of each pixel in the triangle being rendered(e.g. halfway x-wise on the 2d rendered triangle -> halfway x-wise through the 3d triangle, same for the y, then solve for z using the plane's equation), though I'm not certain this would work. The other option I thought of is iterating through each point, with a given quantum, of the 3d triangle, then render each point individually, using the z of that point(which I'd also probably have to find through the plane's equation).
Again, I'm currently mainly considering using interpolation, so the pseudo-code would look like(if I have the plane's equation as "ax + by + cz + d = 0"):
xrange = (pixel.x - 2dtriangle.minX)/(2dtriangle.maxX - 2dtriangle.minX)
yrange = (pixel.y - 2dtriangle.minY)/(2dtriangle.maxY - 2dtriangle.minY)
x3d = (3dtriangle.maxX - 3dtriangle.minX) * xrange + 3dtriangle.minX
y3d = (3dtriangle.maxY - 3dtriangle.minY) * yrange + 3dtriangel.minY
z = (-d - a*x3d - b*y3d)/c
Where pixel.x is the x value of the pixel being rendered, 2dtraingle.minX and 2dtriangle.maxX are the minimum and maximum x values of the triangle being rendered(i.e. of its bounding box) after having been projected onto the 2d view, and it's min/max Y variables are the same, but for its Y. 3dtriangle.minX and 3dtriangle.maxX are the minimum and maximum x values of the 3d triangle before having been projected onto the 2d view, a, b, c, and d are the coefficients of the equation of the plane on which the 3d triangle lies, and z is the corresponding z value of the pixel being rendered.
Will that method work? If there's any ambiguity please let me know in the comments before closing the question! Thank you.
The best solution would be calculating the depth for each vertex of the triangle. Then we are able to get the depth of each pixel the same way we do for the colors when rendering a triangle with Gouraud shading. Doing that simultaneously with rendering allows to check the depth easily.
If we have a situation like this:
And we start to draw lines from the top to the bottom. We calculate the slopes from the point one to the others, and add the correct amount of depth every time we move to the next line... And so on.
You did't provide your rendering method, so can't say anything specific to it, but you should take a look at some tutorials related to Gouraud shading. Do some simple modifications to them and you should be able to use it with depth values.
Well, hopefully this helps!

I want my NPC to look in the direction I am standing at. How would I do this most effectively?

I'm currently building a 2D game with Slick2D, and right now I'm implementing my first NPC.
I already have the sprites, I was able to draw him, did the collisions, and so on, but now I want to add the feature which makes the NPC look into the direction I am currently at, when I am entering a certain range around the NPC (Which would be 2 tiles left, diagonal, right, up and down, but because I want it to be exact, I'm using the x coordinates, so for every tile I would be checking 32x32 possibilities)
To get this a little bit more clear I drew a picture:
The numbers are the x and y coordinates, while my NPC is placed at 704,704.
The problem I have is that I don't know how to check all the coordinates effectively, without having to write 5000 lines of if's. The 2 left diagonal lines, which could both be interpreted as "NPC looks up" and "NPC looks left" would make him look left, same with the 2 right ones, which would make him look right.
Is there some clever method I can use, or should I just go back and divide the x and y by 32 so I only check if my player is on a certain tile? That would be less precise, though.

How to determine the distance from an obstacle without knowing its location

I am writing a code where I have a world filled with various obstacles (of rectangular shapes). My robot which is a circle, originates randomly at any place inside the world. I assume that it has a range sensor on its head and want to get the distance between the nearest obstacle/boundary wall which is in its straight line of view.
I am using a random orientation between 0 and 360 degrees to orient the robot and use sin and cos of orientation to move the robot in the same orientation. But how can I get the distance between any obstacle or the boundary wall along this orientation? It should be able to tell me the distance of the first object it encounters in its vision which would be an angle from 0 to 360.
Please provide me a hint of logic how to encounter this issue?
Thanks
Assuming you know the angle, the robot's position and the position of all the obstacles, you could have a function like this:
if the angle if less than 90 or greater than 270 you increment the x coordinate by 1, otherwise you decrement by 1
you make a for loop from the current x coordinate until the edge of the world (I don't know how you have the world implemented), scanning for any obstacles at position (x, x*tan(angle)), incrementing or decrementing in accordance with the step above
the first obstacle you run across, return sqrt(x^2 + (x*tan(angle))^2) - that's just the pythagorean theorem
Here's what i think you could do.
In real game development, they uses a lot of optimization tricks, often giving approximates for better performances.
Also note that there's a lot of libraries out there for game development, that probably could get you what you want a lot simplified.
But anyway, here's what i'ld do.
identify object you'd pass through if you go straight forward.
identify the nearest one, in the list of objects you just made.
1:
A)
make a formula for your position/angle in the form y = mx + b
[y = tan(angle)x + (positionY - (tan(angle)*x))]
B)
for each object, divide the object in multiple lines segments (2 points).
check if the segment crosses the line made by the formula in point A
(if a point is smaller and the other is greater than the same X value in the formula, it's crossing)
do the same thing for your world boundaries
2: This part is more tricky (to do in programmation).
Next, you have to find the position where your robot orientation formula intersect
with all the lines you previously identified.
For each line, you must again turn the line into a y=mx+b
Let say we have:
y=3x+5 and
y=5x+1
3x+5 = 5x+1
3x-5x = 1-5
-2x = -4
x = 2
Then you replace x with 2 in either formula, you'll get the intersection point:
y = 3(2)+5 = 11
y = 5(2)+1 = 11
So these two lines intersect on point (2, 11)
Next you have to see if that point is in the domain of you're robot path formula.
Since your robot is looking at a single direction, and the formula we made in point 1.A is infinite in both directions, you must ensure the line intersection you found is not in the back of your robot (unless he moves backward...)
I guess you can make it simple, look at cos(angle) signs, then look at the position of the intersection point, if it's to the left of your robot, and cos(angle) is negative it's fine.
Finally,
Once you found ALL the intersect point, you can find the nearest one by using the Pythagorean theorem sqrt((x1-x2)^2 + (y1-y2)^2)
Also, note that it won't work for 90 and 270 angles, since tan(90) doesn't exists.
In that case, just look if both points of the segments are at both side of your robot, and the intersect point is in the right direction, it means you pass through it.
Again, there's a lot of place for optimization.

Java Collision Detection Not Working

I have made threads in the past about similar questions but because of my lack of detail the answers have not really been related to what I needed so I am going to try explain my question in as much detail as I can and hopefully it will be easier for you to understand what I require.
I watched Bucky's slick game tutorials on youtube and made a 2D Java game, the game is basically a 2D player viewed from above (birds eye view) can move around a 2D map with user key input (up, down, left, right). The map the player moves around is very small so that meant boundaries had to be set so that the player could not walk off of the map, to give you a better idea of how this was done, here is the tutorial for setting up the voundries:
http://www.youtube.com/watch?v=FgGRHId8Fn8
The video will also show you exactly what the game is like.
The problem is, these boundaries only require one axis meaning that if the player is walking down you say something like "if player gets to the coordinate (number) on the X axis change the player movement to the opposite direction so that he can not go any further."
Now this creates a problem for me because this only requires one axis so it easy to set up and understand but if you look on the video, on the map there is a house and I want my player not to be able to walk over that also but this deals with 2 dimensions, I have looked at things like rectangle collisions and have seen things relating to them in the other posts but I get confused because I am new to Java and havent really done much with it at the moment apart from watching Bucky's tutorials.
My code at the moment for my game class has got the following methods: init, render and update. So to sum it up I really just want to set up a way of not letting my player walk through the house, I will mention also (I should have mentioned it in my other threads) as I am very new to Java, could you please take a step by step method of showing me how to set up the collisions, I mean even the basics of things like making the rectangle if required.
If my code is required please tell me and I will post it as soon as possible.
Thank you in advance.
You can set up the board as a 2x2 grid of a class that has has property such as 'isBlocked'. By default the edges of the board would have this property set to true to prevent the character from walking off the edge. When you add other obstacles such as a house or a wall the grid position(s) the object occupies would also have the property set to true. Then when moving a character you just check if the grid position the character moves to has the property set to false to see if it's an allowable move. This also makes it quite trivial to save the level data so you can just load them from disk later on.
Two possible options:
Extend Shape or Rectangle or the relevant Slick objects (they should exist IMO) and just check for intersect()
Look for (x1,y1) and (x2,y2) values such that it starts outside and ends up inside.
Assuming you have intersect() methods:
//Grab the previous position
prevPosX = movingobject.X;
prevPosY = movingobject.Y;
//Update the position
movingobject.update();
//Test for collision
if(movingobject.intersects(targetobj)) {
//If it collided, move it back
movingobject.X = prevPosX;
movingobject.Y = prevPosY;
//And reverse the direction
//(might want to do other stuff - e.g. just stop the object)
movingobject.speed *= -1; //Reverse the speed
}
in this case your update class should also add one more condition to look for the house. let say the cooridnates of house(assuming rectanglular house here for other shape just change x and y values) are (x1,y1)(x1,y2)(x2,y2)(x3,y1) you have to add a condition to make sure
x value is not between x1 and x2 and at the same time y value cannot between y1 and y2.

Implementing Terrain destruction like Scorched Earth Game on iphone or Java

I'm looking for an example of how to implement 2D terrain destruction that you see in games like scorched earth or on the iphone iShoot.
I'm looking to implement a game that needs to do destructible terrain and render it using OpenGL (LWJGL in Java) and using OpenGL ES on the iPhone.
(source: vintagecomputing.com)
As I recall, in Worms they used two images; The "pretty" terrain with colour, and a mask terrain that is pure black and white. Hit detection is always done on the mask.
If you actually want the terrain to collapse like it did in Tank Wars, you'll need to iterate over each column of your image and have it search for gaps between the terrain and the bottom of the playing field. If any gaps are detected, shift the terrain above the gap down to the lowest point possible in your column.
A simple example of this could be done with an array where 1 represents solid terrain and 0 represents empty space. In this case, I've set up the left side of the array as ground level, to element [0] would be on the ground:
[1,1,1,1,1,1,0,0,0,0]
Lets assume the terrain is struck from the side and a hole is made:
[1,1,0,0,1,1,0,0,0,0]
You're now left with a floating piece of terrain above another piece of terrain. To make the floating terrain collapse, iterate over the array, keeping track of the first position you find a 0 (empty space). Then, as you continue to iterate, upon discovering a 1 (terrain) simply shift the 1 to where the 0 was. Repeat the process by iterating from that the old 0 position + 1.
[1,1,1,0,0,1,0,0,0,0]
[1,1,1,1,0,0,0,0,0,0]
This is the basic approach, not the most efficient one. It would be much faster to move all indexes of terrain above the gap down at the same time, for example.
EDIT:
As the first comment states, a sort on the list is even easier. I'm keeping my original response intact since it helps explains the actual principle behind the collapsing terrain.
Soviut's answer is great! I use a similar algorithm in the destructive terrain feature in Scorched Earth for iPhone. I decided to stay true to the original and have the terrain settle instantly, but while I was considering having animated terrain settling, I ran into some performance problems. You can see evidence of this in iShoot as well, since iShoot uses a slowly settling animated terrain. There are situations where the ground is still settling from one player's turn when the next player fires a weapon. This can interfere with the shot, and the interference can change depending on how quickly the next player fires. Since Scorched Earth is a turn-based game, it seems like a good idea to have the game wait until the ground is settled until switching to the next player.
To render the terrain, I used OpenGL to draw a polygon with one pair of vertices at each horizontal screen location, like this:
1 3 5 7 9
0 2 4 6 8
Points with even numbers represent the line of pixels at the bottom of the screen. Points with odd numbers represent the vertical pixel location of the terrain. This information is copied into a point array, which is rendered with glVertexPointer, glColorPointer, and glDrawArrays, as a triangle strip, like this:
// prepare vertex buffer
for (int i=0,j,k=0,K=480;k<=K;k++) {
j = (k-(int)offsetX+480)%480;
vGroundLevel[i++] = k;
vGroundLevel[i++] = offsetY>0 ? 0 : offsetY;
vGroundLevel[i++] = k;
vGroundLevel[i++] = [env groundLevelAtIndex:j]+offsetY;
}
....
// render vertex buffer
glVertexPointer(2, GL_FLOAT, 0, vGroundLevel);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, cGround);
glEnableClientState(GL_COLOR_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 2*480);
The offsetX and offsetY parameters allow the terrain to be repositioned relative to the screen, allowing the player to move around the environment interactively, while maintaining the game environment as a wrap-around continuum.

Categories