Hi I am trying to make 2d collision but I dont get it to work
i am doing :
if (collider.posX + collider.sizeX >= obstacle.posX && obstacle.posX + obstacle.sizeX >= collider.posX && collider.posY + collider.sizeY >= obstacle.posY)
the obstacle cannot move on the y axis so this is why i only check for
collider.posY + 50 >= obstacle.posY
the collision works but they are only start when the obstacle is half in the collider
What about:
if( obstacle.posX >= collider.posX &&
obstacle.posX <= collider.posX + collider.sizeX &&
obstacle.posY >= collider.posY &&
obstacle.posY <= collider.posY + collider.sizeY
)
This code should check if obstacle point intersects collider rectangle.
This is better solution because it detects overlapping between 2 rectangles:
if ( obstacle.posX <= collider.posX + collider.sizeX &&
obstacle.posX + obstacle.sizeX >= collider.posX &&
obstacle.posY <= collider.posY + collider.sizeY &&
obstacle.posY + obstacle.sizeY >= collider.posY )
You're running into logical errors, seen by the following code:
collider.posX + collider.sizeX >= obstacle.posX
Suppose the two colliding objects are circles with their positions being their center points. The first object is moving in the positive X direction while the second is static (stationary). You need to check if the first object's X position plus its radius (not diameter) touches the second object's X position minus its radius.
Example code:
collider.posX + (collider.sizeX / 2) >= obstacle.posX - (obstacle.sizeX / 2)
Note: The above inequality assumes that collider.sizeX represents the diameter of collider.
Presumably later on you'll also need to check if the first object is passed the second object. Since the above inequality only accounts for the first object having an increasing X position and its X position being less than the second object's X position.
Related
I am struggling to optimize the following fragment of code. The function is being called for every voxel in a 320x320x320 volume where each voxel is a 16bit grayscale value. The volume is stored as a series of planes (cross sections) and each plane is a contiguous 1D array, hence for example the position of a voxel below current voxel becomes currentPosition + pixelsPerRow and position to the left of it becomes currentPosition - 1.
The function checks for both zero crossings in the volume and if the absolute value of current and neighboring voxel is above certain threshold. This is a neccessary part of Marr-Hildreth edge detector.
currentPosition is the current voxel and relativePosition can be either the current voxel too (in that case zero crossings are checked in 8 directions around it in the same plane) or it can be voxel directly above or directly below it. This way, for every voxel, 27 checks are performed which covers all the possible directions in 3D.
Perhaps it is possible to rearrange the function in such the way that its execution will be faster. I already tried to arrange the order of checks in such the way that branch prediction has a slightly better chance to kick in, but maybe it's possible to speed it up even more. For now it takes 50% processing time of a much larger application so it begs for some optimizations.
bool zeroCrossing(int16_t* currentPosition, int16_t* relativePosition, int pixelsPerRow, int threshold)
{
return *currentPosition * *(relativePosition - pixelsPerRow - 1) < 0 && abs(*currentPosition + *(relativePosition - pixelsPerRow - 1)) > threshold
|| *currentPosition * *(relativePosition - pixelsPerRow) < 0 && abs(*currentPosition + *(relativePosition - pixelsPerRow)) > threshold
|| *currentPosition * *(relativePosition - pixelsPerRow + 1) < 0 && abs(*currentPosition + *(relativePosition - pixelsPerRow + 1)) > threshold
|| *currentPosition * *(relativePosition - 1) < 0 && abs(*currentPosition + *(relativePosition - 1)) > threshold
|| *currentPosition * *(relativePosition) < 0 && abs(*currentPosition + *(relativePosition)) > threshold
|| *currentPosition * *(relativePosition + 1) < 0 && abs(*currentPosition + *(relativePosition + 1)) > threshold
|| *currentPosition * *(relativePosition + pixelsPerRow - 1) < 0 && abs(*currentPosition + *(relativePosition + pixelsPerRow - 1)) > threshold
|| *currentPosition * *(relativePosition + pixelsPerRow) < 0 && abs(*currentPosition + *(relativePosition + pixelsPerRow)) > threshold
|| *currentPosition * *(relativePosition + pixelsPerRow + 1) < 0 && abs(*currentPosition + *(relativePosition + pixelsPerRow + 1)) > threshold;
}
My gut instinct is that this code lends itself well to parallelization. Either use AVX(2), or offload this to a GPU. That would take it outside the realm of C++, but that is a reasonable thing to do for the core function of a program.
I'm assuming you already use threads to parallelize the operation, because that is pretty trivial. Note that with AVX you'd still need threads; each CPU core has it's own AVX unit.
If there is a zero crossing, it will happen in between two neighboring pixels. When running through the volume, you need to check each pair of neighbors only once. If you apply your function to each pixel, you'll check each pair twice. (I use the term pixel for the elements of a 3D image too, I don't like the term voxel a whole lot).
Also, you check pairs of pixels that share an edge or a vertex, you only need to check those that share a face. If there is a zero crossing between pixels a and d in the figure below, there must be one between a and b or between a and c.
a b
c d
Thus, for each pixel, you only need to check three neighbors, not 27. This would reduce your execution time to 1/9.
However, this does not exactly account for your magnitude check, the difference between a and d could be larger than that between either of its other two neighbors. However, I don't think this is important.
On that note, your magnitude check is wrong: if a and b differ in sign and are both very large (an important zero crossing), then abs(a + b) could be 0, and you wouldn't count it. You probably want to take the difference!
I'm currently using this collision code:
( // tx = other x, tex = other end x etc.
( // horizontal collision
(xpos >= tx && xpos <= tex)
||
((xpos + w) <= tex && (xpos + w) >= tx)
)
&&
( // vertical collision
(ypos >= ty && ypos <= tey)
||
((ypos + h) <= tey && (ypos + h) >= ty)
)
)
However, it only detects if the top left pixel, the top right pixel, the bottom left pixel, or the bottom right pixel is within the rectangle to test. I don't know what to do, it already took forever to get to the current collision testing method I'm using, what can I change to fix this problem?
Do I understand correctly that one rectangle extends horizontally from xpos to xpos + w and vertically from ypos to ypos + h, and the other extends horizontally from tx to tex and vertically from ty to tey? With w, h, tex − tx, and tey − ty all being positive?
If so, then you can write:
xpos <= tex && xpos + w >= tx // horizontal collision
&& ypos <= tey && ypos + h >= ty // vertical collision
Alternatively, you may find it easier to reason about if you calculate the conditions whereby they don't collide, and just add a !:
!(
xpos > tex // first rectangle entirely to right of second
|| xpos + w < tx // first rectangle entirely to left of second
|| ypos > tey // first rectangle entirely above second
|| ypos + h < ty // first rectangle entirely below second
)
(The two versions are equivalent, due to one of De Morgan's laws.)
Well I've got a 2D box collision code that basically loops through every block in a list called "Blocks" and it checks if I'm near the sides and whatnot.
It works very well except for the bottom of the block. When I'm jumping up towards the bottom I want my player to simply "bounce" off. It does this, but it is very glitchy. It's hard to explain so I was hoping you guys could possibly spot out what's wrong with my bottom collision code.
Here's the entire thing (this is ran in a loop):
for(unsigned int i = 0; i<blocks.size(); i++){
Block &b = blocks.at(i);
if(!b.passable==true){
//Check if we are on the sides
if(y + height + vspeed >= b.worldY+2 && y + vspeed <= b.worldY+b.height)
{
//Right side
if(x + hspeed <= b.worldX+b.width-1 && x + hspeed > b.worldX+b.width + hspeed-2)
{
x = b.worldX + b.width; hspeed = 0;
}
//Left side
if(x + width + hspeed >= b.worldX +1 && x + width + hspeed <= b.worldX + hspeed + 2)
{
x = b.worldX - width; hspeed = 0;
}
}
//Check if we are on the top or the bottom
if(x + width + hspeed >= b.worldX+2 && x + hspeed <= b.worldX+b.width-2)
{
if(y + height + vspeed >= b.worldY && y + height + vspeed <= b.worldY + vspeed + 1 && jumpstate=="falling")
{
y = b.worldY - height; jumpstate.assign("ground"); vspeed = 0;
}
if(y + vspeed <= b.worldY + b.height && y + vspeed >= b.worldY + b.height + vspeed - 1 && jumpstate=="jumping")
{
y = b.worldY + b.height; jumpstate.assign("falling"); vspeed = 0;
}
}
}
}
I'm not sure you'll get it to work like this. I'll explain a solution that I thought of for some collision detection and bouncing that works smoothly. Record the time interval from when you last checked collisions and adjusted position. If Xplayer+Vplayer*deltaT>Xtarget (if the player would overlap the target) then compute the actual time when it would be touching the target deltaTtouch=(Xtarget-Xplayer)/Vplayer. Now bounce the player back Xplayer=Xtarget-Vplayer*(deltaT-deltaTtouch). You'll have to figure out all the cases when moving forward, backward, up, down.
LE: You can also implement gravity, this involves solving a quadratic equation for finding out the deltaTtouch.
Well I can see a few little details:
1) In this line the hspeed when checking the old position is quite redundant, best to remove it for clarity.
if(x + hspeed <= b.worldX+b.width-1 && x + hspeed > b.worldX+b.width + hspeed-2)
Becomes:
if(x + hspeed <= b.worldX + b.width - 1 && x > b.worldX + b.width - 2)
Same goes for the other similar lines.
2) The small offsets of -2 and -1 are a bit confusing I presume you are trying to achieve a small buffer such that a slight amount of overlap is required. Especially this line where you have used a < instead of the <= you have used every else:
if(x + hspeed <= b.worldX+b.width-1 && x + hspeed > b.worldX+b.width + hspeed-2)
To keep consistancy with the rest of the program I would probably write:
if(x + hspeed <= b.worldX + b.width - 1 && x >= b.worldX + b.width - 1)
3) You seem to be missing a few of your small offsets in the vert checks:
So this check first:
if(y + height + vspeed >= b.worldY && y + height + vspeed <= b.worldY + vspeed + 1 && jumpstate=="falling")
You seem to have forgotten your small offset:
if(y + height + vspeed >= b.worldY + 1 && y + height <= b.worldY + 1 && jumpstate=="falling")
Then the second check:
if(y + vspeed <= b.worldY + b.height && y + vspeed >= b.worldY + b.height + vspeed - 1 && jumpstate=="jumping")
Offset again:
if(y + vspeed <= b.worldY + b.height - 1 && y >= b.worldY + b.height - 1 && jumpstate=="jumping")
4) You will need to be very careful that vspeed and jumpstate always remain in sync as the sign of vspeed needs to always match jumpstate or you will miss collisions. I imagine this might be where your problem is coming from.
5) In both directions if speed exceeds the block size you will skip collision detection and fire through the block.
if(y + height + vspeed >= b.worldY+2 && y + vspeed <= b.worldY+b.height)
The second check in these lines will be false if speed is higher than b.height and the y coords are similar.
Hope that helps some.
Well I've got a 2D box collision code that basically loops through every block in a list called "Blocks" and it checks if I'm near the sides and whatnot.
It works very well except for the bottom of the block. When I'm jumping up towards the bottom I want my player to simply "bounce" off. It does this, but it is very glitchy.
It's hard to explain so I was hoping you guys could possibly spot out what's wrong with my bottom collision code.
Here's the entire thing:
for(unsigned int i = 0; i<blocks.size(); i++){
Block &b = blocks.at(i);
if(!b.passable==true){
//Check if we are on the sides
if(y + height + vspeed >= b.worldY+2 && y + vspeed <= b.worldY+b.height)
{
//Right side
if(x + hspeed <= b.worldX+b.width-1 && x + hspeed > b.worldX+b.width + hspeed-2)
{
x = b.worldX + b.width; hspeed = 0;
}
//Left side
if(x + width + hspeed >= b.worldX +1 && x + width + hspeed <= b.worldX + hspeed + 2)
{
x = b.worldX - width; hspeed = 0;
}
}
//Check if we are on the top or the bottom
if(x + width + hspeed >= b.worldX+2 && x + hspeed <= b.worldX+b.width-2)
{
if(y + height + vspeed >= b.worldY && y + height + vspeed <= b.worldY + vspeed + 1 && jumpstate=="falling")
{
y = b.worldY - height; jumpstate.assign("ground"); vspeed = 0;
}
if(y + vspeed <= b.worldY + b.height && y + vspeed >= b.worldY + b.height + vspeed - 1 && jumpstate=="jumping")
{
y = b.worldY + b.height; jumpstate.assign("falling"); vspeed = 0;
}
}
}
}
My guess is that you should set vspeed = -vspeed; instead of vspeed = 0. Fully elastic bouncing means that the velocity gets mirrored in the box's side.
If you set it to zero, depending on the order in which you perform your updates, you might not move during a frame. And since you use <= and >= for bounds checking, you'll still be inside the box on the next frame, invoke the bouncing behaviour again, and get stuck with your head glued to the block.
My guess at your problem would be negative numbers in your inequality checks. For example, when going down, I guess vspeed will be negative. Depending on where you have set the origin of your box, this could mean that the condition
y + vspeed <= b.worldY + b.height
is always true.
As an aside, by adding a distance to a speed, you have assumed a magic dimension for the unit time. This makes your code brittle because if you change this magic number, then your equations will be wrong.
Try,
y + vspeed*unit_time <= b.worldY + b.height
If you want to handle the units at compile-time (and not pay for that multiplication), then use boost.units.
Additionally,
x + hspeed > b.worldX+b.width + hspeed-2
can be simplified to
x > b.worldX+b.width-2
And the significance of this magic number 2 is anyones guess. (why for instance do you have
//Check if we are on the sides
if(y + vspeed <= b.worldY+b.height)
but have a -2 in
//Check if we are on the top or the bottom
if( x + hspeed <= b.worldX+b.width-2)
)
If I set my player's "hspeed" variable (horizontal speed) to a slow enough speed,
then when he goes over a gap of 16x16 blocks, he will fall through as planned.
However if I set the "hspeed" variable high enough, he will go so fast that he hovers over it.
All though it works when I set it to a slow speed, it's too slow.
Here's an example:
http://img199.imageshack.us/img199/2685/demondj.png
Here's my collision code (loops through a list of blocks):
for(unsigned int i = 0; i<blocks.size(); i++){
Block &b = blocks.at(i);
if(!b.passable){
//Check if we are on the sides
if(y + height + vspeed >= b.worldY+2 && y + vspeed <= b.worldY+b.height)
{
//Right side
if(x + hspeed <= b.worldX+b.width+1 && x + hspeed > b.worldX+b.width + hspeed-1)
{
x = b.worldX + b.width; hspeed = 0;
}
//Left side
if(x + width + hspeed >= b.worldX +1 && x + width + hspeed <= b.worldX + hspeed + 1)
{
x = b.worldX - width; hspeed = 0;
}
}
//Check if we are on the top or the bottom
if(x + width + hspeed >= b.worldX+1 && x + hspeed <= b.worldX+b.width-1)
{
if(y + height + vspeed >= b.worldY && y + height + vspeed <= b.worldY + vspeed + 1 && jumpstate=="falling")
{
y = b.worldY - height; jumpstate.assign("ground"); vspeed = 0;
}
if(y + vspeed <= b.worldY + b.height && y + vspeed >= b.worldY + b.height + vspeed + 1 && jumpstate=="jumping")
{
y = b.worldY + b.height; jumpstate.assign("falling"); vspeed = 0;
}
}
}
}
Do I have a problem in my collision code?
Another problem is when I hit the bottom of a block, it's a bit glitchy.
He's supposed to bounce right off it, and he does, but he jitters if he's moving and he hits the bottom of a block.
Ok, a number of things here:
1) Too many magic numbers. Not sure exactly what the +2, +1, etc. truely mean. I'd like to see those as constants. Also, I'm paranoid about order of operations so I would surround everything in parenthesis, just in case :)
2) Unsure of what types your vars are. Assuming floats, but they feel like ints.
3) The bigger problem, your code as designed will not properly handle "large" velocity well. Something traveling faster than the width/height of your collidable area won't be reliably detected. Nor can you easily with this type of collision code. This is one side effect you are already seeing and my guess is the fudge factor adds you have contribute to the rest.
Consider using a vector based collision system instead. Treat each edge of the box as a line vector. You can then do very simple math to determine if a point starts one one side of the line and ends on the other (sign of cross product) and sign of dot will tell whether the point was within the line segment. Also, it allows your collision objects to be any shape and even makes the math extendable to 3D rather easily. This sort of system also is parallel processing friendlier as well.