Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gdx-ai tests: Box2dSteeringEntity.java issues #94

Open
Relsig opened this issue Jul 19, 2017 · 0 comments
Open

gdx-ai tests: Box2dSteeringEntity.java issues #94

Relsig opened this issue Jul 19, 2017 · 0 comments

Comments

@Relsig
Copy link

Relsig commented Jul 19, 2017

This isn't so much related to the gdx-ai itself as much as the tests, documentation, and tutorials based on them, specifically Box2dSteeringEntity.

I'm still learning so feel free to correct anything I may have wrong, I love constructive criticism.

I noticed in the Box2dSteeringEntity it is using applyForceToCenter(Vector2, boolean). I'm not sure if jBox2d or libgdx made any changes to this but in the Box2D code it's based on applying a force doesn't account for timestep. body.applyLinearImpulse(Vector2, Vector2, boolean), however, does.

In fact, in physics an impulse is defined as the integral of a force over a time period.

Also, it's not accounting for the body's mass.

I couldn't figure out how to run the tests themselves, but after copying the class and having some serious issues I removed line 175 and put:

body.applyLinearImpulse(steeringOutput.linear.scl(body.getMass()), getPosition(), true);

and commented out the lines regarding capping the speeds and the Arrive (steering behavior) works perfectly. The Box2dSteeringEntity's velocity never exceeds the maxLinearSpeed and slows down as it gets closer to the target. I suspect any steering behavior that accounts for max acceleration and max linear speed in their output would also work.

Pursue (steering behavior) does not account for max linear speed so you would have to account for max linear speed before applying the impulse. Setting the current linear speed after applying an impulse or force can cause some undesired side-effects since setting the current linear speed doesn't appear to wipe any current forces or impulses being applied.

Here is some sample code that would limit an impulse on a single (x) axis before it's applied (tested and working, but it's only for the x axis and only scales the Y for body mass. It's also not as efficient as it could be since I only spent a few minutes thinking it over)

/**
* returns an impulse no greater than the force necessary for the body to meet its horizontal top speed.
*  Currently ignoring any vertical steering caps.
*/
public Vector2 getDesiredHorizontalImpulse (){
    Vector2 impulse = steeringOutput.linear.cpy();
    Vector2 current = body.getLinearVelocity().cpy();
    float impulseSign = Math.signum(impulse.x);
    float currentSign = Math.signum(current.x);

    //only cap the speed if we aren't changing directions
    //since max accel should (in theory) be <= max speed.
    if (impulseSign == currentSign) {

        //if we're already going faster than max speed don't apply any impulse.
        //this shouldn't break anything because the case that we're changing directions was 
        //already checked. this is unnecessary in most cases and only prevents a few
        //very unlikely and almost certainly unintended interactions caused by outside forces
        if (Math.abs(current.x) > maxLinearSpeed) {
            impulse.scl(0);
        } else {

            //if our impulse will make us move faster than the max linear speed
            //adjust the impulse, otherwise we're good.
            if (Math.abs(impulse.x + current.x) > maxLinearSpeed) {

                //desired velocity change = max velocity - current velocity
                //used absolutes and carried the sign of the impulse to account for both directions
                //**this is the meat of what you're wanting**
                impulse.x = (maxLinearSpeed - Math.abs(current.x)) * impulseSign;
            }
        }
    }

    //desired impulse = desired velocity change * mass
    return impulse.scl(body.getMass());
}

I'm not sure if something similar would work for the angular or not as angular steering is not needed in my game currently so I haven't tested.

P.S. sorry if this was overly verbose :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant