kripken / box2d.js

Port of Box2D to JavaScript using Emscripten
1.33k stars 196 forks source link

Raycast Bindings #19

Closed shannon closed 11 years ago

shannon commented 11 years ago

I have had no luck getting RayCasting to work. There does not appear to be bindings for b2RayCastInput and b2RayCastOutput. In the ReadMe it says that you can use customizeVTable for RayCasting but without those bindings I am completely lost on how to make it work. Can someone point me in the right direction?

shannon commented 11 years ago

After a day of messing around with this, I was finally able to successfully build Box2D with the b2RayCastInput and b2RayCastOutput bindings. As a web developer it's quite humbling to see the complexity that goes into something like this. I followed the suggestions in Issue #3 and added simple constructors to the missing structures. The method I was after was b2Fixture.RayCast and not b2World.RayCast which led to more confusion with the customizeVTable.

Anyway, I cleared it up and it's running great.

For anyone interested this is what I changed in b2Collision.h

/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
struct b2RayCastInput
{
    b2RayCastInput() {}
    b2Vec2 p1;
    b2Vec2 p2;
    float32 maxFraction;
};

/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
/// come from b2RayCastInput.
struct b2RayCastOutput
{
    b2RayCastOutput() {}
    b2Vec2 normal;
    float32 fraction;
};
otse commented 9 years ago

Without compiling myself, how can I get basic raycasts to work?

cwindolf commented 8 years ago

Even when compiling yourself, do you use a JSQueryCallback to use raycasts? @shannon -- if you're still looking at this issue, just wondering what JS code interfaces with your changes. Thanks!

shannon commented 8 years ago

@cwindolf It's been a really long time but looking over my code from back then it's something like this:

var rayCastInput = new Box2D.b2RayCastInput();
var rayCastOutput =  new Box2D.b2RayCastOutput();

function raycast(b2Fixture, p1, p2, maxFraction){
  rayCastInput.set_p1(p1);
  rayCastInput.set_p2(p2);
  rayCastInput.set_maxFraction(maxFraction);
  if(b2Fixture.RayCast(rayCastOutput, rayCastInput)){
    return {
      normal: rayCastOutput.get_normal(),
      fraction: rayCastOutput.get_fraction()
    }
  }
  return false;
}
cwindolf commented 8 years ago

Whoa, fast reply, was barely expecting one! Looks promising, thanks very much @shannon!

IljaK commented 5 years ago

While looking fix history and change logs, seems like b2RayCastInput/b2RayCastOutput has been already added to b2Collision.h. But still, I'm getting exception while trying to create new instance of those objects: "cannot construct a b2RayCastInput, no constructor in IDL". Tried booth builded versions 2.3.1_min.js/2.2.1_min.js

jobtalle commented 5 years ago

@IljaK I'm having the same issue. I tried doing raycasts through the JSQueryCallback but they don't work for me. Any leads on how to fix this?

jobtalle commented 5 years ago

I did get this to work eventually. The build I'm using doesn't take JSQueryCallback, b2RayCastInput or b2RayCastOutput. It takes a JSRayCastCallback and two points. The JSRayCastCallback must then implement the ReportFixture function, which takes a fixture, a point, a normal and a fraction in that order.

IljaK commented 5 years ago

Could you paste some code example?

jobtalle commented 5 years ago

Sure. In this code, box2d is my instantiated box2D. This code is not finished at all, but it logs the correct fraction of the ray because ReportFixture is called.

    const _callback = new box2d.JSRayCastCallback();

    const configureCallback = () => {
        _callback.ReportFixture = function(fixture, point, normal, fraction) {
            const f = box2d.wrapPointer(fixture, box2d.b2Fixture);

            _callback.m_fixture = fixture;

            if (f)
                console.log(fraction);

            return fraction;
        };
    };

    /**
     * Get the length of the ray.
     * @returns {Number} The portion of the ray that could be cast in the range [0, 1].
     */
    this.getLength = () => {
        let from = body._getBody().GetWorldPoint(new box2d.b2Vec2(x, y));

        world.RayCast(
            _callback,
            new box2d.b2Vec2(from.get_x(), from.get_y()),
            new box2d.b2Vec2(from.get_x() + ray.x, from.get_y() + ray.y));

        return 0.5;
    };

    configureCallback();
IljaK commented 5 years ago

Seems like I've got it working too! Thanks a lot!