Sprites collide with tiled background

Member
Posts: 370
Joined: 2002.04
Post: #1
How do I detect collisions between sprites and a tiled background when some of the tiles are blocking and some aren't? I'm having lots of trouble with my current alogrithm - are there any 'accepted' ways of doing it? Thanks.

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
Moderator
Posts: 916
Joined: 2002.10
Post: #2
[myCell collidesWith:tileMap[12][5] withinRadius:-1 polygonAccurate:YES]

??
Quote this message in a reply
Member
Posts: 268
Joined: 2005.04
Post: #3
Check out SpriteWorld. But basically, take the sprite's old position (last frame) and current position. Use those to create a rect encompassing both. Use that rect to select the start/stop row and start/stop column of the tilemap. Then check the sprite against each tile that occurs in that small area. If the tile is a blocking tile and it's one of the tiles you're checking then a collision occured.

There are optimizations to be had. For instance, if the sprite is moving to the right, you only need to check for tiles on the right side. Just check out SpriteWorld. I believe it's CheckSpriteWithTiles in Tiling.c.
Quote this message in a reply
Member
Posts: 469
Joined: 2002.10
Post: #4
I you've built a large tile map with transparency, you can use CBCell's - (BOOL)containsPoint:(NSPoint)aPoint withAlpha:(float)threshold; method. This'll do fast bitmap accurate point collisions. For more complex collisions you'll probably want to do your own geometry or use the other geometry tools.

---Kelvin--
15.4" MacBook Pro revA
1.83GHz/2GB/250GB
Quote this message in a reply
Member
Posts: 370
Joined: 2002.04
Post: #5
Sky and kelvin: I don't have the tilemap as an array of CBCells, I have an array of CBCells which each has a 10x10 section of tiles. Bachus: The sprite can be rotated, and it's enough to make it fairly obvious that a bounding rect won't work, as when you're at 45 degrees, you 'catch' on corners too easily.

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
Member
Posts: 370
Joined: 2002.04
Post: #6
The SpriteWorld code is ridiculously hard to understand - must be because I've never used the API before Wink
Anyone know of a generic code example for this?

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
Member
Posts: 370
Joined: 2002.04
Post: #7
Well, I cobbled something together -
Code:
if(px[i] < x*16+8 && py[i] > y*16 && py[i] < (y+1)*16){
        [self changeValue:kTankDX toValue:(x*16 - px[i] - 1)*100 forIndex:index];
        goto checkc;
        }
        if(px[i] > x*16+8 && py[i] > y*16 && py[i] < (y+1)*16){
        [self changeValue:kTankDX toValue:(x*16 - px[i] - 1)*100 forIndex:index];
        goto checkc;
        }
        if(py[i] < y*16+8 && px[i] > x*16 && px[i] < (x+1)*16){
        [self changeValue:kTankDY toValue:(y*16 - py[i] - 1)*100 forIndex:index];
        goto checkc;
        }
        if(py[i] > y*16+8 && px[i] > x*16 && px[i] < (x+1)*16){
        [self changeValue:kTankDY toValue:(y*16 - py[i] - 1)*100 forIndex:index];
        goto checkc;
        }

px[] and py[] are the corners of the tank, rotated with sin() and cos(). x and y are the tile location in 16x16 squares. The changeValue calls take the difference multiplied by 100. The problem I have now is that the left and right cases catch even the top and bottom collisions and shove me to the side. What's a good 'sanity check' to prevent this? Thanks.

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #8
eww, goto!

what's wrong with:

Code:
if(px[i] < x*16+8 && py[i] > y*16 && py[i] < (y+1)*16){
                [self changeValue:kTankDX toValue:(x*16 - px[i] - 1)*100 forIndex:index];
            }
            else if(px[i] > x*16+8 && py[i] > y*16 && py[i] < (y+1)*16){
                [self changeValue:kTankDX toValue:(x*16 - px[i] - 1)*100 forIndex:index];
            }
            else if(py[i] < y*16+8 && px[i] > x*16 && px[i] < (x+1)*16){
                [self changeValue:kTankDY toValue:(y*16 - py[i] - 1)*100 forIndex:index];
            }
            else if(py[i] > y*16+8 && px[i] > x*16 && px[i] < (x+1)*16){
                [self changeValue:kTankDY toValue:(y*16 - py[i] - 1)*100 forIndex:index];
            }
            else
            {
                // whatever else came before checkc
            }

            // whatever was at checkc
Quote this message in a reply
Member
Posts: 370
Joined: 2002.04
Post: #9
Heh, the goto is completely unnecessary. It's just left over from when I had it move you one unit at a time away from the wall; now it's a bit smarter. I really should remove it. Also, I should have implemented it as a while loop in the first place but I was too lazy Wink

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
Member
Posts: 370
Joined: 2002.04
Post: #10
Note that that wasn't the problem, it still 'jumps' to the side, if that wasn't clear. Wink

I can't think of a way to check whether it should check x or y collisions first - if I could I think it would solve the problem.

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
Member
Posts: 370
Joined: 2002.04
Post: #11
No, still no progress. Sad I know this is possible, but I can't think of how to do it. Anyone have some generic example code which does it, and doesn't really require knowledge of a specific API? I need some starting point, my code here doesn't work too well...

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
Member
Posts: 370
Joined: 2002.04
Post: #12
I've now gone through some 4 different attempts, with little results. I really need help here... Please? Anyone???
I know this isn't impossible, I'm just so lost...

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
Jammer
Unregistered
 
Post: #13
Quote:Originally posted by Steven
I can't think of a way to check whether it should check x or y collisions first.


No joy, huh. I could be way off base here, but, have you tried getting rid of the else if's AND the goto's? It seems like you are checking one and ignoring the other when you might want to evaluate both.

Here is my 3D box collision detector, just ignore the z value. A box has min x,y,z and max x,y,z bounds co-ordinates and the arrays 0,1,2 indexes access them.

The thing to note, is checks are done on the collisions for all of x , y , z from one box to another before making any decisions and then the one that is more of a collision is the one acted on. You don't seem to be giving yours a chance to do this with the else if's or goto's. You check an x value and then act, and while it may be valid, the y value could be as well. But then, I may not fully understand what you're trying to do ...

Code:
- (BOOL) intersectsBox:(CGKBox *)aBox
{
    float *min = [[self min] elements];
    float *max = [[self max] elements];
    float *theirMin = [[aBox min] elements];
    float *theirMax = [[aBox max] elements];
    CGKVector *move = [self movement];
    float diffX, diffY, diffZ;
    
    if ( min[0] > theirMax[0] || theirMin[0] > max[0] )
    {
        return NO; // no x overlap, means no possible collision
    }
    else
    {
        diffX = min[0] - theirMax[0] > theirMin[0] - max[0]
              ? theirMin[0] - max[0]
              : min[0] - theirMax[0];
    }
    if ( min[1] > theirMax[1] || theirMin[1] > max[1] )
    {
        return NO; // no y overlap, means no possible collision
    }
    else
    {
        diffY = min[1] - theirMax[1] > theirMin[1] - max[1]
              ? theirMin[1] - max[1]
              : min[1] - theirMax[1];
    }
    if ( min[2] > theirMax[2] || theirMin[2] > max[2] )
    {
        return NO; // no z overlap, means no possible collision
    }
    else
    {
        diffZ = min[2] - theirMax[2] > theirMin[2] - max[2]
              ? theirMin[2] - max[2]
              : min[2] - theirMax[2];
    }
    
    // we only adjust moves on a moving box, not a wall box
    if ( move != nil )
    {
        diffX = Absolute( diffX );
        diffY = Absolute( diffY );
        diffZ = Absolute( diffZ );
        if ( diffX < diffY && diffX < diffZ )
            [move setX:Negate( [move x] )];
        else if ( diffY < diffX && diffY < diffZ )
            [move setY:Negate( [move y] )];
        else if ( diffZ < diffX && diffZ < diffY )
            [move setZ:Negate( [move z] )];
    }
    return YES;
}
Quote this message in a reply
DJBlufire
Unregistered
 
Post: #14
Maybe I'm not seeing the entire problem or am missing something, but:

The way I would handle collisions with walls, etc. in a tile-based map would to have a field in the tile class/data structure that indicates whether or not you can walk on it (you can do this from four directions, too). Then when you want to know if the character can walk on that tile you just check to see if the boolean "walkable" field is true; if it is, move to that spot, if not, it's a wall and you can't move. Seems like a much faster method than checking the actual bitmaps...

How would that fit into your engine?
Quote this message in a reply
Member
Posts: 370
Joined: 2002.04
Post: #15
DJ: That's exactly what I do. The only problem is making it look like the tank is actually moving along the wall 'realistically' - calculating the movement (it doesn't just stop, it can slide along the wall, etc)

Jammer: I'll try adapting your code, although I don't understand what the last part's doing.

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
Post Reply