Créer une visée laser

Écrit le 03/07/2003 par DukeNukem
Dernière mise à jour : 30/01/2006

Introduction

Ce tutorial a pour but de vous montrer comment créer une simple visée laser telle que celle du lance roquettes d'Half-life. Pour cela, on va admettre qu'on activera et désactivera notre visée laser avec le second mode de tir de l'arme.

Notre tâche va être grandement simplifiée puisqu'on va justement pouvoir reprendre la classe CLaserSpot originellement créée spécialement pour le RPG.

http://www.game-lab.com/images/tuts/hl1_wpn_laser/01.jpg http://www.game-lab.com/images/tuts/hl1_wpn_laser/02.jpg

Let's go!

Comme je l'ai évoqué juste au-dessus, la visée laser du RPG est constitué d'une entité (matérialisée par un sprite) représentant le point d'impact du laser contre quelque chose de solide. Ce point est appelé "laser dot", d'où sa classe CLaserSpot.

On va donc avoir besoin d'un objet de cette classe pour notre arme. Allez à la définition de classe de votre arme (normalement dans weapon.h) et rajoutez-y ces deux variables membres publiques :

public:
    // laser dot
    CLaserSpot  *m_pSpot;
    bool        m_bSpotActive;

La seconde variable est un flag indiquant si le laser est actif ou pas. On va également créer une nouvelle fonction pour afficher le « laser dot ». Ajoutez à la classe de votre arme la déclaration de cette nouvelle fonction membre :

    void        UpdateSpot( void );

Maintenant déplacez-vous vers le fichier source de votre arme et initialisons notre flag dans la fonction Spawn() (en admettant que la classe de votre arme s'appelle CMonArme) :

// --------------------------------------------
// Spawn() -
// --------------------------------------------

void CMonArme::Spawn( void )
{
    m_bSpotActive = false;

    // ... reste du code de la fonction...
}

Définissons maintenant la fonction que l'on vient de créer :

// --------------------------------------------
// UpdateSpot() -
// --------------------------------------------

void CMonArme::UpdateSpot( void )
{

#ifndef CLIENT_DLL
    if( m_bSpotActive )
    {
        if( !m_pSpot )
            m_pSpot = CLaserSpot::CreateSpot();

        UTIL_MakeVectors( m_pPlayer->pev->v_angle );
        Vector vecSrc = m_pPlayer->GetGunPosition();
        Vector vecAiming = gpGlobals->v_forward;

        TraceResult tr;
        UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 8192,
                        dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr );

        UTIL_SetOrigin( m_pSpot->pev, tr.vecEndPos );
    }
#endif

}

Cette fonction s'assure tout d'abord que le « laser dot » est bien créé. Si ce n'est pas le cas, on appelle la fonction CLaserSpot::CreateSpot(). Ensuite on construit une ligne virtuelle à partir des coordonnées de l'arme et de l'endroit visée pour déterminer la position du spot, lequel on met à jour en appelant UTIL_SetOrigin().

Notez également que l'on s'assure de ne pas refaire deux fois la même chose : on désactive cette partie du code du côté client dll.

Cette fonction, on va l'appeler deux fois : au début de PrimaryAttack() et de WeaponIdle(). Modifiez donc ces fonctions pour qu'elles updatent le « laser dot » :

// --------------------------------------------
// PrimaryAttack() -
// --------------------------------------------

void CMonArme::PrimaryAttack( void )
{
    UpdateSpot();

    // ... reste du code de la fonction...
}



// --------------------------------------------
// WeaponIdle() -
// --------------------------------------------

void CMonArme::WeaponIdle( void )
{
    UpdateSpot();

    // ... reste du code de la fonction...
}

On va maintenant passer à l'activation et désactivation du laser. Modifiez la fonction SecondaryAttack() de sorte à ce qu'elle ressemble à ceci au code suivant. Si vous avez déjà un second mode de tir, vous pouvez aménager votre fonction pour qu'elle accepte et votre second mode de tir, et le laser.

// --------------------------------------------
// SecondaryAttack() -
// --------------------------------------------

void CMonArme::SecondaryAttack( void )
{
    m_bSpotActive = !m_bSpotActive;

#ifndef CLIENT_DLL
    if( !m_bSpotActive && m_pSpot )
    {
        m_pSpot->Killed( NULL, GIB_NORMAL );
        m_pSpot = NULL;
    }
#endif

    m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2;
}

Si le laser est désactivé, on détruit l'entité. S'il est désactivé, on change simplement le flag m_bSpotActive et l'entité sera recrée lors du prochain appel de UpdateSpot().

Il reste enfin une dernière chose à faire : désactiver le "laser dot" s'il est activé lorsque le joueur change d'arme. Pour cela on fait une petite vérification dans la fonction Holster() :

// --------------------------------------------
// Holster() -
// --------------------------------------------

void CMonArme::Holster( int skiplocal /* = 0 */ )
{
    // ... reste du code de la fonction...

#ifndef CLIENT_DLL
    if( m_pSpot )
    {
        m_pSpot->Killed( NULL, GIB_NEVER );
        m_pSpot = NULL;
    }
#endif
}

Et voilà ! Il ne vous reste plus qu'à recompiler la mp.dll et la client.dll.

Vous pouvez aussi désactiver le laser un espace de temps et le réactiver ensuite en utilisant les fonctions suivantes (déjà déclarées et définies dans CLaserSpot) :

    void Suspend( float flSuspendTime );
    void EXPORT Revive( void );