Wavelength Logo
tl.jpg (2351 bytes) blank.gif (837 bytes) tr.jpg (2446 bytes)
blank.gif (837 bytes)
Class System Tutorial by Blake Grant
blank.gif (837 bytes)
There are a few ways of implementing a class system. The first is to just have a flag indicating the class, then do a switch or series of if statements everytime something differs for each class. This can get incredibly cumbersome. Especially if you have multiple classes.

Now before I go into more detail, I'm going to have a disclaimer. This tutorial is meant for programmers who are very familiar with Object Oriented Programming (OOP) in C++, and those who aren't should just skip this and do the cumbersome method :) Feel free to ask me questions about the tutorial so long as they aren't basic C++ or OOP questions.

That said, my suggestion is to make a new class that is the base class for all your player classes (I called it CBaseClass). Then, derive all your classes from that. Add functions like CBaseClass::PlayerSpeed() which return a value. Then, make a pointer to the class in CBasePlayer, and call it's memeber functions to determine what you need to do.

Example 1: The basics
---------------------


OK, quick example. I'll just make 2 actual classes so the code doesn't go on forever. I'll start by just adding one function which you use to determine the class's speed:

Make a new file "classes.h" with the following code:

class CBaseClass {
public:
virtual int PlayerSpeed() { return 200; };
};

class CSpy : public CBaseClass {
public:
virtual int PlayerSpeed() { return 500; };
};

class CSloth : public CBaseClass {
public:
virtual int PlayerSpeed() { return 100; };
};


Now, go modify player.h to include a pointer to a CBaseClass (make sure its public).

CBaseClass * m_pClass;

So it knows what a CBaseClass is, right before the definition of CBasePlayer, add the line:

class CBaseClass;

This'll tell the compiler that there is a class called CBaseClass, but we don't need to worry about its details yet. Now, in player.cpp, add an include for classes.h

#include "classes.h"

How you determine who is what class is up to you, one way is to randomly assign the player to a class when he joins. A better way would be to bring up a menu and let the player select it, but that brings up alot of other nasty issues. Check out my observer tutorial and the menu tutorial to get an idea how this is done.

To do the random select thing, do this in RecountTeams():

float fRand = RANDOM_FLOAT( 0, 1 );
if(fRand < 0.5)
pPlayer->m_pClass = new CSpy;
else
pPlayer->m_pClass = new CSloth;


Don't forget to delete the pointers before you allocate new ones if this function will be called more than once during the game! Now, finally, in PlayStepSound():

g_engfuncs.pfnSetClientMaxspeed( ENT( pev ), m_pClass->PlayerSpeed() );

No if statements, and everything is nicely abstracted!

Example 2: Changing the model
-----------------------------


Say we want to change the player's model based on his class (you're probably going to want to do this). In each of the object's constructors, add this line:

g_engfuncs.pfnSetClientKeyValue( m_pPlayer->entindex(), g_engfuncs.pfnGetInfoKeyBuffer( m_pPlayer->edict() ), "model", "gordon");

where "gordon" can be any model you want. The one thing i left out that you need to make this work (didn't need it until now), is a pointer to the player who's using this class, so add a public constructor to the base class, and a member variable to hold the pointer to the player:

public: CBaseClass(CBasePlayer * pPlayer); CBasePlayer * m_pPlayer;

And now you'll want a classes.cpp file, so make it, and add this code to it:

#include "classes.h"
#include "player.h"

CBaseClass::CBaseClass(CBasePlayer * pPlayer) {
m_pPlayer = pPlayer;
}

I think that should do it. Note that if you want special action for each class's constructor, you'll need to overide the constructor with this code in the .h file:

public:
CSpy(CBasePlayer * pPlayer);


and this code in the .cpp file:

CSpy::CSpy(CBasePlayer * pPlayer) : CBaseClass(pPlayer) {
// Do whatever you want
}

You'll also have to modify RecountTeams() again where you created the object like this:

float fRand = RANDOM_FLOAT( 0, 1 );
if(fRand < 0.5)
pPlayer->m_pClass = new CSpy;
else
pPlayer->m_pClass = new CSloth;


change it to:

float fRand = RANDOM_FLOAT( 0, 1 );
if(fRand < 0.5)
pPlayer->m_pClass = new CSpy(pPlayer);
else
pPlayer->m_pClass = new CSloth(pPlayer);


because you are going to need to pass in a pointer to the player who is using it.

 

blank.gif (837 bytes)
bl.jpg (2471 bytes) blank.gif (837 bytes) br.jpg (2132 bytes)