| Home Page | Recent Changes | Preferences

UScriptAnimPawn

UScript Controlled Animation Pawn

For those interested in creating pawns whose animations are controlled through UScript instead of native code, the following code will provide a base from which you can edit. It is simply the native animation source code rewritten in UScript (c++ source available in the 3186 uscript source). The following code behaves almost exactly the same as the native code (slight difference in rotation yaw, will edit once tracked down). It would probably be beneficial to performance to place the call to UpdateMovementAnimation function in the AnimEnd event as it was back in original UT. -Meowcat

class UScriptAnimPawn extends SomeOtherPawnClass;// SomeOtherPawnClass will typically be xPawn

// added to get around the const values normally set by the native code
var bool bFootTurning; 
var bool bFootStill;
var int  iFootRot;
var int  iTurnDir;
var int SmoothViewPitch, SmoothViewYaw;// These two are only needed if this code is for UT2003, UT2004 pawn code already has them

simulated function Tick(float DeltaTime)
{
      if(!bPhysicsAnimUpdate) UpdateMovementAnimation(DeltaTime);//added to allow switching between native and scripted animation
      super.tick(deltatime);
}

// Epic C++ animation code converted to uscript

simulated function UpdateMovementAnimation( FLOAT DeltaSeconds )
{
    if ( Level.NetMode == NM_DedicatedServer )
        return;
    if( bPlayedDeath )
        return;

    if (Level.TimeSeconds - LastRenderTime > 1.0)
    {
        iFootRot = Rotation.Yaw;
        bFootTurning = false;
        bFootStill = false;
        return;
    }

    BaseEyeHeight = Default.BaseEyeHeight;

    if ( bIsIdle && Physics != OldPhysics )
    {
        bWaitForAnim = false;
    }

    if ( !bWaitForAnim )
    {
        if ( Physics == PHYS_Swimming )
        {
            BaseEyeHeight *= 0.7f;
            UpdateSwimming();
        }
        else if ( Physics == PHYS_Falling || Physics == PHYS_Flying )
        {
            BaseEyeHeight *= 0.7f;
            UpdateInAir();
        }
        else if ( Physics == PHYS_Walking || Physics == PHYS_Ladder )
        {
            UpdateOnGround();
        }
    }
    else if ( !IsAnimating(0) )
        bWaitForAnim = false;

    if ( Physics != PHYS_Walking )
        bIsIdle = false;

    OldPhysics = Physics;// OldPhysics is not const and can be changed in UScript
    //OldVelocity = Velocity;// is a const, may be used in the ModifyVelocity function!! 

    if (bDoTorsoTwist)
        UpdateTwistLook( DeltaSeconds );
}

simulated function UpdateSwimming()
{
    if ( (Velocity.X*Velocity.X + Velocity.Y*Velocity.Y) < 2500.0f )
        PlayAnim(IdleSwimAnim, 1.0f, 0.1f, 0);
    else
        PlayAnim(SwimAnims[Get4WayDirection()], 1.0f, 0.1f, 0);
        //PlayAnim(0, SwimAnims[Get4WayDirection()], 1.0f, 0.1f, true);// native anim call
}

simulated function UpdateInAir()
{
   local Name NewAnim;
   local  bool bUp, bDodge;
   local  float DodgeSpeedThresh;
   local int Dir;
   local  float XYVelocitySquared;

    XYVelocitySquared = (Velocity.X*Velocity.X)+(Velocity.Y*Velocity.Y);

    bDodge = false;
    if ( OldPhysics == PHYS_Walking )
    {
        DodgeSpeedThresh = ((GroundSpeed*DodgeSpeedFactor) + GroundSpeed) * 0.5f;
        if ( XYVelocitySquared > DodgeSpeedThresh*DodgeSpeedThresh )
        {
            bDodge = true;
        }
    }

    bUp = (Velocity.Z >= 0.0f);

    if (XYVelocitySquared >= 20000.0f)
    {
        Dir = Get4WayDirection();

        if (bDodge)
        {
            NewAnim = DodgeAnims[Dir];
            bWaitForAnim = true;
        }
        else if (bUp)
        {
            NewAnim = TakeoffAnims[Dir];
        }
        else
        {
            NewAnim = AirAnims[Dir];
        }
    }
    else
    {
        if (bUp)
        {
            NewAnim = TakeoffStillAnim;
        }
        else

        {
            NewAnim = AirStillAnim;
        }
    }

    if ( NewAnim != GetAnimSequence() )
    {
    // have not quite added this yet.  Will edit later -meowcat     
    //if ( PhysicsVolume->Gravity.Z > 0.8f * (Cast<APhysicsVolume>(PhysicsVolume->GetClass()->GetDefaultActor()))->Gravity.Z )
        //  PlayAnim(0, NewAnim, 0.5f, 0.2f, false); // native anim call
        //else
            LoopAnim(NewAnim, 1.0f, 0.1f, 0);
            //PlayAnim(0, NewAnim, 1.0f, 0.1f, false); // native anim call
    }
}

simulated function UpdateOnGround()
{
    // just landed
    if ( OldPhysics == PHYS_Falling || OldPhysics == PHYS_Flying )
    {
        PlayLand();
    }
    // standing still
    else if ( Vsize(Velocity*Velocity) < 2500.0f  )  /*&& Acceleration.SizeSquared() < 0.01f*/
    {
        if (!bIsIdle || bFootTurning || bIsCrouched != bWasCrouched)
        {
            IdleTime = Level.TimeSeconds;
            PlayIdle();
        }
        PlayIdle();// added this playIdle to force the code to update whatever animation was playing, otherwise the turning anim could potentially continue to loop
        bWasCrouched = bIsCrouched;
        bIsIdle = true;
    }
    // running
    else
    {
        if ( bIsIdle  )
            bWaitForAnim = false;

        PlayRunning();
        bIsIdle = false;
    }
}

simulated function PlayIdle()
{
    if (bFootTurning)
    {
        if (iTurnDir == 1)
        {
            if (bIsCrouched)
                LoopAnim(CrouchTurnRightAnim, 1.0f, 0.1f, 0);
            else
                LoopAnim(TurnRightAnim, 1.0f, 0.1f, 0);
        }
        else
        {
            if (bIsCrouched)
                LoopAnim(CrouchTurnLeftAnim, 1.0f, 0.1f, 0);
            else
                LoopAnim(TurnLeftAnim, 1.0f, 0.1f, 0);
        }
    }
    else
    {
        if (bIsCrouched)
        {
            LoopAnim(IdleCrouchAnim, 1.0f, 0.1f, 0);
        }
        else
        {
        if (PlayerController(controller)!=none &&  PlayerController(controller).bIsTyping )
                PlayAnim(IdleRestAnim, 1.0f, 0.2f, 0);
            else if ( (Level.TimeSeconds - IdleTime < 5.0f) && IdleWeaponAnim != '')
            {
                LoopAnim(IdleWeaponAnim, 1.0f, 0.25f, 0);
            }
            else
            {
                LoopAnim(IdleRestAnim, 1.0f, 0.25f, 0);
            }
        }
    }
}

simulated function PlayRunning()
{
    local Name NewAnim;
    local int NewAnimDir;
    local float AnimSpeed;

    NewAnimDir = Get4WayDirection();

    AnimSpeed = 1.1f * Default.GroundSpeed;
    if (bIsCrouched)
    {
        NewAnim = CrouchAnims[NewAnimDir];
        AnimSpeed *= CrouchedPct;
    }
    else if (bIsWalking)
    {
        NewAnim = WalkAnims[NewAnimDir];
        AnimSpeed *= WalkingPct;
    }
    else
    {
        NewAnim = MovementAnims[NewAnimDir];
    }
    LoopAnim(NewAnim, (Vsize(Velocity)) / AnimSpeed, 0.1f, 0);
    //PlayAnim(0, NewAnim, Velocity.Size() / AnimSpeed, 0.1f, true); // native anim call
}

simulated function PlayLand()
{
    if (!bIsCrouched)
    {
        PlayAnim(LandAnims[Get4WayDirection()], 1.0f, 0.1f, 0);
        bWaitForAnim = true;
    }
}

simulated function UpdateTwistLook( float DeltaTime )
{
    local int look, Update, UpdateB, PitchDiff, t, YawDiff;

    if ( !bDoTorsoTwist || (Level.TimeSeconds - LastRenderTime > 0.5f) )
    {
        SmoothViewPitch = ViewPitch;
        SmoothViewYaw = Rotation.Yaw;
        iFootRot = Rotation.Yaw;
        bFootTurning = false;
        bFootStill = false;
    }
    else
    {
        YawDiff = (Rotation.Yaw - SmoothViewYaw) & 65535;
        if ( YawDiff != 0 )
        {
            if ( YawDiff > 32768 )
                YawDiff -= 65536;

            Update = int(YawDiff * 15.f * DeltaTime);
            if ( Update == 0 ){
                //Update = (YawDiff > 0) ? 1 : -1;
                if (YawDiff>0) Update=1;
                else Update= -1;
            }
            SmoothViewYaw = (SmoothViewYaw + Update) & 65535;
        }
        t = (SmoothViewYaw - iFootRot) & 65535;
        if (t > 32768)
            t -= 65536;

        if (((Velocity.X * Velocity.X) + (Velocity.Y * Velocity.Y)) < 1000 && Physics == PHYS_Walking)
        {
            if (!bFootStill)
            {
                bFootStill = true;
                SmoothViewYaw = Rotation.Yaw;
                iFootRot = Rotation.Yaw;
                t = 0;
            }
        }
        else
        {
            if (bFootStill)
            {
                bFootStill = false;
                bFootTurning = true;
            }
        }

        if (bFootTurning)
        {
           if (t > 12000)
            {
                iFootRot = SmoothViewYaw - 12000;
                t = 12000;
            }
            else if (t > 2048)
            {
                iFootRot += 16384*DeltaTime;
            }
            else if (t < -12000)
            {
                iFootRot = SmoothViewYaw + 12000;
                t = -12000;
            }
            else if (t < -2048)
            {
                iFootRot -= 16384*DeltaTime;
            }
            else
            {
                if (!bFootStill)
                    t = 0;
                bFootTurning = false;
            }
            iFootRot = iFootRot & 65535;
        }
        else if (bFootStill)
        {
            if (t > 10923)
            {
                iTurnDir = 1;
                bFootTurning = true;
            }
            else if (t < -10923)
            {
                iTurnDir = -1;
                bFootTurning = true;
            }
        }
        else
        {
            t = 0;
        }
        PitchDiff = (256*ViewPitch - SmoothViewPitch) & 65535;
        if ( PitchDiff != 0 )
        {
            if ( PitchDiff > 32768 )
                PitchDiff -= 65536;

            UpdateB = int(PitchDiff * 5.f * DeltaTime);
            if ( UpdateB == 0 ){
                //Update = (PitchDiff > 0) ? 1 : -1;
                if (PitchDiff>0) UpdateB=1;
                else UpdateB= -1;
            }
            SmoothViewPitch = (SmoothViewPitch + UpdateB) & 65535;
        }
        look = SmoothViewPitch;
        if (look > 32768)
            look -= 65536;
        //call this native function to actually update the pawn's torso twist
        SetTwistLook(t, look);
        //td_SetTwistLook(t, look);// or call an edited version of the settwistlook so that you can alter how the rotation is applied
    }
}

simulated function td_SetTwistLook( int twist, int look)
{
    local rotator r;
    if (!bDoTorsoTwist)
        return;

    r.Yaw=-twist + SmoothViewYaw - Rotation.Yaw;
    SetBoneRotation(RootBone, r, 0, 1.0f);

    r.Yaw = -twist / 3;
    r.Pitch = 0;
    r.Roll = look / 4;
    SetBoneDirection(HeadBone, r, Vect(0.0f,0.0f,0.0f), 1.0f, 0);
    SetBoneDirection(SpineBone1, r, Vect(0.0f,0.0f,0.0f), 1.0f, 0);
    SetBoneDirection(SpineBone2, r, Vect(0.0f,0.0f,0.0f), 1.0f, 0);
}

defaultproperties
{
    bDoTorsoTwist=true
    bPhysicsAnimUpdate=false
}
 

The Unreal Engine Documentation Site

Wiki Community

Topic Categories

Image Uploads

Random Page

Recent Changes

Offline Wiki

Unreal Engine

Console Commands

Terminology

FAQs

Help Desk

Mapping Topics

Mapping Lessons

UnrealEd Interface

UnrealScript Topics

UnrealScript Lessons

Making Mods

Class Tree

Modeling Topics

Chongqing Page

Log In