[SOLVED] Using the new raycastAll function

Hello!

Right now I am using the raycast function on this way:

    // Sensors
    var sensorLeftFront = this.app.systems.rigidbody.raycastAll(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition());
    var sensorLeftFrontBottom = this.app.systems.rigidbody.raycastAll(this.sensorLeftFront.getPosition(), this.sensorLeftFrontBottom.getPosition());

    // Detections
    if (sensorLeftFront && sensorLeftFront.entity.tags.has("Obstacle") || !sensorLeftFrontBottom) {
        detectionLeftFront = true;
        
        if (visibleSensors) { 
            this.app.renderLine(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition(), colorRed);
            this.app.renderLine(this.sensorLeftFront.getPosition(), this.sensorLeftFrontBottom.getPosition(), colorRed);
        }
    }
    
    else {
        detectionLeftFront = false;

        if (visibleSensors) {
            this.app.renderLine(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition(), colorGrey);
            this.app.renderLine(this.sensorLeftFront.getPosition(), this.sensorLeftFrontBottom.getPosition(), colorGrey);
        }
    }

But I get an error on the tags check:

Cannot read property 'tags' of undefined

I think there is a new way to do this…

raycastAll returns an array of pc.RaycastResults. Not a single pc.RaycastResult.

So how can I check if there is one of them with the tag?

this.app.systems.rigidbody.raycastAll(start, end).forEach(function (result) {
    console.log('Name: ' + result.entity.name);
    result.entity.tags.list().forEach(function (tag) {
        console.log('Tag: ' + tag);
    });
});

Ah I see, that is working. I will work it out later.
Thanks! I am happy with this new feature!

2 Likes

How can I create a list of this:

this.app.systems.rigidbody.raycastAll(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition());

and how do I check if that list is empty or not?

I’m not sure I understand your question. Can you rephrase it please?

I started using your first example with something like this:

    // Left Front Sensor    
    this.app.systems.rigidbody.raycastAll(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition()).forEach(function (result) {
        if (result.entity.tags.has("Obstacle")) {
                this.detectionLeftFront = true;
        } 
        else {
                this.detectionLeftFront = false;
        }
    });

But I also have to set this.detectionLeftFront on false if there is no result.
I don’t think I can do that inside that function?

nevermind :stuck_out_tongue:

1 Like

Oh, this is another problem with the value of this. So you could do one of these options:

Option 1: Use Function.prototype.bind

    // Left Front Sensor    
    var start = this.frontSensors.getPosition();
    var end = this.sensorLeftFront.getPosition();
    
    this.app.systems.rigidbody.raycastAll(start, end).forEach(function (result) {
        if (result.entity.tags.has("Obstacle")) {
            this.detectionLeftFront = true;
        } 
        else {
            this.detectionLeftFront = false;
        }
    }.bind(this));

Option 2: Cache this in self

    // Left Front Sensor    
    var start = this.frontSensors.getPosition();
    var end = this.sensorLeftFront.getPosition();
    
    var self = this;
    this.app.systems.rigidbody.raycastAll(start, end).forEach(function (result) {
        if (result.entity.tags.has("Obstacle")) {
            self.detectionLeftFront = true;
        } 
        else {
            self.detectionLeftFront = false;
        }
    });

Option 3: Pass second argument to forEach

    // Left Front Sensor    
    var start = this.frontSensors.getPosition();
    var end = this.sensorLeftFront.getPosition();
    
    this.app.systems.rigidbody.raycastAll(start, end).forEach(function (result) {
        if (result.entity.tags.has("Obstacle")) {
            this.detectionLeftFront = true;
        } 
        else {
            this.detectionLeftFront = false;
        }
    }, this);

I’d go with Option 3.

1 Like

Ah that’s not the problem, but thanks for solving a future error! :stuck_out_tongue:

    // Left Front Sensor    
    this.app.systems.rigidbody.raycastAll(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition()).forEach(function (result) {
        if (result.entity.tags.has("Obstacle")) {
                this.detectionLeftFront = true;
        } 
        else {
                this.detectionLeftFront = false;
        }
   }, this);

How do I set this.detectionLeftFront on false if there is no result.
I don’t think I can do that inside that function?’

With raycastFirst I did this:

    // Sensors
    var sensorLeftFront = this.app.systems.rigidbody.raycastFirst(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition());

    // Detections
    if (sensorLeftFront && sensorLeftFront.entity.tags.has("Obstacle")) {
        this.detectionLeftFront = true;
    }
    else {
        this.detectionLeftFront = false;
    }

result in the callback should never be null as raycastAll only returns a list of entities that it has hit.

Sounds like you want is:

    // Left Front Sensor    
    this.detectionLeftFront = false;
    this.app.systems.rigidbody.raycastAll(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition()).forEach(function (result) {
        if (result.entity.tags.has("Obstacle")) {
            this.detectionLeftFront = true;
        } 
   }, this);

That way, this.detectionLeftFront is only true if the raycast has hit something.

Oke, can I do that both in the update?
I mean do I not get a true/false/true/false/true effect?

As long as this block of code stays together, you should be fine. (ie you don’t add any extra code between that relies on detectionLeftFront between it being set to false and the raycastall call)

Basically, you are just doing this:

var hasLeftFrontHitSomething = false;
this.app.systems.rigidbody.raycastAll(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition()).forEach(function (result) {
    if (result.entity.tags.has("Obstacle")) {
        hasLeftFrontHitSomething = true;
    } 
});

this.detectionLeftFront = hasLeftFrontHitSomething;

But it gets a bit more complex.

Before setting this.detectionLeftFront on false i have to check another sensor that checks if there is ground.

So if there is no obstacle and there is ground then this.detectionLeftFront = false.
Else if there is an obstacle or there is no ground then this.detectionLeftFront = true.

Because i have a lot of sensors the code should be as minimal as possible.

With raycastFirst I did this:

    // Sensors
    var sensorLeftFront = this.app.systems.rigidbody.raycastFirst(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition());
    var sensorLeftFrontBottom = this.app.systems.rigidbody.raycastFirst(this.sensorLeftFront.getPosition(), this.sensorLeftFrontBottom.getPosition());

    // Detections
    if (sensorLeftFront && sensorLeftFront.entity.tags.has("Obstacle") || !sensorLeftFrontBottom) {
        this.detectionLeftFront = true;
    }
    
    else {
        this.detectionLeftFront = false;
    }

From the code you have written above, this looks like what you need:

var sensorLeftFrontHitObstacle = false;
this.app.systems.rigidbody.raycastAll(this.frontSensors.getPosition(), this.sensorLeftFront.getPosition()).forEach(function (result) {
    if (result.entity.tags.has("Obstacle")) {
        sensorLeftFrontHitObstacle = true;
    } 
});

var sensorLeftFrontBottomHitAnything = false;
this.app.systems.rigidbody.raycastAll(this.sensorLeftFront.getPosition(), this.sensorLeftFrontBottom.getPosition()).forEach(function (result) {
    sensorLeftFrontBottomHitAnything = true;
});

// Detections
if (sensorLeftFrontHitObstacle || !sensorLeftFrontBottomHitAnything) {
    this.detectionLeftFront = true;
}
else {
    this.detectionLeftFront = false;
}

If it’s not right, you should be able to tweak this to get what you need.

A little more code than I hoped, but if that’s the best way, I’ll work it out that way.

Thanks for the effort @yaustar!