I'm building a game and I'm currently working on the physics.
I'm using the SAT algorithm to detect collisions. The collisions are between the character (AxisAlignedBoundingBox) and some rectangles (with rotation).
Everything works fine, except the collision near to a corner in specific situations. (This is a pretty known problem but I didn't find any good solutions).
On Example 1, in the second scene the character should move upwards (stay on the obstacle).
It happens to move left.
On Example 2, in the second scene the character should not get up. Sometimes it gets.
I know why this is happening, because of dx and dy, the Minimum Translation Vector isn't always the wanted one.
There are several solutions to this problem, but not a really good one (in terms of solving the problem and not creating others!).
I'm willing to even use a totally different algorithm from the beginning.
Please give me a hint about an algorithm better than the SAT, or some workaround.
THANK YOU!
A picture is worth many words.
The image has two boxes to test the red and the black..
Note how the center of the black box is always on the darker red box when it is just touching.
You can simplify any AABB test by increasing the size of one box by the size of the other. As long as you referance the boxes position by their centers all works well.
// x,y are box centers
var bBox = { w : 100 , h : 50, x : ?, y ? }; // black
var rBox = { w : 200 , h : 200, x : ?, y ? }; // red
to test if bBox is inside rBox
if(bBox.x > rBox.x - (rBox.w + bBox.w)/2 &&
bBox.x < rBox.x + (rBox.w + bBox.w)/2 &&
bBox.y > rBox.y - (rBox.h + bBox.h)/2 &&
bBox.y < rBox.y + (rBox.h + bBox.h)/2)
// boxes are touching.
}
Also works if boxes are moving. You just test if the vector of bBox movement intersects any of rBox's 4 sides.
Related
I want to move some balls in specific direction. This direction is determined by a "pointer" - which is a simple line with x1,y1 and x2,y2 coordinates.
From this line I get its vector. v = (x2-x1, y2-y1). This vector is then used to move the balls.
ball.x += v.x;
ball.y += v.y;
This works fine as long as I don't want to slow the balls down. To slow them down I divided the vector by 5, which should result in smaller vector with the same direction.
v = (x2-x1)/5,(y2-y1)/5;
This solution slows the balls down, however it also changes their direction. So it look something like this :
What should I do in order to slow the balls down without this direction change ?
I'm making an image using python. But the Lambertian shading does not work.
At first the image saved like this.
enter image description here
But when I reversed the normal vector of sphere, the image saved like this.enter image description here
This is my shading code.
v = -m*ray
if s == 'Sphere':
n = view.viewPoint - list[idx].c - v
n = -n / np.sqrt(np.sum(n*n))
for i in light:
l_i = v + i.position - view.viewPoint
l_i = l_i / np.sqrt(np.sum(l_i * l_i))
x = list[idx].s.d[0] * i.intensity[0] * max(np.dot(l_i, n), 0)
y = list[idx].s.d[1] * i.intensity[1] * max(np.dot(l_i, n), 0)
z = list[idx].s.d[2] * i.intensity[2] * max(np.dot(l_i, n), 0)
list is sphere's list and idx is the number of the closest sphere.
I'd be grateful if anyone could help me. I have been doing this for a week
You have not stated what you think is wrong.
Where is the light in relation to the spheres in the first image? Is it above and slightly behind them? If so - the image looks correct.
Assuming the statements above are correct, then the second image looks correct. The reason the light is on the bottom of the spheres is because the normal is now pointing "in" so the dot() product sign will be opposite to that in the first image.
Note that in your example code, it doesn't look like you have any shadow ray treatment. In other words - all objects will be lit as if all other objects are transparent. No objects will cast shadows on to other objects. This also explains why you can see the bottom of the spheres when the light is coming from the top. If you had proper shadow rays, then it wouldn't actually matter which way the normal is pointing (I would remove the max() functions at that point).
I am trying to find an effective algorithm for the following 3D Cube Selection problem:
Imagine a 2D array of Points (lets make it square of size x size) and call it a side.
For ease of calculations lets declare max as size-1
Create a Cube of six sides, keeping 0,0 at the lower left hand side and max,max at top right.
Using z to track the side a single cube is located, y as up and x as right
public class Point3D {
public int x,y,z;
public Point3D(){}
public Point3D(int X, int Y, int Z) {
x = X;
y = Y;
z = Z;
}
}
Point3D[,,] CreateCube(int size)
{
Point3D[,,] Cube = new Point3D[6, size, size];
for(int z=0;z<6;z++)
{
for(int y=0;y<size;y++)
{
for(int x=0;x<size;x++)
{
Cube[z,y,x] = new Point3D(x,y,z);
}
}
}
return Cube;
}
Now to select a random single point, we can just use three random numbers such that:
Point3D point = new Point(
Random(0,size), // 0 and max
Random(0,size), // 0 and max
Random(0,6)); // 0 and 5
To select a plus we could detect if a given direction would fit inside the current side.
Otherwise we find the cube located on the side touching the center point.
Using 4 functions with something like:
private T GetUpFrom<T>(T[,,] dataSet, Point3D point) where T : class {
if(point.y < max)
return dataSet[point.z, point.y + 1, point.x];
else {
switch(point.z) {
case 0: return dataSet[1, point.x, max]; // x+
case 1: return dataSet[5, max, max - point.x];// y+
case 2: return dataSet[1, 0, point.x]; // z+
case 3: return dataSet[1, max - point.x, 0]; // x-
case 4: return dataSet[2, max, point.x]; // y-
case 5: return dataSet[1, max, max - point.x];// z-
}
}
return null;
}
Now I would like to find a way to select arbitrary shapes (like predefined random blobs) at a random point.
But would settle for adjusting it to either a Square or jagged Circle.
The actual surface area would be warped and folded onto itself on corners, which is fine and does not need compensating ( imagine putting a sticker on the corner on a cube, if the corner matches the center of the sticker one fourth of the sticker would need to be removed for it to stick and fold on the corner). Again this is the desired effect.
No duplicate selections are allowed, thus cubes that would be selected twice would need to be filtered somehow (or calculated in such a way that duplicates do not occur). Which could be a simple as using a HashSet or a List and using a helper function to check if the entry is unique (which is fine as selections will always be far below 1000 cubes max).
The delegate for this function in the class containing the Sides of the Cube looks like:
delegate T[] SelectShape(Point3D point, int size);
Currently I'm thinking of checking each side of the Cube to see which part of the selection is located on that side.
Calculating which part of the selection is on the same side of the selected Point3D, would be trivial as we don't need to translate the positions, just the boundary.
Next would be 5 translations, followed by checking the other 5 sides to see if part of the selected area is on that side.
I'm getting rusty in solving problems like this, so was wondering if anyone has a better solution for this problem.
#arghbleargh Requested a further explanation:
We will use a Cube of 6 sides and use a size of 16. Each side is 16x16 points.
Stored as a three dimensional array I used z for side, y, x such that the array would be initiated with: new Point3D[z, y, x], it would work almost identical for jagged arrays, which are serializable by default (so that would be nice too) [z][y][x] but would require seperate initialization of each subarray.
Let's select a square with the size of 5x5, centered around a selected point.
To find such a 5x5 square substract and add 2 to the axis in question: x-2 to x+2 and y-2 to y+2.
Randomly selectubg a side, the point we select is z = 0 (the x+ side of the Cube), y = 6, x = 6.
Both 6-2 and 6+2 are well within the limits of 16 x 16 array of the side and easy to select.
Shifting the selection point to x=0 and y=6 however would prove a little more challenging.
As x - 2 would require a look up of the side to the left of the side we selected.
Luckily we selected side 0 or x+, because as long as we are not on the top or bottom side and not going to the top or bottom side of the cube, all axis are x+ = right, y+ = up.
So to get the coordinates on the side to the left would only require a subtraction of max (size - 1) - x. Remember size = 16, max = 15, x = 0-2 = -2, max - x = 13.
The subsection on this side would thus be x = 13 to 15, y = 4 to 8.
Adding this to the part we could select on the original side would give the entire selection.
Shifting the selection to 0,6 would prove more complicated, as now we cannot hide behind the safety of knowing all axis align easily. Some rotation might be required. There are only 4 possible translations, so it is still manageable.
Shifting to 0,0 is where the problems really start to appear.
As now both left and down require to wrap around to other sides. Further more, as even the subdivided part would have an area fall outside.
The only salve on this wound is that we do not care about the overlapping parts of the selection.
So we can either skip them when possible or filter them from the results later.
Now that we move from a 'normal axis' side to the bottom one, we would need to rotate and match the correct coordinates so that the points wrap around the edge correctly.
As the axis of each side are folded in a cube, some axis might need to flip or rotate to select the right points.
The question remains if there are better solutions available of selecting all points on a cube which are inside an area. Perhaps I could give each side a translation matrix and test coordinates in world space?
Found a pretty good solution that requires little effort to implement.
Create a storage for a Hollow Cube with a size of n + 2, where n is the size of the cube contained in the data. This satisfies the : sides are touching but do not overlap or share certain points.
This will simplify calculations and translations by creating a lookup array that uses Cartesian coordinates.
With a single translation function to take the coordinates of a selected point, get the 'world position'.
Using that function we can store each point into the cartesian lookup array.
When selecting a point, we can again use the same function (or use stored data) and subtract (to get AA or min position) and add (to get BB or max position).
Then we can just lookup each entry between the AA.xyz and BB.xyz coordinates.
Each null entry should be skipped.
Optimize if required by using a type of array that return null if z is not 0 or size-1 and thus does not need to store null references of the 'hollow cube' in the middle.
Now that the cube can select 3D cubes, the other shapes are trivial, given a 3D point, define a 3D shape and test each part in the shape with the lookup array, if not null add it to selection.
Each point is only selected once as we only check each position once.
A little calculation overhead due to testing against the empty inside and outside of the cube, but array access is so fast that this solution is fine for my current project.
I think swept means determining if objects will collide at some point, not just whether they are currently colliding, but if I'm wrong tell me.
I have objects with bounded boxes that are aligned on an axis. The boxes of objects can be different sizes, but they are always rectangular.
I've tried and tried to figure out an algorithm to determine if two moving AABB objects will collide at some point, but I am having a really hard time. I read a question on here about determining the time intervals when the two objects will pass at some point, and I didn't have a problem visualizing it, but implementing it was another story. It seems like there are too many exceptions, and it doesn't seem like I am doing it correctly.
The objects are only able to move in straight lines (though obviously they can change direction, e.g. turn around, but they are always on the axis. If they try to turn off the axis then it just doesn't work), and are bound to the axis. Their bounded boxes don't rotate or do anything like that. Velocity can change, but it doesn't matter since the point of the method is to determine whether, given the objects' current state, they are on a "collision course". If you need any more information let me know.
If someone could provide some pseudocode (or real code) that would be great. I read a document called Intersection of Convex Objects: The Method of Separating Axes but I didn't understand some of the pseudocode in it (what does Union mean)?
Any help is appreciated, thanks.
When a collision occurs, the boxes will touch on one side. You could check whether they would be touching for pairs of sides (LR, RL, UD, DU).
If it would simplify the problem, you could translate the boxes so the first box is at the origin and is not moving.
Something like the following code:
dLR = B.L - A.R;
dRL = A.L - B.R;
dUD = B.U - A.D;
dDU = A.U - B.D;
vX = A.xV - B.xV;
vY = A.yV - B.yV;
tLR = dLR / vX;
tRL =-dRL / vX;
tUD = dUD / vY;
tDU =-dDU / vY;
hY = dUD + dDU; //combined height
hX = dLR + dRL;
if((tLR > 0) && (abs(dDU + vY*tLR) < hY)) return true;
if((tRL > 0) && (abs(dUD - vY*tRL) < hY)) return true;
if((tUD > 0) && (abs(dRL + vX*tUD) < hX)) return true;
if((tDU > 0) && (abs(dLR - vX*tDU) < hX)) return true;
return false;
I'm writing a little tile-based game, for which I'd like to support light sources. But my algorithm-fu is too weak, hence I come to you for help.
The situation is like this: There is a tile-based map (held as a 2D array), containing a single light source and several items standing around. I want to calculate which tiles are lit up by the light source, and which are in shadow.
A visual aid of what it would look like, approximately. The L is the light source, the Xs are items blocking the light, the 0s are lit tiles, and the -s are tiles in shadow.
0 0 0 0 0 0 - - 0
0 0 0 0 0 0 - 0 0
0 0 0 0 0 X 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 L 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 X X X X 0 0
0 0 0 - - - - - 0
0 0 - - - - - - -
A fractional system would be even better, of course, where a tile can be in half-shadow due to being partially obscured. The algorithm wouldn't have to be perfect - just not obviously wrong and reasonably fast.
(Of course, there would be multiple light sources, but that's just a loop.)
Any takers?
The roguelike development community has a bit of an obsession with line-of-sight, field-of-view algorithms.
Here's a link to a roguelike wiki article on the subject:
http://roguebasin.roguelikedevelopment.org/index.php?title=Field_of_Vision
For my roguelike game, I implemented a shadow casting algorithm (http://roguebasin.roguelikedevelopment.org/index.php?title=Shadow_casting) in Python. It was a bit complicated to put together, but ran reasonably efficiently (even in pure Python) and generated nice results.
The "Permissive Field of View" seems to be gaining popularity as well:
http://roguebasin.roguelikedevelopment.org/index.php?title=Permissive_Field_of_View
You can get into all sorts of complexities with calculating occlusion etc, or you can go for the simple brute force method: For every cell, use a line drawing algorithm such as the Bresenham Line Algorithm to examine every cell between the current one and the light source. If any are filled cells or (if you have only one light source) cells that have already been tested and found to be in shadow, your cell is in shadow. If you encounter a cell known to be lit, your cell will likewise be lit. An easy optimisation to this is to set the state of any cells you encounter along the line to whatever the final outcome is.
This is more or less what I used in my 2004 IOCCC winning entry. Obviously that doesn't make good example code, though. ;)
Edit: As loren points out, with these optimisations, you only need to pick the pixels along the edge of the map to trace from.
The algorithms being presented here seem to me to be doing more calculations than I think are needed. I have not tested this but I think it would work:
Initially, mark all pixels as lit.
For every pixel on the edge of the map: As Arachnid suggested, use Bresenham to trace a line from the pixel to the light. If that line strikes an obstruction then mark all pixels from the edge to just beyond the obstruction as being in shadow.
Quick and dirty:
(Depending on how big the array is)
Loop through each tile
draw a line to the Light
If any pary of the line hits an X, then it is in shadow
(Optional): calculate the amount of X the line passes through and do fancy maths to determint the proportion of the tile in shadow. NB: This could be done by anti-aliasing the line between the tile and the Light (therefore looking at other tiles along the route back to the light source) during the thresholding procedure these will appear as small anomolies. Depending on the logic used you could potentially determine how much (if at all) the tile is in shadow.
You could also keep a track of which pixels have been tested, therefore optimize the solution a little and not re-test pixels twice.
This could be dome pretty well by using image manipulation and drawing straight lines between pixles (tiles) If the lines are semi transparent and the X blocks are semi-transparent again. You can threshold the image to determine if the line has intersected an 'X'
If you have an option to use a 3rd party tool, then Id probably take it. In the long run it might turn out to be quicker, but you'd understand less about your game.
This is just for fun:
You can replicate the Doom 3 approach in 2D if you first do a step to convert your tiles into lines. For instance,
- - - - -
- X X X -
- X X - -
- X - - -
- - - - L
...would be reduced into three lines connecting the corners of the solid object in a triangle.
Then, do what the Doom 3 engine does: From the perspective of the light source, consider each "wall" that faces the light. (In this scene, only the diagonal line would be considered.) For each such line, project it into a trapezoid whose front edge is the original line, whose sides lie on lines from the light source through each end point, and whose back is far away, past the whole scene. So, it's a trapezoid that "points at" the light. It contains all the space that the wall casts its shadow on. Fill every tile in this trapezoid with darkness.
Proceed through all such lines and you will end up with a "stencil" that includes all the tiles visible from the light source. Fill these tiles with the light color. You may wish to light the tile a little less as you get away from the source ("attenuation") or do other fancy stuff.
Repeat for every light source in your scene.
To check if a tile is in shadow you need to draw a straight line back to the light source. If the line intersects another tile that's occupied, then the tile you were testing is in shadow. Raytracing algorithms do this for every object (in your case tile) in the view.
The Raytracing article on Wikipedia has pseudocode.
Here is a very simple but fairly effective approach that uses linear time in the number of tiles on screen. Each tile is either opaque or transparent (that's given to us), and each can be visible or shaded (that's what we're trying to compute).
We start by marking the avatar itself as "visible".
We then apply this recursive rule to determine the visibility of the remaining tiles.
If the tile is on the same row or column as the avatar, then it is only visible if the adjacent tile nearer to the avatar is visible and transparent.
If the tile is on a 45 degree diagonal from the avatar, then it is only visible if the neighboring diagonal tile (towards the avatar) is visible and transparent.
In all other cases, consider the three neighboring tiles that are closer to the avatar than the tile in question. For example, if this tile is at (x,y) and is above and to the right of the avatar, then the three tiles to consider are (x-1, y), (x, y-1) and (x-1, y-1). The tile in question is visible if any of those three tiles are visible and transparent.
In order to make this work, the tiles must be inspected in a specific order to ensure that the recursive cases are already computed. Here is an example of a working ordering, starting from 0 (which is the avatar itself) and counting up:
9876789
8543458
7421247
6310136
7421247
8543458
9876789
Tiles with the same number can be inspected in any order amongst themselves.
The result is not beautiful shadow-casting, but computes believable tile visibility.
I know this is years old question, but for anyone searching for this style of stuff I'd like to offer a solution I used once for a roguelike of my own; manually "precalculated" FOV. If you field of view of light source has a maximum outer distance it's really not very much effort to hand draw the shadows created by blocking objects. You only need to draw 1/8 th of the circle (plus the straight and diagonal directions); you can use symmerty for the other eigths. You'll have as many shadowmaps as you have squares in that 1/8th of a circle. Then just OR them together according to objects.
The three major pros for this are:
1. It's very quick if implemented right
2. You get to decide how the shadow should be cast, no comparing which algorith handles which situation the best
3. No weird algorith induced edge cases which you have to somehow fix
The con is you don't really get to implement a fun algorithm.
TK's solution is the one that you would generally use for this sort of thing.
For the partial lighting scenario, you could have it so that if a tile results in being in shadow, that tile is then split up into 4 tiles and each one of those is tested. You could then split that up as much as you wanted?
Edit:
You can also optimise it out a bit by not testing any of the tiles adjacent to a light - this would be more important to do when you have multiple light sources, I guess...
I've actually just recently wrote this functionality into one of my projects.
void Battle::CheckSensorRange(Unit* unit,bool fog){
int sensorRange = 0;
for(int i=0; i < unit->GetSensorSlots(); i++){
if(unit->GetSensorSlot(i)->GetSlotEmpty() == false){
sensorRange += unit->GetSensorSlot(i)->GetSensor()->GetRange()+1;
}
}
int originX = unit->GetUnitX();
int originY = unit->GetUnitY();
float lineLength;
vector <Place> maxCircle;
//get a circle around the unit
for(int i = originX - sensorRange; i < originX + sensorRange; i++){
if(i < 0){
continue;
}
for(int j = originY - sensorRange; j < originY + sensorRange; j++){
if(j < 0){
continue;
}
lineLength = sqrt( (float)((originX - i)*(originX - i)) + (float)((originY - j)*(originY - j)));
if(lineLength < (float)sensorRange){
Place tmp;
tmp.x = i;
tmp.y = j;
maxCircle.push_back(tmp);
}
}
}
//if we're supposed to fog everything we don't have to do any fancy calculations
if(fog){
for(int circleI = 0; circleI < (int) maxCircle.size(); circleI++){
Map->GetGrid(maxCircle[circleI].x,maxCircle[circleI].y)->SetFog(fog);
}
}else{
bool LOSCheck = true;
vector <bool> placeCheck;
//have to check all of the tiles to begin with
for(int circleI = 0; circleI < (int) maxCircle.size(); circleI++){
placeCheck.push_back(true);
}
//for all tiles in the circle, check LOS
for(int circleI = 0; circleI < (int) maxCircle.size(); circleI++){
vector<Place> lineTiles;
lineTiles = line(originX, originY, maxCircle[circleI].x, maxCircle[circleI].y);
//check each tile in the line for LOS
for(int lineI = 0; lineI < (int) lineTiles.size(); lineI++){
if(false == CheckPlaceLOS(lineTiles[lineI], unit)){
LOSCheck = false;
//mark this tile not to be checked again
placeCheck[circleI] = false;
}
if(false == LOSCheck){
break;
}
}
if(LOSCheck){
Map->GetGrid(maxCircle[circleI].x,maxCircle[circleI].y)->SetFog(fog);
}else{
LOSCheck = true;
}
}
}
}
There's some extra stuff in there that you wouldn't need if you're adapting it for your own use. The type Place is just defined as an x and y position for conveniences sake.
The line function is taken from Wikipedia with very small modifications. Instead of printing out x y coordinates I changed it to return a place vector with all the points in the line. The CheckPlaceLOS function just returns true or false based on if the tile has an object on it. There's some more optimizations that could be done with this but this is fine for my needs.
i have implemented tilebased field of view in a single C function. here it is:
https://gist.github.com/zloedi/9551625
If you don't want to spend the time to reinvent/re-implement this, there are plenty of game engines out there. Ogre3D is an open source game engine that fully supports lighting, as well as sound and game controls.