Creating the Client
Shell
The Client Shell is responsible for handling player input, rendering,
and the like. In a single-player game with no networking component, the client
shell is also responsible for handling physics, AI, and all other game functions.
More detail is available in the LithTech Programming Guide.
This page will lead you through the creation of this class.
To get started, create a new file in Visual Studio and save it as ltclientshell.h. Next, add the necessary
multiple-inclusion protection, and include the engine header for the client
shell class.
#ifndef
__LT_CLIENT_SHELL_H__ |
#define
__LT_CLIENT_SHELL_H__ |
|
#include
<iclientshell.h> |
The next step is to declare a global pointer to the client shell.
|
class CLTClientShell; |
extern CLTClientShell
*g_pCShell; |
We now declare the client shell as CLTClientShell, deriving it from the
stub class provided by LithTech. We also include the constructor and destructor,
along with a macro which declares the client shell interface to the interface
manager.
|
class
CLTClientShell:public IClientShellStub { |
public: |
CLTClientShell(); |
~CLTClientShell(); |
|
declare_interface(CLTClientShell); |
|
The next step is to override necessary LithTech engine functions. The
purpose of each of these functions is explained later on this page, and fully
detailed descriptions are available in the Programming Guide.
|
// LithTech defined functions |
void Update(); |
uint32 OnEngineInitialized(RMode
*pMod, LTGUID *pAppGuid); |
void OnEvent(uint32
dwEventID, uint32 dwParam); |
|
Finally, we add non-LithTech functions and variables that will be used by
our game code.
|
protected: |
// Non-LithTech defined functions |
LTRESULT InitRenderer(RMode
*pMode); |
LTRESULT Render(); |
|
bool m_bRender; |
}; |
|
#endif //
__LT_CLIENT_SHELL_H__ |
|
Save the ltclientshell.h file in the following directory:
<your project directory>\cshell\src
Now, create another file in Visual Studio and save it as ltclientshell.cpp. Include the class header
file along with some engine headers.
#include "ltclientshell.h" |
#include <iltclient.h> |
#include <iclientshell.h> |
|
The following code sets up DLL exports and variables, initializes the
global client shell pointer, and defines our instantiation of the IClientShell
interface.
|
SETUP_CLIENTSHELL(); |
|
CLTClientShell *g_pCShell = NULL; |
|
define_interface(CLTClientShell, IClientShell); |
|
The constructor simply initializes the m_bRender variable to true. This
variable is set to true or false depending on whether the OS will allow LithTech
to render. We also define the destructor for the class.
|
CLTClientShell::CLTClientShell() { |
m_bRender
= true; |
} |
|
CLTClientShell::~CLTClientShell() { |
} |
|
The OnEngineInitialized function is called, appropriately, after the
engine has been initialized. Here is where we will call the InitRenderer
function to set up rendering. We also add some text that will be printed to the
console using the CPrint function. This function works the same way as C’s
printf(), except it prints to the console.
|
uint32
CLTClientShell::OnEngineInitialized(RMode *pMode, LTGUID
*pAppGuid) { |
LTRESULT
result = LT_OK; |
result
= InitRenderer(pMode); |
g_pLTClient->CPrint("Exit
by typing \"quit\" at the console (~)"); return
result; |
} |
|
This is a very simple implementation of an InitRenderer function that
simply sets the current render mode to whatever was requested. Later in the course
we will use a slightly more sophisticated version that checks whether the
requested mode is available and falls back if it’s not. Note the use of
g_pLTClient. This is a global pointer to the client interface (as opposed to
the client shell interface). The client interface is one of many interfaces
provided by the LTDS, and it provides a variety of useful functions.
LTRESULT CLTClientShell::InitRenderer(RMode
*pMode) { |
return
g_pLTClient->SetRenderMode(pMode); |
} |
|
The client shell’s Update function is called by LithTech as often as
possible. This is where much of a game’s logic will exist. This is also where
the engine’s renderer should be called, but only if m_bRender is true.
|
void CLTClientShell::Update() { |
LTRESULT
result; |
|
if
(m_bRender) { |
|
result
= Render(); |
|
if
(LT_OK != result) { |
g_pLTClient->DebugOut("Error
in Render()\n"); |
g_pLTClient->Shutdown(); |
} |
} |
} |
|
The Render function is a very simple function that clears the screen,
renders the 3D scene, then flips the buffers. Notice that nothing is actually
being rendered in our minimal implementation. Anything that needs to be rendered
must be placed between the calls to Start3D and End3D.
|
LTRESULT CLTClientShell::Render() { |
|
LTRESULT
result; |
|
// Clear the screen to prepare for the next
draw |
result
= g_pLTClient->ClearScreen(NULL, CLEARSCREEN_SCREEN | CLEARSCREEN_RENDER); |
if
(LT_OK != result) { |
g_pLTClient->DebugOut("Error
in ClearScreen()\n"); |
g_pLTClient->Shutdown(); |
} |
|
// Tell LithTech we are going to be starting
our 3d render |
result
= g_pLTClient->Start3D(); |
if
(LT_OK != result) { |
g_pLTClient->DebugOut("Error
in Start3D()\n"); |
g_pLTClient->Shutdown(); |
} |
|
// Tell LithTech to finish rendering for this
scene |
result
= g_pLTClient->End3D(END3D_CANDRAWCONSOLE); |
if
(LT_OK != result) { |
g_pLTClient->DebugOut("Error
in End3D()\n"); |
g_pLTClient->Shutdown(); |
} |
|
// Tell LithTech to flip the screen surface |
result
= g_pLTClient->FlipScreen(NULL); |
if
(LT_OK != result) { |
g_pLTClient->DebugOut("Error
in FlipScreen()\n"); |
g_pLTClient->Shutdown(); |
} |
|
return
LT_OK; |
} |
|
Finally, we have a simple event handler that changes the m_bRender variable
to respond to various system conditions..
|
void CLTClientShell::OnEvent(uint32 dwEventID,
uint32 dwParam) { |
|
if
(dwEventID == LTEVENT_LOSTFOCUS || |
dwEventID
== LTEVENT_RENDERTERM) |
m_bRender
= false; |
|
if (dwEventID
== LTEVENT_GAINEDFOCUS || |
dwEventID
== LTEVENT_RENDERINIT || |
dwEventID
== LTEVENT_RENDERALMOSTINITTED) |
m_bRender
= true; |
} |
Save the ltclientshell.cpp file in the following directory:
<your project directory>\cshell\src