Title: Programming with GapiDraw Computer Games Software Engineering
1Programming with GapiDrawComputer Games Software
Engineering
- Last week we covered some basics of C and
looked at a simple console-based Hello World
application for the Pocket PC using eVC. - This week we will start looking at graphics
application for Pocket PC devices. We will
program such applications using the third party
games API GapiDraw. - As we introduced last week, GapiDraw provides a
base class called CGapiApplication from which we
will derive our applications. i.e. we will create
a new class (usually called CMyApplication) which
will be inherited from the GapiDraw base class.
2The games loopComputer Games Software Engineering
Start
Initialise
- Computer games (and any interactive graphics
application) can be thought of as executing in
one big loop (or a cyclic executive). - Whilst in reality this is rarely the real model
that is used anymore (modern OSs like Windows use
message passing and events) we can still largely
think of games operating in such a fashion.
Get User Input
Move Objects
Detect Collisions
Draw Objects
Exit?
n
y
Clean Up
3CGapiApplicationComputer Games Software
Engineering
- CGapiApplication is simply a base class you can
use to quickly create new games and applications. - It has a number of public and protected member
functions you are expected to make use of the
public member functions (but never change them)
and add your own code to the protected member
functions (which sounds the wrong way around). - The public member functions do critical (or
system oriented) things such as starting the
application running, setting up the graphics
hardware and display mode. - The protected member functions typically
automatically run when certain things happen (the
game starts/ends, user presses a key, the
graphics are updated etc.)
4Public Member FunctionsComputer Games Software
Engineering
5Protected Member FunctionsComputer Games
Software Engineering
Ive skipped some here there are also functions
to read stylus (touch screen) activity. Each
returns a HRESULT (either S_OK or GD_OK).
6CGapiApplication data members Computer Games
Software Engineering
- A subclass of CGapiApplication will have the
following member variables- - (1),(2) and (4) are examples of further object
classes that are provided by GapiDraw. You should
already have started reading the GapiDraw
documentation. - GapiDraw surfaces are of particular importance.
- m_pDisplay the primary surface of the
application. - m_config a copy of the GDAPPCONFIG structure
passed to the constructor - m_pInput a CGapiInput object used for all
keyboard and stylus input. - m_pTimer a CGapiTimer object used to sleep
between each CGapiApplicationProcessNextFrame.
7GapiDraw surfaces Computer Games Software
Engineering
- A GapiDraw surface object (a GCGapiSurface) is a
memory area to which you can draw images and
primitives (rectangles, lines, text and etc). - Lots of the GCGapiSurface functionality is a
direct implementation of MS Direct Draw (Direct
X) commands. - This is really what your graphics/games
applications are all about writing graphical
objects to the screen. Each movable object (e.g.
character) you will create for your games will
usually be based on a GCGapiSurface object. - Additionally you have access to the main display
surface (m_pDisplay) which is an object of type
CGapiDisplay - a sub class of CGapiSurface which
adds extra features such as surface flipping and
back-buffer support.
8The backbuffer double buffering Computer Games
Software Engineering
- In any computer graphics application it is
unsafe to draw directly to the screen. Instead,
graphics programmers usually create a back-buffer
to which objects are written only when the
drawing of all objects is complete is the
contents of the back-buffer drawn to the physical
display. - The back-buffer can be thought as an offline
canvas for your application. Before each frame is
rendered you draw all your objects to this canvas
then the GapiDraw application takes care of
writing this to the real screen. - This last process is called a flip.
- The back-buffer is accessible from your
ProcessNextFrame member function in any sub-class
of CGapiApplication.
9CGapiApplicationCGapiApplicationComputer Games
Software Engineering
- The CGapiApplication constructor is used to
create a new instance of a CGapiApplication
CGapiApplication(const GDAPPCONFIG config) - Creating a new CGapiApplication usually consists
of the following steps- - A GDAPPCONFIG structure sets lots of Windows
related parameters (including what icon to use).
- Create a new GDAPPCONFIG structure and set the
parameters you want. - Create a CGapiApplication instance and supply the
GDAPPCONFIG structure. - Start the application with CGapiApplicationRun
10The GapiDraw games loopComputer Games Software
Engineering
- When CGapiApplicationRun is called, the
following steps are performed - CGapiApplicationRun finishes when
CGapiApplicationShutdown is called.
- The main window is created based on the options
specified in the GDAPPCONFIG structure. - The display is opened and the display mode is
set. - InitInstance is called in the subclass.
- CreateSysMemSurfaces is called in the subclass.
- CreateVidMemSurfaces is called in the subclass.
- The main games loop is started and
ProcessNextFrame will be called in the subclass
on each frame.
11The end of an applicationComputer Games Software
Engineering
- When CGapiApplicationShutdown is called, the
following steps are performed - Finally the subclass destructor is called. It is
sometime useful to wait here for a keyboard press
so we can see any printf() statements that have
been directed to a console window.
- CGapiApplicationExitInstance is called in the
subclass. - The GapiDraw display is closed.
- Any pending error messages set with
CGapiApplicationSetErrorMessage is displayed. - The main window is destroyed.
12A typical applicationComputer Games Software
Engineering
include local_include_file.h int WinMain(..)
// standard Windows entry point // create a
config structure // create instance of a
CMyApplication using config // run the instance
of CMyApplication
CMyApplicationCMyApplication(const
GDAPPCONFIG config)
CGapiApplication(config) CMyApplicationCMy
Application() //char cgetchar() // used to
look at console output
13A typical application (cont)Computer Games
Software Engineering
HRESULT CMyApplicationInitInstance() // runs
once at start // initialise variables, random
nos., sprites etc // start any background
sounds return S_OK HRESULT
CMyApplicationExitInstance() // runs once at
end // stop any background sounds return
S_OK HRESULT CMyApplicationCreateSurfaces(CG
apiDisplay display,
HINSTANCE hInstance) // create surfaces and
load bitmaps, PNGs etc
14A typical application (cont)Computer Games
Software Engineering
HRESULT CMyApplicationProcessNextFrame
(CGapiSurface backbuffer, DWORD dwFlags)
// draw background // calculate new object
locations check for collisions // draw the
objects return S_OK HRESULT
CMyApplicationKeyDown(DWORD dwKey,GDKEYLIST
keylist) // do stuff if a key is
pressed HRESULT CMyApplicationMyNewMemberFucti
on() // do something you want to do
yourself return S_OK
15A typical applicationComputer Games Software
Engineering
- This application defines (or implements) a new
sub-class of the CGapiApplication called
CMyApplication. It should be saved as a .cpp
file. To go along with this there should also be
a header file which defines this new subclass. - As we discussed last week, the header file (.h)
defines the interface to the class. Hence it must
list all the member variables and functions that
will be used by the class. - The keyword virtual in the method definition in
the header file on the next slide simply tells
the compiler that the method can be over-ridden. - When a base class pointer points to an instance
of a derived class, the version of the virtual
function in the derived class will be dynamically
called at run-time.
16A typical header fileComputer Games Software
Engineering
include "GapiApplication.h" class
CMyApplication public CGapiApplication public
CMyApplication(const GDAPPCONFIG config)
virtual CMyApplication() virtual HRESULT
InitInstance() virtual HRESULT
ExitInstance() virtual HRESULT
CreateSurfaces(CGapiDisplay display,
HINSTANCE hInstance)
virtual HRESULT ProcessNextFrame(CGapiSurface
backbuffer,
DWORD dwFlags) virtual HRESULT KeyDown(DWORD
dwKey, GDKEYLIST keylist) virtual HRESULT
CMyApplicationMyNewMemberFunction() protected
// member variables here
17ProcessNextFrameComputer Games Software
Engineering
- The most important member function of the
applications that you will derive from the
CGapiApplication class is ProcessNextFrame. - This function defines what happens at each frame
update. - In the second tutorial you will create an
application that cycles through different colours
(i.e. the colour is changed at each frame update)
and fills the screen with a different colour when
the frame is updated. - You can set the target FPS value for your
applications when you create the GDAPPCONFIG
structure. - The code for ProcessNextFrame and InitInstance
for the colour cycling application is shown on
the next slide.
18Color pulsator code Computer Games Software
Engineering
19Color pulsator header Computer Games Software
Engineering
20Color pulsator explanationComputer Games
Software Engineering
- The application has three member variables
(m_red, m_blue and m_green) each of which is a
DWORD type. - Your application uses these three variables to
set the background screen colour as an RGB value
(i.e. a mix of the three colours red, green and
blue with each individual RGB value being a
number in the range 0-255). - All three variables are initialised in the
InitInstance() member function which is run once
at startup. - The green and red variables are fixed whilst the
blue variable is continuously cycled (in steps of
5) throughout its complete range. - The GapiDraw surface FillRect() function draws a
rectangle of the required colour to the
backbuffer.
21DWORDS and other intsComputer Games Software
Engineering
- Using integers in C/C has always been a real
pain. - An int data-type in C/C can be 16-bit, 32-bit,
or even 64-bit depending on the hardware
platform/compiler that is being used. You can
also have long and short ints ! - This leads to all sorts of potentially very nasty
scenarios, and is a common cause for complaint
about the languages. - An int in Java is always stored as a 32-bit
number. A DWORD in Visual C is also always
32bits. - Almost every integer example we will use for our
GapiDraw games are DWORDS. - Note that a WORD is a 16-bit integer.
22StringsComputer Games Software Engineering
- One part of C that we will not cover is the
Standard Template Library (or STL). The STL gives
programmers nice ways of manipulating all sorts
of high level data structures including
strings. eVC does not support STL. - Strings on their own are complicated because two
different types of string are possible desktop
PCs use 8-bit ASCII strings, whilst Pocket PCs
use 16-bit or Unicode strings. - Java also uses Unicode strings.
- This is not normally a problem except when you
are cross compiling for different target
platforms or (worse) when you writing
collaborative networked games where one machine
might be a PC and the other a PDA or one
application is in Java the other in C!
23More about StringsComputer Games Software
Engineering
- Microsoft has a data-type called a TCHAR which
you can use to automatically create either an
8-bit or a 16-bit string depending on the
platform you are compiling for. - Additionally, writing TEXT() around an actual
string stores the string in the format specific
to the platform. - Since all our applications will run on the PDAs
we will frequently use TCHARs and the TEXT()
macro-
DWORD my_number 1 TCHAR str128 _stprintf(str
, TEXT(My_Number d"), my_number) backbuffer.D
rawText(1, 1, str, m_display.GetSystemFontB
order(), 0, NULL, 0, NULL)
24Even more about StringsComputer Games Software
Engineering
- Frequently, as in the previous example, we would
want to create a string from scratch that we want
to write to the display. This string might
typically display the contents of some variables. - The function sprintf() is what we would normally
use in C/C to do this kind of thing. - However we will use the special MS macro
_stprint() to do this as this always creates the
correct format of string. - Annoyingly MS have a myriad of other string types
as well as (our favourite) TCHAR. These include
LPSTR (a char), LPTSTR (a TCHAR), and LPCTSTR (a
const TCHAR). - LP is a historical throwback to 16bit Windows 3.1
days and means Long Pointer.
25Making things interestingComputer Games Software
Engineering
- At the end of Tutorial 2 you will be asked to
modify the color pulsator so that it does
something different. - First, youll be asked to make all the colors
(and not just blue) cycle through their values.
To do this you will need to add two more member
variables m_green_direction and m_red_direction
and use them in the same way as the application
currently uses the m_blue_direction variable
(i.e. to check when the values should move up or
down). - Then, youll be asked to set the screen color to
a random value at each frame update. - Finally, youll be asked to fill the screen with
a static background image.
26Random numbers in CComputer Games Software
Engineering
- You will commonly need to use random numbers in
your games. To do this we will use the C
functions srand() and rand(). - At the start of any application that uses random
numbers you should seed the random number
generator using the srand() function otherwise
your programs will always generate the same
sequence of random numbers! E.g.- - Then, in your program to generate a number, for
instance between 0 and 7, use a line of form-
srand(GetTickCount())
new_direction (rand()(DWORD)8)/ RAND_MAX
27Background imagesComputer Games Software
Engineering
- After the first few tutorials you will begin to
create your own background images for your
applications. - These will typically be created in an external
package (like PSP) and stored as an image file
(JPG, GIF or PNG). When creating images remember
that the screen size of the PDA is only 240x320
pixels (and is 16bits deep). - The GapiDraw library allows you to load images
(as CGapiSurface objects) into your application
before the games loop starts and then use those
images in your game. - You load any images in an overidden
CreateSurfaces function which runs once at the
start of an application. - You can then draw your images (surfaces) to the
back-buffer in the ProcessNextFrame function.
28Extra ReadingComputer Games Software Engineering
- For this week you should make sure that you start
browsing the online GapiDraw documentation. - The documentation for all of the GapiDraw classes
and their functions can be found in the GapiDraw
directory on each PC i.e. at C\CO42032\GapiDraw\
doc\index.html or linked to via an icon on the
desktop. - Also you can get it at http//www.dcs.napier.ac.uk
/shaun/CO42032/doc/ - You should get used to accessing this
documentation whenever you come across GapiDraw
code that is new. - The GapiDraw forum has lots and lots of tips and
sample code from experienced (and not) GapiDraw
developers. http//www.pocketmatrix.com/forums/vie
wforum.php?f23