## Box2D C++ tutorials - Ray casting

Last edited: July 14 2013Chinese version -> 中文

### Ray casting

Ray casting is often used to find out what objects are in a certain part of the world. A ray is just a straight line, and we can use a function provided by Box2D to check if the line crosses a

**fixture**. We can also find out what the normal is at the point the line hits the fixture.

Here is the function I'm talking about, which returns true if the ray hits the fixture. Notice it's a member of the b2Fixture class, which means we'll first need to have one of those to cast a ray against.

1 | bool b2Fixture::RayCast(b2RayCastOutput* output, const b2RayCastInput& input); |

1 2 3 4 5 6 | // Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). struct b2RayCastInput { b2Vec2 p1, p2; float32 maxFraction; }; |

1 2 3 4 5 6 7 | // Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2 // come from b2RayCastInput. struct b2RayCastOutput { b2Vec2 normal; float32 fraction; }; |

### Example

To try out this very handy function, let's set up a scene with a fenced area and some shapes floating inside in a zero-gravity environment. By now you should be getting used to this one, so we'll make the walls as edges instead of boxes just to spice things up.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | FooTest() { //a static body b2BodyDef myBodyDef; myBodyDef.type = b2_staticBody; myBodyDef.position.Set(0, 0); b2Body* staticBody = m_world->CreateBody(&myBodyDef); //shape definition b2PolygonShape polygonShape; //fixture definition b2FixtureDef myFixtureDef; myFixtureDef.shape = &polygonShape; //add four walls to the static body b2Vec2 bl(-20, 0); b2Vec2 br( 20, 0); b2Vec2 tl(-20,40); b2Vec2 tr( 20,40); polygonShape.SetAsEdge( bl, br ); //ground staticBody->CreateFixture(&myFixtureDef); polygonShape.SetAsEdge( tl, tr);//ceiling staticBody->CreateFixture(&myFixtureDef); polygonShape.SetAsEdge( bl, tl );//left wall staticBody->CreateFixture(&myFixtureDef); polygonShape.SetAsEdge( br, tr );//right wall staticBody->CreateFixture(&myFixtureDef); myBodyDef.type = b2_dynamicBody; myBodyDef.position.Set(0,20); polygonShape.SetAsBox(2,2); myFixtureDef.density = 1; for (int i = 0; i < 5; i++) m_world->CreateBody(&myBodyDef)->CreateFixture(&myFixtureDef); //circles b2CircleShape circleShape; circleShape.m_radius = 2; myFixtureDef.shape = &circleShape; for (int i = 0; i < 5; i++) m_world->CreateBody(&myBodyDef)->CreateFixture(&myFixtureDef); //turn gravity off m_world->SetGravity( b2Vec2(0,0) ); } |

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //at global scope float currentRayAngle = 0; //in Step() function currentRayAngle += 360 / 20.0 / 60.0 * DEGTORAD; //one revolution every 20 seconds //calculate points of ray float rayLength = 25; //long enough to hit the walls b2Vec2 p1( 0, 20 ); //center of scene b2Vec2 p2 = p1 + rayLength * b2Vec2( sinf(currentRayAngle), cosf(currentRayAngle) ); //draw a line glColor3f(1,1,1); //white glBegin(GL_LINES); glVertex2f( p1.x, p1.y ); glVertex2f( p2.x, p2.y ); glEnd(); |

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | //in Step() function, continuing on from section above //set up input b2RayCastInput input; input.p1 = p1; input.p2 = p2; input.maxFraction = 1; //check every fixture of every body to find closest float closestFraction = 1; //start with end of line as p2 b2Vec2 intersectionNormal(0,0); for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext()) { for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) { b2RayCastOutput output; if ( ! f->RayCast( &output, input ) ) continue; if ( output.fraction < closestFraction ) { closestFraction = output.fraction; intersectionNormal = output.normal; } } } b2Vec2 intersectionPoint = p1 + closestFraction * (p2 - p1); //draw a line glColor3f(1,1,1); //white glBegin(GL_LINES); glVertex2f( p1.x, p1.y ); glVertex2f( intersectionPoint.x, intersectionPoint.y ); glEnd(); //draw a point at the intersection point glPointSize(5); glBegin(GL_POINTS); glVertex2f( intersectionPoint.x, intersectionPoint.y ); glEnd(); |

1 2 3 4 5 6 7 | //draw intersection normal b2Vec2 normalEnd = intersectionPoint + intersectionNormal; glColor3f(0,1,0); //green glBegin(GL_LINES); glVertex2f( intersectionPoint.x, intersectionPoint.y ); glVertex2f( normalEnd.x, normalEnd.y ); glEnd(); |

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | //new function for FooTest class void drawReflectedRay( b2Vec2 p1, b2Vec2 p2 ) { //set up input b2RayCastInput input; input.p1 = p1; input.p2 = p2; input.maxFraction = 1; //check every fixture of every body to find closest float closestFraction = 1; //start with end of line as p2 b2Vec2 intersectionNormal(0,0); for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext()) { for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext()) { b2RayCastOutput output; if ( ! f->RayCast( &output, input ) ) continue; if ( output.fraction < closestFraction ) { closestFraction = output.fraction; intersectionNormal = output.normal; } } } b2Vec2 intersectionPoint = p1 + closestFraction * (p2 - p1); //draw this part of the ray glBegin(GL_LINES); glVertex2f( p1.x, p1.y ); glVertex2f( intersectionPoint.x, intersectionPoint.y ); glEnd(); if ( closestFraction == 1 ) return; //ray hit nothing so we can finish here if ( closestFraction == 0 ) return; //still some ray left to reflect b2Vec2 remainingRay = (p2 - intersectionPoint); b2Vec2 projectedOntoNormal = b2Dot(remainingRay, intersectionNormal) * intersectionNormal; b2Vec2 nextp2 = p2 - 2 * projectedOntoNormal; //recurse drawReflectedRay(intersectionPoint, nextp2); } |

1 2 3 4 5 6 7 | //calculate points of ray float rayLength = 25; b2Vec2 p1( 0, 20 ); //center of scene b2Vec2 p2 = p1 + rayLength * b2Vec2( sinf(currentRayAngle), cosf(currentRayAngle) ); glColor3f(1,1,1); //white drawReflectedRay(p1, p2); |