Search code examples
ioscocos2d-iphonebox2draytracing

RayCasting in Box2D?


i am creating a project in which i have random Box2d bodies. Now i am drawing a line on basis of TouchesMoved by user in the DRAW method. i need to use the RayCasting method of Box2d to check for intersection between that line and the Box2D bodies.

i am using the following code for it in my Draw method

for(int i = 0; i < [pointTouches count]; i+=2)
{
    CGPoint startPoint = CGPointFromString([pointTouches objectAtIndex:i]);

    CGPoint endPoint = CGPointFromString([pointTouches objectAtIndex:i+1]);

    ccDrawLine(startPoint, endPoint);

    b2Vec2 start=[self toMeters:startPoint];

    b2Vec2 end=[self toMeters:endPoint];

    [self checkIntersectionbtw:start:end];
}

-(void)checkIntersectionbtw:(b2Vec2)point1:(b2Vec2)point2
{
    RaysCastCallback callback;

world->RayCast(&callback, point1,point2);

if (callback.m_fixture)
{
    NSLog(@"intersected");
    checkPoint = true;
}
}

-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{ 

    UITouch *myTouch = [touches anyObject];

    CGPoint currentTouchArea = [myTouch locationInView:[myTouch view]];
    CGPoint lastTouchArea = [myTouch previousLocationInView:[myTouch view]];

    currentTouchArea = [[CCDirector sharedDirector] convertToGL:currentTouchArea];
    lastTouchArea = [[CCDirector sharedDirector] convertToGL:lastTouchArea];

    [pointTouches addObject:NSStringFromCGPoint(currentTouchArea)];
    [pointTouches addObject:NSStringFromCGPoint(lastTouchArea)];


}

but the callback only tells the intersection when the line drawn completely passes the bodies. when user starts from some point outside and leaves the point inside the box2d body the callback doesn't say the line intersected. what am i possibly doing wrong??


Solution

  • Are you drawing a line or a curve? For a line, I assume that you only use the first point and the last point detected. For a curve, you use all the points detected to form the curve that you are drawing.

    If you are drawing a curve then think I understand the problem. You are calculating the intersection line using the consecutive points detected by the touch system. These consecutive points are very close to each other which makes very small ray casts, and what might be happening is that you might be casting the line with a starting and ending point inside the balls, which might issue a negative collision.

    If the objective is to detect if you are touching the balls, I suggest using a sensor maintained under the touch, and then checking a collision with this code in your update method:

    for (b2ContactEdge* ce = sensorbody->GetContactList(); ce; ce = ce->next)
    {   
        b2Contact* c = ce->contact;
    
        if(c->IsTouching())
        {
             const b2Body* bodyA = c->GetFixtureA()->GetBody();
             const b2Body* bodyB = c->GetFixtureB()->GetBody();
    
             const b2Body* ballBody = (bodyA == sensorbody)?bodyB:bodyA;
    
             ...
    
    
        }
    }
    

    If you really want to use a raycast, then I suggest saving a few consecutive points and make a vector with them, to avoid the small ray cast.

    edit: Sorry, The example I wrote is in C++, but you should be able to find an equivalent for Objective-C.