Slicing, splitting and cutting objects with Box2D

After showing you the video of my work in progress engine, it’s time to tell you how to split, cut and slice objects with Box2D version 2.1

There’s a lot to say so let’s start at once.

Drawing the laser

Drawing the laser it’s easy, as it’s the old “press the mouse, move the mouse, release the mouse” action you saw in a million drawing games.

Being the laser a straight line, once the player presses the mouse we will show a line connecting the starting point to the current mouse position, and when the player releases the mouse button we’ll show the final laser ray.

This way the laser will be defined by two points: the starting point and the ending point. Such points will be saved in a b2Segment variable. It’s not mandatory, but since Box2D gives us a segment definition, why not using it?

This is the script:

Let’s see the variables used:

worldScale: this is used to convert Box2D meters to Flash pixels. If you aren’t used to Box2D pixels and meters, read this post. In our case, 1 meter will be represented by 30 pixels.

canvas: it’s the Sprite we will use to draw the laser.

laserSegment: the b2Segment variable used to store laser starting and ending point.

drawing: a simple Boolean variable which tells us whether the player is drawing or not.

Then we have three listeners: one when the mouse is pressed, one when the mouse is moved and one when the mouse is released.

When the mouse is pressed, we set drawing to true because we are actually drawing, we construct a new b2Segment instance and we set its p1 property (the starting point) to a new b2Vec2 variable (think about it just like a Flash Point) with the current x and y mouse coordinates translated into Box2D units.

When the mouse is moved we check if we are drawing, then we draw the laser (a thin red line) from the starting point (the p1 property of laserSegment) to current mouse position.

When the mouse is released, we need to set drawing to false as we aren’t drawing anymore, and set p2 property (the ending point) of our segment to a new b2Vec2 variable with the current x and y mouse coordinates translated into Box2D units, just as we made when we pressed the mouse.

At this time, you are able to draw lasers with your mouse. Try it by yourself:

Click and drag the mouse to draw lasers.

Now we need some object to be cut.

Adding objects

We are going to add three static elements: a floor, a box and a circle. In this step we are only adding objects, so most of you could find this section a bit boring, but I would like you to focus how I am creating the circle: since Box2D does not natively support arcs, I am using a 12 vertices polygon to approximate the circle. Feel free to use a 24 or 36 vertices polygon to achieve a better approximation, I used a low vertices polygon for a teaching purpose. In an everyday project I’d use a 36 vertices polygon.

This is the script at this stage:

That’s a lot of code, but most of it is used to enable the debug draw (lines 42-51) and to add the polygons (lines 52-85). Just look how I created the “circle” at lines 71-84 using a polygon created starting from a vector of b2Vec2 points, populated using trigonometry.

At the end of this step, this is what you have on your stage:

You are still able to draw the laser, and you have a nice set of objects ready to be sliced.

Detecting laser entry point

Since the laser is supposed to slice the objects, every affected object must have an entry point and an exit point. It’s important to know the laser can slice more than one object at once.

This is an easy task thanks to b2World‘s RayCast method, which takes three arguments:

laserFired: the name of the callback function

laserSegment.p1: the laser starting point, in b2Vec2 format

laserSegment.p2: the laser ending point, in b2Vec2 format

laserFired callback function already comes with a set of arguments which will do the job for us:

fixture: the fixture being hit by the laser.

point: the b2Vec2 point of contact (the entry point we are looking for).

normal: the normal vector at the point of intersection.

fraction: the fractional length along the ray of the intersection. You may find it useful if you want to know the ratio between the ray length and the point of contact.

It’s important to know laserFired is called for each body hit by the laser. If you don’t want this to happen, return zero and the ray detection will terminate. Returning one, it will continue looking for other bodies.

Have a look at the code:

At the moment the only thing we do in laserFired function is drawing a small red circle to make you see the entry point.

Here it is the result:

Draw a laser to intersect one or more bodies and watch the red circle showing us the entry point. Now we have to determine the exit point.

Detecting laser exit point

Since RayCast method performs a ray cast and does not simulate a laser passing through objects, there’s no way in Box2D to determine the exit point.

Thank you for reading.

No… wait… since a laser is a straight line going from A to B, we can imagine another laser fired from B to A. B to A entry point will be A to B exit point. That is, only if the laser is large enough to cut the object, and that’s what we want.

So with just another RayCast call at line 91 we can do the job.

This is the code

And this is the result:

Draw a laser line passing through one or more bodies to see the entry and the exit points.

And that’s all for this post. Next time, we’ll see in a few more steps how to physically slice the bodies.

Download the source code.

  • Nice!

    In the next post, can you also use one ‘U’ shaped, combined polygon? Just wanted to see if the logic would also work for splitting complex polygons, and if it can make complex polygons as a results (although simple would be interesting enough as well, and I could probably figure the rest out if it wouldn’t work).

    Thanks again, good article!

  • Anonyous

    @Chris:
    Maybe checking the edges and vertices where one fixture is welded to another would do the trick(partially cancelling the lasers intersecting with the polygons’ welded sides, keeping the welded fixture parts connected to each other)

  • I’m really interested in the actual splitting, can’t wait. You could also write more about using the raycasting feature, it’s not to well documented, I’m using RayCastOne, and other are pretty unfamiliar for me. cheers!

  • Edac

    Very good article. I look forward to working on a project using Box2D in the future.

    @Chris
    It might be possible to create a negative polygon (the inside of the ‘U’) and perform a ray trace on that, using what @Anonyous suggested.

  • Pingback: Slicing, splitting and cutting objects with Box2D – part 2 - Emanuele Feronato()

  • Hey,

    is it possible to add another effect like rotating??

  • Owen

    I’m not able to get this to work. I’m trying to implement this in Citrus Engine, but b2Vec only accepts one argument, an int, so it’s throwing an error at all of the instances of b2Vec. Was this built using a different version of Box2D?

  • Molano

    hi bro, im wondering how to replace the line with a “cutting form” sprite like in ninja fruit game?

    gimme an example

  • Novice

    Can anybody convert this code into c++ and opengl?? will be really grateful

  • Pingback: Cut it Devlog - Part 1 - The Beginning()