June 23, 2011

[Code] Exil : Wall Jump



Today we gonna discuss about the walljump function that I used in my project.
First, I’m not the original creator of this code, I found it on the official UDK forum, here : http://forums.epicgames.com/showthread.php?t=751172 and I have changed it a little after. Currently my walljump code cannot be used more than 3 times. After 3 times, the player must land (touch) the ground for reset the limit.

The Limit

The 3 times limit is handled by the original function CheckJumpOrDuck already created in the PlayerController class. In my player controller I have simply changed it :

function CheckJumpOrDuck()
{
    if ( Pawn == None )
    {
        return;
    }
    if ( bDoubleJump && (bUpdating || ((EXILAcrobaticPawn(Pawn) != None) && UTPawn(Pawn).CanDoubleJump())) )
    {
        //UTPawn(Pawn).DoDoubleJump( bUpdating );
        if (maxJumpCount <= maxJumpLimitCurrent /*&& pIsInJumpVolume*/)
        {
            EXILAcrobaticPawn(Pawn).DoWallJump( bUpdating );
            maxJumpCount++;
        }
    }
    else if ( bPressedJump )
    {
        if (Pawn.Physics == PHYS_Falling)
        {
            if (maxJumpCount <= maxJumpLimitCurrent /*&& pIsInJumpVolume*/)
            {
                EXILAcrobaticPawn(Pawn).DoWallJump( bUpdating );
                maxJumpCount++;
            }
        }
        else
        {
            maxJumpCount = 0;
            EXILAcrobaticPawn(Pawn).AirControlReset();
            Pawn.DoJump( bUpdating );
        }
    }
    if ( Pawn.Physics != PHYS_Falling && Pawn.bCanCrouch )
    {
        // crouch if pressing duck
        Pawn.ShouldCrouch(bDuck != 0);
    }
}

As you can see, I don’t perform the classic doubleJump from the default class with the UDK, instead I call my walljump function. The maxJumpCount variable is used to store the number of walljumped already performed. When this variable reach 3, the player can’t jump anymore. I reset to 0 this variable when the player is not in Air (phys_falling).

The Walljump

Located in the pawn (for an easier access to pawn’s variables, but you can put the walljump function into the playercontroller class), the code looks like this :

function bool DoWallJump( bool bUpdating )
{
    local Vector HitLocation, HitNormal, End, Start;
    local Actor HitActor;

    //Perform trace
    Start = Location + (Vector(Rotation) * GetCollisionRadius()/2);
    End = Start + (vector(Rotation) * GetCollisionRadius() * 2.5);
    HitActor = Trace(HitLocation, HitNormal, End, Start, true,);
    `Log("Player try to jump on " @ HitActor);

    //check on what we want to jump, we jump only on world surfaces
    if (HitActor == WorldInfo || HitActor.isA('StaticMeshActor'))
    {
        `Log("-Player jump on the wall !");

        self.FaceRotation(rotator(HitNormal), GlobalDeltatime);
        Controller.SetRotation( rotator(HitNormal) );

        if( HitNormal.Y != 0)
            HitNormal.Y *= WallJumpBoostXY;
        else if(HitNormal.X != 0)
            HitNormal.X *= WallJumpBoostXY;

        Velocity = HitNormal;

        //PlayerController(Controller).PlaySound(playerSoundWallJump, false, true);

        Velocity.Z = JumpZ + WallJumpBoostZ;

        return true;
    }

    return false;
}

The operation is very simple, first we do a trace to be sure that the pawn is in front of a wall. With this trace we get the normal of the wall that we use to do the jump.
The "if" is used to be sure that we jump on a wall (worldinfo = bsp surface) or on a static mesh. Then in my case I change the rotation of the pawn and the camera with the normal vector and after I do the jump with updating the velocity of the pawn. My variable WallJumpBoostXY is just a number that I can change in the defaultproperties.

With this code we only jump perpendicularly of the wall (like I want for my game) but if you want to jump with the same angle as you were going to the wall, you must do this :

        if (HitNormal.X != 0)
        {
            Velocity.X = HitNormal.X * WallJumpBoostXY;
        }

        if (HitNormal.Y != 0)
        {
            Velocity.Y = HitNormal.Y * WallJumpBoostXY;
        }

Et voilà !