quarta-feira, 27 de junho de 2012

Platformer Kit: SPG_AIPawn class (UnrealScript)

A classe SPG_AIPawn representa os robôs que atacam o jogador no Platform Kit. As variáveis definidas para esta classe são as seguintes:
class SPG_AIPawn extends Pawn
      placeable;

// Dynamic light environment component to help speed up lighting calculations for the pawn
var(Pawn) const DynamicLightEnvironmentComponent LightEnvironment;

// Ground speed of the pawn, display as Ground Speed in the editor
var(Pawn) const float UserGroundSpeed<DisplayName=Ground Speed>;

// Explosion particle system to play when blowing up
var(Pawn) const ParticleSystem ExplosionParticleTemplate;

// Explosion sound to play
var(Pawn) const SoundCue ExplosionSoundCue;

// Explosion damage amount 
var(Pawn) const int ExplosionDamage;

// Archetyped pick up to drop
var(Pawn) const archetype DroppedPickup ArchetypedPickup;

// Percentage chance to drop pickups
var(Pawn) const float ChanceToDropPickup;

// Current enemy
var Actor Enemy;

Existe um Archetype para a classe SPG_AIPawn. A imagem abaixo mostra as variáveis específicas da classe SPG_AIPawn.


A função Tick() é executada a cada frame. Nesta função é armazenada uma referência ao jogador na variável Enemy (inimigo), caso isto ainda não tenha sido feito.

Depois disso, caso o robô já esteja no solo andando (Physics == PHYS_Walking), ele obtém a localização do jogador e ajusta sua velocidade e rotação para mover em direção ao jogador.
simulated function Tick(float DeltaTime)
{
    local PlayerController PlayerController;
    local Vector Direction;
    local Rotator NewRotation;

    Super.Tick(DeltaTime);

    // If we don't have an enemy yet...
    if (Enemy == None)
    {
        // Find the player controller in the world
        PlayerController = GetALocalPlayerController();

        if (PlayerController != None && PlayerController.Pawn != None)
        {
            // Set the enemy to the player controller's pawn
            Enemy = PlayerController.Pawn;
        }
    }
    else if (Physics == PHYS_Walking)
    {
        // Find the direction in order for me to look at my enemy
        Direction = Enemy.Location - Location;

        // Only need to use the yaw from the direction
        NewRotation = Rotator(Direction);
        NewRotation.Pitch = 0;
        NewRotation.Roll = 0;

        // Set the rotation so that I look at the enemy
        SetRotation(NewRotation);

        // Set my velocity, so I move towards the enemy
        Velocity = Normal(Enemy.Location - Location) * UserGroundSpeed;

        // Set my acceleration, so I move towards the enemy
        Acceleration = Velocity;
    }
}



Quando um robô colide com o jogador a função Bump() é executada. Para mais informações sobre colisão leia o artigo: "Colisão em UnrealScript".

O jogador, que é representado pela variável Other nesta função, recebe o dano cujo valor está definido na variável ExplosionDamage. Na imagem do Archetype podemos ver que o valor padrão desta variável é 5.

O efeito com partículas que representa a explosão é acionado e é reproduzido o som da explosão armazenado na variável ExplosionSoundCue. Para mais informações sobre SoundCue, leia o artigo: "Tocando Sons em UnrealScript".
event Bump(Actor Other, PrimitiveComponent OtherComp, Vector HitNormal)
{
    Super.Bump(Other, OtherComp, HitNormal);

    if (SPG_PlayerPawn(Other) != None)
    {
        // Apply damage to the bumped pawn
        Other.TakeDamage(ExplosionDamage, None, Location, Vect(0, 0, 0), class'DamageType');

        // Play the particle effect
        if (ExplosionParticleTemplate != None)
        {
            WorldInfo.MyEmitterPool.SpawnEmitter(ExplosionParticleTemplate, Location);
        }

        // Play the explosion sound
        if (ExplosionSoundCue != None)
        {
            PlaySound(ExplosionSoundCue);
        }

        // Destroy the pawn
        Destroy();
    }
}


Quando um robô é eliminado pelo jogador, a função PlayDying() é executada. Nesta função a física do robô é definida como PHYS_RigidBody para que ele caia no chão.

É verificada a possibilidade de o robô deixar cair um item de energia, que é representada pela classe SPG_HealthPickup. Este teste é feito com a expressão: "FRand() <= ChanceToDropPickup". FRand() é uma função do UnrealScript que retorna um valor aleatório entre 0.0 e 1.0. A variável ChanceToDropPickup está definida no Archetype com o valor "0.3". Isto significa que existe 30% de chance de que um item de energia caia do robô.
simulated function PlayDying(class<DamageType> DamageType, vector HitLoc)
{
    local DroppedPickup DroppedPickup;

    Mesh.MinDistFactorForKinematicUpdate = 0.0;
    Mesh.ForceSkelUpdate();
    Mesh.SetTickGroup(TG_PostAsyncWork);
    CollisionComponent = Mesh;
    CylinderComponent.SetActorCollision(false, false);
    Mesh.SetActorCollision(true, false);
    Mesh.SetTraceBlocking(true, true);
    SetPawnRBChannels(true);

    SetPhysics(PHYS_RigidBody);

    Mesh.PhysicsWeight = 1.f;

    if (Mesh.bNotUpdatingKinematicDueToDistance)
    {
        Mesh.UpdateRBBonesFromSpaceBases(true, true);
    }

    Mesh.PhysicsAssetInstance.SetAllBodiesFixed(false);
    Mesh.bUpdateKinematicBonesFromAnimation = false;
    Mesh.WakeRigidBody();

    // Set the actor to automatically destroy in ten seconds.
    LifeSpan = 10.f;

    // Chance to drop a pick up
    if (ArchetypedPickup != None && FRand() <= ChanceToDropPickup)
    {
        // Spawn a dropped pickup
        DroppedPickup = Spawn(ArchetypedPickup.Class,,, Location,, ArchetypedPickup);

        if (DroppedPickup != None)
        {
            // Set the dropped pick up to falling
            DroppedPickup.SetPhysics(PHYS_Falling);

            // Set the velocity of the dropped pickup to the toss velocity
            DroppedPickup.Velocity.X = 0;
            DroppedPickup.Velocity.Y = 0;
            DroppedPickup.Velocity.Z = RandRange(200.f, 250.f);
        }
    }
}