Building a First-Person Shooter Part 1.2: The Player Class
Published May 08, 2015
by Chris Vossen, posted by ChrisVossen
It's finally time to begin fleshing out our player class. This class will manage the first-person user controls. We will start by setting up player.h. This header file will contain the declarations of the player class as well as the various variables and functions that will be held within the player class. At this time copy and paste the following code into player.h:
#pragma once
#include "MyGame.h"
using namespace Leadwerks;
class Player: public Node
{
private:
Camera* camera;
float standheight;
float crouchheight;
float cameraheight;
float move;
float strafe;
float movementspeed;
float maxacceleleration;
float sensitivity;
float smoothedcamerapositiony;
float cameraypositionsmoothing;
float cameralooksmoothing;
float runboost;
float jump;
float jumpforce;
float jumpboost;
int footstepwalkfrequency;
int footsteprunfrequency;
long footsteptimer;
bool running;
bool crouched;
bool landing;
Vec2 mousespeed;
Vec3 normalizedmovement;
Vec3 cameraposition;
Vec3 playerrotation;
Sound* footstepsound[4];
Sound* landsound[4];
Sound* jumpsound[1];
public:
Player();
virtual ~Player();
virtual void UpdateControls();
virtual void Update();
};
Setting Up the Player Class
The player.cpp file will contain all the logic and code for setting up FPS player mechanics. We start with a basic player class that contains a constructor, destructor, and two empty functions:
#include "MyGame.h"
using namespace Leadwerks;
Player::Player()
{
}
Player::~Player()
{
}
void Player::UpdateControls()
{
}
void Player::Update()
{
}
Since the player class is a child of the node class it will inherit an entity member from its parent. In the player constructor we assign a value to this entity member with a call to Pivot::Create(). A pivot is an invisible entity with no special properties, it is essentially an instantiation of an empty entity:
entity = Pivot::Create();
We now want to setup the player physics properties for the entity:
entity->SetPhysicsMode(Entity::CharacterPhysics);
entity->SetCollisionType(Collision::Character);
entity->SetMass(10.0);
And finally position the player at the origin:
entity->SetPosition(0,0,0,true);
With the code additions our player class will now look as such:
#include "MyGame.h"
using namespace Leadwerks;
Player::Player()
{
//Create the entity
entity = Pivot::Create();
//Set up player physics
entity->SetPhysicsMode(Entity::CharacterPhysics);
entity->SetCollisionType(Collision::Character);
entity->SetMass(10.0);
//Player position
entity->SetPosition(0,0,0,true);
}
Player::~Player()
{
}
void Player::UpdateControls()
{
}
//Update function
void Player::Update()
{
}
Adding in a Camera
In a FPS the player's camera acts as the player's head, in that it should be positioned at a height directly above the player's shoulders and be restricted to normal human movements. For the player's height we will create and initialize three separate variables in the constructor:
standheight=1.7;
crouchheight=1.2;
cameraheight = standheight;
We then create the camera, position it to the height of a standing player, and narrow the camera's field of view:
camera = Camera::Create();
camera->SetPosition(0,entity->GetPosition().y + cameraheight,0,true);
camera->SetFOV(70);
We also don't want to forget to deal with the camera when an instance of the player class gets deleted. so in the destructor we add in:
if (camera)
{
camera->Release();
camera = NULL;
}
After these changes the player class will now look like this:
#include "MyGame.h"
using namespace Leadwerks;
Player::Player()
{
//Create the entity
entity = Pivot::Create();
//Initialize values
standheight=1.7;
crouchheight=1.2;
cameraheight = standheight;
//Create the player camera
camera = Camera::Create();
camera->SetPosition(0,entity->GetPosition().y + cameraheight,0,true);
camera->SetFOV(70);
//Set up player physics
entity->SetPhysicsMode(Entity::CharacterPhysics);
entity->SetCollisionType(Collision::Character);
entity->SetMass(10.0);
//Player position
entity->SetPosition(0,0,0,true);
}
Player::~Player()
{
if (camera)
{
camera->Release();
camera = NULL;
}
}
void Player::UpdateControls()
{
}
//Update function
void Player::Update()
{
}
Up next, we'll talk about movement with keyboard input.
Comments
You must
log in to join the conversation.
Don't have a GameDev.net account?
Sign up!
I see several problem with the Player class:
1) The class is too big. It has 29 members including arrays! It has too many responsibilities: mouse speed, camera, physics, sound, etc.
2) Manual memory management. std::unique_ptr (or boost::scoped_ptr) would be a lot better.
3) It creates its own dependencies instead of using Dependency Injection. It creates coupling an block the possibility of unit testing the class.
4) The meaning of the last parameter of entity->SetPosition is not clear.
5) Not all members are initialized in the constructor.
6) Constructor is not exception safe (assuming ::Create can throw std::bad_alloc).
Such code smells in an article can teach people really bad habbits.