Im working on a 2D game in which the terrain can vary and is composed of any shape of polygons except for self intersecting ones. The player collision box is in the shape of a square and can move about. My question is this: How do I keep an always-upright box to collide with variable terrain and always stay outside?
My current approach that I made up albeit no code yet works like the following:
The blue square is the player hitbox. First, it moves with a velocity downwards as an example. My goal is to find the heighest point in its travel path where it can be safely outside of the terrain polygon. I test all the terrain vertex points inside its travel path and project them to the velocity of the box. I take the farthest projection.
The farthest projection will be the max distance allowed to move in without going into the terrain.
Move the square by distance in the direction of velocity and done.
However, there are few scenarios that I encountered where this does not work. Take this as an example:
To remedy this situation, I now test for one corner of the square. If the distance from the corner is shorter than the farthest projection, then that distance will give the appropriate shift in distance. This pretty much makes the algorithm full-proof. Unless someone states another exception.
Im going a little crazy and I would appreciate feedback on my algorithm. If anyone has any suggestions or good reads about 2D upright box collisions on terrain or anything similar, that would be great.
This may be useful, and here I'll quickly elaborate on "upright" square collision.
First the collision may occur on the side of the square, and not necessarily a corner. A simple solution to check any collision is describe the region delimited by the square, and then check if any point of your uneven terrain is within this region.
To define the square region, assume your upright square is has the corners (x1,y1), (x2,y1), (x2,y2), (x1,y2), where x2>x1 and y2>y1. Then for a point (x,y) to be within the square it needs to satisfy the conditions
If( x1< x < x2 and y1< y <y2) Then (x,y) is in the square.
Then to conclude, all you need do is check if any point on the terrain satisfies the above condition.
Good luck.
Related
I'm building a server-side(!) for online game and I need to check if bullet hit a target.
Client sends me position and angle of bullet fired, I know all the enemies coordinates and sizes. How can I calculate if bullet hit an enemy after a bullet fired? Enemies have different sizes, bullet is 1px size.
For example, I have player shooting angle of 45 degrees from 0, 0 coordinates, and an enemy on 200, 200 coordinates with 10 width, 15 height. How do I calculate that bullet hit the enemy?
UPDATE: The game is 2d dhooter from the top, like Crimsonland. Projectiles have start speed which decreases slowly.
You should get a glance at the power of a point.
It will allow you to know the minimal distance between a line and a point.
So if the distance is lower than the width of the target, it's a hit !
The easiest way is to just check if the bullet is inside the rectangle of the enemy. If it is, dispose the bullet and the enemy.
basically:
while(game.is_on()){
for(enemy = enemyCollection.begin(); enemy != enemyCollection.end(); ++enemy){
if(enemy.contains(bullet)){
enemy.dead();
bullet.hit();
}
}
If you need to check whether line intersects rectangle, then apply orientation test based on cross product - if sign of cross product is the same for all rectangle vertices - line does not intersect it.
Line L0-L1, point P
Orientation = Cross(P - L0, L1 - L0)
(instead of L1-L0 components you can use Cos(Fi) and Sin(Fi) of shooting angle)
If you need to get intersection points, use some algorithm for line clipping - for example, Liang-Barsky one.
It's not quite as easy as it looks. To get a full solution, you need to extrude your objects along their paths of travel. Then you do object to object intersection tests.
That's difficult, as extrusion of an arbitrary shape by an arbitrary path is hard. So it's easier to cheat a little bit. Bullets can have no area, so they are just line segments. Make sure the step size is low enough for the line segment to be relatively short. Then make the ships rectangles, again with relatively short lines. Now it's lots of short line to line intersection tests. You can do these quickly with the planesweep algorithm. The nice thing about planesweep is that you can also extend it to curves or shapes, by returning possible intersections rather than actual intersections.
Once you have an intersection between a bullet and a ship's collision rectangle, you might need to run a timestep to check that a hit actually takes place rather than a narrow miss. You can also determine whether the hit was on front, left, right or back at this point.
I have a rotated Rectangle inside a closed tile map of rectangles.
What would be the best way to check if the player (which is the rotated rectangle) is intersecting with one of the rectangles of the tile map?
Picture from inside the game to better show what the map looks like:
If it matters, the Player's type is sf::Shape and the map's data is inside an int array.
SFML does not provide collision detection, it only has method to check if two axis-aligned rectangles intersect. If you need something more complex, you will have to implement if yourself.
If you don't need precision detection, you can test Sprite.getGlobalBounds().intersects(...) with the rectangle of the map.
If you want ideal collision detection, you have more then one option:
Pixel perfect Collision. First check if bounding box intersect the map tile and them check all non-transparent pixels for collision. Not very fast but easy to implement and may be suitable for your case.
Mathematical methods, there are more that one, but take a look at Separating Axis Theorem. If your are only limited to rectangles (or/and circles and convex polygons), it will work best.
For anyone still having this issue:
You should look into the getTransform() and getInverseTransform() functions of sf::Transformable (https://www.sfmldev.org/documentation/2.5.1/classsf_1_1Transformable.php). Getting the inverse transforms of the player and a specific wall allows you to use a simple AABB collision algorithm (like SFML already implemented it in getGlobalBounds().intersects(...)). You basicly look at the local coordinate system of the player and how the wall is positioned to it, all translations, rotations and scaling ignored.
I am using OpenTK(OpenGL) and a general hint will be helpful.
I have a 3d terrain. I have one point on this terrain O(x,y,z) and two perpendicular lines passing through this point that will serve as my X and Y axes.
Now I have a set of 2d points with are in polar coordinates (range,theta). I need to find which points on the terrain correspond to these points. I am not sure what is the best way to do it. I can think of two ideas:
Lets say I am drawing A(x1,y1).
Find the intersection of plane passing through O and A which is perpendicular to the XY plane. This will give me a polyline (semantics may be off). Now on this line, I find a point that is visible from O and is at a distance of the range.
Create a circle which is perpendicular to the XY plane with radius "range", find intersection points on the terrain, find which ones are visible from O and drop rest.
I understand I can find several points which satisfy the conditions, so I will do further check based on topography, but for now I need to get a smaller set which satisfy this condition.
I am new to opengl, but I get geometry pretty well. I am wondering if something like this exists in opengl since it is a standard problem with ground measuring systems.
As you say, both of the options you present will give you more than the one point you need. As I understand your problem, you need only to perform a change of bases from polar coordinates (r, angle) to cartesian coordinates (x,y).
This is fairly straight forward to do. Assuming that the two coordinate spaces share the origin O and that the angle is measured from the x-axis, then point (r_i, angle_i) maps to x_i = r_i*cos(angle_i) and y_i = r_i*sin(angle_i). If those assumptions aren't correct (i.e. if the origins aren't coincident or the angle is not measured from a radii parallel to the x-axis), then the transformation is a bit more complicated but can still be done.
If your terrain is represented as a height map, or 2D array of heights (e.g. Terrain[x][y] = z), once you have the point in cartesian coordinates (x_i,y_i) you can find the height at that point. Of course (x_i, y_i) might not be exactly one of the [x] or [y] indices of the height map.
In that case, I think you have a few options:
Choose the closest (x,y) point and take that height; or
Interpolate the height at (x_i,y_i) based on the surrounding points in the height map.
Unfortunately I am also learning OpenGL and can not provide any specific insights there, but I hope this helps solve your problem.
Reading your description I see a bit of confusion... maybe.
You have defined point O(x,y,z). Fine, this is your pole for the 3D coordinate system. Then you want to find a point defined by polar coordinates. That's fine also - it gives you 2D location. Basically all you need to do is to pinpoint the location in 3D A'(x,y,0), because we are assuming you know the elevation of the A at (r,t), which you of course do from the terrain there.
Angle (t) can be measured only from one axis. Choose which axis will be your polar north and stick to. Then you measure r you have and - voila! - you have your location. What's the point of having 2D coordinate set if you don't use it? Instead, you're adding visibility to the mix - I assume it is important, but highest terrain point on azimuth (t) NOT NECESSARILY will be in the range (r).
You have specific coordinates. Just like RonL suggest, convert to (x,y), find (z) from actual terrain and be done with it.
Unless that's not what you need. But in that case a different question is in order: what do you look for?
I am making a simple 3D OpenGL game. At the moment I have four bounding walls, a random distribution of internal walls and a simple quad cube for my player.
I want to set up collision detection between the player and all of the walls. This is easy with the bounding walls as i can just check if the x or z coordinate is less than or greater than a value. The problem is with the interior walls. I have a glGenList which holds small rectangular wall segments, at the initial setup i randomly generate an array of x,z co ordinates and translate these wall segments to this position in the draw scene. I have also added a degree of rotation, either 45 or 90 which complicates the collision detection.
Could anyone assist me with how I might go about detecting collisions here. I have the co ordinates for each wall section, the size of each wall section and also the co ordinates of the player.
Would i be looking at a bounded box around the player and walls or is there a better alternative?
I think your question is largely about detecting collision with a wall at an angle, which is essentially the same as "detecting if a point matches a line", which there is an answer for how you do here:
How can I tell if a point belongs to a certain line?
(The code may be C#, but the math behind it applies in any language). You just have to replace the Y in those formulas for Z, since Y appears to not be a factor in your current design.
There has been MANY articles and even books written on how to do "good" collision detection. Part of this, of course, comes down to a "do you want very accurate or very fast code" - for "perfect" simulations, you may sacrifice speed for accuarcy. In most games, of the players body "dents" the wall just a little bit because the player has gone past the wall intersection, that's perhaps acceptable.
It is also useful to "partition the space". The common way for this is "Binary space partitioning", which is nicely described and illustrated here:
http://en.wikipedia.org/wiki/Binary_space_partition
Books on game programming should cover basic principles of collision detection. There is also PLENTY of articles on the web about it, including an entry in wikipedia: http://en.wikipedia.org/wiki/Collision_detection
Short of making a rigid body physics engine, one could use point to plane distance to see if any of the cubes corner points are less than 0.0f away from the plane (I would use FLT_MIN so the points have a little radius to them). You will need to store a normalized 3d vector (vector of length 1.0f) to represent the normal of the plane. If the dot product between the vector from the center of the plane to the point and the plain normal is less than the radius you have a collision. After that, you can take the velocity (the length of the vector) of the cube, multiply it by 0.7f for some energy absorption and store this as the cubes new velocity. Then reflect the normalized velocity vector of the cube over the normal of the plane, then multiply that by the previously calculated new velocity of the cube.
If you really want to get into game physics, grab a pull from this guys github. I've used his book for a Physics for games class. There are some mistakes in the book so be sure to get all code samples from github. He goes through making a mass aggregate physics engine and a rigid body one. I would also brush up on matrices and tensors.
So, I have a Triangle->AABB collision algorithm and I have it returning the triangle that the AABB collided with. I was hoping with the 3 vectors of the triangle and the direction/magnitude of the movement would let me determine a deflected vector so that when you run against the wall at an angle you move slower, depending on the angle of collision, but along side the wall. This would remove the sticky collision problem with only moving when there is not a collision. Any suggestions or references would be greatly appreciated! Thanks.
First, I would convert magnitude/direction to a vector (it's much more convenient).
Then (c++):
float towards=dot(velocity,norm); // velocity component into triangle
if(towards<0) // is moving into triangle
velocity-=towards*norm; // remove component
Then it can't move into the triangle. towards<0 might need to be reversed depending on your normal. It's also nice to have a spring force pushing it out.
Remove the component of the velocity along the normal of the triangle.
The idea is that you can represent the movement as the part that's moving "into" the triangle and the remainder (which will be in perpendicular directions). If you then just move with the remainder, you will no longer be getting any closer to the triangle by the movement (or further, but you shouldn't be detecting a collision in that case).
In pseudo-code:
// v := velocity vector of moving object
// p[3] := points that make up the triangle
triangle_normal = cross(p[2]-p[0], p[1]-p[0])
problematic_v = project(v, onto=triangle_normal)
safe_movement = v - problematic_movement
Note that this intentionally doesn't preserve the magnitude of the movement vector, as doing so would make you slide along a wall very quickly when running straight at it.
For more details and some nice pictures, see Pool Hall Lessons: Fast, Accurate Collision Detection Between Circles or Spheres at Gamasutra. You're not using spheres, but you are essentially doing a perfectly plastic (since you don't bounce) collision.