BetterCharacterControl in the works

I can see everybody posting here their improvements to the BetterCharacterControl so I would like to share my tweaks too. I solved (at least is working for me :stuck_out_tongue:) two issues with this control:

  1. Stucking over stairs and any kind of slopes.
  2. Stucking when it goes over a wall (just changing the character friction when isn’t in ground).

Walking over stairs:

protected void checkSlope() {
    TempVars vars = TempVars.get();
    Vector3f rayFrom = vars.vect1;
    Vector3f rayTo = vars.vect2;
    Vector3f feetLoc = vars.vect3;
    Vector3f aux = vars.vect4;

    feetLoc.set(location);
    rayFrom.set(feetLoc).addLocal(aux.set(localUp).multLocal(slopeDepth));//.addLocal(localUp.mult(0.05f));
    rayTo.set(rayFrom).addLocal(aux.set(getWalkDirection()).normalizeLocal().multLocal(getFinalRadius())).addLocal(aux.set(localUp).mult(maxAcclivity));


    List<PhysicsRayTestResult> results = space.rayTest(rayFrom, rayTo);

    for (PhysicsRayTestResult physicsRayTestResult : results) {
        if (!physicsRayTestResult.getCollisionObject().equals(rigidBody)) {
            rayTo.set(rayFrom.addLocal(rayTo.subtractLocal(rayFrom).multLocal(physicsRayTestResult.getHitFraction())));
            rayTo.addLocal(aux.set(getWalkDirection()).normalizeLocal().multLocal(slopeDepth));

            results = space.rayTest(rayFrom.set(rayTo).addLocal(aux.set(localUp).multLocal(maxStepHeight)), rayTo);

            if(!results.isEmpty()) {
                rayFrom.addLocal(rayTo.subtractLocal(rayFrom).multLocal(results.get(0).getHitFraction()));
                warp(location.setY(rayFrom.getY()));
            }

            vars.release();
            return;
        }
    }
    vars.release();
}

The character can only go over a slope if there is no obstacle just over that slope so a “checkSomethingInFront” must be done:

protected void checkSomethingInFront() {
    TempVars vars = TempVars.get();
    Vector3f rayFrom = vars.vect1;
    Vector3f rayTo = vars.vect2;
    Vector3f aux = vars.vect3;
    Vector3f aux2 = vars.vect4;

    aux.set(location).addLocal(aux2.set(localUp).multLocal(getFinalHeight()));
    rayFrom.set(aux);

    rayTo.set(aux.addLocal(rayTo.set(walkDirection).normalizeLocal().multLocal(getFinalRadius() + 0.05f)));

    List<PhysicsRayTestResult> results = space.rayTest(rayFrom, rayTo);

    for (PhysicsRayTestResult physicsRayTestResult : results) {
        if (!physicsRayTestResult.getCollisionObject().equals(rigidBody)) {
            somethingInFront = true;
            vars.release();
            return;
        }
    }

    rayFrom.set(aux);
    rayTo.set(rayFrom).subtractLocal(aux.set(localUp).multLocal(getFinalHeight() - maxStepHeight));

    results = space.rayTest(rayFrom, rayTo);

    vars.release();

    for (PhysicsRayTestResult physicsRayTestResult : results) {
        if (!physicsRayTestResult.getCollisionObject().equals(rigidBody)) {
            somethingInFront = true;
            return;
        }
    }

    somethingInFront = false;
}

To use it just:

@Override
public void prePhysicsTick(PhysicsSpace space, float tpf) {
    super.prePhysicsTick(space, tpf);

    checkSomethingInFront(); // Checks if something is in front of the character
    if(!somethingInFront) checkSlope(); // If not, checks if there is a slope and goes up it

    // This is a "botched fast fix" for the character getting stuck on a wall
    if(onGround) { if(rigidBody.getFriction() != friction) rigidBody.setFriction(friction); }
    else if(rigidBody.getFriction() != 0) rigidBody.setFriction(0f);
}

The initial values of the variables used on the checks are:

float maxStepHeight = 0.5f;
float maxAcclivity = 0.13f;
float slopeDepth = 0.05f;

The acclivity is used to avoid unnecessary relocations on ramps (kind of false slope positives).

3 Likes