Ai Notes

For those struggling with their own AI - this might be a useful starting point. Note it delibrately doesn't play back animations. You'll need to do that yourself.

It also relies on a number of other classes - so it is unlikely to compile on your TC. It's more for guidance than copy & paste.

Here's my FFTimmy.uc which extends Pawn

//=============================================================================
// Timmy the dog
//=============================================================================
class FFTimmy extends Pawn
    placeable;

#exec OBJ LOAD FILE="..\Animations\Animals.ukx"
#exec OBJ LOAD FILE="..\Textures\TimmySkins.utx"    

// PostBeginPlay() is originally defined in Actor().
event PostBeginPlay()
{
    local FFTimmyController FFTC;
    Log("Spawning FFTimmy");
    Super.PostBeginPlay();

    if ( ( ControllerClass != None ) && ( Controller == None ) )
    {
        Controller = spawn( ControllerClass );
        Log("Spawning FFTimmyControllerClass");    
    }
    else
    {
        Log("Controller class already exists");
        FFTC = FFTimmyController( Controller );
        if ( FFTC !=None )
        {
            Log("Controller class is already FFTimmy");
        }
        else
        {
            Log("Wrong Controller class created");
        }
    }
    if ( Controller != None )
    {
        Controller.Possess( self );
        Log("Possessing FFTimmy");    
    }
}

defaultproperties
{
//    IdleAnim(0)="stand"
//    IdleAnim(1)="bark"
//    IdleAnim(2)="piss"
//    IdleAnim(3)="lay_in"
//    IdleAnim(4)="lay_on"
//    IdleAnim(5)="lay_out"
//    bMeleeFighter=True
//    bCanDodge=False
//    bCanDodgeDoubleJump=False
//    WallDodgeAnims(0)="stand"
//    WallDodgeAnims(1)="stand"
//    WallDodgeAnims(2)="stand"
//    WallDodgeAnims(3)="stand"
//    IdleHeavyAnim="Stand"
//    IdleRifleAnim="Stand"
    bCanJump=False
    bCanClimbLadders=False
    bCanStrafe=False
    bCanDoubleJump=False
    bCanUse=False
    MeleeRange=250.000000
    GroundSpeed=400.000000
    WaterSpeed=75.000000
    JumpZ=75.000000
    ControllerClass=Class'FFTimmyController'
    MovementAnims(0)="Run"
    MovementAnims(1)="Run"
    MovementAnims(2)="Run"
    MovementAnims(3)="Run"
    TurnLeftAnim="Walk"
    TurnRightAnim="Walk"
    SwimAnims(0)="Run"
    SwimAnims(1)="Run"
    SwimAnims(2)="Run"
    SwimAnims(3)="Run"
    WalkAnims(0)="Walk"
    WalkAnims(1)="Walk"
    WalkAnims(2)="Walk"
    WalkAnims(3)="Walk"
    AirAnims(0)="stand"
    AirAnims(1)="stand"
    AirAnims(2)="stand"
    AirAnims(3)="stand"
    TakeoffAnims(0)="stand"
    TakeoffAnims(1)="stand"
    TakeoffAnims(2)="stand"
    TakeoffAnims(3)="stand"
    LandAnims(0)="stand"
    LandAnims(1)="stand"
    LandAnims(2)="stand"
    LandAnims(3)="stand"
    DoubleJumpAnims(0)="stand"
    DoubleJumpAnims(1)="stand"
    DoubleJumpAnims(2)="stand"
    DoubleJumpAnims(3)="stand"
    DodgeAnims(0)="stand"
    DodgeAnims(1)="stand"
    DodgeAnims(2)="stand"
    DodgeAnims(3)="stand"
    AirStillAnim="stand"
    TakeoffStillAnim="stand"
    IdleCrouchAnim="Stand"
    IdleSwimAnim="Walk"
    IdleWeaponAnim="Stand"
    IdleRestAnim="Stand"
    Mesh=SkeletalMesh'Animals.meshDog'
    skins(0)=Texture'TimmySkins.Dog'
    PrePivot=(Z=0.000000)
    CollisionRadius=34.000000
    CollisionHeight=34.000000
    Mass=+00150.000000
    Buoyancy=+00150.000000
    RotationRate=(Pitch=3072,Yaw=60000,Roll=2048)
    HeadScale=+1.0
    SightRadius=+05000.000000
    MaxDesiredSpeed=+00001.000000
    AirSpeed=+00440.000000
    AccelRate=+02048.000000
    DesiredSpeed=+00001.000000
    Physics=PHYS_Walking        
}

And the corresponding FFTimmyController class which extends AIController

class FFTimmyController extends AIController;

/*SIT
    Stays still
    Switches into lay animations

FOLLOW
    Locates a valid position behind the player
    Walks to this location
    If Treasure is spotted - switch to TreasureHunter

TREASURE_HUNTER
    Searches for Treasure within a specified radius.
    Walks towards treasure
    Switches to Sit

WANDER (extra)
    Randomly chooses locations close to a central point
*/

var Actor followTarget;
var Actor nextPathPoint;
var float distanceToTarget;
var int randomChoice;

var int treasureLevel;
var int dogBiscuits;
var bool treasureHunting;

function AddBiscuits(int i)
{
    dogBiscuits+=i;
}

function FindNewFollowTarget()
{
    local ExamplePawn EP;

    Log("Timmy (FindNewFollowTarget)");

    ForEach DynamicActors(class'ExamplePawn', EP )
    {
        // should probably check for the closest?
        // or someone with a reason to follow
        followTarget = EP;
        Log("Timmy (FindNewFollowTarget) FOUND");
    }
}

function FindNewTreasureTarget()
{
    local HiddenTreasure HT;

    Log("Timmy (FindNewTreasureTarget)");

    ForEach DynamicActors(class'HiddenTreasure', HT )
    {
        // should probably check for the closest?
        // or someone with a reason to follow
        followTarget = HT;
        Log("Timmy (FindNewFollowTarget) FOUND");
    }
}

event PostBeginPlay()
{
    Super.PostBeginPlay();
    Log("Timmy (PostBeginPlay)");

    GotoState('Sit');
}

auto state Sit
{
    Begin:
        Log("Timmy (SIT) Begin");
        Sleep(RandRange(3,10));
        GotoState('ChooseBehaviour');
}

state ChooseBehaviour
{
Begin:
    randomChoice = rand(3);

    if ( dogBiscuits > 2 )
    {
        // treasure hunt
        // if we reward Timmy - only then should we go into the treasure hunter mode.
        // dog biscuits?
        // if we stop very close then he'll find it for us
        // otherwise we need to return home to find more biscuits
        FindNewTreasureTarget();
        treasureHunting = true;
        dogBiscuits = dogBiscuits - 3;
        GotoState('Follow');
    }

    switch( rand(2) )
    {
        case 0:
            // follow player
            FindNewFollowTarget();
            GotoState('Follow');
            break;
        case 1:
            // sit
            followTarget = NONE;
            GotoState('Sit');
            break;
    }

    GotoState('ChooseBehaviour');
}

state WaitByTreasure
{
Begin:
    if ( followTarget !=NONE )
    {
        //Pawn.PlayAnim();
        Sleep(3);
        GotoState('WaitByTreasure');
    }
    else
    {
        // treasure has been taken
        treasureHunting = false;
        GotoState('ChooseBehaviour');
    }
}

state Follow
{
    // tick?
    Begin:
        Log("Timmy (Follow) Begin");
        if ( followTarget == NONE )
        {
            FindNewFollowTarget();
        }
        distanceToTarget = vsize(Pawn.Location - followTarget.Location);

        Log( "Distance Timmy to Target: " $ distanceToTarget );

        if ( distanceToTarget < 100.0f)
        {
            if ( treasureHunting == true )
            {
                GotoState('WaitByTreasure');
            }
            else
            {
                GotoState('ChooseBehaviour');
            }
        }
        else
        {
            GotoState('MoveTowards');
        }
}

state MoveTowards
{
    Begin:
        Log("Timmy (Follow) MoveTo New Target");
        Log("Timmy Location: "$Pawn.Location);
        Log("Target Location: "$followTarget.Location);
        if ( PointReachable( followTarget.Location ))
        {
            Log("Point reachable");
            MoveTo( followTarget.Location);//,, true ); // should walk = true
        }
        else
        {
            Log("Point Unreachable using current locomotion method - using FindPathTo");

            nextPathPoint = FindPathTo( followTarget.Location );
            if (nextPathPoint != NONE)
            {
                Log("Found path - following");
                MoveToward(nextPathPoint);
            }
            else
            {
                Log("Failed to generate path");
                Log("Using FindPathToward");
                nextPathPoint = FindPathToward( followTarget );

                if (nextPathPoint != NONE)
                {
                    Log("Found path - following");
                    MoveToward(nextPathPoint);
                }
                else
                {
                    Log("Total Failure - lets give up and go home!");
                }
            }
        }
        GotoState('Follow');
}

defaultProperties
{
    treasureLevel = 1
    dogBiscuits = 0
    treasureHunting = false

    FovAngle=+00085.000000
    bCanOpenDoors=true
    bCanDoSpecial=true
    bIsPlayer=false
    bStasis=false
    RotationRate=(Pitch=3072,Yaw=30000,Roll=2048)
    RemoteRole=ROLE_None

}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License