terça-feira, 26 de junho de 2012

Platformer Kit: SPG_Weapon class (UnrealScript)

A classe SPG_Weapon representa a arma utilizada no Platformer Kit. Ela é baseada na Link Gun do Unreal Tournament, mas possui apenas a opção de tiro com projétil.

Se você não conhece a classe Weapon, dê uma lida no artigo: "Classe Weapon (UnrealScript)".

As variáveis da classe SPG_Weapon estão disponíveis para modificação no editor.
class SPG_Weapon extends Weapon;

// Name of the socket which represents the muzzle socket
var(Weapon) const Name MuzzleSocketName;

// Particle system representing the muzzle flash
var(Weapon) const ParticleSystemComponent MuzzleFlash;

// Projectile classes that this weapon fires. DisplayName lets the editor show this as WeaponProjectiles
var(Weapon) const array< class<Projectile> > Projectiles<DisplayName=Weapon Projectiles>;

// Sounds to play back when the weapon is fired
var(Weapon) const array<SoundCue> WeaponFireSounds;

Também foi criado um Archetype para a classe SPG_Weapon. A imagem abaixo mostra os valores de algumas variáveis.



A classe SPG_Weapon utiliza dois Sockets. Um para marcar a posição no modelo 3D da arma de onde o tiro será disparado. O outro Socket pertence a classe SPG_PlayerPawn e marca a posição onde a arma deve ficar em relação ao jogador. Para entender mais sobre Sockets, dê uma lida no artigo da UDN: "Skeletal Mesh Sockets".

Na função PostBeginPlay() o Componente de Sistema de Partículas representado pela variável "MuzzleFlash" é anexado ao Socket da arma. A arma é anexada ao jogador na função ClientGivenTo().
simulated event PostBeginPlay()
{
    local SkeletalMeshComponent SkeletalMeshComponent;

    Super.PostBeginPlay();

    if (MuzzleFlash != None)
    {
        SkeletalMeshComponent = SkeletalMeshComponent(Mesh);
        if (SkeletalMeshComponent != None && SkeletalMeshComponent.GetSocketByName(MuzzleSocketName) != None)
        {
            SkeletalMeshComponent.AttachComponentToSocket(MuzzleFlash, MuzzleSocketName);
        }
    }
}

Uma das funções que é executada quando a arma é disparada é a PlayFireEffects(). Ela é responsável por ativar o Sistema de Partículas e reproduzir o som de disparo da arma.

Para mais informações sobre Sistemas de Partículas, acesse o artigo da UDN: "Particles Systems".

Segue abaixo a imagem de quando a arma é disparada e o código da função PlayFireEffects().

simulated function PlayFireEffects(byte FireModeNum, optional vector HitLocation)
{
    if (MuzzleFlash != None)
    {
        // Activate the muzzle flash
        MuzzleFlash.ActivateSystem();
    }

    // Play back weapon fire sound if FireModeNum is within the array bounds and if the 
    // weapon fire sound in that array index is not none
    if (FireModeNum < WeaponFireSounds.Length && WeaponFireSounds[FireModeNum] != None && Instigator != None)
    {
        Instigator.PlaySound(WeaponFireSounds[FireModeNum]);
    }
}

A outra função que é executada quando a arma é disparada é a ProjectileFire(). Ela é responsável por criar um novo projétil e iniciá-lo na posição e direção corretas.

A posição do projétil é obtida a partir da função GetWeaponStartTraceLocation() da classe SPG_PlayerPawn, que é representada no código pela variável Instigator.
simulated function Projectile ProjectileFire()
{
    local Vector SpawnLocation;
    local Rotator SpawnRotation;
    local class<Projectile> ProjectileClass;
    local Projectile SpawnedProjectile;

    // tell remote clients that we fired, to trigger effects
    IncrementFlashCount();

    // Only allow servers to spawn projectiles
    if (Role == ROLE_Authority)
    {
        // This is where we would spawn the projectile
        SpawnLocation = Instigator.GetWeaponStartTraceLocation();

        // This is the rotation we should spawn the projectile
        SpawnRotation = GetAdjustedAim(SpawnLocation);

        // Get the projectile class
        ProjectileClass = GetProjectileClass();
        if (ProjectileClass != None)
        {
            // Spawn the projectile setting the projectile's owner to myself
            SpawnedProjectile = Spawn(ProjectileClass, Self,, SpawnLocation, SpawnRotation);

            // Check if we've spawned the projectile, and that it isn't going to be deleted
            if (SpawnedProjectile != None && !SpawnedProjectile.bDeleteMe)
            {
                // Initialize the projectile
                SpawnedProjectile.Init(Vector(SpawnRotation));
            }
        }
      
        // Return it up the line
        return SpawnedProjectile;
    }

    return None;
}