Escolar Documentos
Profissional Documentos
Cultura Documentos
Salvatore A. Buono
CRC Press
(tf* Taylor &. Francis Group
Boca Raton London New York
This book contains information obtained from authentic and highly regarded sources. Reasonable efforts
have been made to publish reliable data and information, but the author and publisher cannot assume
responsibility for the validity of all materials or the consequences of their use. The authors and publishers
have attempted to trace the copyright holders of all material reproduced in this publication and apologize to
copyright holders if permission to publish in this form has not been obtained. If any copyright material has
not been acknowledged please write and let us know so we may rectify in any future reprint.
Except as permitted under U.S. Copyright Law, no part of this book may be reprinted, reproduced,
transmitted, or utilized in any form by any electronic, mechanical, or other means, now known or hereafter
invented, including photocopying, microfilming, and recording, or in any information storage or retrieval
system, without written permission from the publishers.
For permission to photocopy or use material electronically from this work, please access www.copyright.com
(http://www.copyright.com/) or contact the Copyright Clearance Center, Inc. (CCC), 222 Rosewood Drive,
Danvers, MA 01923, 978-750-8400. CCC is a not-for-profit organization that provides licenses and
registration for a variety of users. For organizations that have been granted a photocopy license by the CCC,
a separate system of payment has been arranged.
Trademark Notice: Product or corporate names may be trademarks or registered trademarks, and are used
only for identification and explanation without intent to infringe.
QA76.73.C154.B85 20 04
00 5.13 ’3-d c 2 2
2 0 04 05 341 2
To my unborn son
Though I have already felt your spirit, though I already love your soul, I still w ait in
anticipation, for your presence to make me whole.
Preface xvii
vii
C# and Game Programming
Whitespaces...................................................................................................... 22
Preprocessor Directives.................................................................................... 22
Indenting............................................................................................................. 23
Nanning Variables............................................................................................... 23
Declaring Variables and the Integer Data Types................................................ 26
The Data Types float and double........................................................................ 28
The Data Type decimal........................................................................................30
The Data Types character and string.................................................................31
Keywords sizeof and unsafe............................................................................... 33
Enabling unsafe mode in C #............................................................................... 33
The Data Type void..............................................................................................35
Assignment Statements.................................................................................... 36
Type Compatibility: Implicit Conversions.............................................................36
Formatting Strings............................................................................................. 37
Arithmetic........................................................................................................... 38
Keyboard Input................................................................................................... 44
Uninitialized Variables......................................................................................... 45
Access Modifiers: constant, Readonly, and volatile........................................... 46
Incrementing and Decrementing Operators...................................................... 48
Type Safety versus Metonym Data Types.......................................................... 49
Keyword Defaults................................................................................................50
Using, System, and Namespace........................................................................ 51
Hungarian Notation............................................................................................ 52
Things to Remember..........................................................................................53
Troubleshooting.................................................................................................. 53
Questions............................................................................................................ 57
The if Statement................................................................................................. 59
The else Statement............................................................................................ 63
The else-if Statement..........................................................................................64
viii
Table of Contents
Program Walkthrough....................................................................................... 65
Compound if Statements....................................................................................66
and, or, and n o t...................................................................................................68
Nested if Statements......................................................................................... 69
Mathematical Abbreviations.............................................................................. 71
The while Loop................................................................................................... 73
Battle B it.............................................................................................................77
The do-while Loop............................................................................................... 81
The for Loop....................................................................................................... 83
The switch Statement........................................................................................ 85
Converting from C++ to C # ............................................................................... 88
Boolean Expressions.......................................................................................... 90
Short Circuit Evaluation...................................................................................... 91
The Conditional Operator....................................................................................92
Predefined Functions..........................................................................................93
Type Casting: Explicit Conversions..................................................................... 99
References, Values, and the Boxing Technique..............................................1 □□
Introduction to User-Defined Functions........................................................... 101
Writing Our First User-Defined Function........................................................ 102
Variable Scope................................................................................................. 103
Functions that Return Values.......................................................................... 105
Passing Variables: Calls-By-Value.................................................................... 108
Writing Functions as Black Boxes...................................................................110
Passing Variables: Calls-By-Reference............................................................. 112
The Keyword o u t.............................................................................................. 114
An Introduction to Polymorphism.................................................................... 115
Introducing Recursion......................................................................................118
Inline Functions.................................................................................................119
Troubleshooting................................................................................................119
Things to Remember....................................................................................... 121
Questions..........................................................................................................123
ix
C# and Game Programming
Writing Games.................................................................................................131
Game 1—Paddle Tennis....................................................................................132
Brainstorming................................................................................................ 132
Drawing Characters......................................................................................... 133
Plotting Motions............................................................................................. 138
Writing an Algorithm......................................................................................139
Displaying Graphics Using Native C + + .......................................................... 143
Displaying Graphics Using C # ..........................................................................143
Displaying Graphics Using DirectDraw.......................................................... 144
Introducing Object-Oriented Programming.................................................... 146
Adding Files to Our Projects...........................................................................146
Programming a Character............................................................................. 148
Directlnput: the Keyboard............................................................................... 149
Erasing Residual Images.................................................................................. 150
Collision Detection: The Players’ Boundaries................................................. 151
Collision Detection: The Ball in M otion........................................................... 152
Collision Detection: Deflecting the Ball........................................................... 154
A Few Minor Details: Scores, Speed Settings, and Additional Graphics 156
Adding Colors................................................................................................. 160
Adding Sounds Using Windows Multimedia....................................................161
Adding Sounds Using DirectSound.................................................................162
Adding in the Mouse...................................................................................... 164
Directlnput: The Mouse.................................................................................. 168
Directlnput: The Joystick.................................................................................. 169
Introducing Menus........................................................................................... 171
Introduction to Artificial Intelligence............................................................... 176
Paddle Tennis: Putting It All Together.............................................................179
Bonus Games................................................................................................. 179
Game 2—Space Fighters................................................................................. 179
Table of Contents
Brainstorming.................................................................................................. 180
Selecting Characters & Plotting Motions........................................................ 181
Writing the Algorithm.......................................................................................183
Animating Characters: Animating Spaceships................................................ 185
Animating Characters: Projectiles and Explosions........................................ 187
Adding Directlnput: The Keyboard and Joystick...............................................188
OnPaint............................................................................................................ 189
Defining Hyperspace........................................................................................ 190
Boundaries & Projectile Limits........................................................................ 191
Drawing with DirectDraw................................................................................. 194
Artificial Intelligence: Evasion........................................................................... 196
Including Obstacles: The Sun........................................................................... 199
Gaining Momentum......................................................................................... 20 0
Including More Obstacles: Asteroids as Extra Credit...................................... 201
Menus.............................................................................................................. 202
Space Fighters: Putting It All Together.............................................................20 4
Game 3—Asteroid M iner................................................................................. 20 4
Brainstorming..................................................................................................20 4
Asteroid Miner: Putting it All Together.............................................................208
Troubleshooting............................................................................................... 209
Things to Remember....................................................................................... 212
Questions......................................................................................................... 212
xi
C# and Game Programming
Theforeach loop...............................................................................................237
Enumerating Constant Integers.......................................................................238
Pointers............................................................................................................239
Enabling unsafe Mode......................................................................................240
Pointer Variables.............................................................................................. 242
Call-By-Reference Values with Pointer Arguments..........................................24 4
Pointer Arithmetic............................................................................................246
String and Address Arithmetic........................................................................ 248
The void Pointer............................................................................................... 252
Finding the Mean, Median, Mode, and Range................................................. 25 4
Pointers as Arrays: The Keyword stackalloc...................................................256
Double Asterisk Pointers................................................................................. 258
Functions Returning Pointers.......................................................................... 25 9
Storage Class Specifiers: extern and static.................................................... 260
Manipulating String D ata................................................................................. 262
Converting and Safeguarding D ata.................................................................. 26 4
From Strings to Streams: System.lO............................................................... 265
Exampling Object Types................................................................................... 266
The Keywords checked and unchecked.......................................................... 266
The goto Statement..........................................................................................268
Game 4—Battle W ave......................................................................................269
Brainstorming..................................................................................................270
Brainstorming..................................................................................................270
Drawing Characters and Defining M otions..................................................... 271
Drawing Characters.........................................................................................273
Alternative Rendered Designs.........................................................................277
Animating Characters: Displaying Characters.................................................279
Animating Our Characters: Patterns of Movement........................................ 28 0
Defining Character Limitation.......................................................................... 282
Keyboard Controls........................................................................................... 283
Force Feedback Controls................................................................................ 28 4
Artificial Intelligence..........................................................................................286
Resetting Levels...............................................................................................287
xii
Table of Contents
Structures........................................................................................................ 309
Declaring and Assigning Fields........................................................................ 3 1 0
Multiple Structures......................................................................................... 313
Complex Structures.........................................................................................315
Structures as Function Arguments: Calls-by-Value......................................... 316
Structures as Function Arguments: Calls-by-Reference..................................318
Passing Entire Structures................................................................................319
Storing and Retrieving Data............................................................................. 321
Introducing Classes......................................................................................... 32 4
Replacing Structures with Classes................................................................. 325
private and protected Fields.............................................................................328
The Internal Access M odifier.......................................................................... 3 3 3
Arrays as Member Fields................................................................................ 335
Overloading Member Functions.......................................................................336
private and protected Member Functions.......................................................338
xiii
C# and Game Programming
Constructors....................................................................................................34 0
Overloading Constructors................................................................................342
Assigning Instances.........................................................................................343
Reading and Writing to Private M em bers.......................................................34 4
The Keyword th is ............................................................................................. 34 4
Destructors......................................................................................................349
Introducing Operator Overloading.................................................................... 350
Overloading Comparison Operators................................................................ 35 4
Nesting Overloaded Operators........................................................................ 356
Overloading Unary Operators.......................................................................... 358
Introducing Inheritance.................................................................................... 359
Inheritance versus Composition...................................................................... 361
Inheriting Constructors and Destructors........................................................ 362
private versus protected Inheritance...............................................................362
Using Multiply Linked Single-Inheritance.......................................................... 36 4
Overriding and Virtual Methods....................................................................... 366
A bstract........................................................................................................... 371
The Keyword base............................................................................................375
Exception Handling........................................................................................... 376
Nested try Blocks............................................................................................ 378
The Keyword throw .......................................................................................... 379
User-Defined Exception Classes...................................................................... 38 0
Nested Exceptions........................................................................................... 382
The Binary Operator a s ................................................................................... 38 4
Delegates......................................................................................................... 385
Preprocessor Directives..................................................................................387
The external Modifier....................................................................................... 388
The explicit Operator........................................................................................ 389
The implicit Operator....................................................................................... 390
Fixed Pointers...................................................................................................390
The get and set Accessors............................................................................. 391
Linking Interfaces............................................................................................. 393
The is Operator................................................................................................ 396
xiv
Table of Contents
XV
C# and Game Programming
Index 501
xvi
Preface
This is an introductory textbook th a t covers Microsoft’s C# and game program ming a t the
same time with a unique combination of traditional source coding and game program ming
techniques. W ritten in accordance with ECMA (European Computer M anufacturers’Asso
ciation) certification standards, its purpose is to bring to the student everything tau g h t in
a traditional first sem ester classroom without the traditional first sem ester boredom. This
book would also serve well as a second sem ester tutorial on object-oriented program m ing
and the .Net Base Class Library. W hether you’re a beginner ju st trying to learn the C#
language or an experienced program m er trying to find your way into the .Net program
ming environm ent (not to m ention the Microsoft Visual Studio series), C# and Game
Programming is the book for you.
xvii
C# and Game Programming
W h a t You’ll Need
The graphics and sound portions of this text are based on the Windows XP (Home or
Professional) and 2000/ME operating system s. C# as a whole will potentially be avail
able on any num ber of operating system s, including UNIX, Linux, IBM’s 0/S2, BeX
OS, Apple-Macintosh X, and Alpha’s OpenVMS.1The basic requirem ents for learning the
C# language include a com puter and a .Net level compiler. However, due to cu rren t
restrictions, you’ll also need to ru n your compiler under either Windows XP, 2000/NT, or
ME. The hardw are requirem ents listed to ru n M icrosoft’s .Net 1.1/2.0 beta include a
Pentium II Class PC w ith a m inim um of 233 MHz, 64 m egabytes of RAM, 1.5 gigabytes
of free hard drive space, 4x Speed CD-ROM, and a SVGA monitor. Additional components
required and/or referred to in this book include a mouse, sound card (with speakers), and
(optional) modem—see your compiler’s m anual for additional restrictions and/or require
m ents.
W h a t I Used
The program s w ritten for this text are developed w ith the un d erstan d in g th a t not
everyone can afford the very best in technologies. The compilers referenced include a
list of student, beta, and tria l editions, w ith the more advanced coding progressing
into the sta n d a rd and professional versions. Again, the compilers were installed under
several Windows environm ents including Window’s XP through NT. I also used a host of
hardw are configurations ranging from AMD & In te l’s late st to a few m uch older AMD
and Cyrix type m achines.
xviii
Preface
To load and use the source code that accompanies this book:
1. C reate a new directory and/or subdirectory. This will be used to
store the program s from the CD-ROM and the program s you
create on your own. Nam e your folder and note w here you place
it (in the C drive, D drive, etc,), including which subdirectory
and/or subdirectories you chose to place it under. If you use the
default, you’ll more th an likely find your lost files under:
C :\\D o cu m en ts and settings\Y ourU serN am e \M y
D ocum entsW isual Studio Projects\ProjectsNameHere.
2. M ake sure your compiler is installed and working properly.
3. Load and m ake active the C# compiler. Close any and all
nonessential windows (this includes the C# tour box). Closing
unnecessary background program s will also help to speed up
your system.
4. In sert the CD-ROM into the appropriate drive.
5. Select “Open” from the C# compiler’s file menu (see Screen Shot 1).
Screen
Shot 1.
6. From the “Open” Windows menu, select the folder titled “Source”
and then the appropriate subfolder(s). The subfolder titled “MSNET”
contains all of the source code for the Microsoft .Net compiler(s)2 (see
Screen Shots 2 and 3).
Screen
Shot 2.
Jp f* ?
_! H,_ <>x
1
-J0 Ca*tK2
H'K
^a1rx J^C sutS
:-aJiocavrnsgcS
tK*!^
g? oactdgty?it
giaJstfe
Screen
; 5’A
«top
Shot 3.
*; P_Av±orJ*t« 7
»X
—
1& [isr«: |**"
1
r
=*«»»M»pA<ProtectNkr•*>;*•<*»r;*.aprol;*.vt*;**oro!•dn»J itcc* I ......J
7. Select “Save As” from th a t file’s m enu and save it to the directory
you created in Step 1 (see Screen Shot 4).
Ig jjM B B fr' r> ; - la i XI
7* ® »>!XI l**s &***» ijete
h»* ►j 4 D - a i i o * » ....... m m * Z iff* ?
. Sl» ►]
[4» 0* X
fc*N»Btten> . CW+SM*+* j
ftWExsaiflttw*.. ShftWW+a
................ jtfi
»*;PTOl«* ►
SJ C^-nSofcjbon...
Si C*.«5<*Jtlon jiptio n to r CIo m i .
Screen t t S N r V lb * ^ ' "< *** j
' Classl.cs^...
Shot 4 ft
*kanc"JSa<* Options...
Al CtfU-SWt*S
!*ln(>crlngt) arga)
S**.;ceContrci ►
Prn
« « (H »
COUP
►
.... .................1
...................... ' ■
jtT
PXSftt ProjaCt* ►
: M
|f-:. esr
! ! * Iff
~ >*P' I
__ :::::: ............ . ........... •■»
XX
Preface
Your program is now linked to th a t directory. You can remove the CD-ROM from its
drive (remember to repeat these steps for each program as needed). To edit the source code
and/or to proceed with compiling, see the instructions listed in C hapter 1.
XXI
C# and Game Programming
recommended th a t you do eventually work through those games in order to apply some of
the more advanced concepts on object-oriented program m ing and .Net design.
xxii
Preface
Remember: for the best results, I suggest using the same compiler and operating system(s)
I use; Microsoft’s Visual C# .Net 2003/2005 beta, under Windows XP Home or Professional.
Book Reviews: The Washington Post said, “I don’t know what to say about it.” The New York Times
raved, “It came in the mail.” And Ebert & Roeper said “We don’t review books, please stop calling!”
xxiii
Programming Basics
I
Chapter One
“Everything should be made as simple as
possible, but not simpler.”
-Albert Einstein
his chapter covers the basic aspects of the C# language including its history, compilers,
algorithm s, variables, and the use of the Base Class Library. Each section is designed to
facilitate a quick and easy introduction and to ensure a strong foundation in program ming
and problem solving. Special atten tio n was placed on w hat a new program m er needs to
know and/or m ight be confused about; the sections can, however, be covered quickly. There
are a few sections set aside to cover history and theory, but the core of this chapter is about
program m ing. Two sections promote good program m ing habits and there is a section on
runtim e, program ming, and compiler errors (recommended reading even if you don’t get
into trouble). If you’ve skim m ed th e lessons, you know th a t this first chapter doesn’t
include any games, but don’t let th a t fool you. All of the concepts covered here are ju st as
im portant for games as they are for business and/or m ath related topics.
3
C# and Game Programming
reached the popularity of the original C and C++ languages. C and C++ have been used to
create everything from operating system s and word processing packages to compilers for
other high-level languages. C and C++ have been the programming languages of choice for
more th an 50 percent of all program m ing applications, and with their advances in object-
oriented programming and Internet applications, both Managed C++ and C# are sure to fuel
the popularity of C languages well into this new millennium.
4
Chapter 1: C# from the Beginning
H ejlsberg was also responsible for the development of Microsoft’s Visual J++, Turbo P as
cal, and Delphi, for which he finally received the Dr. Dobb’s Jo u rn al Award for Excellence
in Program m ing early in 2001. For fu rth e r inform ation on the history of Turbo Pascal,
Visual J++, and the Dr. Dobb’s Journal Award, you should consult your local library... now
let’s get back to business.
5
C# and Game Programming
th a t is no longer being referenced. While garbage collection dim inishes the program m er’s
power to control memory deallocation, it does help to prevent dangerous memory leaks,
and saves the program m er additional tim e th a t would norm ally be spent im plem enting
destructors. Likewise, zero-impact installation has been developed to save the program
m er and consum er m any hours of fru stratio n by elim inating the errors caused by faulty
reversioning. U nder norm al Windows operation, a typical .dll type file would be included
as p a rt of a centralized reference, which in tu rn would m ake it subject to deletion w hen
ever a new version is installed. If th a t new version is not entirely backw ard compatible,
th en the replacem ent file can cause the program to fail. W ith zero-im pact installation,
a ltern ate versions of otherw ise identical files can exist side by side, thereby elim inating
this problem.
In addition, .Net offers increased code security, application dom ain restrictions,
strong typing, and nam espacing. The increase in security allows the consum er to con
trol th e level of access g ran ted to any single program , w ith MSIL also determ ining the
level of access requested by a program before its execution (This m ay help to prevent
some unscrupulous program m ers from dam aging our files.). A pplication dom ain re
strictions prevent mem ory conflicts betw een in te rre la te d applications through the
use of virtual memory barriers, w hich are b a rrie rs th a t restric t access, but do not
impose processor delays. (This process is controlled th rough MSIL). Strong typing ,
also governed by MSIL, requires th a t we specifically sta te d a ta types, th u s p rev e n t
ing am biguous ru n tim e errors; unfortunately, th is also prevents us from using te m
plates (excluded from th e C# program m ing language). Finally, nam espacing, origi
nally designed to prevent N ative C++ nam ing conflicts, is now a req u irem en t of the
.Net architecture, w herein all types m ust be defined w ith e ith e r an explicit or a global
nam espace.
6
Chapter 1: C# from the Beginning
Algorithms
Before we can jum p into w riting program s, we’ll have to learn a little bit about designing
them . The first step in designing a program is writing its algorithm. W riting an algorithm
is not the same as w riting a program; it doesn’t require the use of a computer language, or
even a computer. An algorithm can be applied to any task or set of tasks. W riting down
directions is probably one of the most common exam ples of an algorithm ; recipes, diets,
and m ath solutions are others. Some beginner program mers don’t understand the need for
algorithm s, believing instead th a t they can plan th eir program s as they go, or after com
pleting the introductory part of their coding. However, such programming styles often lead
to hazards such as additional tim e spent problem solving and/or more tim e spent rew rit
ing code to incorporate each new idea or feature. Thus, it is always best to s ta rt w ith an
algorithm. Therefore, I’ve included an outline of the algorithm used to write a C++ version
of the first arcade style game tau g h t in C hapter 3—Paddle Tennis (see Example 3.5).
If th is seem s a bit long, keep in m ind th a t the actual Paddle Tennis subroutines are
p a rt of a program th a t is more th a n 100 pages long, and even the sim plest profession
ally designed program will ten d to ru n over a 1000 pages. A lgorithm s do not have to
include com plete sentences, have correct gram m ar, or even need to be entirely in
English. Yet, having som ething th a t you can actually read and th a t lists the steps to
the solution is im portant. Further, w hen w riting an algorithm shared by others, never
assum e th a t they can read som ething w ritten in C#; after all, they m ight be planning
to w rite the program in an o th er language such as VISUAL BASIC, m anaged C++, or
ju st plain old-fashioned C.
8
Chapter 1: C# from the Beginning
u n d e rsta n d the endless rolls of ones and zeroes, such as 01010011 00010100 00011101,
found in m achine language. In add itio n to m achine language, th e re is also a low-
level language know n as A ssem bly Language, w hich serves as an in te rm e d ia ry b e
tw een C and th a t b in ary code. However, th e a d v en t of C# and th e .N et fram ew ork
replaced th is concept.
The new way of th in k in g about com pilation is to b reak it into two steps: The first
step is, a conversion to MSIL, which allows for both the construction and testin g of our
products from w ith in th e com piler’s sim u lated environm ent. The second step, JIT
com pilation, isn ’t im plem ented u n til the m om ent of execution, hence th e nam e ju st in
tim e. W ith th is new form of compiling, M icrosoft h a s been able to im plem ent several
new fea tu re s, including role-type and code-type based security, m em ory type safety,
a nd interoperability. Role-type and code-type based security rela te to a program ’s base
of id en tity an d th e level of access g ra n te d to th a t code. If an u n a u th o rize d program
a tte m p ts to access/alter any other application w ithout MSIL’s express perm ission, the
execution of th a t program is not allowed. The sam e is tru e for type safety; if the M SIL
environm ent detected th a t any newly executed program will cause a mem ory address
conflict, th a t program is also denied system access. In addition, this new m ethod opens
up our coding to an entirely new level of code interoperability; w ith it, we can interm ix
betw een objects w ritte n in different languages, step betw een references, and even use
those objects as in h e ritin g classes. T here is also th e p o ten tia l for reflective com pari
sons w ith respect to both in tero p erab le and in te rn a l files (See la te r ch a p te rs for de
tails.).
9
C# and Game Programming
i i l .iff! xl
] £d* $ew fyoject look Jgndksw fcfcip
8*" * - ?
Span > “J ^ - £ .
Qose £ SankSolution... d PX
-n AddNewItem... Ctr»+SNft+A ±
Sd AddExsftnfl Raw . Shdt-fAk+A
AddProject »
3 OpjjpScAiton...
3i ClMcSoMon m
e SefactedStow OrN-5 onsoleApplicefeonl 5/17/2001
Screen SelectedRems
Open Project Nee* Project j
SaveAjl Cu\+Sbtt+5
Shot
SendeeControl ►sport« Visual Studic.NETissue
1 .1 .
CtrteP
Retent Nes »
zJ
RecentProjects » — ,—
| Es*
d
a ™ ™ jB oagd
Peody r — :•..
10
Chapter 1: C# from the Beginning
*j
Project Types: m
: Visual Basic Protects 3
5 3 Visual C++ Projects
% # ftsj
r § Setup and Deployment Projects ASP.NET Web ASP.NET Web Web Control
Application Service Library
Other Projects
' Visual Studio Scijtwns
Name: | CcrsoSeAppfc<sU>ri2
You will need to e n te r a nam e in th e box title d “N am e.” I called th is first ex
am ple “C h a p te rl,” b u t you can use any nam e you like. Once you have e n te red a
nam e, the “OK” b u tto n is enabled; click it to continue. Your com piler is now set up
a n d ready for in p u t. For fu rth e r d etails on how to setup th e C# compiler, see the
T roubleshooting section a t th e end of th is chapter, check your com piler’s help files,
or check out M icrosoft’s online guide at: http://m sdn.m icrosoft.com /vcsharp/.
Now, w ithout reg a rd for any p a rtic u la r com piler or series, we’ll w an t to te s t to
m ake sure th a t ev ery th in g is set up and ru n n in g correctly. We’ll do th is by in p u ttin g
w h at is know n as a “do-nothing” program , th a t is, a program th a t creates no signifi
c a n t o utput, yet by com piling, conveys the m essage th a t our com pilers are ready.
The a c tu a l com m ands used in th is program are u n im p o rta n t a t th is tim e.
11
C# and Game Programming
namespace Chapterl {
class Classl {
static void Main () {
/* "executable statements go here" */
6. Now, from the m ain “Build” m enu, select the subm enu option
also labeled as “Build” (see Screen Shot 1.3).
/// j
/// Smmskry 'description f o t C l & z s l .
Screen E rr
Shot
1.3
IS**
"3
0 Tas*Us£ |
: u> is cd t cht ;..T rm
You should notice a stream of inform ation appearing in the lower compiler window,
norm ally located a t the bottom of the screen. M ake sure you get a m essage saying zero
errors and zero w arnings (see Screen Shot 1.4).
12
Chapter 1: C# from the Beginning
SMPilM
& . Protect guM fisbug loo f* «elp
-S -&&a * ■ *-P’Q|.B5ST #
Screen
Shot
1.4.
If you got an error a t th is step, it m eans the project was not set up correctly. Repeat
all the steps again or see the Troubleshooting section a t the end of the chapter.
7. Finally, to execute the program , sim ply click on the “Debug” m enu
and select “S ta rt W ithout Debugging.” Your do-nothing program
will now produce a large window asking you to “P ress any key to
continue.” Doing so will end the program (see Screen Shots 1.5 and 1.6).
ConsoleAppltcatton2 - Microsoft VtMi.il i
0te £d* $*»» frotert
:eP>H|-l#BCP *
| Start W fth o tA O a b y ® ^ O rl+ F 5 |
i'lfr Processes... <
Exceptions... Qri+ A k+E ?
•X Step Into P it j
f.S StepQver F10 !
Newgreekpont... Ctri+B i
gtj Ci
“3
) ( a ile d , 0 skipped
.3
3T«kU',t Q Octa*!
B»Jd succeeded Coh ..ws
13
C# and Game Programming
Screen
Shot
1.6
hi
14
Chapter 1: C# from the Beginning
Comments
Com m ents are nothing more th a n system notes, usually w ritten by a program m er, to
m ark or explain a certain passage th a t m ay not seem as obvious to us a t a late r date.
For example, we m ight m ention th a t the m ain m ethod ends w ith a particu lar brace or
th a t we need to a lte r or rep air a line or two to increase system performance. Exam ples
1.3 and 1.4 dem onstrate the general use of single and m ultiple line comments, while
Exam ple 1.5 dem onstrates a th ird type of pseudo-comment th a t is p a rt of C#’s ability to
m anipulate in te rn et resources.
namespace Chapterl {
class Classl {
static void Main ( ) { // Main method
// Begin executable statements
} // End main method
}
}
namespace Chapterl {
class Classl {
static void Main ( ) { /* Main method */
/* Put something here please! */
} /* End main method */
15
C# and Game Programming
Adding additional forw ard slashes will not invalidate our comments, but they will
open our C# coding to accept the Extended M arkup Language (XML) commands. XML
commands are included as p a rt of the collective .Net fram ework to make Webpage design
faster and more convenient (see Example 1.5).
using System;
namespace Chapterl {
/// Place your XML tags here
/// . . .
class Classl {
static void Main () {
/* this is still a do nothing program */
}
}
}
Screen Output
Now th a t we have the basics of w riting a do-nothing program , let’s see if we can add
som ething other th an comm ents to it. Traditionally, a first program will display the
m essage “Hello, world!” However, since this book em phasizes game program m ing, w hat
could be more appropriate th en “Game Over?” (see Exam ple 1.6).
E xam p le 1.6. S c r e en o u tp u t 1.
using System;
namespace Chapterl {
class Classl {
static void Main () {
Console.Write ("Game Over! \n" );
}
}
}
16
Chapter 1: C# from the Beginning
Now there are two commands added to our do-nothing program th at, in fact, m ake it
do something. The actual commands th a t m ake the words “Game Over” appear can be
simplified to:
C o n s o l e .Write ("Game Over!");
We have combined these two commands in Example 1.6. Replacing Console.Write (“Game
Over!”); w ith Con sole. Write (“”); would result in a program th a t seems to do nothing,
since there was nothing w ritten betw een the inner and outer quotes (changing “Game
Over!” to “Hello, World!” produces the classic result—see Example 1.7).
E xam p le 1.7. S c r e e n o u tp u t 2.
using System;
namespace Chapterl {
// Purpose: Displays the words "Hello, world!"
class Classl {
static void Main () {
Console.WriteLine ("Hello World!");
}
}
}
You can replace the words “Hello, World” w ith virtually any other sentence, or you
could add additional sentences to th e program by rep eatin g the W rite command.
Exam ple 1.8 displays a program with two lines of output. Feel free to input a few lines of
your own.
E xam p le 1.8. S c r e e n o u tp u t 3.
using System;
namespace Chapterl {
class Classl {
17
C# and Game Programming
S ym b ols P u r p o se
\a A lert (bell)
\b Backspace
\f Formfeed
\n Newline
\r C arriage re tu rn
\t H orizontal tab
\ V Vertical tab
\\ Backslash
18
Chapter 1: C# from the Beginning
using System;
namespace Chapterl {
class Classl {
static void Main ( ) {
C o n s o l e .Write ("Hello, Programmer. ");
Console.Write ("How are you today? \n") ;
}
}
}
In this program, the newline character was not placed after the phrase “Hello, d y
Programmer.” As a result, the program did not move to a new line, and thus
“How are you today” did not transfer to the second line, producing, instead, the
single line “Hello, programmer. How are you today?” A similar result is shown
in Example 1.10.
namespace Chapterl {
class Classl {
static void Main() { //Begin main
C o n s o l e .Write ("This is line 1\ n" );
19
C# and Game Programming
We can also disable the automatic formatting of the newline character (or any
other escape sequence), thus reproducing the codes as actual text. This is done
using the @ symbol as shown in Example 1.11.
namespace Chapterl {
class Classl {
static void Main() {
C o n s o l e .W r i t e (@ "\n This is line 1");
Console .Write (11\n This is line 2 M);
C on so l e . W r i t e (M\n This is line 3");
C o n s o l e .W r i t e (@ "\n This is still line 3");
Console .Write ("\n This is line 4\n,!);
C o n s o l e .W r i t e (@ "\n This is line 5\n");
The WriteLine command is w ritten in a m anner sim ilar to the Console .Write com
m and, but it does not require the newline character. It can also be used as an output
stream or statem ent, and (as shown above) it can be referenced w ithout any other com
m ents or inform ation. To dem onstrate, we’ll revise our last example, replacing its Write
comm and w ith a WriteLine statem en t (see Exam ple 1.12).
namespace Chapterl {
20
Chapter 1: C# from the Beginning
class Classl {
static void Main() { // Begin main
Console .W ri te Li ne ("This is line 1");
C o n s o le .W ri te ("This is line 2\n");
C o n s o l e .W r i t e ("This is line 3");
Console.Write (" This is still line 3\n");
C o n s o l e .W r i t e ("This is line 4\n");
We can also combine separate sentences inside a single command by linking th eir
statem ents and dividing them up w ith newline commands, which can be done w ith
either the W rite or W riteLine commands (see Exam ple 1.13).
namespace Chapterl {
class Classl {
static void Main() { // Begin main
C o n s o l e .W r i t e L i n e ("This is line l\nThis is line 2");
C o n s o l e .W r i t e ("This is line 3" + " This is still line 3\n"
+ "This is line 4 \n");
}
}
From the u se r’s perspective there will be no difference, yet to the program m er there
is quite a change in coding. Exam ple 1.14 ends this section by replacing every newline
character w ith a WriteLine command; reexecution of these last few program s should
provide identical results.
namespace Chapterl {
class Classl {
static void Main() { // Begin main
21
C# and Game Programming
The Semicolon
W hen the compiler detects a semicolon (;), it knows th a t the command line has ended and
th a t it should move to the next set of instructions. This is especially im portant when
dealing with commands th a t are often w ritten in varying sizes or those th a t extend over
more th an one line. Having such a requirem ent also lim its or restricts the potential for
overlapping errors found during compilation. The semicolon is always placed at the end of
a complete statem ent and is always used to signal the end of th a t statem ent. Commands
th a t do not require a semicolon often do not term inate until the end of a particular section
or set of commands. Some program m ing commands do not term in ate u n til the program
itself ends, and hence, do not require a semicolon.
W hitespaces
Whitespaces are simply blank spaces used to separate coding term s. Variable nam es as
well as keywords require these separations, but in m any other cases, these w hitespaces
are ju st ignored. It is, however, im portant to rem em ber th a t these spaces do not indi
cate the end of a line, term inations of any coding, or any other such control. You should
be careful not to abuse this ability to separate command lines (abuse would be any
instance where such spacing causes visual confusion on the p a rt of the program m er).
Preprocessor Directives
If you have ever worked w ith either C or C++, you’re probably wondering when we’ll talk
about preprocessor directives, since it was through the use of those directives th at we were
given access to the bulk of w hat was known as the runtim e libraries. If you’ve never heard
of preprocessor directives or the term s included and/or header files, then here’s a quick bit
of history.
22
Chapter 1: C# from the Beginning
Indenting
Indenting is a simple way to keep your program s looking n eat and organized. Indenting
h as been shown in all of the examples, and simply m eans to set commands several spaces
inw ard from the first line of a segment, which is done to indicate th a t they are p art of th a t
segm ent. W hen a line is not indented, it can m ean th a t it is not p a rt of the segment.
Indenting, while easier on the eyes, has only a cosmetic effect on source coding and will not
affect the com puter’s/compiler’s view of the m aterial.
Naming Variables
Regardless of the language, the sim plest method of storing and/or m anipulating general
ized data has always been the use of variables. A variable is used by program s to store and
retrieve both character and num eric data. While we’ll save the technical/coding portions
for the next few sections, we’ll w ant to at least understand the nam ing procedures before
moving forward. There are three basic rules w hen nam ing variables:
23
C# and Game Programming
In addition to these variable rules, there are also some good nam ing practices th a t
should be followed.
Naming suggestions
1. Give the variable a descriptive nam e such as p layer_l, ball, or
joystick2; descriptive nam es reduce the likelihood of confusion.
2. Use a consistent style w hen w riting variables, such as alien _ l
and alien_2 or A lien_l and Alien_2. Do not random ly mix upper
and lower case letters as in A liEN _l, A liE n_l. C#, like both C
and C++, is a case sensitive language—it reads uppercase and
lowercase lette rs as different symbols, and thus, these random ly
nam ed variables will not be read as the sam e value.
3. To rem ain consistent, you can adopt one of two styles: H um pback,
which capitalizes the first letter of each word (PlayerOne); and
Camel (also known as Pascal), which capitalizes the first le tte r of
interior words, but not the initial lette r (playerOne). These
notations are the standard for most companies, including Microsoft.
4. C and C++ also follow a special nam ing procedure known as
H ungarian Notation. This notation involves giving d a ta types
beginning lette rs th a t identify th e ir declared types. Since C# uses
an object based method, the practicality of using H ungarian
N otation is lim ited. However, for backw ard com patibility and
historical purposes, it is helpful to have a knowledge of this
notation (see the H ungarian Section late r in this Chapter).
24
Chapter 1: C# from the Beginning
Exam ple 1.15 d em onstrates how to use a variable nam ed OurVariable, and uses
several com m ands not yet com pletely explained in th is section. Therefore, we’ll only
need to focus on the highlighted lines. You should edit and recompile th is program sev
eral tim es, testing different variable names. Remember, you can use any nam e you w ant
as long as it follows the rules stated above.
25
C# and Game Programming
using System;
namespace Chapterl {
class Classl {
static void Main() {
int OurVariable; // an integer data type.
OurVariable = 1; // we can assign the value 1 to the variable
C o n s o l e .W r i t e L i n e ("The number is " + OurVariable);
Rem ember th a t if you change the nam e in the declaring line, you’ll also have to
change it in the assigning and referencing lines.
-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10...
26
Chapter 1: C# from the Beginning
using System;
namespace Chapterl {
class Classl {
static void Main() {
// these variable were declared using the data type integer
int Numberl, Number2;
using System;
namespace Chapterl {
class Classl {
static void Main() {
System.Int32 Numberl, Number2;
Numberl = 1;
Number2 = 1;
The integer data type uses less memory th a n the other basic num erical data types;
thus, it is the form at of choice for program m ing tasks th a t do not require a floating point
(real number) variable. You can also increase or reduce an integer’s storage size by replacing
27
C# and Game Programming
th a t keyword with any of the other seven predefined integer data types: byte, sbyte, ushort,
short, uint, ulong, and long. Byte and sbyte require the least am ount of systems RAM, with
8 bits of unsigned and signed allocated space and a range of 0 to 255 and -128 to 127,
respectively. U short/short also reduces the am ount of storage space needed by a variable
while ulong/long increases th a t amount. Increasing the size allows you to input larger inte
gers, while decreasing it saves system memory (see Example 1.19).
using System;
namespace Chapterl {
class Classl {
static void Main() {
ushort Numberl; // unsigned short
long Number2; // long integer
Numberl = 1;
Number2 = 1;
C o n s o l e .W r i t e L i n e ("The first number is " + Numberl
+ "\nThe second number is " + Number2 + "\n");
The unsigned d a ta types, byte, ushort, uint, and ulong (all other variables are
signed by default) do not actually modify a v ariab le’s m em ory capacity, rath er, they
m erely a lte r th e range of those variables. An unsigned short (ushort ), for example,
gives us twice the upper lim it by shifting the to ta l range from -32,768, -32,767 to 0,
65,535 (for a complete list of ranges, see Table 1.3).
28
Chapter /\ : C# from the Beginning
C# uses the keywords float and double in nearly the same way, but doubles have twice
th e precision. Doubles are twice as accurate as floats and do not suffer the sam e risk of
da ta loss w hen assigned to constants. The precision range of a float is seven digits
(±1.5 x 10-45 to ±3.4 x 1038), while the range for doubles is 15-16 digits (±5.0 x 10-324 to
±1.7 x 10308). Examples 1.21 and 1.22 dem onstrate these keywords.
using System;
namespace Chapterl {
class Classl {
static void Main() {
float Numberl, Number2; // float is short for floating point
Numberl = l.Of; // using the f converter
Number2 = l.lf; // to convert to float
using System;
namespace Chapterl {
class Classl {
static void Main() {
double Numberl, Number2;
29
C# and Game Programming
Numberl = 1.0;
Number2 = 1.1;
using System;
namespace Chapterl {
class Classl {
static void Main() {
decimal Numberl, Number2;
Numberl = 1.0M;
Number2 = 1.1m;
30
Chapter 1: C# from the Beginning
using System;
namespace Chapterl {
class Classl {
static void Main() {
char Symbol;
string Sentence;
Symbol = 1A ';
Sentence = "This is a string.";
31
C# and Game Programming
Note: We can also use the “@” symbol to create a literal string , for example:
Console.Writeline(@ “The \ n character is neat.”) This example is slightly
obvious - the string will print out “The \ n character is neat.” Without the @, it
would print out “The
Character is neat.”
32
Chapter 1: C# from the Beginning
namespace Chapterl {
class Classl {
static unsafe void Main() {
C o n s o l e .W r i t e L i n e ("Byte = " + sizeof(byte));
C o n s o l e .W r i t e L i n e ("Sbyte = " + sizeof(sbyte));
C o n s o l e .W r i t e L i n e ("Ushort = " + sizeof(ushort));
C o n s o l e .W r i t e L i n e ("Short = " + sizeof(short));
C o n s o l e .W r i t e L i n e ("Uint = " + sizeof(uint));
C o n s o l e .W r i t e L i n e ("Int = " + s i z e o f (i n t ));
C o n s o l e .W r i t e L i n e ("Ulong = " + sizeof(ulong));
C o n s o l e .W r i t e L i n e ("Long = " + s i z e o f (lo ng));
C o n s o l e .W r i t e L i n e ("Float = " + sizeof(float));
C o n s o l e .W r i t e L i n e ("Double = " + sizeof(double));
C o n s o l e .W r i t e L i n e ("Decimal = " + sizeof(decimal));
1. From the folder labeled “View,” select the file titled “Solution
Explorer” (see Screen Shot 1.7).
33
C# and Game Programming
m e* S&
indow tie!
[J fi5>eo A,
sp*m OpegWith...
Tasklist
N **gat* k«*ward
_CXiU-Mti-
_ _
> ✓m
C kkhert to add a new task
*& Program 'C:\Documerits and Settmgs\Pk»g>Je\My Oo>
8\ a- •:*- - % * % % % ,
§3 * & - & O & - - r :* ►Debug » ”
&J Setting Visual C *fro » d ; Property Classt.es 1*
$ : j^ConsoteAppicationZ.aassl ' |a%Ma«n(stringO args)... 3 3 j ^ _____
C on sole.W riteL in e("U S h oct - " + s i z e o f ( u s h o r t)) ; le e Solution 'ConsoteAppfcabon? (1 pro*
C on sole.W riteL in e ("S h ort * * + s i z e o f ( s h o r t ) } ; 2n- mmBBsamm
II bai References
C o n s o le .W rite L in e ("U in t * * + s i s e o f (uint));
>3 AssemfalyIrtfo.es
C o n s o le .W r ite L in e ("I n t - * + s i z e o f ( i n t ) ) ;
«J] aassl.es
Console.WriteLine("Ulong - " + sizeof(ulong)};
Console.WriteLine("Long • " + sizeof(long));
2) Tasklist I 3 f t ~
34
Chapter 1: C# from the Beginning
i r i Common Properties 0 . . .
$ 1 Configuration Properties Conditional Completion Constan DEBUG; TRACE
* Build Optimize code False
Debugging Check fix Arithmetic Overfiow/l False
Screen
Advanced ............................ .... j j
£3 V-' - : ■ N M H N N !
Shot
Warning level warning level 4
Treat Warnings As Errors Fafee 1.9
Output Path bin\Debog\
XML Documentation Fie
Generate Debugging Inform*** True
jjJR sgB ter ( « COM wtetop jFetee
-* ■ ' '■
Mem unsafe code blocks
Enable use of the unsafe keyword (/unsafe).
| OK | Cancel j
35
C# and Game Programming
U nlike m athem atical expressions, assignm ent statem en ts are alw ays form ulated
w ith the receiving variable positioned to the left. Exam ple 1.26, although sim ilar to an
algebraic expression, does not involve any inference of data. In fact, an unreferenced or
undefined variable used to assign such a value would result in the m inimum of a compiler
w arning (see Example 1.27).
- int n , x = 2, y;
// Any variable assigned to another
// variable must by requirement be
- n = x + 1;
// assigned a value itself, b e f o r e
// that secondary assignment can o c c u r .
36
Chapter 1: C# from the Beginning
and double to double), but when this is not possible, converting betw een d ata types is an
option. The safest data conversions always involve converting from sm aller to larger data
types, e.g., short to int, int to long, long to float, and float to double, or any of the
sm aller to larger types (see Table 1.3 for data type sizes). Any other type of conversion may
result in the loss of data and/or a calculation error. Since float, double, and decimal are
all floating point values, you may not notice a problem when preparing your algorithm
(that’s not to say there wouldn’t be a problem, ju st th a t you m ight not notice it). The worst
type of interm ixing would be from floating point to integer, which would be allowed under
native C/C++, but C# dem ands th a t any integration betw een our data types is strictly
regulated. T hat said, m any program m ers still w rite program s th a t involve the interm ix
ing of these larger to sm aller data types relying on compiler defaults to calculate them in
their favor.
Dear IRS, in regards to my last SEVEN tax returns: There was a slight error in my
program’s ability to convert data types and although it was quite an amusing error...
Formatting Strings
In addition to being able to display simple text layouts using the Write and WriteLine com
mands, we can also format text to give our programs a more controlled output. This works
especially well when dealing with variables. A single numeric value indicates a reference to
the appropriate variable: {0}, {1}, and {2} reference the first, second, and third variables, respec
tively. Moreover, we can also apply right and left justifications by inserting a secondary control
sequence for example, inserting a positive number, as in {0, 6}, denotes a shift to the right,
in this case 6 spaces, w hereas the insertion of a negative control sequence results in a left
handed shift: {0, -3} would move the cursor three spaces to the left.
We can also exert a third level of control, which involves string formatting, for example {0, -
3:C2}, where C stands of our local currency and 2 represents the num ber of decimal places to
be displayed (See Table 1.4 for a complete list of form atting strings). Finally, we can use the
37
C# and Game Programming
String
Description
Format
C Currency (local)
F Fixed point
P Percent
X Hexadecimal
Arithm etic
Using arithm etic operators in C# is much like using a handheld calculator or doing a rith
metic on paper. There aren’t any formulas or fancy codes to remember, it’s just adding,
subtracting, multiplying, dividing, and finding rem ainders (yes, rem ainders, like the ones
you use to find before learning long division). Since we’ve already seen an example of adding
th a t’s where we’ll start. To add two or more num bers together we’ll have to use the plus sign
(+). Nevertheless, you can’t just write “1 + 1 - ’ and expect the computer to do the rest—
you’ll have to write it out into a program as shown in Example 1.28.
using System;
namespace Chapterl {
class Classl {
static void Main() {
38
Chapter 1: C# from the Beginning
This program starts with the normal introductory comments—the using and
Program
W alkthrough
namespace references (remember, these references are required when working
with our Base Class Library). Next, there’s the void data type linked to Main.
Then as we start the main method, we declare three variables, all of type integer.
We assign the first two variables values of 5 and 2 using the assignment operator
(=). Then, something new: We tell the computer to make the third variable
equal to the sum of the other two. Finally, we displayed the equation “5 + 2 = 7.”
Try compiling and running this program and you’ll see th a t the W riteLine command
displays our equation. You can also change the variables to any positive or negative whole
number. Recompile and w atch the display change.
Not surprisingly, subtraction, m ultiplication, and division are used in exactly the
sam e m anner (see Exam ples 1.29-1.31). You can retype each example or ju st reedit the
first one to m atch the changes; you m ight also w ant to experim ent w ith alte rn a te data
types, comments, and the variables names.
using System;
namespace Chapterl {
class Classl {
static void Main() {
int numberl, number2, total;
numberl = 5;
number2 = 2;
total = numberl - number2; /* 5 - 2 */
39
C# and Game Programming
To m ultiply and divide, use the asterisk (*) and the forw ard slash (/), respectively.
using System;
namespace Chapterl {
class Classl {
static void Main() {
float numberl, number2, total;
numberl = 5.OF; // When using float include an F
number2 = 2. Of;
total = numberl * number2; /* 5 Multiplied by 2 */
using System;
namespace Chapterl {
class Classl {
40
Chapter 1: C# from the Beginning
We can also use combinations of symbols, as shown in Example 1.32. This example m ain
tains the values for num berl and number2 as previously introduced; it multiplies them to
gether (5x2 equals 10) and then adds the value of num berl to th at product (10 + 5= 15).
To change the order of the calculation, use parentheses as shown in Exam ple 1.33. This
equation now adds the last two num bers first and th en m ultiples th eir sum by the first
value working left to right(in the default), m ultiplication and division take precedence
over addition and subtraction, m aking the total 35, showing the im portance of defining
the order of operations.
41
C# and Game Programming
In some cases, the order of calculations can be left to the default settings, but most of the
time we’ll w ant to guarantee the order of execution through the enlistm ent of parenthetical
expressions. Example 1.34 shows how confusing an undistinguished expression can be, while
Example 1.35 clears up much of the confusion with a minor bit of effort.
There is one last arithm etic symbol, but its m eaning isn’t as obvious. It is the rem ain
der, as in, to find the rem ainder of a num ber divided by a second number. Exam ple 1.36
gives a sam ple of how to w rite this in a program .
Since we have been using the data type in te g e r , 5 divided by 2 is not 2.5, but 2, because, the
result is the truncated integers(by definition are whole numbers) and therefore a whole num
ber; thus, we use the rem ainder symbol (%) to find the rem ainder (see Example 1.37).
42
Chapter 1: C# from the Beginning
class Classl {
static void Main() {
int numberl, number2, total, remainder;
numberl = 5;
number2 = 2;
total = numberl / n u m b e r 2 ;
remainder = numberl % number2;
Console.WriteLine("\n {0,7:N}\n/ {1,7:N}\n ---\n {2,7:N}",
numberl, number2, total);
Console.WriteLine("And the remainder is {0,7:N}", remainder);
Console.WriteLine("\nAnd the remainder is {0:#.00}",
remainder) ;
If you find any of the equations confusing, try rew riting them out on paper, choose
some new num bers, and see if you can predict th eir outcome; then when you’re ready
move on to the next section, which, by the way, finally explains how to input data from the
keyboard.
43
C# and Game Programming
Keyboard Input
The Read and ReadLine commands, as th eir nam es imply, allow us to input inform ation
from the keyboard. Both statem ents are w ritten as console m ethods, sim ilar to the W rite
commands, the difference being th a t they are used to extract inform ation ra th e r th an
project it. The basic Read command is only capable of storing single character inputs (see
Exam ple 1.38). The ReadLine m ethod, in contrast, can input virtually all d a ta types.
Doing so, however, requires a parse conversion reference th a t is linked to the appropriate
data type, w ith string as the default setting. Parse, like the ReadLine and WriteLine,
is not actually a keyword, but ra th e r a referencing m ethod available through the .Net
architecture via the “system ” reference.
using System;
namespace Chapterl {
class Classl {
static void Main() {
char character;
int integer;
Program
Like all of the previous programs, this one begins with a comment describing
W alkthrough
its purpose. The .Net system is referenced, and the void data type declares the
main function. The first statem ent prints the text line “Enter a number here.”
Now the ReadLine function waits for the user to input a number. When a
number is entered, the program will store this information into the variable
my_number. The program will then reprint its value after the words “The
number you entered is:” This process can be repeated for any of the real number
data types, as well as the character data type—see Example 1.39.
44
Chapter 1: C# from the Beginning
Exam ple 1.39. The R eadLine com m and w ith various data types.
using System;
namespace Chapterl {
class Classl {
static void Main() {
string Name, convert;
float RealNumber;
RealNumber = f l o a t .Parse(convert);
C o n s o l e .W r i t e L i n e ("Your name is " + Na m e ) ;
C o n s o l e .W r i t e L i n e ("And the number you entered is "
+ R ea lNumber);
}
}
}
Uninitialized Variables
A nother key component of the C# language and .Net 2003 compiler is the inaccessibility of
undeclared variables. This new stan d ard produces an error ra th e r th a n a w arning upon
any attem pt to access th a t unassigned memory location. The decision to change was based
prim arily on the need to offset the abundance of m inor errors found w hen those u n a s
signed values were represented by random data access. Understandably, if we do not filter
out those random value, our results become unpredictable and subsequently useless in
any m atter of importance. Keep in mind th a t we have been properly declaring and initial
izing variables throughout this text. Moreover, in our last few examples, we even expanded
upon the m ethods used to assign those variables. However, the most practical of all the
m ethods is to include an assignm ent statem ent a t the m om ent of declaration, thereby
removing any chance of error (see Exam ple 1.40).
45
C# and Game Programming
using System;
namespace Chapterl {
class Classl {
static void M a i n (s t r i n g [] args) {
int OurVariable = 1;
C o n s o l e .W r i t e L i n e ("Our variable was assigned as
+ OurVariable);
}
}
using System;
namespace Chapterl {
class Classl {
static void Main() {
const int OurVariable = 1;
C o n s o l e .W r i t e L i n e ("Our variable was assigned as
+ OurVariable);
Adding the keyword const to a variable of data type float, double, or char would
m ake them constants as well. Keep in m ind th a t th eir values also have to be assigned as
they are declared (see Example 1.42).
46
Chapter 1: C# from the Beginning
using System;
namespace ConsoleApplicationl {
class Classl {
static void Main() {
const int numberl = 1;
const float number2 = 2.5F;
const double number3 = 3.14159; // PI
const char symboll = 'A1;
const string sentence = "This is a constant string!";
47
C# and Game Programming
#define: Unlike C and C++, C# cannot use the preprocessor directive #def ine
to declare constant variables. It does, however, allow for a Boolean type
assignment, which signals to the compiler that a certain definition has either
been defined (interpreted as true) or not defined (interpreted as false)—see
preprocessor directives in Chapter 5 for details.
using System;
namespace Chapterl {
class Classl {
static void M a i n (s t r i n g [] args) {
int number = 1;
48
Chapter 1: C# from the Beginning
number++;
using System;
namespace Chapterl {
class Classl {
static void Main(string [] args) {
int number = 1;
n u m be r+ +;
49
C# and Game Programming
#include <iostream>
using namespace std;
using System;
namespace Chapterl {
class Classl {
static void Main() {
int number = 1;
}
}
} // no ambiguity here
Keyword Defaults
The C/C++ language includes a few keyw ords, nam ely auto and signed, used to
declare actions th a t are eq u iv alen t to th e system ’s defau lt settin g s. These keyw ords
are not of th e C# language, b u t th ey are still im p o rta n t w hen dealing w ith u p g ra d
ing. The first of these, auto, a storage class specifier, is used to express th e need for
each v ariab le declared u n d e r th a t title to be localized as a single function, w here
localized m eans created w hen th e block is opened and destroyed as th e block is
closed. This action is p a rt of th e definition used to describe local v ariab les and hence
auto is not needed w hen declaring C# variables. The keyw ord auto goes back to th e
days of the B language, and only exists now to keep a backw ard com patibility w ith
some older C program s.
Signed, allows v ariab les to hold both positive and negative values; again, som e
th in g we assum e w hen declaring variables. U sing th e reverse, unsigned, is very
common in C++ and is usually an attem p t to save memory while increasing an in teg er’s
50
Chapter 1: C# from the Beginning
positive range, b u t alas, it too h a s no rea l p ractical value, i.e., you won’t see it m uch,
b u t w hen you do, you’ll need to u n d e rsta n d th e concept b ehind it.
E xam p le 1.48. N ot u s in g u s in g .
namespace Chapterl {
class Classl {
static void Main() {
S y s t e m .Co ns ol e.W ri te Li ne ("Hello, W o r l d !");
}
}
}
Additionally, if we were to encounter a secondary namespace th a t offered an identi
cal, thus conflicting reference, then there would be few options th a t didn’t include writing
out an alias to the formal definition or the formal definition (see Example 1.49).
51
C# and Game Programming
namespace Chapterl {
class Classl {
static void Main() {
sys.Console.WriteLine("Hello, w or l d ! ");
}
}
}
Hungarian Notation
H u n g a ria n n o tatio n , nam ed for th e e th n ic ity of its developer C h a rle s Sim onyi, is
M icrosoft’s form al w ay of id en tify in g v a ria b le s b ased on th e ir d a ta types. T his
n o tation is used by m any program m ers, especially those who work for M icrosoft, and
it is not lim ited to the C++ language. The notation uses prefixes atta ch e d to variables
th a t are alw ays w ritte n in low ercase. For exam ple, th e prefix th a t id en tifies a c h a r
a c te r is sim ply th e le tte r c, th u s, a d e c la ra tio n of a c h a ra c te r can be as sim ple as
(char cV ariable;). The in te g e r d a ta type is id en tified w ith th e le tte r i, th e le tte r n
id en tifies a sh o rt integer, an d 1 in d ic a te s a long in te g e r (e.g., i n t i p a s s w o r d ;
short nID; and lAccount). (Note: W hile th e re is less of a need for such n o tatio n ,
we still use Pascal/C am el N otation as p a rt of our C# references—see Table 1.6).
Hungarian notation does not include prefixes for the data types float,
double , or decimal. This makes sense, since they’re all floating point variables
and the lack of notation is in essence a form of notation.
We m ight also consider the reasoning th a t floating point variables should alw ays
reflect th eir data requirem ents, and should only be converted or declared using higher
precision d ata types in order to avoid data loss.
52
Chapter 1: C# from the Beginning
Boolean b
Function Fn
Handle H
Integers i
Long Integers I
String s
Pointer p
Short Integers n
Troubleshooting
Before going through the steps involved in th e process of troubleshooting, let’s m ake
sure th a t we u n d e rsta n d th e four basic types of errors. The first type, known as a
syntax error, is w hat m ight be described as a gram m atical error. The compiler, acting as
a spell-checker, looks through our program s trying to find any and all m isspelled com
m ands and/or forgotten punctuation m arks. If it finds any errors, the compiler im m edi
ately sends notification and directs us to the problem. Program s w ith th is type of error
cannot be “bu ilt”, and th u s no linkable objects are produced.
The second type of error is known as a runtim e error. R untim e errors usually in
volve asking the com puter to do som ething it can’t, such as dividing by zero or storing a
53
C# and Game Programming
character as a num ber. This type of erro r will not be detected by the com piler and will
alm ost alw ays produce a program prone to problem s and crashes, or one which will ju st
not run.
The th ird type of erro r is a logic error, which could also be called the poor planning
error. Exam ples of this type include telling the com puter to subtract when you m eant for
it to add, or telling it to skip a line w hen you w anted it to prin t. Not th in k in g out the
problem and/or not w riting out an algorithm usually causes th is type of error. Logic
errors, like ru n tim e errors, won’t usually show up w hen you’re compiling, bu t th ey ’re
sure to show up a t some point. The best way to detect a problem of this n atu re is to reru n
the program for several situ atio n s and, if possible, to recheck th e resu lts a g ain st a
secondary source.
The fourth type of error, described as a linking error, occurs w hen d ata is m issing,
faulty, or ju st unavailable a t the tim e of compilation. If your program compiles w ithout
errors, but there are errors when you build/rebuild it, then you’ve more th en likely m ade
a m istake setting up your program . If your compiler is not m entioned in this chapter, you
m ust consult your user m anual to find the problem. If you’re using Microsoft Visual Studio
.Net 2004 or any of the earlier versions, repeating the aforem entioned procedures should
solve your problem.
54
Chapter 1: C# from the Beginning
If your program compiles without errors, but there are errors when you build/rebuild
them , then you’ve more then likely made a m istake setting up your program. If your com
55
C# and Game Programming
piler is not m entioned in this chapter, you m ust consult your user m anual to find the prob
lem. If you are using Microsoft Visual Studio .Net 7.0 or any of the earlier versions, you more
th an likely selected “Win32 Application” without the word “Console,” or one of the other
choices. In any event, you should carefully repeat the steps given for setup.
Things to Remember
1. W hen creating a new compiler project always set it to “Console.”
2. M ost compilers change keywords to blue, green, or red (Microsoft
uses blue); if a keyword doesn’t change color it ju st m ight be
misspelled.
3. A fter a program is compiled and linked, it can th en be executed
from e ith er th e Windows MS-DOS prom pt or its executable
Windows icon (XP, ME, and Windows 2000 all have MS-DOS
prom pts, they’ve ju st been relocated to a spot under the
“Accessories” subm enu).
4. Com m ents should be used to explain source coding and to m ark
im p o rtan t points.
5. U sing integers or bytes reduces the am ount of RAM (Random
Access Memory) th a t your program will need. Gam es th a t use
less RAM can be played on more com puters (also, the extra RAM
can be used to improve graphics and sounds or ju st plain speed
things up).
6. W hen using floating point variables, you can save memory by
choosing float over double.
7. The character data type can only hold one lette r or symbol and
uses the single quote (don’t worry, th ere are ways to store whole
words, and even sentences, bu t they’re several chapters away).
8. V ariables should not be read w ithout first being initialized.
9. The u ser cannot change variables declared as constants; using
th e keyword volatile prevents unw anted optim ization.
10. Indenting m akes things easier to read but does not affect the way
the com puter reads the m aterial.
11. Although your compiler doesn’t care about good gram m ar, you
should m ake sure to use proper spacing, including adding one
space after each comma and spaces betw een arithm etic operators.
56
Chapter 1: C# from the Beginning
12. You should tak e the tim e to study your operating system and
compiler; feel free to experim ent w ith keywords and com m ands—
try to get a feel for w hat they do and where on the screen they do it.
13. Avoid variable nam es th a t s ta rt w ith single or double
underscores, as these m ay cause conflicts w ith advanced
assignm ent statem ents.
14. Use parentheses ra th e r th a n relying on the order of operations
w hen using arithm etic operators. U sing excess p aren th eses won’t
h arm your program , b u t excluding necessary ones will. The key
is to m ake things clear through the use of spacing and a
comfortable am ount of parentheses.
15. Finally, don’t worry about rushing to th e end or trying to jum p
rig h t into th e advanced code. E verything you’ll need is in this
book; you’ll ju st have to be patient.
57
13. W rite a program th a t declares four separate variables using the
d ata types i n t , f l o a t , d o u b le , and c h a r.
14. Continuing from Question 13, add four additional lines of coding
th a t assign appropriate values to each of the listed variables.
58
I long to accomplish a great and noble task,
but it is my chief duty to accomplish sm all
tasks as if they were great and noble.
-Helen Keller
his ch ap ter covers th e basic control sequences, including com parisons and
59
C# and Game Programming
using System;
namespace Chapter2 {
class Classl {
static void M a i n () {
// Begin main
int cResponse;
// Step 2
cResponse = Console.Read ();
// Step 3
C o n s o l e .WriteLine ("\n You typed Y\n");
Now, in order to m ake th is program respond correctly ( i.e., responding w here the
proper key is depressed), w e ll have to give our program the ability to com pare data.
This is done w ith the keyword i f and th e com parison operator (e.g., = =, see Table
2.1). The first step, then, is to rew rite the last program using the i f sta te m e n t (see
Exam ple 2.2).
Remember the C# language is case sensitive, thus the letters Y and y are
not considered equivalent inputs. For the correct response, the uppercase Y
is required.
using System;
namespace Chapter2 {
class Classl {
60
Chapter 2: Branches, Loops, and Functions
// Step 1
Console .Write (" Input <Y> for YES: 11) ;
// Step 2
cResponse = C o n s o l e .R e a d ();
This program still displays the m essage “You typed Y,” but now only if the letter Y is
actually entered. If any other character is entered, the program simply ends and noth
ing is w ritten to the screen. This is tru e for any letter or character d ata as long as it
equals the variable. Try reediting this program so th a t it responds to both upper and
lowercase letters (TP | | ‘y’). If you alte r the required input, rem em ber to alter the ac
companying inquiry. For our next task, we’ll modify the program so th a t it uses num eri
cal data (see Example 2.3).
using System;
namespace Chapter2 {
class Classl {
static void Main() {
int iAnswer;
// Step 1
C on s o l e . W r i t e ("1 + 1 = ") ;
// Step 2
iAnswer = i n t .Parse(Console.R e a d L i n e ());
61
C# and Game Programming
// Step 4
if (iAnswer != 2)
C o n s o l e .W r i t e L i n e ("\n W r o n g !!!\n");
}
}
}
Floats and doubles will work equally well in these comparisons. You m ight also w ant
to try a varied list of operators such as byte, ushort, and ulong, (keeping in m ind th a t u
stands for unsigned). The next section actually continues with the if statem ent, combining
//w ith the keyword else. Everything th a t we’ve studied here still applies, but else gives if
some added control.
62
Chapter 2: Branches, Loops, and Functions
Your programming abilities should now enable you to alter the program’s data
type, add comments, rename variables, and edit the output message without
further mention. However, I will still mention any opportunities to use the
data types b y t e , ushort, and ulong, should they arise.
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
double Answer;
if (Answer == 2.5)
C o n s o l e .W r i t e L i n e ("\n That is c o r r e c t !\n");
else
C o n s o l e .W r i t e L i n e ("\n W r o n g ! !!\n");
63
C# and Game Programming
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
double Answer;
if (Answer == 2.5)
C o n s o l e .W r i t e L i n e ("\n That is correct!");
else if (Answer > 2.5)
C o n s o l e .W r i t e L i n e ("\n Wrong, too high!!!");
else if (Answer < 2.5)
C o n s o l e .W r i t e L i n e ("\n Wrong, too low!!!");
}
}
}
64
Chapter 2: Branches, Loops, and Functions
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
double Answer;
if (Answer == 2.5)
C o n s o l e .WriteLine ("\n That is correct!");
else if (Answer > 2.5)
C o n s o l e .W r i t e L i n e ("\n Wrong, too h ig h !!!");
else
C o n s o l e .WriteLine ("\n Wrong, too low!!!");
Program
The last two programs are essentially identical, with the minor exception of the W alkthrough
altered else statement, which concludes Example 2.6. This emphasizes the
key points on how the if, else-if and else statements are linked. Following
the logic of the i f statement, we find that if our number is not 2.5, the program
proceeds to the next else-if. If we then find that the number is not greater
than the 2.5, we again move to the next else. In order to get to the else statement,
our number would have to be smaller then 2.5. Therefore, we do not need to test
to see if that value is actually smaller.
65
C# and Game Programming
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
float MyNumber;
The rules guiding the execution of compound if statem ents are simple. W hen the i f
statem en t is true, all the statem en ts inside the compound statem en t are executed, and
when the i f statem en t is false, all the statem en ts are ignored. This m ay not seem like
much when discussing a compound statem en t m ade up of only two lines, but im agine
dealing w ith compound statem ents of over two hundred lines. M any C# commands can
be placed inside of these compound statem ents including other if statem ents, but we’ll
leave such m atters to the sections ahead. The e l s e and e l s e - i f statem ents can also
use compound statem ents, as dem onstrated in Example 2.8. Notice how im portant it be
comes to comments when program s become longer and more complicated.
66
Chapter 2: Branches, Loops, and Functions
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
float MyNumber;
This is the last example for this section, but if statem en ts are explained fu rth e r in
the next two sections. As for compound statem ents, they’ll be used repeatedly in several
types of loops including the while and for loops coming up shortly. These new com
m ands also follow the sam e rules (i.e., ru n w hen true; ignore w hen false); after a while
this type of behavior should seem natu ral. The next section discusses th ree new decision
operators: and, or, and not. These, like the comparison operators, can be combined w ith
if statem ents and program m ing loops to define program paths.
67
C# and Game Programming
There are th ree decision operators: and (w ritten as &&), or (w ritten as | |), and not
(w ritten as !). Of these, and (&&) and or ( I I ) are used to combine i f and e l s e - i f
statem ents while the third operator not (!), is used to reverse our comparison’s outcomes,
the operators && and | | inside the parenthetical stru ctu re of i f statem en ts (see Table
2.2). By adding an && or a | | we can reduce w asteful and repetitive i f statem ents.
Exam ple 2.9 shows how the | | operator can tu rn two ifs and six comm ands into one i f
and three commands.
1. and (&&) meaning “both must be true for the statement to be true”
- if (variablel> variable2 && variable2 == variable3)
/ / 20 > 10 and 10 = 10
3. not (!) meaning “makes true statements false and false statements true"
- if ! (1 == 1) / / 1 = 1 then not (true) or false
if ! (1 == 2) / / 1 = 2 then not (false) or true
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
double Age, Weight;
int cQuickAnswer;
C o n s o l e .W r i t e ("How old are you? ");
input = C o n s o l e .R e a d L i n e ();
Age = d o u b l e .P a r s e (input);
68
Chapter 2: Branches, Loops, and Functions
if (Age < 3) {
C o n s o l e .W r i t e ("\nThe law requires you to
+ "sit in a car seat\n"
+ "\n Do you have a car seat? ");
cQuickAnswer = C o n s o l e .R e a d ();
}
The not operator is placed directly in front of an expression (as show in Table 2.2).
A lthough the not operator can be useful, it can also be confusing. I suggest reediting
Example 2.9 so th a t it uses the not operator. [Hint: the if statem ent would be w ritten like
this as (age > 3 | | weight >35)].
69
C# and Game Programming
namespace Chapter2 {
class Classl {
static void Main() {
string Input;
float Age, Weight;
int iQuickAnswer;
70
Chapter 2: Branches, Loops, and Functions
namespace Chapter2 {
class Classl {
static void Main() {
string Input;
int iVariablel, iVariable2, iVariable3, iCharacter;
// Note: later we'll learn techniques that will allow us
// to read partial bits of info, but until then w e ’ll still
// want to enter each number with a return statement
C o n s o l e .W r i t e ("\n Enter two numbers: ");
Input = C o n s o l e .R e a d L i n e ();
iVariablel = i n t .P a r s e (Input);
Input = C o n s o l e .R e a d L i n e ();
iVariable2 = i n t .P a r s e (Input);
iVariable3 = iVariablel;
if (iCharacter == '+') {
iVariablel = iVariablel + iVariable2;
Cons ol e. Wr it eL in e("\n Your longhand sum is "
+ iVariablel);
71
C# and Game Programming
iVariable3 += iVariable2;
C o n s o l e .W r i t e L i n e ("\n Your shorthand sum is also "
+ iVariable3);
}
72
Chapter 2: Branches, Loops, and Functions
73
C# and Game Programming
be acceptable for a real program. This section therefore shows us how to repeat a p ro g ram , or
p o rtio n s of a pro g ram , in a re p e a tin g cycle or loop. T he firs t ty p e of loop w e’ll
exam in e u se s th e keyw ord while; th u s , it is called th e while loop. The while
loop can be se t up to re p e a t a n d /o r te rm in a te in se v e ra l d iffe re n t w ays: th e m ost
com m on in clu d e u sin g a p re d e te rm in e d co u n t (as in to re p e a t a n ite r a tio n five
tim e s th e n end); u sin g th e u s e r ’s in p u t (end by req u e st); a n d a te rm in a tio n com
m an d (a com m and t h a t s h o rt-ste p s or b re a k s th e loop—w e’ll le a rn a b o u t th e s e
shortly).
A while loop com pares m ost directly to a com pound if sta te m e n t, while, like
i f , is w ritte n first, followed by a com parison operato r and th e n a set of com pound
sta te m e n ts. W hen while is tru e , all th e sta te m e n ts betw een its b rac k e ts will be ex
ecuted, and w hen it is false, all of its sta te m e n ts will be skipped, while, un like if,
will not term in a te when the last sta te m e n t is executed. R ather, and if it rem ains true,
it will th e n execute the compound s ta te m e n t again. This process rep e a ts indefinitely,
ending only w hen som ething is a lte re d to cause the com parison to become false or
o th er special steps are ta k e n to rero u te th e co m p u ter’s line of execution. The te c h
niques for te rm in a tin g a while loop are th u s ju s t as im p o rta n t conceptually as the
keyword while Exam ple 2.12 dem onstrates a lim ited or predeterm ined type of while
loop; th is exam ple te rm in a te s w hen th e variable te sts a t a value g re a te r th e n four.
using System;
namespace Chapter2 {
class Classl {
static void Main() {
int iCounter_l = 0;
Console.WriteLine("Program complete!\n");
}
}
}
74
Chapter 2: Branches, Loops, and Functions
When the whi le loop is first executed, the value of the counter is compared to 5. Since Program
zero is less than five, the loop is executed and the variable “iCounter_l” is incremented W alkthrough
by one. The loop retests itself, finding the variable at one, which is still less than five.
The loop continues to run until the counter variable is incremented to 5, at which point,
the loop ends. The program moves to the next line—Console.WriteLine (“Program
complete!”); and the program ends. This would hold true if we had made the value 15 or
even 50 million, although that would take a bit longer to execute.
We could have used an arithm etic statem ent or shortcut to alter our indexing variable’s
value, e.g., counter = counter + 1 and counter += 1. We could have even rew ritten five as
negative 5 instead of 5 and counted backw ards using the decrem enting operator or short
cut -= 1. Any such combination would work as long as we m ade sure the variable would
eventually reach a value th a t term inates the loop. Otherw ise we have w ritten a program
w ith a nonterm inating or infinite loop; which usually locks up program s, m aking them
unusable. The second type of term ination is by user input; this can be done either with the
u se r’s knowledge, as in asking the user ‘W ould you like to continue?” or w ithout the u se r’s
knowledge, as in w hen his ship is destroyed, the loop autom atically ends. Exam ple 2.13
dem onstrates a simple user-term inated loop.
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string Quit = "no";
75
C# and Game Programming
Program The first thing we do is declare the variable Quit and initialize it. We’ll use “no”
W alkthrough as its initial value (note: “no” has no real meaning to the program). Next, we’ll
set up a while loop that compares the value of Quit to “yes” and makes the loop
comparison true only when Quit’s value does not equal “yes.” We then ask the
user from inside the compound statement whether he or she wishes to end the
loop. The user’s input is then stored in the variable Quit; the loop will continue
to repeat until the user enters “yes.” Then, the last statement “Program
complete!” will be executed and the program will terminate.
As w ith counting loops, user input loops can be m ade nearly infinite if you forget to
tell the user how to end them (which, of course, should be avoided). For the th ird type of
term ination, we’ll have to introduce the keyword b r e a k , b r e a k , as its nam e implies,
term inates any enclosed loop or conditional statem ent. Exam ple 2.14 dem onstrates this
final while term ination technique.
using System;
namespace Chapter2 {
class Classl {
static void M a i n () {
string Quit = "no";
W hen b r e a k is executed, it simply breaks the loop and moves down to the next sta te
ment, skipping the rem aining loop statem ents, and the while loop is considered complete.
76
Chapter 2: Branches, Loops, and Functions
The program executes the last comm and “Program complete! \ n ” and th en term inates,
b r e a k works as an in sta n t end to an otherwise structured loop.
A nother interesting keyword in c o n tin u e , which, like b r e a k , shortcuts its it
erations; but ra th e r th a n ending the loop, it m errily brings the loop back up to the top.
The loop continues from the top w ith a new iteration and everything else continues
accordingly (see Exam ple 2.15).
using System;
namespace Chapter2 {
class Classl {
static void Main() {
int iVariablel = 10, iVariable2 = 0;
Console.WriteLine (iVariable2);
}
}
}
Battle Bit
Finally, after m any painful hours of lost sleep, burning eyes, scream s of m adness, and
dogged determ ination, you have reached the pinnacle of gaming knowledge and can now
create dynamically anim ated, graphically breathtaking, and hardw are accelerated th ree
dimensional video adventures capable of running on all platform s and com puter systems.
Hey, wake up! This is C hapter 2. Real game program m ing doesn’t even s ta rt u n til C hap
te r 3, and th ere ’s nothing in th a t chapter about hardw are acceleration or three-dim en
sional programming. As for your abilities up until this point, well maybe, ju st maybe, you
m ight be ready to try out a little text style program th at, a t least partially, will ease you
77
C# and Game Programming
into the whole gaming concept. The game is called B attle Bit and the p layer’s objective is
to destroy the aliens before they land. To play, you simply guess the aliens’location, which
is represented by num bers typed into your com puter’s keyboard. To win you m ust guess
the correct answ er before you use up your shots. Oh, and if you fail, I’ve set up a bug th a t
will autom atically erase your h ard drive—but don’t fret, it shouldn’t take too long to
reinstall everything!
namespace Chapter2 {
class Classl {
static void Main() {
string input;
int iAmmo = 12, // player has 12 guesses
iAlienShip = 49, // the alien ship starts here
iTarget = 50; // This variable stores your input
78
Chapter 2: Branches, Loops, and Functions
while (iAmmo > 0) { // when ammo runs out the loop ends
Console .W ri te Li ne ("\n\n Enter targeting information?");
input = C o n s o l e .R e a d L i n e ();
iTarget = i n t .P a r s e (i nput);
if (iTarget == iAlienShip) {
// if your input equals the ships location
C o n s o l e .W r i t e L i n e ("Alien ship hit, the ships been
destroyed sir.");
break; // break ends loop
} else if (iTarget > iAlienShip) {
// when input is too high
Conso le .W ri te Li ne ("You missed, try aiming a little
lower");
iAmmo— ; // ammo— reduces the total ammo by 1
} else {
// when input is to low
Console .W ri te Li n e("You missed, try aiming higher");
iAmmo--; // also reduces ammo by 1
}
if (iAmmo > 0 ) / / i f you have ammo you must have hit the alien
Conso le .W ri te Li ne ("\n Good work soldier, remind me to
promote you.");
else // if your out of ammo you can't protect the hall
Console .W ri te Li ne ("\n BOOM!!! You're dead.\n");
79
C# and Game Programming
while (iAmmo > 0) { // when ammo runs out the loop ends
Conso le .W ri te Li ne ("\n\n Enter targeting information?");
input = C o n s o l e .R e a d L i n e ();
iTarget = i n t .Parse (input);
if (iTarget == iAlienShip) {
// if your input equals the ships location
Conso le .W ri te Li ne ("Alien ship hit, the ships been
destroyed sir.");
break; // break ends loop
} else if (iTarget > iAlienShip) {
// when input is too high
C o n s o l e .W r i t e L i n e ("You missed, try aiming a little
lower");
iAmmo--; // ammo-reduces the total ammo by 1
} else {
// when input is to low
C o n s o l e .W r i t e L i n e ("You missed, try aiming higher");
iAmmo--; // also reduces ammo by 1
}
if (iAmmo > 0) // if you have ammo you must have hit the alien
C o n s o l e .W r i t e L i n e ("\n Good work soldier, remind me to
promote y o u .") ;
else // if your out of ammo you can't protect the hall
Console .W ri te Li ne ("\n BOOM!!! You're dead.Xn");
80
Chapter 2: Branches, Loops, and Functions
The d o - w h i l e Loop
The second type of w h ile loop, which is known as the d o - w h ile loop, is essentially the
w h ile loop tu rn ed up-side down. Here we insert the w h ile loop comparison a t the end of
the loop, which also allows for one complete execution before the 1st comparison takes
p la c e .
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string Quit = "no";
do {
// this is an endless loop
} while (Quit != "yes"); // notice the semicolon?
}
}
}
The keyword do is placed a t the top of the loop and the keyword w h ile is placed at
the end. The compound statem ent is w ritten directly after the keyword do, ju st as it was
with w h ile and i f . One obvious difference between the w h ile loop and the d o -w h ile loop
is th a t the comparisons are not made until the loop is already running. Again, this guaran
tees us at least one execution before the coding is tested. Example 2.18 demonstrates the do-
w h ile loop in action.
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string Quit;
do { // do-while loop
Consol e. Wr it eL in e("\n Would you like to end this loop? ");
81
C# and Game Programming
C o n s o l e .W r i t e L i n e ("Program c o m p l e t e !\n");
}
}
}
Needles to say, the w h ile and d o - w h ile loops can also take advantage of the and
(&&), or ( | | ), and n o t (!) operators. They can be rew ritten w ithout compound statem ents
as single-line w h ile and d o - w h ile statem ents (although th a t would be considered poor
program m ing style). Moreover, you can nest w h ile /d o - w h ile loops inside of each other.
Exam ple 2.19 gives an example of both the nesting technique and th e && operator. You
may also w ant to test th is program using either the I I or ! operators, b u t Fll leave the
exact phrasing of those two operators up to you.
using System;
namespace Chapter2 {
class Classl {
static void Main() {
// Begin main
int iNumber = 0 ;
string Quit;
82
Chapter 2: Branches, Loops, and Functions
Console.WriteLine("Program complete!\n");
}
}
}
You don’t have to use the same variable in both loops; in fact, the use of the
same variable is what made this example so confusing. In addition, for preset
numbers such as zero to ten you might be better off using the for loop, which
just happens to be the subject of the next section.
The f o r Loop
The f o r loop, also known as the f o r statem ent, is a repetitive process th a t is set up under
certain conditions to ru n a p articu lar num ber of tim es. This term inating factor will also
help us to separate it from the other two looping processes, because it’s not dependent on
an unknown variable. The f or-loop thus predefines its variable as p art of its initial sta te
m ent. The comparison operators are still used to determ ine w hether to continue or term i
nate, b ut this will always happen a t a predeterm ined point in the loop, as w hen our v ari
able equals 10, 100, or x num ber of cycles. The f o r statem en t is constructed much like
the w h ile loop, but w ith its initializing variable and its increm enting operator both
becoming one with its declaration (see Example 2.20).
83
C# and Game Programming
using System;
namespace Chapter2 {
class Classl {
static void Main() {
int iCounter 1;
Console.WriteLine("Program c o m p l e t e !\n");
Program
W alkthrough The for statement begins by assigning our variable the value zero. This value is
then compared to 5 and found true since zero is less than five. The incrementing
operator then adds one to the value of our variable making its value one. The loop
is then executed and our variable iCounter_l is displayed. The loop then finds
the variable is still less than five, and the variable is then incremented a second
time. The third time the loop runs, our value increases to three, which is still less
than five, so the loop runs again. The fourth iteration increases our value to four
and the loop runs again. Finally, our variable equals five and the loop terminates.
The program moves to the next line “Program complete!” and the program ends.
The f o r loop can become an infinite loop or m indless hole w ith even the most
subtle of errors. For example:
84
Chapter 2: Branches, Loops, and Functions
fo r (iC o u n t e r _ l = 0; iC o u n t e r _ l < 5/ iC o u n t e r _ l+ + ) {
iC o u n t e r _ l = 1;
C o n s o le .W r it e L in e (iC o u n t e r _ l);
}
T h at’s it for the looping processes, bu t there are still two additional comparison pro
cesses—the s w i t c h statem ent and the f o r e a c h statem ent. Both are very sim ilar to the
i f and e 1 s e - i f statem ents, bu t they can handle much longer lists of comparisons w ith
out repeating them selves or becoming cluttered. W ith respect to game program ming tech
niques, these comparisons also m akes long lists of comparisons sm oother and sim pler to
modify.
using System/
namespace Chapter2 {
class Classl {
static void Main() {
int Grades;
85
C# and Game Programming
// Begin main
C o n s o l e .Write ("How would you grade yourself so far A, B, or
C? ") ;
Grades = Console.Read ();
case 1B 1:
case 'b 1:
Console.WriteLine ("You're sure of yourself");
break;
default:
Console.WriteLine ("A, B, and C inputs only!");
break;
} // end switch statement
Note th a t this term ination sequence is actually only the keyword b re a k , which does
nothing more th a n move us out of a block and onto the next segment, b re a k , like c a se , is
repeated for each comparison.
C# also requires a break statem ent, which prevents the falling through of case values.
You can, however, include m ultiple c a s e statem ents, ju st as long as they do not contain
executable statem ents. This new method, while only a m inor change in syntax, should
flag several of the older C/C++ conversions. To those program m ers th a t don’t like to write
th eir switch statem en ts using only individually controlled case statem ents, I apologize
(see Example 2.22).
86
Chapter 2: Branches, Loops, and Functions
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
int byNumber;
switch (byNumber) {
default:
C o n s o l e .W r i t e L i n e ("\n Good job now take a lap!");
break;
case 0:
C o n s o l e .W r i t e L i n e ("\n Zero is not greater than
o n e !\n");
break;
case 1:
C o n s o l e .W r i t e L i n e ("\n I said a number greater than
o n e !");
break;
}
87
C# and Game Programming
statem ents, but switch statem ents inside of other switch statem ents should be used spar
ingly to avoid confusion.
Defining a Block:
A block (opening and closing brackets {}), although technically identical to a
compound statement, can in fact refer to any set of brackets placed anywhere
in a program. For example, the main program is enclosed by opening and
closing brackets but is not considered as a compound statement. Blocks allow
programmers to separate special sections of code, opening up new ways to use
local variables, or enclose certain code including confining subroutines
(discussed later in this chapter). When a block is nested within another block,
the outsider block is considered global to the inner block, just as code written
outside of the main program is considered global to the program. Global and
local concepts are very important when working with C# and will be discussed
in greater detail throughout this text.
Converting from C ++ to C#
W hile m any of us may rem em ber the older C and C++ I/O notations, it is safe to assum e
th a t not everyone reading this text can do so w ithout some type of reference. This sec
tion defines the C/C++ comm ands th a t were replaced by our W rite and W riteLine ex
tensions. W hen the older commands are encountered, the trick is to replace them w ith
the appropriate combination of extensions and form atting strings.
The p r i n t f and c o u t functions are alternatives to the Write and W riteLine com
m ands, and the s c a n f and cin function are alternatives to the R e a d and R e a d L i n e
commands. Like our Reads and W rites, these functions are not keywords, but instead
they are added commands linked by the older included file structure (see C hapter 1). The
included file th a t controlled these commands were <cstdio> (written as#include <cstdio>
and #include <stdio.h>) and iostream (w ritten as #include <iostream > and #include
<iostream.h>); <stdio.h> actually reaches back to the original C language. Printf, and
for th a t m atte r scanf, have the most in common w ith C#’s notation, which becomes obvi
ous when comparing them directly. For an extended list of p r i n t f / s c a n f notation, see
Table 2.4.
88
Chapter 2: Branches, Loops, and Functions
using System;
namespace Chapter2 {
class Classl {
static void Main() {
int Number; // char name [10];
string Answer; // char Answer; or char Answer [];
89
C# and Game Programming
We could also convert m ultiple references, including form atting strings, to represent
the change in notation (see Example 2.24).
Boolean Expressions
Boolean expressions a re m a th e m a tic a l re p re s e n ta tio n s for th e concepts of tru e an d
false. T h a t is, w hile th e ir a c tu a l ev a lu a tio n s a re based on m ath e m a tic a l d a ta , th e ir
outcom es a re in fact d e te rm in e d by a conceptual u n d e rsta n d in g . T his type of d e te r
m in a tio n is re p re s e n te d in C# as th e d a ta type bool, w ith its v a ria b le s assig n e d to
th e B oolean c o n s ta n ts true or fa lse. In th e p a s t, as w ith C an d C++ , th is process
90
Chapter 2: Branches, Loops, and Functions
using System;
namespace Chapter2 {
class Classl {
static void Main() {
bool Variablel = true;
string Test;
while (Variablel) {
C o n s ol e. Wr it e("\n Would you like to end this loop? ");
Test = C o n s o l e .R e a d L i n e (); // yes will break the loop
91
C# and Game Programming
As you can see, Tests 1 and 2 required complete evaluation because neither outcome
could be determ ined w ithout the second evaluation. This is not the case w hen using
short circuit or p a rtia l com parison reasoning (as shown in Tests 3-8). In such cases, the
decision to label the com parison as tru e or false would be done w ithout the second test,
and would th u s save us the tim e and trouble of the second comparison. In addition, we
can use this p a rtial comparison to safeguard against runtim e errors such as dividing by
zero—see Example 2.26.
92
Chapter 2: Branches, Loops, and Functions
question m ark (?) and a colon (:). The statem ent requires three expressions: a n i f - e l s e
comparison, a tru e calculation, and a false calculation as shown below.
if(x == y)
// followed by an assignment
x = 41;
else
// and then an else
// statement
x = 72;
W here x equals y , the comparison is tru e and x is reassigned as 41. W hen x does not
eq u a ls, x is reassigned as 72.
The conditional operator can also be placed inside of other commands and
statements (including the while, do-while, and Write commands).
Predefined Functions
T here are two types of functions (also known as m ethods) used in C#: those th a t are
w ritte n by us and used like little subprogram s, and those th a t were w ritte n for us and
used to save us th e tim e of w riting them ourselves. The first type, referred to as
user-defined functions, are a bit more com plicated and a re n ’t completely explained
u n til th e end of th is chapter. The second type are m ost commonly referred to as p re
defined functions, which I actually began back in C hapter 1. This section tak e s a
m om ent to introduce form ally the concept of the predefined function.
The good news is th a t w ith the advent of the .Net architecture we no longer have to
m em orize dozens upon dozens of included file references in order to use a few sim ple
com m ands. The bad news is th a t m ost of us have already m em orized so m any of them
th a t it ju st m ight feel a little bit unfair, to which I say not to w orry—the basics of the
93
C# and Game Programming
new structure a ren ’t th a t different from the old one and everyone, including the newbies,
should pick it up p retty quickly. Again, all predefined functions referenced u n d er th is
new arch itectu re involve an object (class); th u s, the procedures for referencing those
functions are very sim ilar to w hat you m ight expect when referencing a stan d ard C/C++
m ethod (or m em ber function). Now, not all of our user-defined functions are accessed in
the same way (this should become apparent with time). Moreover, not even the best of us
can truly claim to know them all, but they’re now much easier to access, especially w hen
you’re using a visual compiler. The next few p arag rap h s explain some of the m ost com
mon extensions.
Characters
The first function w e’ll define is C h a r . T o U p p e r , w hich litera lly m eans to m ake a
le tte r th a t is low ercase into one th a t is uppercase. This function also h a s an antonym
nam ed C h a r . T o L o w e r , which changes uppercase lette rs into th e ir lowercase counter
p arts. The T o U p p e r function is useful w hen you cannot control th e u s e r’s input, as we
couldn’t in Exam ple 2.2. In th a t exam ple, I h ad to ask th a t you lim it your responses to
uppercase Y. This w as necessary a t th e tim e, b u t is no longer th e case, since we can
easily rew rite th is program to use th e T o U p p e r function (see Exam ple 2.27).
using System;
namespace Chapter2 {
class Classl {
static void Main() {
int Response;
if (Response == 'Y')
Console.WriteLine ("\n You typed {0}\n", (char) Response);
}
}
}
94
Chapter 2: Branches, Loops, and Functions
Math
The next few functions we’ll cover are from th e predefined m ethod M ath. These
function can be extrem ely useful w hen calculations are required. O ur first function
is M a t h . S q r t ( ) , which stan d s for th e square root of a num ber. This function r e
tu rn s the square root of any value placed w ithin its p a re n th ese s (see Exam ple 2.28).
A second function linked to M ath is th e M a t h . Pow ( ), w hich sta n d s for an expo
n e n tia l power of a num ber (rem em ber we can alw ays su b stitu te variables for lite ra l
constants). This could be used to reverse th e square root, or w ith other powers such as
cubes.
O ur th ird and fourth functions are M a t h . C e i l i n g and M a t h . F l o o r , which are
used to round rea l num bers to th e ir h ighest or low est whole value, respectively. The
m ost im p o rtan t point to rem em ber w hen w orking w ith these functions is th a t Ceiling
alw ays rounds up and Floor alw ays rounds down, regardless of th e size of th e decim al
value th ey ’re reading. T h a t is, M ath.C eiling would round 3.2 to 4 and M ath.Floor
would round 3.9 to 3.0. Therefore, you’ll have to decide w hich way you w ant to go
before using eith e r one.
Trigonometric Functions [w here x is a d ou ble/floa ting point value read in radians):
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
double number1, n u m b er 2, number3 2 .0 ;
95
C# and Game Programming
number2 = M a t h .Sqrt(numberl);
C o n s o l e .W r i t e L i n e ("\nThe square root of {0} is {1}",
numberl, numbe r2 );
number2 = M a t h .Pow(number2, nu m be r3 );
C o n s o l e .W r i t e L i n e ("Do these number match {0} and {1}?",
numberl, number2);
numberl = M a t h .C e i l i n g (3.2);
number2 = M a t h .F l o o r (3.9);
namespace Chapter2 {
class Classl {
static void Main() {
96
Chapter 2: Branches, Loops, and Functions
string input;
char cYesNo;
do { // do-while loop
double iAlienShipl = Math.Round (rnd.NextDouble () * 100) + 1,
iAlienShip2 = Math.Round (rnd.NextDouble () * 100) + 1,
iTarget = 0,
iAliensMissiles = 0;
const double iYourLocation = 50;
if (Math.Ceiling(iTarget) == M a t h .C e i l i n g (iAlienShip2)
I| Math.Ceiling(iTarget) == Math.Floor(iAlienShip2)
I| Math.Floor(iTarget) == Math.Ceiling(iAlienShip2)
II Math.Floor(iTarget) == Math.Floor(iAlienShip2)) {
C o n s o l e .W r i t e L i n e ("\nAlien ship hit, you took him
d o w n !!\n");
iAlienShip2 = -1;
}
97
C# and Game Programming
if (Math.C e i l i n g (iAliensMissiles) ==
M a t h .C e i l i n g (iYourLocation)
|| M a t h .C e i l i n g (iAliensMissiles) ==
Math.Floor(iYourLocation)
|| M a t h .Floor(iAliensMissiles) ==
M a t h .Ceiling(iYourLocation)
II M a t h .F l o o r (iAliensMissiles) ==
M a t h .Ceiling(iYourLocation))
break;
else
iAliensMissiles = r n d .N e x t D o u b l e ();
} // end loop
98
Chapter 2: Branches, Loops, and Functions
T ext E xam p le 1:
W hen a value is larger th an is required for practical purposes, th a t value can be truncated
to save space or to refine the final displayed statem ent, e.g.,$10,012 becoming $10.01, the
am ount owed.
T ext E xam p le 2:
W hen an irrational num ber is the result doing integer m athem atics, the value is always
tru n cated to an integer value. This will happen regardless of th e assigned variables
d a ta type and w ithout regard for the tru n catin g variables tru e value. For example, in
th e equation 9 divided by 2, the real quotient should be 4.5, but after truncating, using
rules of integer division, we are left w ith the value of 4. A lthough incorrect, this is the
value passed to the variable, even if th a t variable is of a floating-point d a ta type. The
sim plest way to correct this is to m ake a t least one of the values a real number, for
exam ple 9.0/2 equals 4.5. However, the problem here is th a t th is type of change only
works for literal constants and not for variables th a t hold integer d ata (as in x = 9, y = 2,
xly yielding 4). A more creative solution would be to use type casting. Type casting, as
explained above, allows us to convert both literal constants and variables by using d ata
type conversions, e.g., (<double)9 or doubled) (see Exam ple 2.30).
99
C# and Game Programming
class Classl {
static void Main() {
double numberl = 9/2; // Warning - returning 4
C o n s o l e .WriteLine(numberl);
int integer2 = 9;
double number3 = (double)integer2 / 2; // 4.5
C o n s o l e .WriteLine(number3);
^ Unsigned values by definition have twice the range of signed values, thus the
potential of data loss increases when attempting to convert to a restricted
data type.
100
Chapter 2: Branches, Loops, and Functions
using System;
namespace Chapter2 {
class Classl {
static void Main() {
double Happy = 4.0;
10 1
C# and Game Programming
namespace Chapter2 {
class Classl {
static void OurFunction () {
/* This is a do nothing function */
}
Although this program is similar to the do-nothing programs of Chapter 1, it still represents
a true user-defined function. From here, we could have inserted a slue of information including
declared variables, predefined functions, loops, and switch statement. Still, it’s best if we hold off
on some of these at least until we’ve completely defined user-defined function. The next few
10 2
Chapter 2: Branches, Loops, and Functions
sections include descriptions of prototypes, global and local variables, data structures, and return
statem ents all of which are crucial to th at definition, so try to be patient.
A second way to write a simple do-nothing function is to place it under the main function as
in Example 2.33. If you take a moment to examine this example, you’ll find th at it is relatively
unchanged in regard to its contents and purpose (this being to do nothing). The minor revision
simply moves the completed function out of the way while we return to work on the main
method.
using System;
namespace Chapter2 {
class Classl {
static void Main() {
OurFunction ();
}
Variable Scope
Local variables are variables declared inside the m ain or subsequent methods. Their values
are not known beyond the lim itations of their block. Program mers who wish to transfer
data from one block to another m ust do so using a referencing function. There are generally
two types of passing variables: calls-by-mechanism, where information is merely passed to
new variables, and calls-by-reference, which allow the programmer to alter the original memory
locations. Local variables, as well as their secondary counterparts, can be passed and repassed
endlessly, so limitations are minimized. In addition, user-defined functions have the ability to
return data to the m ain or other calling functions.
C# doesn’t actually allow for truly global variables, but the word global can be used to
distinguish betw een localized and inclusive variables w ithin a single m ethod or class.
Global variables allow for the exchange of data, b ut do not require a passing variable (see
Example 2.34).
103
C# and Game Programming
namespace Chapter2 {
class Classl {
static int NumberOne, NumberTwo, GlobalTotal = 0;
int LocalTotal = 0;
C on so l e . W r i t e ("\n How many apples did Johnny shoplift? M ),
input = C o n s o l e .R e a d L i n e ();
NumberOne = i n t .Parse(input);
All global references that conflict with local variables are generally hidden by
the compiler when those blocks are accessed, thus a local reference will always
be chosen over a global value. When working with local and global variables
that require dual references, two important distinctions must be made. First,
a new function reference must be declared and second, the global variables
must be completely defined using the class’definition (see Examples 2.35).
10 4
Chapter 2: Branches, Loops, and Functions
using System;
namespace Chapter2 {
class Classl {
// global variable (also the value of a gold bar on e a r t h ) .
const double GoldBar = 1000.00;
E xam p le 2.36. R e tu r n in g v a lu e s.
using System;
namespace Chapter2 {
105
C# and Game Programming
class Classl {
static void Main() {
string input;
int iNumberOne = 0, iNumberTwo = 0; // Local variables
iNumberTwo = R an do m N u m b e r ();
if (iNumberOne == iNumberTwo) {
C o n s o l e .W r i t e L i n e ("\n Hey you win, with a smile
+ "with a grin! ! !") ;
iNumberTwo = RandomNumber ();
} else if (iNumberOne > iNumberTwo) {
C o n s o l e .W r i t e L i n e ("\n Too high smart guy!");
iNumberTwo++;
} else {
C o n s o l e .W r i t e L i n e ("\n Too low slow Joe");
i NumberTwo--;
static int R a n d o m N u m b e r () {
Random rnd = new R a n d o m ();
int n2 = (int)Math.Round(rnd.NextDouble() * 9) + 1;
return (n2);
O ur next comparison opens the field a bit by m aking our random function capable of
retu rn in g character data. Here we also included a whi l e loop th a t protects our function
from returning anything other th a n a letter (see Exam ple 2.37).
10 6
Chapter 2: Branches, Loops, and Functions
namespace Chapter2 {
class Classl {
static void Main() {
char Letter = 1 Response;
string input;
do {
Letter = LetterGenerator(Letter);
Console.Wr it eL in e("{0} is this correct?\n", Letter);
input = C o n s o l e .R e a d L i n e ();
Response = c h a r .Parse (input);
if (char.ToUpper(Response) == 'Y')
C o n s o l e .W r i t e L i n e ("Great let's play again");
else
C o n s o l e .W r i t e L i n e ("How a b o u t ...");
} while (char.ToUpper(Response) != fQ');
}
return ((char)Lett er );
107
C# and Game Programming
The m ain m ethod is also easily adaptable to include both storage d ata types and the
retu rn statem ent (see Examples 2.38 and 2.39). Note th a t referencing a retu rn statem ent
from w ithin the m ain m ethod causes the im m ediate term ination of th a t program .
using System;
namespace Chapter2 {
class Classl {
static int Main() {
return 0;
using System;
namespace Chapter2 {
class Classl {
static void Main() {
return;
108
Chapter 2: Branches, Loops, and Functions
namespace Chapter2 {
class Classl {
static void Main() {
string input;
float number = 0, root = 0;
10 9
C# and Game Programming
We could also have replaced that user-defined function with the predefined
function Math.Sqrt ().
110
Chapter 2: Branches, Loops, and Functions
Again, we can also reconstruct the last program using the predefined function
M ath.Sqrt () (see Example 2.42).
namespace Chapter2 {
class Classl {
static void Main() {
string input;
float number = 0, root = 0;
m
C# and Game Programming
Well want to take the black box approach to most, if not all, of the predefined
functions listed in this text.
using System;
namespace Chapter2 {
112
Chapter 2: Branches, Loops, and Functions
class Classl {
static void Main() {
string input = "Y", Horse;
intiNumberl = 0, iNumber2 = 0, iNumber3 = 0;
TheRace(ref iNumberl);
TheRace(ref iNumber2);
TheRace(ref iNumber3);
113
C# and Game Programming
T h e R a c e ( r e f N u m 2 );
T i e B r e a k e r ( N u m l , ref N u m 2 ) ;
The Keyword o u t
The keyword out is a special exception m arker th a t notifies the compiler th a t the variable
under scrutiny does not need to be assigned before it can be passed as a referenced v a ri
able. This is usually the case when dealing with variables th a t wouldn’t otherwise have a
meaningful value before the appropriate functions can be executed. Since an out value is
also a referenced value, this keyword negates the need for the second reference (re f) (see
Example 2.44).
using System;
n a m e s p a c e Ch a p t e r 2 {
class Cla s sl {
sta ti c v o i d Main() {
s tr i n g input = " Y M , Horse;
int iNumberl, iNumber2, iNumber3;
w hi l e ( c h a r .T o U p p e r ( c h a r .P a r s e (i n p u t )) != 'N') {
C o n s o l e . W r i t e L i n e ("(1) for W h i t e f i r e \ n "
+ "(2) for The T r ai n and, \n"
+ "(3) for N o i s y G l u e \ n " ) ;
H ors e = C o n s o l e .R e a d L i n e ();
T he R a c e (out i N u m b e r l ) ;
T he R a c e (out i N u m b e r 2 ) ;
Th e R a c e (out i N u m b e r 3 ) ;
114
Chapter 2: Branches, Loops, and Functions
s ta t ic v o i d T h e R a c e { o u t int Num) {
R a n d o m rnd = new R a n d o m ();
Nu m = (i n t )M a t h .R o u n d (r n d .N e x t D o u b l e () * 1000);
}
An Introduction to Polymorphism
Polymorphism (also known as overloading) occurs when any reference has a closely matching, but
not identical definition. These secondary, or substitute functions, while not technically required,
generally tend to stay within the confines of the first function’s purpose. If an overloading function
were to be altered to a degree that promoted a completely new definition, then overloading would
not be necessary. While overloading functions do share the same referencing title, their definitions
must differ in arrangement by at least one transferring data type. The use of these differing access
points guides the compiler to the correct (overloading) function. Since more than one possible
referencing point exists, there is also an increased chance of miscalling that function, thus creating
a runtime error. Examples 2.45 and 2.46 give alternate functions that can produce the same
results, but only one is actually performing correctly.
115
C# and Game Programming
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
int iNumberl = 0, iNumber2 = 0, iNumber3 = 0, iTotal;
input = C o n s o l e .R e a d L i n e ();
iNumberl = i n t .Parse(input);
input = C o n s o l e .R e a d L i n e ();
iNumber2 = i n t .P a r s e (input);
input = C o n s o l e .R e a d L i n e ();
iNumber3 = i n t .Parse(input);
if (iNumber3 == 0)
iTotal = Sum(iNumberl, iNumber2);
else
iTotal = Sum(iNumberl, iNumber2, iNumber3);
116
Chapter 2: Branches, Loops, and Functions
If you’re not sure if this program is working correctly, try retesting the three
variables using two zeros and a negative one.
using System;
namespace Chapter2 {
class Classl {
static void Main() {
string input;
int iNumberl = 0, iNumber2 = 0,
iNumber3 = 0, iTotal;
input = C o n s o l e .R e a d L i n e ();
iNumberl = i n t .P a r s e (input);
input = C o n s o l e .R e a d L i n e ();
iNumber2 = i n t .P a r s e (input);
input = C o n s o l e .R e a d L i n e ();
iNumber3 = i n t .P a r s e (input);
117
C# and Game Programming
Introducing Recursion
A recursive function is a user-defined function th a t contains one or more odd iterations
caused by the u nusual placem ent of a secondary call to th a t function. The position or
placem ent of this secondary function call is considered u nusual or a t least a special topic
because it invokes a function from w ithin th a t function. T hat is to say, when the program
m ers created the function, they included it in a call to itself th a t causes th a t function to
loop repeatedly, or at least m ultiple times. (Note: This would also m ean th a t it would have
to re tu rn to itself m ultiple tim es before retu rn in g to the m ain or calling function). The
reasons for m anipulating a function in this m anner are diverse and a t tim es confusing,
b ut ultim ately, the coding for such exam ples is quite simple, as shown in Exam ple 2.47.
Note the recursive function used to test our horseracing program earlier in this chapter.
using System;
namespace Chapter2 {
class Classl {
static void Main() {
P a s s w o r d ();
}
static void P a s s w o r d () {
string input;
int password;
118
Chapter 2: Branches, Loops, and Functions
Inline Functions
A nother interesting thing about C# is its autom atic use of inline functions, which are
functions th a t are in serted into every line th a t requires its reference. T h at is, ra th e r
th a n having the function reference search out the function a t runtim e, the function is
compiled into th a t line of coding. This speeds up the program , bu t it also increases the
code size. The biggest problem w ith “inlining” in C/C++ w as th a t it was only a request
and not an order, so the compiler could refuse to do it. The m ajority of com pilers (and
th is includes the M icrosoft’s V isual C++ series) won’t inline a recursive function, nor
will they allow functions th a t are referred to through pointers (see C hapter 4 for infor
m ation on pointers). The C/C++ keyword inline is not required in C#, and th u s falls
u n d er the list of a n tiq u a te d coding. Note: M icrosoft versions of both C and C++ also
included two variations on the inline command, ( inline a n d forceinline); these key
words also have no place in C#.
Troubleshooting
I t’s tim e for another deep breath and a bit of problem solving. Remember th a t if you don’t
find the answ ers here they m ight have been explained in the last troubleshooting section
(see C hapter 1). First, let’s look at the problem from a logical standpoint; let’s assum e th a t
you’ve worked, successfully, w ith all of the program s listed in the last chapter. If so, then
any problems would have to relate to syntax. Question: do errors occur at compilation? Try
resetting the w arning level to a lower setting; did those errors become warnings? Perhaps
you had a syntax error; look for errors caused by using the wrong symbols in your com
parisons. If there are no compiling errors, but the program ’s d ata is still producing incor
rect output, try looking for reversed symbols, typographical errors, or incom plete
coding errors.
119
C# and Game Programming
12 0
Chapter 2: Branches, Loops, and Functions
14. Rem em ber C# requires th a t all case statem ents conclude w ith a
break reference.
15. Rem em ber the o u t statem en t replaces the ref statem ent when
defining calls-by-reference.
Things to Remember
1. I f statem ents are used w ith lim ited comparisons, while switch
sta te m e n ts are used in m ultiple cases.
2. A compound statem en t is a set of statem en ts th a t are contained
betw een to braces.
3. M athem atical shortcuts should only be used if they m ake things
sim pler to read. (Note: Some compilers will convert these
shortcuts into faster running code.)
4. System .Console.W rite, and using System; w ith Console.W rite do
exactly the sam e thing.
5. The while loop te st and th en ru n s its first cycle, w hereas the do-
while loop ru n s first and tests after ru n n in g its first cycle.
6. You’ll have to rem em ber everything about predefined and user-
defined functions. The best way to rem em ber them is through
practice, so I’ll include as m any as I can—the re st you’ll have to
practice on your own.
7. Rem ember C# doesn’t require function prototypes or included files.
8. Calls-by-reference can completely replace global variables.
9. Overloaded functions m ust not contain the sam e arrangem ent of
passing variables.
10. Recursion m eans nothing more th a n repeating the sam e function
from w ithin th a t function.
11. W hen w riting a sta te m e n t th a t stretches over a single line try to
break it up. B reak a t a comma or other m arking to m ake the split
easier to read.
121
C# and Game Programming
12 2
Chapter 2: Branches, Loops, and Functions
123
C# and Game Programming
10. W rite a program th a t allows the u ser to choose from any one of
the five basic m ath types. Use a w h i l e loop to rep eat the choices
after each calculation.
11. Revise the program from Q uestion 10 using a continue statem en t
th a t forces the w h ile loop to skip the actual calculation.
12. Revise the program from Q uestion 10 using the d o - w h i l e loop.
13. Revise the program from Q uestion 10 using the for loop.
14. A lter the program from Q uestion 10, replacing all the if
statem en ts w ith s w i t c h statem ents.
15. Revise the program from Question 14, replacing cout with p r i n t f
and ci n w ith scanf.
16. Revise the program from Q uestion 14, replacing cout w ith p u t s
and ci n w ith gets.
17. W rite a program th a t tests an i f statem en t using the Boolean
d ata type (bool test).
18. W rite a program th a t uses short circuit evaluation to safeguard
ag ain st division by zero.
19. W rite a program th a t uses type casting to convert a double
constant (as in 1.3) to the float data type.
20. Revise the program from Q uestion 5 by replacing (Y | | y) w ith
the ToUpper function.
21. W rite a do-nothing program th a t calls the user-defined function
Hello (). Hello should display the words “Hello world!”
22. Revise the program from Question 21 to use a prototype to Hello ().
23. U sing global variables, w rite a program th a t compares two
variables inside a user-defined function.
24. Revise the last program using local variables; use Hello (int
iV all, int iVal2).
25. Revise the last program so th a t the two variables are declared
and assigned inside the user-defined function and only th e final
value is sent back to the m ain function (Hint: Use static int Hello()).
26. W rite a program th a t uses two user-defined functions, one to add
the sum of two num bers, the other to add the sum of three
num bers, using an overloaded user-defined function.
27. W rite a user-defined function th a t uses recursion to count from
zero to ten.
12 4
Game
Programming Basics
"
nr
LJ
Introducing DirectX
fe iV i I
■ i n i anaged DirectX is an alternative Application Program m ing Interface (API),
^ developed by Microsoft, to handle the higher dem ands of graphic and sound
program m ing found in today’s applications. M anaged DirectX allows for direct access to
video, sound, and input devices to include video cards, sounds cards, keyboards, mice, and
joysticks. There are several components th at make up Managed DirectX, including Direct3D,
Draw, Input, Play, Sound, AudioVideoPlayback, Diagnostics, and Security, but for this
introductory chapter, we’ll lim it ourselves to the concepts and techniques relating to
DirectDraw, Sound, and Input. We’ll also use this chapter to introduce several game
algorithm s and the concepts of character development, anim ation, collision detection, and
artificial intelligence, as well as techniques to display both hand-draw n and rendered
graphic. The benefits to using M anaged DirectX include the elimination of the Component
Object Model (COM) interoperability layer, which decreases code size while improving
performance.
Inside DirectX:
DirectX gains its speed by bypassing the standard Window’s API; there are two
underlying layers that interface with DirectX: the HAL (Hardware Abstract
Layer), which interfaces directly with our hardware, and the HEL (Hardware
129
C# and Game Programming
Diagram
3.1.
DirectX
Referencing DirectX
To install DirectX simply download Microsoft’s SDK (Software Development Kit), avail
able free from Microsoft. You can find detailed instructions on the CD included w ith this
book. You’ll be prom pted with two choices, Debug and Release; both are adequate for our
purposes. DirectX is linked to our files using one of two methods; the first is to create a
standard Windows Application, loading the DirectX-components from the “Add Reference”
m enu (see Appendix I). Second, we can create our projects using the DirectX 9 Visual C#
Wizard, selecting “DirectDraw,” “Audio,” and “D irectlnput.” Note th a t Windows inserts a
certain level of base coding; while this coding can be a useful sta rtin g point, for study
purposes, we’ll delete all pre-generated code and begin from scratch (See Screen Shot 3.0).
130
Chapter 3: Writing Games
Project Settings
Specifythe DirectXcomponentsandsupport featuresfor your application.
r DirectPlay
Bnish parcel
If you were left on a deserted island and you could only bring one thing, what would that be?
I’d bring scratch, because everything is made from it.
W riting Games
Before we can write a program, game, or otherwise, we m ust first have an idea of w hat our
program is going to be about. Next, we’ll have to develop our idea using a list of thoughts
usually expanding in phases and alw ays increasing in detail. As we progress, we’ll also
w ant to tu rn this list into a formal document, or algorithm . This algorithm could th en be
enhanced both logically and pictorially through the use of m athem atical and graphical
designs. For the beginner, this usually m eans peeking into the C# language, but for the
moment we won’t really begin to write code. In gaming term s, this also often requires the
131
C# and Game Programming
ability to draw or the enlistm ent of a graphic a rtist, but for these examples, w e ll rely
prim arily on simple mouse and hand-draw n graphics. In addition, w hen we do begin to
convert to code, w ell also w ant to develop our tasks using the sim plest coding possible, but
w ith the added criteria th a t it is generic in nature. Remember, the higher the level of
abstraction, the greater the level of reusability.
Brainstorming
Brainstorm ing is the first creative step. It’s nothing more th an throwing out ideas, but it’s
also the foundation for everything th a t follows. Example 3.1 shows w hat we might w rite if
we were planning to create a sports game like Paddle Tennis.
1. The game should have two players. One placed on the right, the
other on the left.
2. There should be a net th a t divides the screen vertically.
3. The players should move freely, up, down, left, and right, b u t
they should not be allowed to leave the screen or cross over to
the other player’s side.
4. There is a ball th a t bounces around, which the players can
h it back and forth, w ith the upper and lower lim its used to
sim ulate the ground.
132
Chapter 3: Writing Games
5. The ball can increase in size when it’s moving closer to the net,
th u s sim ulating a 3D environm ent.
6. W hen one player m isses the ball, the other player should get a
point and/or win the serve.
7. The game should s ta rt w ith a simple m enu th a t allows players to
select the type of game, e.g., two players, one player, or demo
mode. (Note: One player and demo modes m ean th a t we’ll have to
w rite some simple artificial intelligence coding).
8. The game should also allow our players to quit a t any tim e via
the ESC key. Asking the players if they’re sure they w ant to quit
before actually ending the program could also be an option.
9. The game should be colorful with a blue background, yellow net
and two brightly dressed characters (it would be best if the tennis
ball actually looked like a tennis ball).
10. The game should also have sounds w hen the ball h its the ground
(edges of the screen) and/or the players. There should also be a
cheer from the unseen viewers when a player scores.
11. You m ay also w ant to p u t in a tim er th a t autom atically s ta rts
the demo mode if nothing happens for, say, two m inutes.
Finally, the game should reset itself to allow for repeated play.
Drawing Characters
Now that we have a general idea of what we’ll need pictorially, we’ll have to convert those ideas into
actual illustrations, and then we’ll have the fun task of figuring out how those images are going to be
manipulated. The actual designs aren’t really that important, but the steps used to access and complete
those designs are. The first step then is to familiarize ourselves with how the graphic tools work in this
new environment. Note: If you’re not an artist not to worry, the CD-ROM includes a complete list of
predrawn images relating to all ofthe games listed.
Tb begin, Fll assume you’re sitting in front of your computer with your .Net compiler fully loaded
and that you have already selected both the “New Project” listing and the ‘Windows Application’’icon
Note: do not confuse this application with the console version used in the pervious chapters). Now
change the name ofthe project to “Chapter3” and press “OK’(see Screen Shots 3.1-3.3).
133
C# and Game Programming
I n0^E 8l H ew P ro je c t fx ■
What’ s New
i j | Visual Studio Solutions
% #* i£I
A5P.nct web ASP,NET web web control
Or fine Ccmrnur Appfcation Service library
TPMorjt Help
0 Bufd EitotL . *X
v Description
Cfckhereto add* task
File £dt View Project Bufcl Debug Data Fgrroat Tods Window Help
.
Start Page Form I .cs [Design] |
Screen
Shot
3.2.
134
Chapter 3: Writing Games
3
.............................................
| using System. D m w i n g ?
i usin-3 System.Collections;
j using System.ComponentModel;
using System.Windows.Forms;
| using System. Data;
L
g namespace Chapter3
Screen
/// <sun*aary>
Shot /// Suaauary d e s c r ip t io n f o r Forml.
/// </3unwary>
3.3. p u b lic c la s s Forml : System.W indows. Forms.Form
{
/// <8uw»arv>..................................
if1
Task List - 0 Buld Error tasks shown (filtered)
! y Do*cr<Jtion
I C ‘<k here to odd a new task
The first screen you’ll see is only the visual portion of our program; to open the
text portion, simply double click on that grid (see Example 3.2 on the CD-
ROM).
Next, we’ll w ant to open a new graphics file. To create such a file, simply click the
“File” m enu and select “New,” and th en the secondary “File” listing. A second window
labeled “New File” should appear with a host of options; select the icon titled “Bitmap File”
and then press “Open” (see Screen Shots 3.4 and 3.5).
135
C# and Game Programming
j £
Task List - 0 Buid Erri
2JTM
kLutIB Search fuwdt* for Exnptton |
“ 1 " 1 ~
Si
sKHHHSHfc
Screen
Shot
3.5.
pf|||I i l
.-.{SSSJSSfj
SSffiimprrttrI
ntHmgpj
From this point, we’ll use these tools in basically the sam e m anner as any
other graphics program ; in fact, if you prefer, you can ru n all your designs through an
alternative program , ju st as long as you m ake those files available to your project(s).
136
Chapter 3: Writing Games
The three characters we'll concern ourselves w ith are the two players and their tennis
ball. To shortcut this further, we’ll assum e th a t the two players will ju st be the reverse of
each other (see Screen Shots 3.6-3.8).
§] - S 9 & tl @ • f# 5core
!ra Q j O \ P -j|7]^ t \ ) A □ 0 » o © « o • • €u
% Colors 9 X sage j Fcrml.cs[Design] j forml.cs ; CtassS.cs I €lass2.s ; Clashes ; Ciass4..:; ; CiassS.ts I lerrasBaH to p P ta ye rl.b m p | < •:- x
m
Efe 0K View Project gold gebug loots Image Window Help
• 43 ’ • ► Ortug - j# Score
Screen
Shot
3.7.
- J C#42.<toe>M*«tt»K...
137
C# and Game Programming
mm
mm
■
8.| mmm
¥ mm '
mm
Screen
Shot
3.8.
Plotting Motions
The next step is to plot the motions of our players and their ball. The player’s movements are
a bit easier to define so we’ll discuss those first. The players have free and easy two-dimen
sional movement. Their playing field is limited to the screen size and they are not allowed to
cross into the other player’s area (see Example 3.3).
I
i
One-dimensional movement Two-dimensional movement
The ball, unlike the players, requires us to include diagonal movements, which techni
cally are still only two-dimensional movements; the added visual effect is im portant when
conveying the feel of free motion. This, however, still only totals six directions, since we won’t
allow the ball to travel directly up or directly down (see Example 3.4).
138
Chapter 3: Writing Games
t i ''vt/'
© ! ♦ ■ o h
* i
I 2D 8-directional movement
I
Again, the ball is not allowed to move outside the viewable screen, and it should
bounce off our characters. W hen a player misses the ball, it should autom atically reset to
the scorer’s side and position. Finally, the ball’s initial motion will be decided by a random
motion function, e.g., Random () rnd = new Random (). We’ll also w ant to add a random
change of motion as the players interact with the ball, and potentially, we may allow the
players to alter the ball’s path by striking it from different angles.
W riting an Algorithm
After brainstorm ing, choosing characters, and plotting their motions, the next logical step
is to weave those im ages into a program document or algorithm . An algorithm , as in tro
duced in C hapter 1, is an abstract, yet detailed, list of everything th at needs to occur inside
of a program. Since this is only a quick look at algorithm s, and since there are still several
program m ing aspects th a t haven’t been explained, once again we won’t worry too much
about completely defining all the details th a t m ake up this program. Eventually, however,
when our program s actually necessitate an algorithm ic breakdown, we’ll include all such
details (see Example 3.5).
139
C# and Game Programming
140
Chapter 3: Writing Games
7. Player Input
a. Key Controls: Assign player keyboard controls, escape keys
b. On Mouse: Assign player mouse controls
8. P layer Controls: Setting the ball to a random direction: W hen
converting directions to coding I often use th e num eric keypads
layout as my foundation (4 equals left, 6 is right, 8 is up, 2 is
down and so on). If we apply this technique to a function such as
rn d 0 and a random num ber count form 1 to 9 our game ball will
th en seem to have random motion. W rite a function to propel the
ball. As explained in an earlier section the ball will move in one
of six directions. This function th en modifies the balls location
continually in one of those direction based on th e selected path.
(Note: The functions call should be subject to th a t balls activation).
9. We should include sounds w hen the ball bounces: Sound effects
are sim ple, but im portant - a n enhancem ent th a t really m akes a
big difference in game program m ing. All the gam es have th ere
own pre-recorded sounds, b ut you’re welcome to replace them
w ith your own.
10. Check to see if the ball and players have collided (collision
detection II). The ball will bounce off the player: The actions of
the ball on the playing characters would be identical to th a t of
the ball and the wall if not for the additional p a tte rn s and added
random ness of srand. We’ve also considered allowing th e playing
characters to a lte r the balls course by h ittin g it form an angle,
but we won’t discuss how to im plem ent such details un til we’re in
the program m ing stage.
11. If the ball gets to the end of the screen and the player is not th ere
give the other player a point. Now, reset the ball: To add a scoring
point we sim ply increm ent the players score, but before
re sta rtin g or redraw ing the ball, we’ll have to reset/reassign its
location to the other p lay er’s side. To m ake things sim ple we’ll
ju st use the scoring p layer’s last position and the spacebar as the
shared serving key.
12. R epeat the loop until either player scores five points: We’ll
term in ate either the loop on request or when a certain score is
141
C# and Game Programming
142
Chapter 3: Writing Games
Paddle Tennis
.N et Library
Game Namespace
Initialization Controls
Diagram
3.2
Paint A.I.
Keyboard Events
J oystick Sub-Class
143
C# and Game Programming
upper left-hand corner and increase w hen moving both to the right, respectively, down
w ard as is shown in Exam ple 3.6.
O (40, 12)
(0, 25)
The value of x increases as the ball travels to the right and decreases as it travels back
to the left. The value of y behaves similarly, only its value increases as it travels down, and
decreases as it travels up. Thus, through a combination of these points our characters can
travel anywhere on the screen (see Example 3.7 on the CD-ROM).
Diagram 3.3.
DirectDraw.
Hardware
14 4
Chapter 3: Writing Games
M anaged D irectDraw is the sim pler of two graphical components used in M anaged
DirectX; the other Direct3D also includes two-dimensional application, offering support for
textures, increases speed, and alpha blending, etc. (see C hapter 5 for details).
To include DirectDraw w ell need to follow several steps. The first is to add the decla
ration private Microsoft.DirectX.DirectDraw.Device draw = null;. Here, the word draw
could be replaced with any variable name; examples include Draw, ScreenDisplay, device,
th e v a ria b le b e g in s w ith a n u ll v a lu e , b u t is la te r a s sig n e d as d raw = new
Microsoft.DirectX.DirectDraw.Device 0;* Next, w ell declare the prim ary and secondary
surfaces; the prim ary surface is the screen area used by the program , the secondary
surface is a buffered surface, which is switched w ith the prim ary surface after all charac
te r surfaces are included. The variable nam e prim ary is commonly used to represent the
prim ary surface e.g., private Surface prim ary = null; The secondary surface is common
dubbed offscreen or backbuffer, character surfaces often include descriptive nam es as in
private Surface PlayerLD raw = null;. A nother essential p a rt to creating our prim ary and
secondary surfaces is the concept of clipping. Clipping simply m eans to delete any graph
ics th a t go beyond the defined area. For example, through clipping, our little tennis player
would not be allowed to sneak off the screen and find his way into A tari’s pong. Using the
variable nam e clip is very common as in private Clipper clip = null; Here, we’ll also define
our area as in a simple rectangle, again the nam e destination is common among DirectX
program m ers e.g., private Rectangle destination = new Rectangle 0;* Now th a t we have
our prelim inaries in order, we’ll w ant to build a CreateSurface function. This function is
the setting for our description, primary, and clipper values as well as a crux for our bitm ap
references. Once all the components are in place, it becomes a simple m ater of setting the
coordinates of the surface and referencing the bitm ap (see CD-ROM’s Example 3.8).
145
C# and Game Programming
146
Chapter 3: Writing Games
Open File
lookfrl: j. )Term" “3 «*'£) I x G U S "Tools*
, Tennis .csproi.ciser
jM ■Mi i Jennis.sln
j i l AssefnblyInfo.cs 4Tenn.s-s.jo
History
’sgQCheer.wav TennisBall.bmp
(.^IV'/aH.wav
\m
My Ejects mi Open
a
Desktop
i
m
! Open Wfch...
| Send To ►
Screen
Shot
3.9.
&E
m
H3 m Create Shortcut
•S3 1 Delete
i ! Rename
lip
My Network
Rle £ Properties
Obin
ill t o obi
History
1 [fiB Chapter 3A1. csoro i
m
j4^ter3Al,suo Screen
My Projects
‘*^1 Forml.cs Arrange Icons By
Shot
Refresh
w 3.10.
Desktop
Paste Shortcut
Undo Delete Ctrl+Z
km New
Properties
My Network
Filename:
"3
Places Files of fcype: | a ! Files (*.*)
147
C# and Game Programming
Next, we’ll need to link these files to our current project. Note th a t included files such
as “headers” do not exist in C#.
4. From the C#’s compiler m enu, select “File” and th en the a ttrib u te
labeled “Add existing item (s)” Choosing th a t a ttrib u te will bring
up the corresponding m enu, nam ely “Add existing item —
YourProjectsNam eH ere” Again, m ake sure to rep eat these steps
for each item added (see Screen Shot 3.11).
Pi %Is AS iwiw 1 1
H StartPac Add E xistin g Item • Chapter3A1
Chapter3A1 if X
i My Projects
3.11 Cbss5.cs
Forml.cs
Psste
Paste 5horbcut
! Desktop
m New >
Properties
: JJ [
Favorites
\
Task List
Network
m F4e Qame: [
3
Places Flesof {ype: | c * Fites C*,cs)
3 Caocd 1.
Programming a Character
148
Chapter 3: Writing Games
O ur second step is to anim ate our first character. This is done through a com bination of
the O nPaint and OnKeyDown commands. Once again, we’ll use the increm enting opera
tor to change the characters’position, but this time we’ll also need to include the decrementing
operator for reversing th a t motion (rem em ber both of those examples are bundled w ithin
our first class, Anim atedlm age.es—see C hapter 5 for details). We’ll use the arrow keys to
control our characters (see Example 3.9 on the CD-ROM).
The player’s input is the data gathered by the OnKeyDown command. This is
translated into movements by the computer and allows us to change the
direction of the character. The player’s x and y components indicate the player’s
current position. The initial settings place our first character at about eye
level, but to the right of the screen (as in the accompanying sketch).
(577, 220) : ©
In the last section, we introduced the concept of data input through the keyboard. Our
first gamming model (Example 3.8 on the CD-ROM) included the GDI+ function OnKeyDown
(KeyEventArgs e), which Windows periodically references as users’ input is detected. Our
OnKeyDown function also included a reference to e.KeyCode, the Key Event A rgum ent
Key Code, which allowed us to read and respond to the input provided by our users. The
GDI+ model th u s offers us the sim plest way to derive our u sers’ intentions while still
confining us to a single function. D irectlnput, in contrast, forces us to take a more global
approach.
149
C# and Game Programming
using Microsoft.DirectX.Directlnput;
Next we will need to include a reference to th a t tim er, as well as an event handler:
Remembering to include our actually Keyboard_Tick function and the reference, we use:
K e y b o a r d .Start ();
Finally, w ell need to test this sequence (see Example 3.10 on the CD-ROM).
While the background color used to create the tennis ball bitmap is blue, the
ColorKey colorkey = new ColorKey (); and Ba l l D r a w .SetColorKey
(ColorKeyFlags .SourceDraw, colorkey) ; commands along with the
buffer .ColorFill (Color. Blue) ; actually allow us to reuse that drawing
with alternate background colors.
150
Chapter 3: Writing Games
th a t come with this reference, since the overuse of invalidating commands will cause undue
flickering and possibly m ake our games unplayable. For an interm ediate reference, we’ll
also w ant to localize our rectangles, which will reduce overall flickering (this will become
especially im portant when working with more complex games).
Our third step, although slightly out of phase with our algorithm, will be to demonstrate
these techniques. This task could be accomplished in a num ber of ways, but to get the best
results (as little flickering as possible), we’ll have to use our invalidation command sp ar
ingly, and thus we’ll only call th a t command when a change in imagery is absolutely neces
sary. For example, if the ball is active we’ll have to call it, and if a player moves to a new
position we’ll have to call it, but if the ball is in motion and the player moves, only the
predom inating ball movement needs to invalidate the screen, since the entire screen will
still be updated.
151
C# and Game Programming
word th is, as in this.O urO bject.V ector.ReadV alue (), depending upon th e type of refer
ence (see Exam ple 3.11).
// Default Constructor
public PaddleTennis () {
// Initialize the players
playerL = new Player(5, 225);
playerR = new Player (580, 225);
p l a y e r L .isActive = true;
p l a y e r R .isActive = true;
// Draw a box (x, y, width, height) that constrains each player
p l a y e r L .constraintBox = new Rectangle (0, 0,
(t h i s .C l i e nt Si ze .Width >> 1) - 10, t h i s .C l i e nt Si ze .He ig ht );
p l a y e r R .constraintBox = new Rectangle (
(this.ClientSize.Width >> 1) + 10, 0,
t h i s .C l i e nt Si ze .Width - ((t h i s .C l i e n tS iz e.Width >> 1) + 10),
t h i s .C l i e nt Si ze .He ig ht );
}
}
}
152
Chapter 3: Writing Games
should resem ble a t least a rough physical model (not to worry, it should all be common
sense stuff). The m odel w e ll use is based on th e num eric keypad/10-key system w ith
th e num bers in th e ir d efau lt positions (4 is left, 6 is rig h t, 7 is u p p er left, 9 is u p p er
right, 1 is lower left, a n d 3 is lower rig h t—8, 5, a n d 2 are not used). If th e order of our
num bers doesn’t seem to m ake sense, try looking a t them again from the point of view
of the keypad as shown in Exam ple 3.12.
This is also easily converted to code using a switch statem en t w ith the cases set to
those values (e.g., case 1:, case 2:, case 3:, etc.), b u t we’ll save th a t coding for later. O ur
next step will be to redefine or change the paths as the ball collides with the walls. Remem
ber th a t the ball is guided by an inherent force and when the ball is deflected, its path will
not be reversed or made random. Instead, we’ll use a simple conversion form upper right to
lower right and lower left to upper left. This can be expressed num erically as 9 to 3, 3 to 9,
7 to 1, and 1 to 7 (see Exam ple 3.13).
153
C# and Game Programming
Still words and pictorials don’t teach coding, so h ere’s a stand-alone example of a
bouncing ball (see Example 3.14 on the CD-ROM). My suggestion is th a t you study it, alter
the ball’s speed, size, and boundaries, then try to add the player back into the game. If you
can’t figure out the last part, don’t worry about it, I’ll definitely do it for you. Next up, we’ll
go back to our players and give them the ability to deflect the ball.
Incoming: 1 3
| 4 6I
7 9
Outgoing 9 7
I 6 4 I
3 1
154
Chapter 3: Writing Games
The num ber scheme for this example splits the num bers up horizontally ra th e r th an
vertically with 7 to 9, 9 to 7, 1 to 3, and 3 to 1. In addition, two alternate paths are intro
duced, namely path 4 (left) and path 6 (right). These will have to be handled with random
functions since they simply do not fall into our basic patterns of change. Reclaiming them as
diagonal paths will also be handled by randomization (see Example 3.16).
155
C# and Game Programming
Keeping score
Optimally, in order to maximize the reuse of our program’s coding, we’ll have to declare most
of our variables as members of a class. These members will normally be stored as private
members, thus, we’ll also have to create member functions (also known as methods) to access
these values. Methods are usually referenced in pairs: one to store the data and another to
retrieve it. At this level, however, we won’t worry too much about the details used to create
these classes, and instead we’ll focus on how to use them. The two key references th at control
the players’ scores are assignm ents and increm ents (see Example 3.17).
We also w ant to create overloaded versions of our increm enting and decrem enting
operators, which, of course, will be used to alter the players’ scores (see Exam ple 3.18).
156
Chapter 3: Writing Games
Game Controls
The next step is to create a real-tim e loop not unlike a console while loop, but this tim e
we’ll let Windows handle most of the work. Here, we’ll rely on our second class GameControls
(listed under GameState.es), which we will continually test to see if our value GameActive
is true. If the value is not true, then the playable portion of the game will term inate. We’ll
also use this class to define the game’s speed, i.e., the speed of the ball (see Examples 3.20
3.23).
E x a m p le 3.20.
GameState gameState = new G a m e S t a t e O ;
157
C# and Game Programming
E xam p le 3.22:
// End the game if either side has scored MAX_POINTS.
if (gameState.currentState == G am eState.S t a t e .Started &&
(playerR.score == MAX_POINTS || p l a y e r L .score == MAX _P OI NT S)) {
ga m eS t a t e .currentState = Ga m e S t a t e .S t a t e .Stopped;
}
We can also increase or decrease the playable speed w ith a simple call to the gam e’s
speed reference, gameState . currentSpeed; . Remember, increasing the value increases
the looping process, which subsequently increases the ball’s speed. The larger the value,
the faster the ball will move (this m ay seem odd to program m ers fam iliar with the older
C++ sleep function, since increasing th a t value had the opposite affect).
gameState.currentSpeed = SPEED_DEFAULT;
int speed = gameS ta te .currentSpeed;
The Net
We can draw a net and load it using a few simple commands such as Image DisplayNet ;
DisplayNet = I m a g e .F r o m F i l e (@ " c : \ G a m e s . N e t \ T e n n i s \ N e t .b m p " ) ;
this . A ut oSc rol lM inS ize = D i s p l a y N e t . S i z e ; , followed by a graphic reference
such as dc .Drawlmage (DisplayNet, 350, 0, 10, 5 5 0 ). Or, w e can use a function
from the list presented in the next section (see Example 3.24).
158
Chapter 3: Writing Games
if (theBall.direction == A n i ma te dl ma ge .EAST ||
th e Ba ll .direction == A n i ma te dl ma ge .NORTHEAST ||
t h e B all .direction == A n i ma te dl ma ge .SOUTHEAST) {
theBall.imagePosX = playerL.imagePosX + playerL.imageWidth + 1;
t he B a l l .imagePosY = p l a y e r L .imagePosY;
} else {
t he B a l l .imagePosX = p l a y e r R .imagePosX - t he B a l l .imageWidth;
t h e B a l l .imagePosY = p l a y e r R .imagePosY;
159
C# and Game Programming
Adding Colors
There are two very basic color references—background and foreground. We’ve already
referenced the background colors this.BackColor = Color.Blue;, which, of course, can be
changed to a whole range of references (140), not including any user-defined references
(as shown in Screen Shot 3.12). The foreground colors are equally obnoxious, I m ean
beautiful, and again, the sam e p lethora of choices is available. We can also set colors
using the b ru sh option, B rush YellowBrush = Brushes.Yellow;, and/or w ith the pen op
tion, Pen YellowPen = new Pen(Color.Yellow, 3);, where the “3” represents the thickness
of th e pen. Once we have declared a color, we m ight also th in k about using th a t color to
sp e c ify a b a s ic s h a p e — a s q u a r e , r e c ta n g le , c irc le a n d /o r e llip s e (see
Example 3.26).
th is.B a c k C o lo r = C o lo r .|
EfFiAliceBlue
D is p i a y C o m p u te r = Iir A n tique W N te n e s .N e
D is p la y H u m a n = I m a g e [?gj* Aqua N e tM
16 0
Chapter 3: Writing Games
x2 = lmagePosX+SCALE/2,
y2 = ImagePosY+SCALE
x+
Paddle Tennis GDI+: The GDI+ version of Paddle Tennis uses two basic shapes, the
F i l l R e c t a n g l e and the FillEllipse. The rectangle is used to create both the net and
the players (the coding for the net is identical to the Windows Forms version). The players
are constructed using a simple format, brush color, x-coordinate, y-coordinate, width, and
height. All colors need to be declared before being referenced, as in Br u s h Whi t e B r u s h =
n e w (Color. White);, etc. The x- and y-coordinates are governed by the object refer
ences, as in thi s .X and thi s .Y, for whichever instance to which they are declared. The
Scale component is a constant th a t is used to control the size; in this case, the value is 25,
so the w idth is 12 and the height 25, giving the paddle a rectangle shape.
The ellipse, used to represent the ball, is w ritten in the sam e m anner, as was the
rectangle; the color is entered first, followed by the x- andy-coordinates, the width, and
th en the height.
161
C# and Game Programming
public static extern long PlaySound(String IpszName, long hModule, long dwFlags);
Sounds may also be copied from the CD-ROM to local directories. Sounds are
listed according to their project reference (see C hapter3\projectl, project2...).
In addition to inserting coding for sound, we may also need to modify our com piler’s
settings to include the ability to access these sounds. Here you may need to add an addi
tional library reference or change some other settings within your project (see your compiler’s
documentation for details).
162
Chapter 3: Writing Games
using Microsoft.DirectX.DirectSound;
using Buffer = M icrosoft.DirectX.DirectSound.SecondaryBuffer;
using Microsoft.DirectX.DirectInput;
// DirectSound
sound = new M i c r o s o f t .D i r e ct X.DirectS ou nd .D e v i c e () ;
s o u n d .SetCooperativeLevel (this, C oo perativeLevel.Priority); }
Finally, we’ll w ant to reference the sound. Note th a t the file reference
can be either an audio data stream or a file nam e type. Setting the
cooperative level to default (default offering the highest level of
m ultitasking) its priority set to zero (for a complete list of settings see
Table 3.0).
163
C# and Game Programming
Methods.Properties: Description:
B u f f e r P l a y F l a g s .Default Default, the first property of the method
publ ic e n um Buf f erPla yF la gs
allocates to hardware and software.
B u f f e r P l a y F l a g s .L oc a t e i n H a r d w a r e Boolean type; sound supported through
hardware.
B u f f e r P l a y F l a g s .L oc a t e i n S o f t w a r e Boolean type; sound supported though
software.
B u f f e r P l a y F l a g s .L oo pi ng Looping, Repeats sound indefinitely.
B u f f e r P l a y F l a g s .T e r m i n a t e b y D i s t a n c e Selects buffer by 3D distance (farthest).
B u f f e r P l a y F l a g s .T e r m i n a t e b y P r i o r i t y Selects buffers by priority (lowest
priority).
B u f f e r P l a y F l a g s .T er mi n a t e b y T i m e Selects buffer by time (longest running).
164
Chapter 3: Writing Games
Next, we’ll w ant to add some button controls, like our players’ ability to serve the ball.
Again, this can be done w ith either an OnMouseDown or an OnMouseUp command (see
Example 3.30).
if (gameState.currentState == Ga m eS t a t e .S t a t e .Started) {
Serve ();
}
}
In addition, we’ll w ant to reference our cursors with the show and/or hide functions. It
is im portant to keep a balance between these two features by calling only one hide and one
show per cycle. If a program m er fails to keep track of these procedures, the hides and/or
the shows will end up overlapping and the cursor will be lost indefinitely.
16 5
C# and Game Programming
Finally, you may wish to alte r the icon used to represent your mouse as in the
arrow /hand, which can be done through a simple reassignm ent, e.g., C ursor.C urrent =
Cursors.Hand; (see Table 3.1).
C u r s o r .Current = C u r s o r s .AppStarting;
a
Appstart.ani
C u r s o r .C u rrent = C u r s ors.Arrow;
Arrow_m.cur
C u r s o r .Current - C u r s o r s .C r o s s ;
Cross.cur
C u r s o r .C u rrent = C u r s o r s .D e f a u l t ; Current System
Default.
C u r s o r .Current = C u r s o r s .Hand;
01
Harrow, cur
C u r s o r .C u rrent = C u r s o r s .Help;
5
■
H elpJ.cur
C u r s o r .Current = C u r s o r s .H S p l i t ;
Hsplit.cur
C u r s o r .C u rrent = C u r s o r s .IBeam;
BeamJ .c u r
C u r s o r .Current = Cursors.No;
NoJ.cur
C u r s o r .C u rrent = Cur s o r s . N o M o v e 2 D ;
Im_panhv.cur
166
Chapter 3: Writing Games
C u r s o r .Current = Cursors.NoMoveHoriz;
Im_panh.cur
C u r s o r .Current = C u r s o r s .No Mo ve Ve rt ;
il
Im_orgv.cur
C u r s o r .Current = C u r s o r s .P anEast; Ea
Im_pane.cur
C u r s o r .Current = C u r s o r s .P a nN E;
Im_panne.cur
C u r s o r .Current = C u r s o r s .PanNorth;
Im_pann.cur
C u r s o r .Current = C u r s o r s .PanNW;
Im_pannw.cur
C u r s o r .Current = C u r s o r s .Pa nS E;
Im_panse.cur
C u r s o r .Current = C u r s o r s .PanSouth;
■
.....
Im_pans.cur
C u r s o r .Current = C u r s o r s .PanSW;
Im_pansw.cur
C u r s o r .Current = C u r s o r s .P a nWest;
Im_panw.cur
C u r s o r .Current = C u r s o r s .S i ze Al l;
Trck4way.cur
C u r s o r .Current = C u r s o r s .SizeNESW;
Trcknesw.cur
C u r s o r .Current * C u r s o r s .S i z e N S ;
1; ^v?
Trckns.cur
C u r s o r .Current = C u r s o r s .SizeNW SE ;
Trcknwse.cur
C u r s o r .Current = C u r s o r s .Si z e W E ;
Trckwe.cur
C u r s o r .Current = C u r s o r s .UpArrow;
Up_m.cur
C u r s o r .Current = Cursors.VSplit;
Spilth,cur
C u r s o r .Current = Cursors.WaitCursor;
B
167
C# and Game Programming
// Directlnput
private Mi cr os of t.DirectX.DirectInput.Device mouse = null;
if (!Mouselnquire) {
DialogResult result = M e s s a g e B o x .Show (this,
"Do you want to enable the mouse?",
"Mouse Detected", MessageBox Bu tt o ns .YesNo,
MessageB ox Ic on .Question, MessageBoxDefaultButton.B ut to n1,
M es sag eBoxOptions.RightAlign);
Mouselnquire = true;
if (result == D ia logResult.Y e s ) {
MouseOverride = true;
}
}
The mouse also requires a tim er and event-handling references, as well as a sta rt up call:
M o u s e .Start ();
Example 3.30 replaces Example 3.29 for our DirectX version o f the game.
168
Chapter 3: Writing Games
m o u s e .SetDataFormat (DeviceDataFormat.Mouse);
mouse.Acquire ();
m o u s e .Poll () ;
if (MouseOverride) {
Stephen D. Bristow and Steven T. M ayer invented the joystick in 1975 (P atented 1977)
while working a t A tari Gam ing Systems; little did they know th en th a t th eir invention
would change not only the way games were played, but also the way they were perceived.
The ability to step away from the table—to shift the body and lean from left to right as our
characters stroll, jum p, and even fall—is simply im placable to the concept of game play
Today joysticks include features like program mable functions, rotating handles, on-board
processors, force feedback, and downloadable game-specific controller profiles. Designs in
clude throttles, game pads, gloves, and flight yokes; yet the basic concept rem ains the
same. Here we’ll w ant to include a very simple joystick design: basic two-dim ensional
m ovem ent w ith a single button reference. The steps th en mimic the steps used to set up
the keyboard. Device assignm ents are generally listed as private class m embers, includ
ing a tim er reference, e.g.:
169
C# and Game Programming
Finally, we’ll need to include a call to sta rt our joystick and the function used by our game
(see Example 3.31).
if (joystick == null) {
retur n;
}
j oy st ic k.Acquire ();
j oystick.Poll ();
JState = j oy st ic k.CurrentJoystickState;
p l a y e r R .direction = 0;
bool Joystick = false;
170
Chapter 3: Writing Games
Introducing Menus
A nother in te restin g featu re available to us as V isual C# program m ers is the ability to
create a host of m enus both visually and through basic text references. The visual method,
while straightforw ard, is not alw ays as complete as the text-based m ethod, hence the
need to u n derstand both techniques. O ur first look will be a t how to create a basic visual
m enu (this technique also applies to labels, buttons, boxes, pictures, etc.). F irst, we’ll
need to reference our design window (Forms.cs [Design]). Next, we’ll need to reference
the toolbox m enu (located to the left side of our screen) and choose the appropriate in te r
face (in this case, the M ain Menu). From there we’ll simply drag and drop th a t selection
onto our grid. (See Screen Shots 3.13 and 3.14).
171
C# and Game Programming
Ffe £<* tfovf Project guild fcebug Dflto loo b ^ndow yelp
Pj Porml .c»“ i
* Date
mmm
a #
.« Cexponents
“ 1* Pointer
Screen A LeW
& Unktebe)
Shot «ej Button
|»3 TextBox
3.13. warwenu p
F CheckBox
RadtoButton
L J GroupBox
4»j PictureBox
□ Panel
5 D OaUGrid m
i j j ListBox
* X
1 3 CheckedlistBox
t 3 ComboBox
............................................ ........................................... ...........................3
US* Llstview
CSpboard Rng ▼
General |reh Rciufts. j
pw Text8ox
1
F CheckBox
(* Rad«e...
P eroupeox
y g Picture... Si
Screen
Output » X
Shot
r ........ .......... .... — ........................... ..........................................................................................................3
3.14.
l 2 Task. List El Output | Q Search Resuks ;
172
Chapter 3: Writing Games
To add the appropriate m enu items, simply double click onto th a t m enu (or submenu)
and type in the appropriate heading(s) (see Screen Shot 3.15). For reference, I’ve labeled
those item s 1, 2, and 3. You should also notice the secondary listing available to the right;
clicking this option allows us to create additional subm enus (see Screen Shot 3.16).
^ Pointer
A Label
&UnkLaW
ltd Button
1*5 TextBox Screen
j | } MaWteru
F CheckBa< Shot
RedioB...
0 Groupecx 3.15.
S 3 Picture... I f mainMenul
ateUzl
General
<? X
- yjerosau V j s o j t f o r r n i . c s f D s s f e n J *
Bfe £ck 53ew Project BuW Qetug Data Tools &ndow t±e*p
fp * * q£ Q £P & % *•> * : p| * ► Debug 3 &* ?
i-t ml m + & &i # ft §t %%*
Screen
Shot
3.16.
173
C# and Game Programming
Now, simply switch back to the text portion of our project (Forms.cs) and note the
changes. Here w ell find everything from the basic references to the nam es we inserted as
m enu item s (see example 3.32). Of course, if we w anted to create these files by hand, it
would just be a question of inputting those references manually. It is im portant to rem em
ber to list each item, as well as th eir accompanying index points.
namespace Example32 {
public class Forml : S y s t e m .W i n d o w s .F o r m s .Form {
private S y s t e m .W i n d o w s .F o r m s .MainMenu mainMenul;
private S y s t e m .W i n d o w s .F o r m s .Menultern menulteml;
private S y s t e m .W i n d o w s .F o r m s .Menultern menultem2;
private S y s t e m .W i n d o w s .F o r m s .Menultern menultem3;
private S y s t e m .W i n d o w s .F o r m s .Menultern menultem4;
public F o r m l () {
InitializeComponent ();
}
this.mainMenul.Menultems.AddRange (
new S y s t e m .W i n d o w s .F o r m s .Menultem [] {t h i s .m e n u l t e m l });
t h i s .m e n u l t e m l .Index = 0;
this.menulteml.Menultems.AddRange (
new S y s t e m .W i n d o w s .F o r m s .Menultem [] {
t h i s .me nu lt em 2,
t h i s .m e nu lt em 3,
th is .menultem4});
t h i s .m e n u l t e m l .Text = "Menu";
174
Chapter 3: Writing Games
t his .m enultem2.Index = 0;
t h i s .m e n u l t e m 2 .Text = "One";
t h i s .m e n u l t e m 3 .Index = 1;
t h i s .m e n u l t e m 3 .Text = "Two";
t hi s. menultem4.Index = 2;
t hi s.m enultem4.Text = "Three";
From here, w e ll w ant to link those item s to a specific function and or a set of func
tions, depending upon w hat we’re using those item s to reference. In our key example,
the Paddle Tennis game, we’ll use these points to reference the gam e’s sta rtin g points,
the two-player, single-player, and demo version options (see Exam ples 3.33-3.36).
175
C# and Game Programming
p l a y e r R .imagePosX = 595;
p l a y e r R .imagePosY = 200;
p l a y e r R .score = 0;
p l a y e r L .imagePosX = 5;
p l a y e r L .imagePosY = 200;
p l a y e r L .score = 0;
t h e B a l l .isActive = false;
t h e B a l l .imagePosX = p l a y e r R .imagePosX;
t h e B al l.imagePosY = p l a y e r R .imagePosY;
C u r s o r .H i d e ();
Invalidate ();
}
176
Chapter 3: Writing Games
subject, but don’t let the simplicity of these references fool you—programming for artificial
intelligence can be surprisingly thought provoking, tactically tricky, and well w orth the
tim e it will take to m aster. To begin, we’ll focus on the key points needed to complete this
game; a model of tracking and random motion.
Tracking
Tracking, as its nam e implies, is the ability to keep track of, or follow, a moving character
as it travels across a predefined area. This is accomplished by an independent portion of
program m ing, a subroutine, th a t can either im plem ent position changes or send th a t
inform ation to a secondary subroutine. The coding used to track an object resem bles the
coding used to im plem ent our characters’ movements. The only difference is th a t it is
im plem ented by the com puter’s judgm ent, for example, when a comparison “says” th a t
the tracked object is higher or lower, allowing it to adjust its position. Unfortunately, this
technique h as one fault, which is th a t the com puter cannot m ake m istakes, and th a t
b reaks the prim ary rule of hum anistic realism . Luckily, we can overcome this need for
perfection by adding in random events, hence the necessity of applying these techniques in
unison.
Random Motion
In the last two chapters, we’ve used random num bers several tim es to create new inform a
tion and to dynam ically change the results of otherw ise predictable behaviors. This pro
cess is also very useful when attem pting to break the monotony of projected m ovements
and is the prim ary source of new input used by our artificial characters. The one key tw ist
th a t m akes this procedure a bit different is th a t we’ll use th a t random input to reduce the
artificial players’ ability to seek the projectile. The idea behind this m aneuver is to in
crease the level of error, and hence, the playability of the game (see Exam ples 3.37
and 3.38).
177
C# and Game Programming
s witch(theBall.direction) {
case 3: // ball moving southwest
i f (th e B a l l .imagePosY > p l a y e r R .imagePosY) {
if( th eB al l.imagePosY < t h i s .W id t h / 2 )
// move SW to spike
p l a y e r R .direction = A n i m at ed lm ag e.SOUTHWEST;
else
// move south to line up with ball
p l a y e r R .direction = A n i m at ed lm ag e.SOUTH;
} else
// move back to give playerR more time
p l a y e r R .direction = A n im at ed lm ag e.EAST;
break;
178
Chapter 3: Writing Games
O ur final construct is built using the nam espace Games and will include references to
classes and techniques tau g h t throughout this text. This version of Paddle Tennis re
quires DirectX 9 or higher; C hapter 3 includes four versions of this game (Forms, GDI+,
DirectX, and DirectX w ith GDI+). (See the CD-ROM for details). Gam eClasses is a com
mon utility used to define all aspects of our characters movement, including boundaries,
sounds, and life span (see Example 3.39/Tennis.C# on the CD-ROM).
Bonus Games
Before jum ping back into the thick of C#, I thought you m ight enjoy crunching out a few
more games. This will provide an opportunity to introduce a few more topics and some time
to improve upon our initial techniques. For this second game, I’ll assume th at you’ve already
m astered the techniques presented earlier and th a t you’d prefer a shorter review. I will,
however, still take the tim e to mimic the creation of the game and to give a realistic view of
how one might go about developing it (keeping everything in real time, of course).
179
C# and Game Programming
Brainstorming
180
Chapter 3: Writing Games
14. We'll also place a sun in the middle of the screen, and use a set
num ber of cycles to sim ulate the force of gravity pulling the ships
into the sun. Gravity will also make a sound as it pulls in the ships.
Screen
Shot
3.17.
Ships
181
C# and Game Programming
Screen
Shot
3.20.
The sun.
The movements for these characters will be simple, with one key set aside as a th ru st
and two others set to tu rn the crafts to altern ate sides (see Exam ple 3.41). We’ll continue
to use the arrow keys and the num eric keypad for m ovements. The left and right arrow s
will adjust the direction of the vessel, and the upw ard arrow key will be the th ru st. The
downward arrow key will revive the characters and send the ships into hyperspace, and
the zero key will fire weapons. For Player Two, <Q> tu rn s left; <A> tu rn s right; <X>
thrusts; <S> sends the ship to hyperspace, and the spacebar fires weapons. The angles of
motions are shown in Example 3.41.
E x a m p le 3.41. A n g le s o f m o tio n s .
We’ll also need two characters to represent th eir m issiles and another image to
represent explosions (see Screen Shot 3.21).
182
Chapter 3: Writing Games
Screen
Shot
3.21.
Finally, we’ll w ant to give our crafts some m om entum (m om entum being the force
th a t keeps ships gliding in one direction even after we’ve tu rn ed it to another). M om en
tum will fade w ithin a few program cycles, but the effects will combine when the th ru s t
key is applied at more frequent intervals (see Example 3.42).
Ship's Momentum:
(10, 10) (15, 10) (20, 10)
*► M i
* * *
m i5> ▼ 0 * ij)
183
C# and Game Programming
184
Chapter 3: Writing Games
18. Ask player(s) if they w ant to play again: Rem em ber a good game
loop should always allow the player(s) the option of playing again.
19. End or repeat game: Ending the gam ing loop in our case m eans
ending the gam e and retu rn in g to th e m enu portion. This allows
the users to either quit the program or continue on to another game.
(90°)
(135°) 7 8 9 (45°)
(225°) 1 2 3 (315°)
(270°)
185
C# and Game Programming
if (result > 8) {
result %= 8;
if (result == 0)
result = 8;
} else if (result < 1) {
result = (result % 8) + 8;
}
direction = result;
186
Chapter 3: Writing Games
// Asteroid collision?
if (useAsteroids) {
for (int i = 0; i < MA X_ASTEROIDS; i + + ) {
if (asteroids[i ].isActive) {
if (asteroids[i ].Intersects(player)) {
ShipCollided (player, n u l l ) ;
return true;
}
}
187
C# and Game Programming
if (joystick == null) {
retu rn ;
}
188
Chapter 3: Writing Games
j oy st ic k.Acquire();
j o y s t i c k .P o l l ();
State = j o ys ti ck .CurrentJoystickState;
if (player2.isActive == true) {
if (-400 < State.X && -600 > State.Y) {
p l a y e r 2 .R o ta te Di re ct io n(1);
Of course, we can also use a sm aller version of the sun to represent the ships as they
b u rst into flames (Remember: A ship th a t has been destroyed is not effected by additional
weapons fire, nor should it be effected by the sun’s gravity). Again, a combination of both i f
and s w itc h statem ents are used to reduce clutter.
OnPaint
We will override the Windows OnPaint method to create a simple, yet collective list of display
commands th at generate the visual portion of our game. It is im portant to include conditional
commands th a t restrict/control the direction of the ships and the exhaust (which will be inde
189
C# and Game Programming
pendent entities), and display and/or hide the asteroids, as necessary. We will use the OnPaint
method to display introductory statem ents as well as some background stars and the sun.
(see Example 3.50.) Asteroids are defined later in this chapter.
if (plEvent.isActive) {
try {
int X = p l a y e r l .imagePosX
+ exhaustImages[playerl.d ir e c t i o n ] .imageOffsetX;
int Y = p l a y e r l .imagePosY
+ exhaustImages[playerl.d i r e c ti on ].imageOffsetY;
destination = new Rectangle(X, Y, SCALE / 2, SCALE / 2);
b u f f e r .Draw(destination, ExhaustDraw [player1.dire ct io n],
D r a w Fl ag s.W a i t );
} catch (SurfaceLostException) {
CreateSurfaces ();
Defining Hyperspace
M ost of us see the world as a 4-dim ensional platform , i.e., x, y, z , and tim e, and this
severs us well in our daily lives. Yet, w hen working w ith the concept of space travel, we
have to consider the possibility of moving through a fifth dimension, a.k.a. hyperspace. In
190
Chapter 3: Writing Games
hyperspace, tim e, distance, and m atte r are irrelevant, given th a t they do not intersect
w ith us. To visualize hyperspace ju st imagine yourself watching television; see the box in
front of you as having all four dimensions. The actors move through th eir world the same
as we do, they age and live and die, but th eir dimensions (including time) do not effect us.
Thus, if we could reach into the box and take an item, if only to im m ediately put it back,
the item would appear to travel instantaneously in the actors’ world. Thus if we are inside
the Space F ighter game and our spaceship is moving through hyperspace, th en we’d see
our spaceship moving instantly from position to position. Of course, we as program m ers,
which would place us in a sixth dimension, can easily build a function th a t can sim ulate
such movement, as in a function to random ize th a t ships position (see Exam ple 3.51).
if (!isActive)
return false;
191
C# and Game Programming
return retVal;
}
Additionally, the W eaponLim its function will be used to access th a t rerouting sub
routine. The secondary purpose of this function, however, will be to term inate a weapon’s
fire if it fails to m ake contact w ith an object after a set lim it of 100 cycles. This com bina
tion will aid in creating th e illusion of a tru ly open environm ent (see Exam ples 3.53
3.54).
192
Chapter 3: Writing Games
try {
SoundBuffer = new SecondaryBuffer(MEDIA_ROOT + "Fire.wav",
sound );
SoundB uf fer .P l a y (0, Bu fferPlayFlags.Default);
} catch {
U t i l s .PlaySound(MEDIA_ROOT + "Fire.WAV");
}
break;
CheckMissileCollision (missile);
}
if (e.tickCounter <= 1)
m i s s i l e .isActive = false;
193
C# and Game Programming
DirectDraw provides us w ith several methods used to produce everything from basic
shapes to some intricate designs. Here, Fll introduce some of the alternative drawing tools
and m any of the techniques associated w ith rendered graphics. (For inform ation on re n
dered graphics using Direct3D, see C hapter 5.)
DirectDraw: Text
Before we begin to draw, first w ell w ant to learn to write. This is done using three simple
references, namely ColorFill, ForeColor, and DrawText. ColorFill is used to paint the back
ground, while ForeColor and DrawText are used to paint and display text, respectively.
Failing to assign a ForeColor or assigning a single color to both ForeColor and ColorFill
will result in undetectable text. The DrawText method includes four param eters: int X, int
Y, String, and, draw at last position (a Boolean type), where X and Y are C artesian coordi
nates, String is the content to be display, and the last param eter, draw a t last position, is
set to false, as it is superfluous (see Example 3.55 and Example 3.56 on the CD-ROM).
E x a m p le 3.55. T e x t d is p la y .
Chapter 3: Writing Games
DirectDraw: Lines
The sim plest image to draw is undoubtedly the straig h t line. Here, only two points are
required, P l (xv y x) and P 2 (x2, y2) (as defined by the C artesian coordinate system). A
stra ig h t line is created w hen these two points are connected. S traight lines can be both
horizontal and vertical; they require ColorFill and ForeColor references, as well as a call to
D r a w L i n e (int x., int y,, int x 2, int y 2) ; . Diagonal lines can also be created
using DrawLine, but if the line is asym m etrical it will appear coarse or jagged. In such a
case, a solution known as anti-aliasing is used. A nti-aliasing is a sm oothing technique,
based on shading, which is used to reduce sharpness. To the a rtist this would m ean apply
ing softer shades, shadows th a t follow the line; to the program m er this includes im ple
m enting new techniques (GDI+ offers S m o o t h i n g M o d e and P i x e l O f f SetMode). As for
DirectDraw, a more hands-on approach is required (see Exam ple 3.57 and Example 3.58
on the CD-ROM).
E x a m p le 3.57. L in e s d isp la y .
DirectDraw: Shapes
D irectDraw has only two basic shapes, the rectangle, and the ellipse. The rectangle is
referred to as a DrawBox, while the ellipse has three references DrawCircle, DrawEllipse,
and D r a w R ou nde dB ox . Here, C o l o r F i l l can be used w ith D r a w B o x to create solid rect
angles (see Example 3.59 and Example 3.60 on the CD-ROM).
195
C# and Game Programming
// DrawBox
destination = new Rectangle (100, 100, 150, 150);
b u f f e r .ColorFill (destination, C o l o r .Green);
b u f f e r .DrawBox (100, 100, 150, 150);
196
Chapter 3: Writing Games
if (!p l a y e r 2 .isActive)
return;
// Seek him o u t !
T r a c k ();
plLastDirection = p l a y e r l .direction;
if (rndNum >= 9) // 1/10 of the time
EngageThrusters(playerl);
else if (playerl.imagePosX > p l a y e r 2 .imageOffsetX &&
p l a y e r l .imagePosY < p l a y e r 2 .imagePosY &&
p l a y e r 2 .imagePosX - p l a y e r l .imagePosY ==
-1 * (player2.imagePosY - p l a y e r l .imagePosY)) {
FireMissile (playerl, playerlMissiles);
}
(int)Math.Round(rnd.NextDouble () * 10))
197
C# and Game Programming
switch(inbound.direction) {
case A n i m a te dl ma ge .S O U T H :
if (playerl.imagePosY > i nb o un d.imagePosY) {
if (playerl.imagePosX > i n b o un d.imagePosX)
tempDir = A n i m a t ed lm a ge .E A S T ;
else
tempDir = A n i m at e dl ma ge .W E S T ;
}
break;
case A n i m a t e dl ma ge .W E S T :
if (playerl.imagePosX < i n b ou nd .imagePosX) {
if (playerl.imagePosY <= i n b ou nd .imagePosY)
tempDir = A n i ma te dl ma ge .NORTH;
else
tempDir = A n i ma te dl ma ge .SOUTH;
}
break;
198
Chapter 3: Writing Games
if (tempDir > 0) {
Random rnd = new R a n d o m ();
if (r n d .Next (10) > 5) {
p l a y e r l .direction = tempDir;
p l a y e r l .Animate ();
}
19 9
C# and Game Programming
Gaining Momentum
Unlike our tennis game, we’ll also w ant to th in k about how the ships experience motion.
For example, how far should the th ru ste rs push our characters, and w hat happens if
players change course after they apply th ru sts? This question can be answ ered quite
simply through a solid function dedicated to the concept of m om entum . We don’t really
have to stress over any of the physical details; rather, we focus only on the appearance of
the movement. This can be accomplished through the use of some sim ple tim ers and
anim ation calls as shown in Exam ples 3.67.
200
Chapter 3: Writing Games
As w ith the previous characters, the asteroids should have unique p attern s of move
m ent. Here, the asteroids will both travel across the screen and change direction as they
are struck by players’ fire. The asteroids need to be rerouted to the opposite side of the
screen whenever those screen lim its are reached. Since we’ll be w riting for four asteroids,
we’ll conveniently use the four basic directions (upper right (9); lower right (3); upper left
(7); and lower left (1)—see Example 3.69).
201
C# and Game Programming
These method extensions also refer to secondary methods that are used to
discern between ship and asteroid contact, a.k.a. collision detection. Hidden/
lower level classes, while accessible through these methods, will not formally
be explained until Chapter 5.
Menus
As w ith Paddle Tennis, we will add in the appropriate m enu options, but this tim e we
won’t include any additional mouse controls (see Examples 3.70—3.73).
202
Chapter 3: Writing Games
p l a y e r l .imagePosX = SCALE;
p l a y e r l .imagePosY = t h i s .Cl ie n t S i z e .Heig ht /2 ;
p l a y e r l .score = 0;
p l a y e r l .isActive = true;
p l a y e r l .direction = A n i ma te dl ma ge .EAST;
t i m e r .S t a r t ();
}
203
C# and Game Programming
1. The game should have one player (a spaceship), which s ta rts in the
center of the screen.
2. The game sta rts the m om ent it’s loaded.
3. The player’s m ovem ent should be two-dim ensional in respect to the
screen, but it should include diagonal movement.
4. The ship should have a th ru st, but not a brake or reverse, allowing
m om entum to carry it forward.
5. The ship will have weapons, or at least one weapon, nam ely a
m issile th a t can be fired a t the asteroids. To keep things simple,
the m issiles won’t be able to injure our player.
6. We’ll use a black background w ith sta rs random ly placed across it.
7. The ship should m ake sounds including a th ru st, weapon’s fire,
and an explosion when hit. The A steroids should also m ake a sound
w hen they are hit.
8. The ship should not be able to fire w hen dead, w ith the asteroids
able to pass through the exploding vessel w ithout damage.
204
Chapter 3: Writing Games
9. The player will gain points for destroying the asteroids, losing
points when he crashes.
10. The player should have the stan d ard three lives, w ith an autom atic
game term ination.
11. We’ll include a comm and th a t allows the player to revive dam aged
ships; this control will also double as hyperspace mode.
The game will keep track of the players score, allowing for a saved
high score. (Note: the technique used to save scores will be
explained in C hapter 4.)
GDI+ Graphics
For our th ird game, we’ll w ant to replace our hand-draw n images w ith some rendered
examples. The ship represented in Screen Shot 3.17 can be replaced w ith a simple GDI+
D raw Pie command. Here, the changing angle, p l a y e r . s t a r t A n g l e (), readjusts our
ship, and hence only a single reference is required (see Exam ples 3.76 and 3.77).
Craft
x1 = ImagePosX, y1 = ImagePosY
p x2 = ImagePosX+SCALE, y2 = ImagePosY+SCALE
x3 = StartArc, y3 = Sweep Arc
Exhaust
x1 = ImagePosX+int, y1 = ImagePosY+int
x2 = int, y2 = int
205
C# and Game Programming
xl = ImagePosX, y l = ImagePosY+10
x2 = X+10, y2 = Y+10
x3 = X-10, y2 = Y-10
O ur ship’s exhaust is also based on the player’s position, but here we’ll tran sfer most
of the m athem atics to our Exhaust method listed as part of the subprogram Shapes.cs (see
Example 3.78).
Given th a t the asteroids are shared by both Space Fighter and A steroid Miner, it
seems only logical th a t their polygon constructor would be placed in the class (Shapes.cs)
ra th e r then in the actually program s (SpaceFighter.es andA steroidM iner.es). (See Ex
amples 3.79-3.81.)
206
Chapter 3: Writing Games
p i (x-5, y-10)
p8 (x-5, y+10)
p2 (x+5, y-10)
p9 (x-5, y+5)
p3 (x+5, y-5)
plO (x-10, y+5)
p4(x+10, y-5)
pH (x-10, y-5)
p5 (x+10, y+5)
p i 2 (x-5, y-5)
p6 (x+5, y+5)
p7 (x+5, y+lC)
E xam p le 3.80. D o P a in t.
public void DoPaint(Graphics g) {
// Draw asteroids
asteroids [0].Asteroid(g, B r u s h e s .R e d ) ;
asteroids [1].Asteroid(g, B r u s h e s .B l u e ) ;
asteroids [2].Asteroid(g, B r u s h e s .O ra n g e );
asteroids [3].Asteroid(g, B r u s h e s .Ye ll ow );
207
C# and Game Programming
t h i s .imagePosY+2*this.imageHeight/5),
new Point( th is .imagePosX-this.imageWidth/5,
t h i s .imagePosY+2*this.imageHeight/5),
new Poi nt (t hi s.imagePosX-this.imageWidth/5,
t h i s .imagePosY+this.imageHeight/5),
new Point( th is .imagePosX-2*this.imageWidth/5,
t h i s .imagePosY+this.imageHeight/5),
new Point( th is.imagePosX-2*this.imageWidth/5,
t h i s .imagePosY-this.imageHeight/5),
new Point (th is .imagePosX-this.imageWidth/5,
t h i s .imagePosY-this.imageHeight/5),};
The missile by comparison is the simplest of the set with a single call t o F i l l E l l i p s e ,
this coupled w ith a simple f o r loop allows for m ultiple im ages (see Exam ples 3.81 and
3.82).
Chapter 3 includes four versions of this game (Forms, GDI+, GDI+ with DirectX, and pure
DirectX; seeAsteroidM iner.es on the CD-ROM for details).
208
Chapter 3: Writing Games
Troubleshooting
H ere we are again, back in troubleshoot. This tim e, however, we’re more like seasoned
veterans, working through the details of games th a t seemed foreign to us just a few weeks
ago. We’ve built the stan d ard games, we modified them once, twice, a th ird tim e maybe,
and now we’re ju st trying to figure out the end pieces. Sure, th e re ’s obviously som ething
wrong, but try looking a t it another way—look how far we’ve come. Moreover, if it takes a
few more days to reach th a t next level, well then, th a t’s w hat it takes.
The problems and solutions found in this section are exclusively for DirectX 9.0, listed
under the categories of Installing, DirectDraw, D irectlnput, and DirectSound. If you have
any other compiling or troubleshooting questions, please see the troubleshooting sections
in the last two chapters.
W hen installing DirectX, it’s im portant to rem em ber to un in stall the previous or
even th e sam e version of DirectX before installing either a new compiler or a new SDK.
Installing the SDK w ithout first removing the old version will result in a bad installation.
D irectD raw ’s errors seem to center around the bitm ap. First, if you attem p t to load
any file type other th a n bitm ap, you’ll have an error. Second, if the program fails to find
the designated bitm ap, you’ll have an error. Third, if the program attem pts to display the
bitm ap anyw here but inside its designated area, you’ll have an error. Fourth, if your
program attem p ts to display a bitm ap before the last bitm ap was draw n, you’ll have an
error. Of course, the first two errors are physical in n a tu re (a moved file, a m istyped
format); it’s actually only the second two th a t can be rem edied through code m anipula
tion. Here, we’ll have two choices: 1) to include a try-catch block to bypass the exception or
2) to use an ignore exception (see Exam ples 3.83 and 3.84).
209
C# and Game Programming
Directlnput
The most detrim ental error caused in D irectlnput is a crash w hen the com puter cannot
findyour joystick. If you Ve included the i f ( j o y s t i c k == n u l l ) { r e t u r n / } s ta te
m ent, then this error should have been averted. Therefore, if you're still having trouble,
the problem is probably more along the lines of not being able to get our inp u t devices to
work. L et’s begin w ith the joystick.
The Joystick
Rem ember th a t I cautioned you about th e S t a t e setting, as in S t a t e . X and S t a t e . Y .
The r a n g e here could be off; you should try m anipulating the input range itself, perhaps
s e t t in g i t to 0,1. H ere you’d be looking for a response in either direction; again, if you get
o n e r e s p o n s e , you’ll be able to find the others.
Another possibility is th a t you’ve improperly setup your bitmap; does it move with the
keyboard? If not, can you set it to move on a for-loop? Check for a changing variable or an
invalidating statem ent. Does the joystick’s input include an invalidating statem ent? Do
the pre-assem bled program s work w ith the joystick? How about a th ird p arty game? If
you’re using a special type of joystick, like a steering wheel or m ultiple joysticks, try
replacing them with a simple two-button pad. (For additional possibilities read this section’s
portion on the keyboard.)
The Keyboard
Here you’re far more likely to have forgotten something. A missing command: did you
forget to include a K e y b o a r d . S t a r t () ? Did you include the tim er coding? Rem ember
th a t the key states began with the lowest setting and worked their way through to the top;
d id you s ta rt the search a t a different point? Also, check the obvious; did you forget to
in c lu d e an invalidating reference? (For additional possibilities read this section’s portion
on the joystick.)
210
Chapter 3: Writing Games
The Mouse
Again, w ith the mouse you’re more th an likely to have forgotten something. Forget
ting to include the M o u s e .S t a r t () and/or M o u s e _ T i c k are the most common errors.
A nother problem w ith D irectlnput’s mouse is th a t it tends to override the other input
device, hence, the need for mouse inquiries (see D irectlnput: the Mouse for details).
DirectSound
DirectSound cannot play compressed audio data. This is compounded by the fact th a t
DirectSound does not te st for faulty audio data. This issue is best solved by testing the
wave files used w ith your game. Replacing a questionable file w ith a known good file
usually helps in identifying the problem. The try-catch block can also be used, but this
tends too merely hide the problem. O ther problems include corrupt or missing wave files.
211
C# and Game Programming
Things to Remember
1. Game program m ing s ta rts w ith an idea; first you brainstorm and
th en you refine. Use diagram s and an algorithm as necessary.
2. Always list algorithm s in English, not code—you won’t alw ays
know w hat language you’ll need to use for th e program .
3. Use top-down design to simplify your task s and w rite your code
in m odules so th a t they can be reused.
212
Chapter 3: Writing Games
1. Using w hat we’ve discussed in the last th ree games, rew rite
Paddle Tennis to include th ree characters on each side. These
players should move in unison, i.e., all th ree characters should
play as one. Give this altered game a new file nam e and title
(soccer would be a good choice). You could also lim it the scoring
area w ith a goal post, redesign the ball, etc.
2. Using Space Fighter, add a second computer-controlled spaceship
th a t come out only when users choose the deluxe version.
3. U sing A steroid Miner, rein sert the com puter as an opponent. Use
the d a ta type bool to include th a t choice. Give yourself 25 points
each tim e th a t ship is destroyed; also, use a tim e delay to slow
the re tu rn of th a t ship.
213
I found Rome a city o f bricks and left it
a city o f Marble.
-A ugustus C aesar
Arrays
Arrays are referenced values associated with the collective heap. They are instances of the
Base Class Library and th u s considered objects, which also m akes them subject to the
autom atic garbage collector. In th eir sim plest form, they can be thought of as a collection
2 15
C# and Game Programming
of variables used under one d ata type w ith sim ilar values and identities. These variables
often share the sam e program m ing task s w ith red u n d an t calculation and sim ilar or re
d undant concluding data. The inform ation generated is stored collectively, bu t also w ith
an independent reusability th a t reduces or prevents the need for repetitive coding.1The
sim plest way to dem onstrate the conversion from several variables to an arra y is to ex
press th a t process visually, as done in Exam ple 4.1.
As you can see, the first line of code represents the declaration of five variables and the
th ird line represents a value equivalent to five variables. The a rra y ’s components are
broken-down in Example 4.2.
1 The idea of con vertin g several sim ilarly s tru c tu re d variables to a single o r m u ltifu n ctio n a l a rra y
p re da te s th e o rigin s of both C ++ and C. A rra y s could also be th o u g h t of as th e fa th e rs and
nnanHfathers of s tru c tu re s and classes, respectively.
216
Chapter 4: Arrays, Pointers, and Strings
Component num ber [5] is not a usable variable and instead holds the null character th at
term inates the line. Additional indexed variables (for example, num ber [6], [7]), will also
exceed the a rray ’s declared space, which may not be flagged as a compilation error.
In Example 4.2, the first value is zero (not one).2 In addition, you might conclude
that this array should hold six values since number [5] was not used. This
conclusion would be in error since C#, like C/C++ before it, withholds that last
space as a termination marker. C#, however, does not use the zero-null character
namely “\ 0 ” to assign that value. Our first chore then will be to convert a simple
singular variable program into one that can take advantage of the new array
format (the potential of arrays will become obvious very shortly).
namespace Chapter4 {
class Classl {
static void Main() {
string input;
2 In C#, as with C /C + + and assembled languages, the array’s numeric notation can be seen as a measure of
the distance from one space in the array to another. Since the firs t space has no space or distance from
itself this would in fact be noted as zero. Although it is possible for higher-level languages to a lte r this v r L ~
unepufeps'bre^Git11.1,07 Jn?rap|L»rtfceedi v?s'L,tbc't.,'?i!Jw*6s,7i5,L o n ^ n rt,+Fbse^^i'dfc!S7i i^ G f
217
C# and Game Programming
namespace Chapter4 {
class Classl {
static void Main() {
string input;
char[] student = new c h a r [5];
218
Chapter 4: Arrays, Pointers, and Strings
In addition to displaying the values as fragm ents, we can also display them as a
whole (see Exam ple 4.5).
namespace Chapter4 {
class Classl {
static void Main() {
string input;
char [] students_grades = new c h a r [5];
C o n s o l e .WriteLine () ;
219
C# and Game Programming
// all in one
i n t [] arrayl = new int[7] {16, 15, 12, 99, 31, 2, 34};
// split
int[] arrayl;
arrayl = new int[7] {16, 15, 12, 99, 31, 2, 34};
// shorthand
i n t [] arrayl = {16, 15, 12, 99, 31, 2, 34};
// all in one
doublet] array2 = new double[4] {16.5, 54.95, 3.14159, 34.0};
// split
doublet] array2;
array2 = new doublet4] {16.5, 54.95, 3.14159, 34.0};
// shorthand
doublet] array2 = {16.5, 54.95, 3.14159, 34.0};
// all in one
chart] array3 = new char[13] { 'a1, 'b', fc f, 'd1, fe', !f 1, 'g' ,
1h ', 'i ', 'j ', 'k ’, ’1' , 'm '} ;
// split
chart] array3;
array3 = new c h a r [ 1 3 ] {'a', 'b', 'c1, 'd', fe', 'f', fg',
'h ', 'i ', 'j ', 'k ', '1' , 'm ' };
// shorthand
chart] array3 = new char[13] {' a1, !b', 'c', fd', 'e', 'f', 'g1,
220
Chapter 4: Arrays, Pointers, and Strings
// all in one
i n t [] array4 = new int [] {1, 2, 3};
// split
i n t [] array4;
array4 = new int [] {1, 2, 3};
// shorthand
i n t [] array4 = {1, 2, 3};
Here, the brackets are used to indicate that a value is an array. The assignment
statem ent is always enclosed by two braces and again, commas are required to
separate those values. Single quotation marks are also used to store single
character values and the assignments them selves can be used to replace the
formal parameters.
Another useful tool is to include a string value reference, replacing the older value
type character array w ith a dynamic value. This new form at elim inates the need to
m ake a rb itrary guestim ations about string size, and th u s it will be m uch less likely th a t
w e ll have to tam per w ith the coding in order to deal w ith any unu su al changes (see
Example 4.8).
E xam p le 4.8. S tr in g v a lu e re fe r en ce .
221
C# and Game Programming
namespace Chapter4 {
class Classl {
static void Main() {
string input;
int[] childrens_ages = new int [20];
We can also pass arrays containing literal constants, such as ages [0], ages
[1], and ages [2], etc.
222
Chapter 4: Arrays, Pointers, and Strings
namespace Chapter4 {
class Classl {
static void Main() {
string input;
int[] childrens_ages = new int[20];
Ageism(ref childrens_ages[counter]);
if (childrens_ages[counter] > 6)
Console.WriteLine("Your child is to old.\n");
}
}
The procedure for passing an entire argum ent differs somewhat from the method used
to pass a single elem ent. For example, the initial identifying brackets are not required
when sending those values, but they are essential to the receiving statem ent (see Example
4.11). In C++, it was also im portant to include a secondary reference th a t included the
a rra y ’s size; however, this is no longer the case since an a rra y ’s length can always be
found using the length extension (included as a m ethod th a t is accessible by all properly
declared arrays).
223
C# and Game Programming
namespace Chapter4 {
class Classl {
static void Main() {
string input;
const int array_size = 20;
int[] childrens_ages = new int[array_size];
Of course, we could have rew ritten these values as int [ ] childrens_ages = new int
[20] and Ageism (childrens_ages, 20), but th en we’d also have to individually change
each value every tim e the classroom ’s size changed.
224
Chapter 4: Arrays, Pointers, and Strings
These steps may seem a bit redundant, but they almost become m andatory
when dealing with multidimensional arrays (see the next section).
Multidimensional Arrays
M ultidim ensional arrays (also known as multiple subscript arrays) are arrays specifically
declared to hold more th an one set of values. These values are usually linked in a way th a t
m akes viewing them sim pler th an just writing them as independent variables or singular
arrays. They are initialized in the sam e m anner as stan d ard arrays, only w ith the addi
tion of a few more brackets. The practicality of using m ultidim ensional arrays varies from
project to project, but in general, they tend to drain the system resources and are usually
computed slower th a n stan d ard arrays; thus, anything over four dim ensions should be
avoided (see Example 4.12).
namespace Chapter4 {
class Classl {
static void Main() {
string input;
char[,] students_grades = new char[5, 5] ;
225
C# and Game Programming
Console.WriteLinei
You also should have noticed th a t our first arra y didn’t have any individual values,
i.e., the elem ents of the first dim ension were actually only the first elem ent of each of
the secondary arrays. This is usually described as an array o f arrays, but th a t tends to
confuse people. The best way to th in k about it is as a set of single arrays listed together
in a single column as dem onstrated in Exam ple 4.13.
226
Chapter 4: Arrays, Pointers, and Strings
Ju st as standard arrays can be initialized, passed, and included as entire arrays inside
functions, so can m ultidimensional arrays. Although slightly different in appearance, they
follow the sam e rules and have the sam e basic lim itations. The next few exam ples show
how this type of coding is im plem ented (see Example 4.14).
The program in Example 4.14 accepts a list of six names of five letters each.
The values are stored in a multidimensional array (6x5).
namespace Chapter4 {
class Classl {
static void Main() {
string[,] names = new string[6, 5];
file(names);
}
227
C# and Game Programming
Three-Dimensional Arrays
Algebra uses C artesian coordinates to graph dimensions, e.g., x, y , and z. Physics uses the
letters i j , and k , which m ean exactly the sam e thing (see Exam ples 4.15 and 4.16).
i
Most program m ers use i j , and k to reference an array's memory locations, as well as
to represent nested loops, three-dimensional space, etc. The values for a three-dimensional
a rray are basically the sam e in coding term s, b ut the d a ta ’s reference points are quite
different, as shown in Example 4.17.
228
Chapter 4: Arrays, Pointers, and Strings
This cube shows us how the values are laid out from 0, 0, 0 to 3, 3, 2. We can assign
reference points such th a t i equals the list of arrays, j is the first value of each array, and
k is the last value stored for each list.
E xam ple 4.18. D eclarin g, in itia lizin g , and p a ssin g a th ree-d im en sio n a l
array.
using System;
namespace Chapter4 {
class Classl {
static void Main() {
char [, ,] names = new char[7, 5, 6] {
{
T'/ ' h' r 1 i 1i r ' s ' ,
i i
r 'i ’}/
* i ’a ’ / i i i
't '
s ’, r r r 1e ' } /
i ii i i
S 1, 1 1 ' r r t t ' t' r 1h 1 } ,
i \ 1s '\ t i ii
r ' i’ , 1S i
' r '
i
o ' , ' n 1r r ' y ' /
i i
t ’ a ' } ,
{
it 1e ', 's', ' t \ 1• '},
\n ’, 1F ’, ’o', 'r 1, * i/ ' t ' },
h ’, 'e' , ' '/ ’n 1, 'e 1, ’x ’},
t \ i it 1m 1, 'i 1, 1n ', 'u' },
t ', 'e ', ' 'y\ 'o' , 'u* },
{
r ', i i/ 'C' , 'o' , 1m 1, ' p '}.
u !, 't* , 1e ', 'r' , t i! 'w' },
i ', ’1 ’, '1', i i/ 1b ', 1e 1}/
it 'C , ' o ' , 'n 1, 'd' , 'u' },
o' , 't', 1n 1, ' q ' r '\n'},
{
a' , t i/ 't', 's' , 11 f },
(D
i 'o', i i 't'f 1h 1 },
r 'f t
229
C# and Game Programming
{
{' 'a' , ' r \ ’r', ’a ’, 'y '},
{' \ 's' , 'e' , 'q', ’u ’, 'e' },
{'n\ 'c' , 1e 1, * i '\ n ', »T * }
• r
i i
{'H\ ' I \ 'S' , f ’I', 'S' },
{' \ ’O ’ , 'N' , 'L' , ’Y ’, '
{
{ 'A', i i 'T ', 'E' , 'S', 'T ' }
r
{
{ 'W', 'X', 'Y', 'z ', 'a', 'b ' },
{ 'C', 'd', 'e' , 'f', 'g' f 'h' },
{ 'i ’, 'j', 'k', 'i', ’m ', 'n' },
{ 'o’, 'P'r 'q'. 'r', 's', 't ' },
{'u\ 'V, ' W , 'x', 'y' / 'z' },
}
};
Display (names) ;
}
Console.WriteLine ();
}
}
}
M ultidim ensional arrays are also considered to be either jagged (w ithout a constant
shape) or rectangle/square (to have two or more sides w ith the sam e length).
230
Chapter 4: Arrays, Pointers, and Strings
Sorting Arrays
Sorting, as related to an array, is the action of rearranging or reorganizing the order of
elem ents to m ake a particu lar task easier to follow. This usually involves some logical
reference point such as letters placed in alphabetical order and num bers listed in a
num eric order. The principle m ethod used to displace these values involves both the com
parison and reassignm ent of th a t data. The techniques used to sort these values range
from the very simple to the complex, b ut they all do pretty much the same thing; thus, the
need for alte rn a te techniques th en has more to do w ith the speed of the process th a n the
result. The sim plest of these is known as the bubble sort (also referred to as the sinking
sort); values are listed in a single array, compared w ith one another and swapped as
needed, until all the values are in the proper order. The word bubble is used to aid in
visualizing the sm aller (lighter) values rising to the top and the word sinking is used to
visualize the larger (heavier) values sinking to the bottom. The coding for this type of sort
is also very straight forward—see Example 4.19.
namespace Chapter4 {
class Classl {
static void Main() {
const short array_size = 12; .
i n t [] simple_array = new int[array_size] {
31, 31, 54, 0, 60, 35, 34, 29, 18, 17, 13, 10};
231
C# and Game Programming
my_array[j] = m y _ a r r a y [j+1];
m y _ a r r a y [j+1] = temp ;
Conso le .W ri te Li ne ("\nsorting...\n" +
"\nln ascending order");
for (int i = 0; i < size; i + +)
C o n s o l e .WriteLine (" {0}", m y _ a r r a y [i ]);
Searching Arrays
There are two basic types of searches th a t are useful and relate directly to data stored in
an array. The first is the linear search, which, as its nam e implies, is a consecutive
comparison th a t tests each elem ent un til the correct inform ation is found. This is a very
common and particularly useful search algorithm , especially when dealing w ith random
or u n related d ata th a t cannot be sorted. The second, also considered the more efficient
search, is the binary search. This search divides and compares two criteria, where the
total value is divided into two sets and the irrelevant set is discarded. This process is
repeated as m any tim es as possible before reverting back to a basic lin ear search. Both
searches are considered effective, but the binary search is preferred when dealing w ith
longer, sortable data stream s th a t require repeated searches (see Examples 4.20 and 4.21).
The binary search also requires th a t the data be presorted; the presorted data can also be
stored as a secondary file, thus, elim inating the need for continuous resorting.
namespace Chapter^ {
class Classl {
static void Main() {
string input;
const int array_size = 100;
232
Chapter 4: Arrays, Pointers, and Strings
CreateArray(our_array, array_size);
namespace Chapter4 {
class Classl {
static void Main() {
string Screenlnput;
const long array_size = 100;
long[] our_array = new long[array_size];
long input;
233
C# and Game Programming
CreateArray (our_array);
BubbleSort (our_array);
while (true) {
C o n s o l e .W r i t e L i n e ("Enter a number between 1-100:");
Screenlnput = C o n s o l e .R e a d L i n e ();
input = long.Parse(Screenlnput);
if (found)
Console.WriteLine("Value f o u n d !");
else
C o n s o l e .W r i t e L i n e ("Value not found!");
found = false;
}
}
234
Chapter 4: Arrays, Pointers, and Strings
}
}
C on so le .W ri te Li ne ("\nsorting..A n "
+ "\nln ascending or der");
Co ns ol e. Wr it eL in e();
}
Dynamic Arrays in C#
The word dynamic is defined as the ability to adapt or alter an otherwise restricted set of
coding. The m ost prom inent example of this is the dynamic variable (what we think of as
235
C# and Game Programming
the standard variable). This variable, unlike a “constant,” can be adjusted to virtually any
value both a t compile tim e and during execution. While the definition of the C# array is
far more dynamic then th a t of the C++ or C version, it is still a constant param eter th a t
cannot be changed while the program is in motion. We can, however, set up arrays to include
dynamically calculated assessm ents th a t occur a t runtim e using a nonconstant integer
variable type. Again, this is fairly sim ilar to the method used to create dynamic arrays
under Native C++, with the coding actually m atching the basic C# references.
The most inconvenient aspect of declaring an array is in its requirem ent of a constant
variable, or literal constant, which always forces the program m er to make a guestim ation
th a t can lead to arrays th a t are either too small (making them incapable of the task) or
oversized (unnecessarily tying up much needed system resources). The solution to both of
these problems lies in the use of dynamic arrays. Dynamic arrays, as the term implies, are
arrays th a t do not require predeterm ined constants a t declaration, but they do require a
constant size once th at value is assigned, which is almost the same thing, but it does offer up
a few new options.
Since C# always uses the n e w keyword to declare its arrays, we won’t actually have to
change the way we reference those values to m ake them dynamic. In addition, since the
.Net structure offers a m anaged heap, we won’t need to refer to a deallocating m ethod (as
was done with the word delete in C++). We should, however, at least formally define the word
new. The keyword new allows us to declare dynamic arrays using standard variables, which
are then referenced from inside the heap. The heap is a special area of memory reserved for
dynamic arrays, reference variables, etc. To assign an array’s param eters, simply follow the
form at listed in Example 4.22 (char m y_array = new char [array_size];).
namespace Chapter4 {
class Classl {
static void Main() {
string input;
int array_size;
236
Chapter 4: Arrays, Pointers, and Strings
C o n s o l e .W r i t e L i n e ();
namespace Chapter4 {
class Classl {
static void M a i n (s t r i n g [] args) {
char[] integer = {'a', 'g 1, 'nf, 'u'};
237
C# and Game Programming
namespace Chapter^ {
class Classl {
public enum Months {
Jan = 1, Feb, Mar, Apr,
May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}
public enum Day {
AprilFools = 1, Birthday = 16,
XMas = 25, Feb2 9 = 29, NYeve = 31}
238
Chapter 4: Arrays, Pointers, and Strings
while (true) {
C o n s o l e. Wr it e("Enter the current Month (Example: \"Jan\" =
1) : ") ;
input = C o n s o l e .R e a d L i n e ();
TheMonth = i n t .Parse(input);
if (TheMonth == (int)Months.Dec) {
if (TheDay == (int)Day.XMas) .
Conso le .Wr i te Li ne ("Merry C hr i s t m a s !")
if (TheDay == (int)Day.NYeve)
Conso le .Wr i te Li ne ("Happy New Year!");
Pointers
A pointer is a special type of variable used to access the space in memory occupied by
trad itio n al variables. They point a t th e values held inside of those locations, and a l
though they are capable of assessing and even changing th a t inform ation, they rem ain
239
C# and Game Programming
only links to the address. This should rem ind you of the call-by-reference in C hapter 2.
These were, for the most part, lim ited pointers, which as you’ll recall, enabled us to both
access and alter the passed variables from inside our subprograms. This gave us the power
to use those values as if they were global variables, but w ith the increased plug-n-play
ability of local variables, which m akes pointers very useful, b ut also potentially danger
ous. Thus, C# allows pointer m anipulations, b u t only under the newly defined unsafe
mode.
Enabling u n s a fe Mode
Once a project is loaded into the .Net compiler, it becomes only a simple m atter of altering
th a t project’s build configuration to enable unsafe mode. From the folder labeled ‘View,”
select the file titled “Solution Explorer” (see Screen Shot 4.1).
(S’ Open
P - tsa OpeQWith...
* *
Sokjtion Exgloref Ctri+Atel ...^ O x
% pSetbry;
^ Cl^ss View
I
IttC o r r
% Server Explorer
Qrl+Shft+C
Ctrf+Afc+S
-I ja#Main(5tringOargs) 3
Pjji Resource View Ctri+Shtft+E
* * + s ir e o f ( u s h o r t ) );
- * + s i r e o f (s h o r t )); —
I gg* Properties Ijfindow H " + s i z e o f ( u in t ) );
” + s i z e o f ( i n t ) );
# Tootes Ctrt+Ak+X
A/
«* * + s ir e o f (u lo n g ));
Pendng CKeckirts " + s i r e o f ( l o n g ) );
Screen WebBrowser I » " + s i z e o f ( f l o a t ) );
■ ” + s iz e o f (d o u b le ));
C*h<r Windows i
Shot 1 » " + s ir e o f (d e c im a l));
Show Tasks i
4.1. loo ters i
D Fyl Screen Shft+AIOEnter
TaskUst
Od-fShlt*- .................. ____________ 1.......
> vr line
I________Click here to add a new task___________________
' Program 'C^Documents and Settngs\Piague\My Do
A second side window will open; m ake sure to highlight the project rath e r th an the file
name. Select “Properties,” the third icon, depicted in th a t sm aller window (see Screen Shot
4.2).
240
Chapter 4: Arrays, Pointers, and Strings
^ ° ' r*- m
Setting Visual€# ProjectProperties Classl.cs J SoMon Explww - ConsoleAppl.
jp-ta-sEBflF e
ConsoteApplicatian? Property Pages D
f^ T £orfigurabon: |Actfve(C>ebug) 3 0#tfonm: fAcUv«(>CT).. “3 iguration Manager... §ppfca0on?(l pro#
11 C j Common Properties BBBBI
t j Configuration Properties Conditional Completion Constan DEBUG; TRACE
8urfd Optimrte code False
Debugging Check for Arithmetic Overflow)! False
Advanced <=m?
3
Warning level Warning level I
Screen
B
TreatWarnlngsAsErrors Fake Shot
Output Path
XMl Documentation He
4.3
Generate Debuggng Informatics True
15 eg»t«r for COH nteroc Fofc*
241
C# and Game Programming
Pointer Variables
Pointer variables, like all o th er types of v ariables, need to be declared, b u t because
they req u ire a location to point to, th ey also need to be assigned before th ey can be
referenced. P ointers are also lim ited, like s ta n d a rd variables, by th e ir d a ta types and
rules of nam ing. Thus, it sta n d s to reason th a t p o in ters declared as in teg ers can only
point to sta n d a rd variables th a t were also declared as integers, doubles w ith doubles,
floats to floats, and c h a ra c te rs to ch ara c te rs. The one key v isu al difference w hen d e
claring pointers is th e in se rtio n of th e a s te ris k symbol (*), which is placed in fro n t of
th e d a ta ty p e’s reference. This a s te ris k tells th e com piler th a t th is d a ta type is a c tu
ally in ten d ed to declare p o in ter v ariables. The a ste risk , in th is case, is referred to as
the dereferencing operator, and the variable is referred to as th e dereferenced variable.
The second step is to assign the pointer; this is done by m aking the pointer equal to the
sta n d a rd variable. An am persand symbol (&) m ust precede th e sta n d a rd variable (am
p ersands are referred to as address operators). Remember, a pointer th a t has not been
assigned has nothing to point to, and cannot be used (see Exam ple 4.25). Note: There is
also a void d a ta type pointer, which is a generalized pointer th a t can be linked to any of
the oth er d a ta types. Void p ointer d a ta types are discussed la te r in th is chapter.
E x a m p le 4.25. P o in te r s .
using System;
namespace Chapter4 {
class Classl {
static unsafe void Main() {
int* pointerl;
int variablel = 1;
float* pointer2;
float variable2 = 2 . Of;
double *pointer3;
double variable3 = 3.01;
char *pointer4;
char variable4 = ’A';
pointerl = Svariablel;
pointer2 = &variable2;
pointer3 = &variable3;
pointer4 = &variable4;
242
Chapter 4: Arrays, Pointers, and Strings
We can also assign numeric values to pointers, but only after they have been assigned
memory locations. Again, we’ll use the equal sign to assign the values and the asterisk symbol to
reference the pointer. You should note th at since pointers place their new values in the memory
locations used by standard variables, any previous information is overwritten.
Pointers can also assign locations to other pointers—see the code in Example 4.26.
namespace Chapter4 {
class Classl {
static unsafe void Main() {
int* pointerl, pointer2;
// Warning, pointer3 is not an actual pointer!
int variablel = 1, pointer3;
243
C# and Game Programming
namespace Chapter4 {
class Classl {
static unsafe void Main() {
string input;
char race = 1Y 1;
244
Chapter 4: Arrays, Pointers, and Strings
input = C o n s o l e .R e a d L i n e ();
if (winner == 11 1)
C o n s o l e .W r i t e L i n e ("Whitefire");
else if (winner == '2')
Conso le .W ri te Li ne ("The Train ");
else
C o n s o l e .W r i t e L i n e ("Noisy G l ue ") ;
245
C# and Game Programming
*num2 = *num2 - 1;
C o n s o l e .Write (" .");
return(winner);
namespace Chapter4 {
class Classl {
static unsafe void Main() {
int numberl = 0, number2 = 0;
int* pointerl = &number2;
246
Chapter 4: Arrays, Pointers, and Strings
*pointerl = *pointerl - 1;
C o n s o l e .WriteLine ("{0} {1}”, numberl, nu mber2);
namespace Chapter4 {
class Classl {
static unsafe void Main() {
int numberl = 0, number2 = 0;
int* pointerl = &number2;
247
C# and Game Programming
numberl = 5;
*pointerl = 5;
numberl = numberl*=2;
*pointerl = *pointerl*=2;
C o n s o l e .WriteLine ("{0} {I}", numberl, number2)
numberl = numberl/=2;
*pointerl = ^pointer1/ =2;
C o n s o l e .WriteLine ("{0} {1}", numberl, numb er 2) ;
numberl = numberl/=2;
*pointerl = *pointerl/=2;
C o n s o l e .WriteLine ("{0} ;1}M, numberl, num be r2 );
numberl = 5;
*pointerl = 5;
numberl = numberl%=2;
*pointerl = *pointerl%=2;
Console.WriteLine ("{0} ;1}M , numberl, n u mb er 2) ;
248
Chapter 4: Arrays, Pointers, and Strings
249
C# and Game Programming
In addition, if a d ata type takes up 4 bytes per elem ent, it would produce
a larger span or cluster of data.
250
Chapter 4: Arrays, Pointers, and Strings
M anipulating strings using arithm etic is fairly straightforw ard, but we’ll still have to
m ake a few tiny adjustm ents (see Example 4.31).
You can also subtract one pointer location from another as long as they’re
referencing the same string. This special situation gives us an integer value
equal to the distance between the two. jr
The program in Example 2.31 converts letters from uppercase to lowercase and
back from lowercase to uppercase using string (address) arithmetic rather
. than the ToUpper and ToLower functions.
namespace Chapter4 {
class Classl {
static void Main() {
char input;
do {
input = c h a r .Parse(Console.R e a d L i n e ())
input = M y T o u p p e r (input);
Console.WriteLine ("{C}", input);
input = M y T o l o w e r (input);
Consol e. Wr it eL in e(input);
} while (input != 1z 1);
}
251
C# and Game Programming
return (input);
}
The v o id Pointer
The v o id d a ta type can be used to declare generalized pointers, th a t is, pointers th a t do
not ,as yet, have a set data type. These all-purpose pointers can be reassigned to different
d ata types w ith each function call or as p a rt of an abstract subroutine, v o id pointers can
be converted to any of the other data types and can be used as a sort of tem plate, always
changing to fit the needs of a program (see Exam ple 4.31).
namespace Chapter4 {
class Classl {
static unsafe void Main() {
short variablel = 20;
int variable2 = 20;
long variable3 = 100000;
float variable4 = 6. OF;
double variable5 = 123.456789;
decimal variable6 = 321.123456M;
Console.WriteLine (M {0}\n{l}\n{2}\n{3}\n{4}\n{5}\n",
variablel, variable2, variable3, variable4, variable5,
v ar iable6);
252
Chapter 4: Arrays, Pointers, and Strings
case 1i 1 : {
* ( (int *)values) -= 1;
break;
}
case 11' : {
*((long *)values) *= 2;
break;
}
case 1f 1: {
* ( (float *)values) /= 2;
break;
}
case 1d 1: {
* ( (double *)values) = * ( (double *)values) + 2;
break;
}
case 'e 1: {
* ( (double *)values) = * ( (double *)values) - 2;
break;
}
253
C# and Game Programming
default: {
C o n s o l e .WriteLine ("ERROR");
break;
}
E xam ple 4.33. M ean, m ed ia n , m od e, and ran ge w ith p o in ter s and arrays.
using System;
namespace Chapter4 {
class Classl {
static void Main() {
Random rnd = new R a n d o m ();
const short aSize = 25;
short [] random_array = new s h o r t [a S iz e];
Display(random_array);
M e a n (random_array);
M e d i a n (random_array);
M o d e (random_array);
R a n g e (random_array);
}
254
Chapter 4: Arrays, Pointers, and Strings
// The median is the number that sits in the middle of the list
// take the middle two numbers, add them and divide by two.
static void M e d i a n (short [] array) {
if (array.Length%2 > 0)
C o n s o l e .W r i t e L i n e ("The median is "
+ a r r a y [(array.L ength/2)]);
else
C o n s o l e .W r i t e L i n e ("The median value is "
+ (array[array.Length/2 - 1]
+ arr ay [a rr ay .Lengt h/ 2])/2 ) ;
}
Array.Sort(array);
255
C# and Game Programming
A r r a y .Sort(my_array);
Console.WriteLine("\nsorting...\n"
+ "\nln ascending order\n");
A r r a y .Reverse(my_array);
256
Chapter 4: Arrays, Pointers, and Strings
namespace Chapter4 {
class Classl {
static unsafe void Main() {
const int array_size = 5;
i n t [] kids = new i n t [array_size];
int* our_pointer = stackalloc int[array_size];
257
C# and Game Programming
namespace Chapter4 {
class Classl {
static unsafe void Main() {
int* pointerl, pointer2;
int** p ointer3;
int variablel = 1;
Pointers can normally be assigned to other pointers without this special notation
(as in pointerl = pointer2 ;).
Chapter 4: Arrays, Pointers, and Strings
namespace Chapter4 {
class Classl {
static unsafe void Main() {
int variablel = 1;
int* pointerl = &variablel, pointer2 = pointerl;
int** pointer3 = &pointerl;
259
C# and Game Programming
namespace Chapter^ {
class Classl {
static unsafe void Main() {
int variable;
int* pointer = &variable;
260
Chapter 4: Arrays, Pointers, and Strings
caused by moving between files. This keyword is prim arily used to convey global references,
and are usually of the object data types (as are structures and classes).
S t a t i c variables are specialized local variables th a t are not physically discarded with
their function’s term ination, but instead are stored and reapplied to those functions if and
when they are recalled. There are m any practical instances when this added flexibility
becomes im portant, and it helps us to remove any further need for global variables.
String Basics
The principles behind arrays and pointers should reveal th a t characters can be com
bined to total much more th a n the sum of th eir parts. One sim ple use of this collection
is simply to m ake a sentence such as:
261
C# and Game Programming
262
Chapter 4: Arrays, Pointers, and Strings
std::cout« S « std::cout«S; }
std::endi;}
Appends the original string with a limited portion of the additional string
using System; #include <iostream> # inc lude <iostream>
namespace Chapter4 #include <string> # inc 1ude <cstring>
{class Classl using namespace std; using namespace std;
{static void Main() void main(void) void main(void)
{siring S = "This is a string\n", {string S("This is a {char OurArray[50] = "This is a
Extra = "Good bye”; string\n"), string of data\n",
S = S.Insert(17, Extra.Substring(0,4)); Extra("Good Bye\n"); Extra[] = "Good Bye\n This
Console.WriteLineCfG}", S); } } } S.append(Extra, 0, 4); string is too long and would
std::cout« S « cause an error.”;
std::endl;} strncat(OurArray, Extra, 10);
Where 0 is the starting std::cout« OurArray «
point and 4 is the length std::endl; }
o f the attachment.
Compares two strings
using System; #include <iostream> # inc 1ude <iostream>
namespace Chapter4 # include <string> #include <cstring>
{class Classl using namespace std; using namespace std;
{static void Main() void main(void) void main(void)
{string S = ‘This is a string\n”, {string S(”This is a {char S[ ] = "This is a string\n",
Extra = “Good bye”; string\n”), S1[ ] = "This is a string\n”,
if(Extra.CompareTo(S) == 0) SI (This is a string\n"), S2[ ] = "Is this string larger?
Console. WriteLine( S2("Is this string larger? \n";
“They match!”); \n“); if(!strcmp(S, SI))
else if(S == SI) std::cout«
Console. Wri teLi ne( std::cout« ”1 can’t tell them a part \n";
They don’t match!"); "I can’t tell them a part if(strcmp(S, S 2 ) > 0 ) / / T > S
ft(sirmg.Equals(S, S)) \n"; std::cout«
Console. WriteLine( "Found!”); int test = "I think I was cheated \n"; }
if(stri ng.ReferenceEquals(S, S Sl.compare(S2);
Console. WriteLine("Found!"); if(test == 0) std::cout«
}}} "There equal";
else if(test > 0) std::cout
« "S2 is greater";
else if (test < 0) std::cout
« "SI is greater";
std::cout« std::endl; }
Compares a limited portion of string 1 to string2
using System; #include <iostream> #include <iostream>
namespace Chapter4 # include <string> #inelude <cstring>
{class Classl using namespace std; using namespace std;
{static void Main() void main(void) void main(void)
{string S = "This is a string\n", {int T; {char S[ ] = "This is a string\n",
263
C# and Game Programming
There are dozens more, all quickly accessible from the visual compiler’s pop-up
\ menu.
264
Chapter 4: Arrays, Pointers, and Strings
265
C# and Game Programming
c# C++
using System ; #include <fstream .h>
using System .IO ; void main (void)
{char output[80];
nam espace Chapter4 ofstream save;
{class C la ssl save.open("File.dat");
{static void Main () save « "This is a test!";
{StreamW riter S aveF ile = new save.close();
StreamWriter( @ "C:\M yFile.txt"); ifstream read;
SaveFile.W riteLine ("This is a test!"); read.open("File.dat");
S aveF ile.C lose(); if(re a d .fa il())
{ c o u t« "File not found!"
StreamReader R eadFile = new « endl;
StreamReader( @ "C:\M yFile.txt" ); return; }
siring M yFile = R eadFile.R eadLine(); w hile( !read.eof())
C onsole.W riteL ine(M yFile); {read » output;
R eadFile.C lose(); }}} cout « output « " "; }
c o u t « endl;
read.closeO; }
266
Chapter 4: Arrays, Pointers, and Strings
data type exceeds its preset range. Once a value exceeds th a t range, its variable reference
no longer produces the implied response, thus th a t program is considered corrupt and all its
data considered invalid. To protect against such errors, the designers of C# implemented two
options: first, we can include coding references such as the keywords checked and unchecked;
second, we can include a generalized compiler reference th at tests our code for us. To imple
m ent these references see Examples 4.38-4.30 and Screen Shot 4.5.
namespace Chapter4 {
class Classl {
static void Main() {
byte Max255 = 255;
C3 Common Properties
£3 Configuration Properties
I■ ■ ■ n
Condtoonal Compfabon Constan DEBUG; TRACE
fy BuiW Optriwecode False
Debugging
Advanced ABow unsafe code blocks False Screen
m m h m h h h Shot
Warnmg Level Warning level 4
Treat Warrings As Errors False
bhhnmhi 4.5.
Output Path bn\Debug\
XMl Documentation Fie
Generate Debuggng Wormatiot True
Recuse; forCOMtytnop iFatse
j OK | Cancel j [ Hefp |
S3 Tasklist H Ociputj
267
C# and Game Programming
From the “Solution Explorer,” modify the program ’s “Build” properties to include auto
m atic checking and then execute this coding.
C ontinuing from the last program , override the system ’s autom atic checking w ith
the keyword unchecked encasing the last block (see Exam ple 3.40).
namespace Chapter4 {
class Classl {
static void Main() {
byte Max255 = 255;
unchecked {
Max255 += 1; // this error will go undetected
}
}
}
}
268
Chapter 4: Arrays, Pointers, and Strings
one practical reason for using the g o to statem en t in C#, which is to allow for artificial
drops when dealing w ith s w itc h statem ents. Remember, C# no longer allows us to drop
betw een s w itc h statem en ts th a t contain executable statem ents, so g o to m akes a good
fix. C#’s g o to also has some lim itations, including not being able to jum p into localized
blocks, between classes, and it can’t (and shouldn’t) be used to alter t r y - c a t c h blocks, as
explained in C hapter 5 (see Example 4.41).
namespace Chapter4 {
class Classl {
static void Main() {
char Character = 11';
switch (Character) {
case 11 1:
Console.WriteLine ("1 and a");
goto case2;
case 12 1:
case2:
Console.WriteLine ("2");
goto case3;
case 13 1:
case3:
Console.WriteLine ("and a 3");
break;
}
Console.WriteLine ("Program Terminated") ;
}
}
269
C# and Game Programming
simply by using pointer notations for both singular and m ultidim ensional arrays. As a l
ways, the steps to create a game rem ain the same, only this tim e I’ll detail certain areas
th a t were cut short in the previous chapter and shortcut some others th a t were already
discussed in detail.
Brainstorming
In our fourth game, I see a wave of aliens sta rtin g a t the top of the screen and slowly
m arching downward. They’ll step from side to side, walking from one end of the screen to
the next, each tim e moving one step lower. They’ll have the power to destroy our ship with
energy blasts ju st as we’ll be able to destroy theirs. Finally, they’ll either crush us as their
lines reach our ship or we’ll destroy them all.
1. We’ll draw out four distinct aliens in four distinct lines (each
alien will have four copies of itself on th a t sam e line). And each
alien in th a t line will be a different color.
2. The aliens will w alk tow ard the right of the screen and th en
when a t the end, they’ll move down one step and proceed to w alk
to the left of the screen. Again, once there, they’ll move down and
proceed to the rig h t...
3. O ur p lay er’s character will be able to move both left and right,
b ut not up or down.
4. O ur character will be able to fire a weapon th a t will move
stra ig h t up—this beam will destroy any alien it strikes.
5. The aliens will also fire beam s at the character, and if they strike
it, the ch aracter will be destroyed.
6. The character will be given three chances (lives) before the game ends.
7. Also, the aliens will be attem pting to reach the bottom of the
screen—if th a t happens, the game ends no m atte r how m any
lives are left.
270
Chapter 4: Arrays, Pointers, and Strings
8. If all aliens are destroyed, a new set of ships will appear a t the top.
9. The destruction of the aliens’ ships will be scored and the scores
will be saved to a file th a t keeps high scores.
10. The aliens’ point values will be from lower (forward ships) to
higher (rear ships).
11. The aliens will move faster as th eir num bers dwindle.
12. The aliens will also occasionally fire a t random .
E x a m p le 4.42b. D e s ig n in g C h a r a c te r s .
u H I I X X
K H X X X
A A A A A
I I X X X X
X
271
C# and Game Programming
The aliens follow a simple preset pattern of movement, while the player is
as* given use of the keyboard. The controls will be set to values 4 (B) and 6 (a) with
the spacebar set up to release the character’s weapons.
BattleWave.cpp:
1. Setup Windows. This includes everything required by our
operating system and compiler.
2. W rite a set of functions th a t will anim ate our characters
(including alien/ hum an ships and weapons fire).
3. W rite a function to define screen lim itations.
4. Set up a keyboard function to include left and right m ovem ents
as well as a weapons key.
5. W rite a set of functions to control both the players’ weapons and
an artificially intelligent alien weapons control.
6. W rite a function to reset the aliens once the level is complete.
7. Access the two functions used to save and retrieve the players’
high scores.
272
Chapter 4: Arrays, Pointers, and Strings
O uter Loop:
18. Repeat the loop u ntil aliens reach our players’ y-axis values.
19. Ask player(s) if they w ant to play again. End or rep eat game.
Before going further, make sure everything is set up correctly (creating a new
project, a new source file, adding sound files, test compiling, and linking using
all of the previous game files—all of which is done as project4).
Drawing Characters
Our initial designs included only seven unique drawings, the four target images (each
reproduced five tim es using multiple colors), the targ et weapons/bombs (also reproduced
using m ultiple colors), and the single hum an image, as well as his two rockets/m issiles.
The four alien images include Bulb, Frog, Robot, and Eye, with the H um an playfully being
referred to as Gus (see Game 4 Designs).
273
C# and Game Programming
Game 4 Designs
Up • » y ® Jt I: f: £Ml ►Release ^ |#
□q j jPH<r \ ■> A □ ** -■% t.j„
^ Colors J |l X / | \Targetl.bmp meda\Target10.bmp | media\Targeti I.timp m e d la \T arg et!2.b < >
274
Chapter 4: Arrays, Pointers, and Strings
Ready
--------
| / start C2new.doc - Microsof... 8W - Microsoft Visual t-C4j.bmp • Ratnt 4k ' irKPM j
"'«■ M
□□
• T • *8 «*
E»s Ed* flew Project guild Qebug loots (mage Window Help
m m m u ..................................... ?
*
’ M i l l 'J i l l
H
j d
6 : I Magrrficatior.
Start a an ew do -Microsof. r*' 8W- PljosottVisual >. E>OK.bmp- Pwnt ^ i*, • “I -HPM
276
Chapter 4: Arrays, Pointers, and Strings
| D” O: M n: m * n w m
This set of polygons is used to represent B attle Wave’s rendered images. As w ith the
previous draw ings, these will be set to a 20x20 Scale w ith the position (x = image PosX,
y = imagePosY) being the center of the model (see the figures listed below). Note th a t
these polygons will also be incorporated into an inheriting class (see C hapter 5).
Alienl
pi (x-10, y-10)
*11 ' 2 5 p ll (x+10, y+10)
p2 (x-5, y-10)
3 pl2 (x-10, y+10)
IE
15 p3 (x-5,
Q pl3 (x-10, y+5)
p4 (x+5,
p 14 (x-5, y+5)
1H
p5 (x+5, y-10)
pl5 (x-5, y-5)
p6 (x+10, y-10)
pl6 (x-10, y-5)
P7 (x+10, y-5)
pl7 (x-10, y-10)
p8 (x+5, y-5)
p9 (x+5, y+5)
plO (x+10, y+5)
277
C# and Game Programming
Alien3
pi (x-5, y-10)
13 p2 (x+5, y-10) p9 (x-5, y+10)
12 3 p3 (x+5, y-5); plO (x-10, y-5)
p4 (x+10, y-5) p l l (x-10, y-5)
B 1 p5 (x+10, jr+lO) pl2 (x-5, y-5)
p6 (x+5, y+10) p l3 (x-5, y-10)
p7 (x+5, y)
ID p8 (x-5, y)
Alien4
pi (x-10, y-10) plO (x-5, y+5)
11 p2 (x+10, y-10) p l l (x-5, y+10)
IE H
p3 (x+10, y-5) pl2 (x-10, y+10)
15
p4 (x+5, y-5) pl3 (x-10, y+5)
p5 (x+5, y+5) P14(x-5, y+5)
13 1H 5
p6 (x+10, y+5)
1G R pl5 (x-5, y-5)
p7 (x+10, jr+lO) pl6 (x-10, y-5)
12 11 B p8 (x+5, y+10) pl7 (x-10, y-10)
p9 (x+5, y+5)
278
Chapter 4: Arrays, Pointers, and Strings
if (player.isActive) {
try {
destination = new Rectangle(player.imagePosX, player.imagePosY,
player.imageWidth, player.imageHeight);
buffer.Draw(destination, PlayerDraw, DrawFlags.Wait);
279
C# and Game Programming
if (playerMissiles[i ].isActive)
try {
destination = new R ectangle(playerMissiles[i ].imagePosX,
pl ay er M i s s i l e s [i ] .imagePosY, p l a y er Mi ss il es [i ] .imageWidth,
p la ye rM i s s i l e s [i ].imageHeight);
b u f f e r .Draw(destination, PlayerMissilesDraw[i ],
Dra wF la gs .W a i t );
if (targetMissiles[i].isActive) {
try {
destination = new Rectangle(targetMissiles[i ].imagePosX,
targe tM iss il es [i ] .imagePosY, targe tM is si le s[i ] .imageWidth,
targetMissiles[i ].imageHeight);
b u f f e r .Draw(destination, T ar ge tMissilesDraw[i ],
DrawFlags.Wait);
primary.Flip(buffer, FlipFlags.DoNotWait);
bu ff er .Dispose ();
The function Alien_Click, is required to test and compare the positions of the
first and last characters of our lines. The i f and if-else statements are used
to test the cycles, while the for statem ents are used to facilitate the
movements.
280
Chapter 4: Arrays, Pointers, and Strings
int newDirection = 0;
Random rnd = new R a n d o m ();
if (targets[0].direction == A n i m at ed lm ag e.SOUTH) {
newDirection =
(targets[0].imagePosX < t a r g e t s [0].c on st raintBox.Width / 2)
A n i m at ed lm ag e.EAST : A n i m at ed l ma ge .W E S T ;
} else {
for (int i = 0; i < N UM _T ARGETS; i + +) {
if (! t a r g e t s [i ].isActive)
continue;
if (targets [i] .imagePosX <= t a r g e t s [0].constrai nt Bo x.X ||
t a r g e t s [i ].imagePosX + t a r g e t s [i ].imageWidth >=
t a r g e t s [0].co nstraintBox.X +
t a r g e t s [0].co nstraintBox.Width) {
newDirection = A n i m a t e dl ma ge .SOUTH;
break;
if (newDirection == An i m at ed lm ag e.SOUTH) {
for (int j = 0; j < 5; j++)
targets [i] .Animate();
if (targets[i ].isActive && t a r g e t s [i ].imagePosY +
t a r g e t s [i ].imageHeight >= p l a y e r .imagePosY) {
E n d G a m e ();
}
} else {
t arg et s[ i].Animate();
if (rnd.N e x t (100) > 85)
if ((targets[i ].direction == A n im at ed lm ag e.EAST &&
t a r g e t s [i ].imagePosX < p l a y e r .imagePosX + 50 &&
t a r g e t s [i ] .imagePosX > p l a y e r .imagePosX) ||
(targets[i ].direction == A n im at ed lm ag e.WEST &&
t a r g e t s [i ].imagePosX < p l a y e r .imagePosX &&
281
C# and Game Programming
if (!isActive)
return false;
282
Chapter 4: Arrays, Pointers, and Strings
return retVal;
}
// Initialize p l a y e r ’s objects
player = new Player (0, 0);
p l a y e r .constraintBox = new R e c t a n g l e (0, 15 * SCALE,
C l i e nt Si ze .Width, C l i e nt Si ze .Heigh t);
pl a y e r .Rescalelmage(SCALE, SCALE);
p l a y e r .direction = Animatedlmage.EAST ;
Keyboard Controls
We’ll also w ant to give our player some simple keyboard controls; these controls should
lim it our player’s movement to only one dimension (see Example 4.48a).
keyboard = new
M i c r o s o f t .D i r e ct X.Di rectlnput.D e v i c e (Sy st em Gu id .K ey board);
keyboard.Properties.BufferSize = 8;
ke yb oa rd.A c q u i r e ();
283
C# and Game Programming
The basic joystick controls for B attle Wave are actually much sim pler th en the code used
to control Space F ighter and Asteroid Miner. T h a t’s because B attle Wave only requires
late ra l movement. This, however, affords us the opportunity to test the more advanced
features included w ith Force Feedback. Here we’ll im agine th a t each explosion creates a
ripple in space causing a quake-like effect th a t affects our characters’ ability to move. The
most im portant thing to rem em ber about Force Feedback is th a t it requires exclusive
device access (see Example 4.48b).
joystick = new
M i c r o s o f t .D i r e c t X .Di re ctlnput.D e v i c e (in st a n c e .InstanceGuid);
break;
}
joystick.SetDataFormat(DeviceDataFormat.Joystick) ;
284
Chapter 4: Arrays, Pointers, and Strings
j oystick.Acquire ();
j oy s t i c k .Poll ();
JState = j oy st i c k .CurrentJoystickState;
p l a y e r .direction = 0;
if (Joystick) {
for(int i = 0; i < 3; i++) {
p l a y e r .Animate ();
p l a y e r .C o n s tr ai nT oB ox ();
}
I n v a lid at e();
}
285
C# and Game Programming
Artificial Intelligence
Forced pattern s of movement tend to conflict w ith applicability/necessity of an observant
com puter controlled-opponent, or w hat I’ve defined as artificial intelligence. Yet, because
these lim itations do not apply to the ability of the alien crafts to engage in weapons fire,
we’ll still need to program a strategy for our computer to rely upon in battle. It is best if we
also tie our com puter’s weapons fire into a more general weapons control used by both our
computer and our players. The three key functions include testing and locating the player’s
ship, activating our weapons (for both the player and the computer), and detecting any and
all collisions from both sides (see Example 4.49).
TimedEvent missileEvent =
t i m e r .g e t E v e n t ("targetMissile" + index);
m iss il e E v e n t .isActive = true;
286
Chapter 4: Arrays, Pointers, and Strings
Resetting Levels
Once all the aliens are destroyed, ra th e r th an ending the game, we can ju st reset all the
aliens and s ta rt again. This is essentially a m a tte r of resettin g all the variables back to
th eir original positions, but you m ight also w ant to either speed up the game or have the
aliens s ta rt a little lower w ith each tu rn . I’ve left those choices up to you (see Exam ple
4.50).
g a m e St at e.currentSpeed++;
timer .ChangeStep (11targets " , gameState .currentSpeed < 10 ?
10 - g a m e St at e.currentSpeed : 1);
287
C# and Game Programming
basic display function. The key changes here include a string value and a decimal output
(see Example 4.51).
try {
file = new S t re am Wr it er (@ ".\HighScore.t x t " );
f ile.Wri te Li ne ("Battle Wave High Scores");
file.WriteLine (" ") ;
file.WriteLine();
f i l e .W r i t e L i n e (score + "\t" + Dat eT im e.N o w ) ;
f i l e .F l u s h ();
} catch (Exception e) {Console.WriteLine (e);}
finally {if (file != null) f i l e .Close (); }
}
TimedEvent miss il eE ve nt ;
// shoot the first missile that's not already out there!
for (int i = 0; i < N UM_MISSILES; i + +) {
if (!p la ye r M i s s i l e s [i ].isActive) {
// set missiles properties so that it will get
// properly animated
pl ay er M i s s i l e s [i ].isActive = true;
p la ye r M i s s i l e s [i ].direction = A n i m a t e dl ma ge .NORTH;
288
Chapter 4: Arrays, Pointers, and Strings
289
C# and Game Programming
Adding Graphics
By now you should be fairly comfortable using the graphics tools included in the .Net
package. Here I might suggest saving and altering the Windows Forms images and coding
to include the *.gif, *.jpg, and *.dib formats. The different form ats will dictate the size and
quality of the images.
Screen
Shot
4.6.
The
window.
// from Shapes.cs
public void Window(Graphics g, Brush b W indowColor) {
Brush GrayBrush = new SolidBrush(Color.G r a y ) ;
290
Chapter 4: Arrays, Pointers, and Strings
g .FillRectangle(GrayBrush, this.imagePosX,
this.imagePosY, 24, 24); // frame
g.FillRectangle(bWindowColor, this.imagePosX+2,
this.imagePosY+2, 20, 20); // glass
g.FillRectangle(GrayBrush, this.imagePosX+11,
this.imagePosY, 3, 24); // brace
g .FillRectangle(GrayBrush, this.imagePosX+11,
this.imagePosY+11, 5, 3); // lock
}
Tennis - Microsoft Visual C#.NET [design] YellowPlant.bmp
Screen
Shot
4.7.
The
potted
plant.
,--------
6 i 1 Magnification If ~1
I j Start 3l Myb03ki9 .doc-p \ Tennis- Microsoft Vts... ikj 1:41 PM
// from Shapes.cs
public void F l o w e r (Graphics g, Brush bFlowerColor, Pen p Fl owerColor) {
// pedals
g .DrawArc(pFlowerColor, t h i s .imagePosX, // down
t h i s .imagePosY-8, 5, 15, 0, 180);
g .DrawArc(pFlowerColor, t h i s .imagePosX-10, // left
t h i s .imagePosY-8, 15, 5, 90, 180);
g .DrawArc(pFlowerColor, t h i s .imagePosX, // up
t h i s .imagePosY-17, 5, 15, 180, 180);
g .DrawArc(pFlowerColor, t h i s .imagePosX+1, // right
t h i s .imagePosY-8, 15, 5, 270, 180);
// center
g.FillEllipse(bFlowerColor, t h i s .imagePosX-2,
t h i s .imagePosY-10, 10, 10);
291
C# and Game Programming
// base
P o i n t [] Vase = t h i s .s h ar pT ri an gl e ();
g .FillPolygon(bFlowerColor, V a s e ) ;
- dM
I sfe j Sew Project Quid Debug Jocfe [mage Window Help
Ia o J o 0 - \J\<? F0,
9 x Start Page | Foml.cs lOeagn] jCbssl.ts j fcrml.a | YekwWmdow.bmp YeilowTV.bmp |YeJowPlanttxop j YefowLampbrnp ;
: ium sm is, sm
Screen | |pjji|pl|q|p
Shot
4.8. 1 !lI!!!lllli!!P! si
* * « w IiP 5 -
The TV : ____
set.
* ** ™ , ------------- ---------------------
6 :1 MagnfIcation
292
Chapter 4: Arrays, Pointers, and Strings
* <p — ► «
gle E.d* sew grofcct &j#d Qpbug loots Image Jgndovt [jttp
\J]<? > t \ 7 A : a » » o « « o m m £j
Screen
Shot
4.9.
The
lamp.
■A
■
□
if (!Mo uselnquire) {
DialogResult result = M e s s a g e B o x .S h o w (t h i s ,
"Do you want to enable the mouse?",
"Mouse Detected", MessageBo xB ut to ns .Y e s N o ,
Messa ge Bo xI co n.Question, MessageBoxDefaultButton.Button1,
Me ss ag eBoxOptions.RightAlign);
C# and Game Programming
Mouselnquire = true;
if (result == Di alogResult.Y e s ) {
MouseOverride = true;
}
}
} else {
// draw background color
b u f f e r .Co lo rF ill(Color.B l ac k) ;
b u f f e r .ForeColor = Color.Blue;
// Draw the scores
if (player.score < HighScore) {
b u f f e r .D r a w T e x t (4*SCALE, 2*SCALE, H ig hS c o r e .T o S t r i n g (),
false);
} else {
b u f f e r .D r a w T e x t (4*SCALE, 2*SCALE, p l a y e r .s c o r e .T o S t r i n g (),
false);
}
294
Chapter 4: Arrays, Pointers, and Strings
b u f f e r .Draw(destination, T a r g e t D r a w [i ],
D ra wFl ag s.W a i t );
keyboard = new
Microsoft.DirectX.Directlnput.D e v i c e (Sys te mG ui d.K ey board);
ke yb oa rd .Pro pe rt ie s.BufferSize = 8;
keybo ar d.Acquire () ;
295
C# and Game Programming
if (gameState.currentState == G a me S t a t e .S t a t e .Stopped)
return;
joystick.SetDataFormat(DeviceDataFormat.Joystick);
foreach (DeviceObjectlnstance d in jo ys t i c k .O bj ec ts ) {
if ((0 != (d.Objectld & (i n t )DeviceObjectTypeFlags.A x i s ))) {
joystick.Properties.S e t R a n g e (P arameterHow.ById,
d.Objectld, new I n p ut Ra ng e(-1000, 1000));
}
}
joystick.SetCooperativeLevel(this,
M i c r o s o f t .D i r e ct X.Direc tl np ut .CooperativeLevelFlags.Background |
M i c r o s o f t .D ir e c t X .Direc tl np ut .CooperativeLevelFlags.No nExclusive);
j o y st ic k.Prope rt ie s.AxisModeAbsolute = true;
j o y s t i c k .A c q u i r e ();
j o y s t i c k .P o l l () ;
JState = joystick.CurrentJoystickState;
p l a y e r .direction = 0;
296
Chapter 4: Arrays, Pointers, and Strings
if (0 != (b & 0x80)) {
FireBall();
m o u s e .S etD ataFormat(DeviceDataFormat.M o u s e );
mouse.Acquire ();
m o u s e .Poll ();
if (MouseOverride) {
p l a y e r .imagePosX = C u r s o r .Po si ti on .X;
p l a y e r .imagePosY = C u r s o r .Po si ti on .Y;
p l a y e r .C o n s t ra in To Bo x();
297
C# and Game Programming
Properties: Description:
BufferBytes A read/write integer property, Buf ferBytes must be
set to zero when creating a buffer with
PrimaryBuf fer set to true.
Can GetCu rrentP ositio n A read/write Boolean property, used with emulated
sounds.
Control3D A read/write Boolean property, not to be mistaken with
Buf ferCaps .Control3D, used to indicate type
compatibility for sound production in 3D space.
Control 3D cannot be used with ControlPan.
ControlEffects A read/write Boolean property, used to determine if a
buffer can use effect processing, conditions include 8/16
bit PCM format and no more than two stereo channels.
C o n t r o l Freque ncy A read/write Boolean property, used to determine if a
buffer’s frequency could be altered.
ControlPan A read/write Boolean property, used to determine if a
buffer could support panning, Con trolPan cannot be
used with Control 3D.
C o n t r o l P o sition Notify A read/write Boolean property, used to determine if a
buffer would support position notification.
ControlVolume A read/write Boolean property, used to determine if a
buffer could support the volume.
DeferLocation A read/write Boolean property, used to determine if a
buffer should be assigned to a hardware or software
resource at playtime. This flag must be set for buffers that
use voice management.
Flags A read/write enumeration property, used to assign
Boolean references relating to the other
Buf fer De script ions.
GlobalFocus A read/write Boolean property, used to determine if a
buffer is global.
G u i d 3 DA lgori thm A read/write GUID property specifies the algorithm used
for 3D virtualization.
LocateInH ardwar e A read/write Boolean property, used to determine if a
buffer requires hardware.
LocateInSof tware A read/write Boolean property, used to determine if a
buffer requires software (note that this setting ignores any
available hardware).
T a b le 4.5
298
Chapter 4: Arrays, Pointers, and Strings
T a b le 4.5 ( c o n tin u e d )
Three-Dimensional Sound
Most people are inherently fam iliar with monophony or monophonic sound (the reproduc
tion of sound through the use of a single transm ission path), as well as stereophony or
stereophonic sound (the recording and transm ission of sound using m ultiple channels).
M any are also becoming acquainted w ith three-dim ensional sound and surround sound
systems. Thus, DirectX or the DirectSound API has been equipped with m ethods used to
sim ulate three-dim ensional space. The two key m ethods are Buffer3D and Control3D,
used to m anipulate the source as well as the position and orientation, respectively. It is
im portant to rem em ber th a t while Buffer3D controls the 3D settings, w ell still be relying
on the original buffer to control our play settings (see Table 4.6).
299
C# and Game Programming
Properties: Descriptions:
C o n e A n g le s A read/write structured property, used to record and
retrieve the internal and external angles o f a cone.
C o n e O rie n ta tio n A read/write structured property, used to manipulate a
sounds orientation.
C o n e O u ts id e V o lu m e A read/write integer property, used to manipulate the
volume of an external cone.
D e fe rre d A read/write Boolean property, used to determine if a
property change should be updated immediately (false)
or deferred (true). Settings are not applied until the
application (true) calls the
L i s t e n e r 3 D . C o m m itD e fe rre d S e ttin g s ( ) .
M a x D is ta n c e A read/write float property, used to determine the
maximum distance from the listener.
M in D is ta n c e A read/write float property, used to determine the
minimum distance from the listener.
Mode A read/write enumeration property, used to determine
the 3D mode for sound processing.
P o s itio n A read/write structured property, used to determine the
sounds current position.
V e lo c ity A read/write structured property, used to determine the
sound’s velocity (in meters per second).
T a b le 4.6
Listener3D m ust be used w ith a prim ary buffer; there is only one listener per device (see
Table 4.7).
D irectSound’s API also comes w ith several simple sound effects; these can be used in
conjunction with the basics sounds (included in C hapter 3) and with the three-dimensional
aspects discussed earlier in this chapter. The practically of using sound effects generally
relates to the environm ent th a t the program m er creates. For example, if we w anted to
300
Chapter 4: Arrays, Pointers, and Strings
Properties: Description:
Commit Deferr edSett ings A void property, used to determine if any new
settings have been deferred, if they have then those
settings are committed.
D istanceFactor A read/write float property, used to manipulate the
number o f meters in a vector.
DopplerFactor A read/write float property, used to manipulate the
multiplier for the Doppler effect.
Deferred A read/write Boolean property, used to determine
if a property change should be updated
immediately or deferred.
Orienta tion A read/write structured property, used to
manipulate the orientation o f the listener.
Rol loffF actor A read/write float property, used to determine the
rate o f attenuation over distance.
Position A read/write structured property, used to
determine the current position o f the listener.
V e l oc ity A read/write structured property, used to
determine the velocity o f the listener (in meters per
second).
T ab le 4.7.
create the illusion of a hall or canyon, we could include an echo effect. O ther m anipula
tions m ight include distortion, compressions, or reverberation (see Table 4.8).
301
C# and Game Programming
Effect: Description:
Chorus A voice-doubling effect, the original sound is
repeated after a short delay. The sound is also
slightly altered, creating the illusion o f multiple
voices.
Compression A reduction in the fluctuation o f amplitude as it
is measured from the signal’s average.
Distortion An abrupt slicing of the top o f a waveform
created by adding harmonics to the signal as the
level increases.
Echo Sounds are repeated after a fixed delay, usually
at a diminished volume. This process repeats for
several cycles.
Environment Reverberation An implementation o f the listener properties; a
sound reaching the listener has three temporal
components: direct path, early reflections, and
late reverberation. The combination o f early
reflections and late reverberation is also referred
to as the room effect.
Flange Also known as flanger, an echo/sweeping effect,
which includes a shorter delay and some
variance.
Gargle An intonation/modulation o f a signal’s
amplitude meant to causes a unique sound.
Parametric Equalizer Used to amplify or attenuate a signal, allowing
for different pitches that can be applied in
parallel.
Waves Reverberation Intended for use with music, the wave’s
reverberation DirectX Media Object (DMO) is
based on the wave’s MaxxVerb technology.
T a b le 4.8
302
Chapter 4: Arrays, Pointers, and Strings
Changing Levels
Another key aspect to creating a multilevel game is to include a level changing or resetting
method. In this case, we’ll also w ant to use this method to dem onstrate DirectSound’s 3D
and special effect features explained in the last few sections. The NextLevel method uses a
for-loop to reactivate all targ et creators. The NextLevel m ethod is referenced as p art of a
tim e based comparison (see Exam ples 4.60 and 4.61).
if (th e B a l l .isActive) {
the Ba ll .A ni ma te ();
if (theBall.Intersects(player)) {
H i t T h e B a l l ();
return;
}
if (theBall.C o n st ra in To Bo x()) {
303
C# and Game Programming
t h e B a l l .D e f l e c t () ;
return;
Troubleshooting
In this troubleshooting section, we’ll begin learning how to use our compilers to isolate,
identify, and explain our errors. This is done in three steps; first, use the “Task List” as a
hyperlink, which can isolate our errors to w ithin a few lines. Second, use the error
“D escription” to identify the error. Third, use the “Help M enu” to explain the error. L et’s
test these three aspects by adding a bit of sabotage to our last game, Asteroid Miner. Here
I’ve commented out the Game Classes.
304
Chapter 4: Arrays, Pointers, and Strings
would all be in error. M ake sure all the bitm aps, wav files and
classes are not only included as p a rt of your project, bu t also
referenced at the appropriate locations.
2. A ttem pting to access elem ents th a t go beyond an a rra y ’s size will
resu lt in a system error.
3. A ttem pting to a lte r the size of an array inside of a user-defined
function will resu lt in a system error.
4. A ttem pting to use floating point num bers or integers th a t are
negative as a rra y elem ents will resu lt in a system error.
5. A ttem pting to assign pointers to variables and/or pointers to
other pointers of different data types will result in a system error.
6. You cannot allocate more system memory th a n available to your
system . (Note: If you do not te s t for successful allocation of th a t
memory, your system may act incorrectly or crash).
7. A ttem pting to access a pointer th a t h as not been assigned an
address, will resu lt in a program error.
8. A ttem pting to copy a larger a rray into a sm aller one will resu lt in
a program error.
Things to Remember
1. An a rra y is an aggregated set of variables th a t are of the sam e
d a ta type. They are linked by th eir location in mem ory and can
be accessed eith er individually (by th eir subscripts) or as a whole
(when a term in atin g value “\ 0 ” is assigned).
2. A rray subscripts can be either literal constants or variables
declared as constants. Dynam ic array s allow for sta n d a rd
variables, bu t once declared, the a rra y ’s size m ust not be altered.
3. A rrays can be passed as elem ents (as in a rray [x]), or as whole
arra y s (as in array).
4. Multidimensional arrays list their rows first and then their columns.
5. L inear searches compare d a ta in a consecutive order beginning
w ith one elem ent and moving to the next,w hile binary searches
short cut th a t process by repeatedly dividing the total by two and
th en searching the final nondivisible portion.
305
C# and Game Programming
Q uestions
1. Describe an array.
2. Declare and assign an a rra y of 5 real num bers using the values
3.5, 2.34, 25.4, 2.002, 1.0.
3. W rite a program th a t uses an a rra y to p rin t the word “hello.”
(Hint: array[4] = “hello.”)
4. Revise the last program so th a t the word “hello” is passed to a
secondary function before being displayed.
5. W rite a program th a t displays the values 1, 2, 3, 4, 5, 6, 7, 8, 9.
6. Revise the last program so as to use a m ultidim ensional array.
7. W rite a simple bubble sort program using lette rs ra th e r th a n
numbers.
8. W rite a sim ple linear search program th a t counts the to tal
num ber of lower case letters.
9. W rite a sim ple binary search program th a t attem p ts to find a
num ber betw een 1 and 100. Allow the user to en ter a searchable
number.
10. W rite a program to find the mode, m ean, m edian, and range.
11. Declare and assign a dynamic array.
12. Describe a pointer.
13. Declare and assign a pointer variable.
306
Chapter 4: Arrays, Pointers, and Strings
307
Object-Oriented
Design
his chapter begins w ith several sections th a t define and detail the m any a t
trib u tes of the collective data type known as the s t r u c t u r e . This aggregated
data type includes several options th a t aid in the rem oval of literal lim itations,
and th u s help us to fu rth er our move into object-oriented program m ing. Once the b a
sics of these sim pler concepts are com m itted to memory, we’ll w ant to progress onto the
extended topics using c l a s s e s . Classes, while not m eant to totally replace structures,
do allow for a greater level of control, which includes the use of reference types. The
second portion of this chapter will also offer several new keywords and operators whose
potential can only be reached through class m anipulations. Finally, we’ll conclude w ith
the underlying classes used to power all the games, and I’ve throw n in two additional
gam es th a t add a few final touches.
Structures
Structures are user-defined d ata types th a t allow for groupings of sim ilar or related data
th a t do not have a single base d ata type. These groups can include all the basic value data
types, as well as a list of methods used to m anipulate those values. The data types declared
inside a structure are referred to as the stru ctu re’s members (or fields), while their decla
rations are referred to as its instances. The correlations between these internal values and
309
C# and Game Programming
our structures are usually guided by some common them e or purpose. A structure is made
up of the keyword s t r u c t , the stru c tu re ’s tag (or name), a list of the fields (w ritten as
declared members), and a list of possible m ethods used to m anipulate th a t data. S truc
tures are generally contained within a single block placed inside our referencing namespace,
but as shown below, they can also be used to invoke our m ain m ethod (see Exam ple 5.1).
While the use of a C++ style terminating semicolon is allowed, it is not required
when working with C#.
namespace Chapter5 {
struct BankAccount {
string first_name;
string last_name;
long account_number;
decimal Checking;
decimal Savings;
short pin_number;
Console.WriteLine(Balance.account_number);
}
}
}
310
Chapter 5: Object-Oriented Design
m ents is also restricted from w ithin those structures. Once a structure is listed, the proper
declaration and assignm ent includes both a declaring stru ctu re’s instance and an assign
m ent to th a t field (see Exam ples 5.2 and 5.3).
namespace Chapter5 {
struct BankAccount {
public string first_name;
public string last_name;
public long account_number;
public decimal checking;
public decimal savings;
public short pin_number;
if (a c c o u n t .pin_number == 2001) {
a c c o u n t .account_number = 43297;
a c c o u n t .first_name = "John";
a c c o u n t .last_name = "Doe";
a c c o u n t .checking = 0;
a c c o u n t .savings = 112.53M;
C o n s o l e .W r i t e L i n e ("Account Number: {0}",
a c c o u n t .account_number);
C o n s o l e .W r i t e L i n e ("Iden ti ty : {0} {1}",
a c c o u n t .first_name, a c c o u n t .last_name);
Console.WriteLine("Savings Account Balance: {0}",
account.savings);
Console. Wr it eLi ne ("Checking Account Balance: {0}",
a c c o u n t .c hecking);
311
C# and Game Programming
Screen
account number
Shot 0 balance
5.1. 0 firstjiarae
0 last_name
0 pin_number
When inserting the dot operator, visual compiler users may encounter a popup
window resembling Screen Shot 5.1. This window is generally used as a reminder
indicating to the programmer that certain fields are available. If a certain
item is not present, this may indicate that it was coded incorrectly or that a
certain reference is missing or incomplete. A padlock symbol indicates a
protected or private member/field.
using System;
namespace Chapter5 {
struct BankAccount {
public string first_name;
public string last_name;
public long account_number;
public decimal checking;
public decimal savings;
public short pin_number;
}
class Classl {
static void Main () {
BankAccount accountl, account2;
account1.pin_number = 2001;
account1.account_number = 43297;
account 1.first_name = "John";
account 1.last_name = "Doe";
account1.savings = 0;
account1.checking = 112.53M;
312
Chapter 5: Object-Oriented Design
a c c o u n t 2 .pin_number = 2002;
a cc o u n t 2 .account_number = 78978;
a c c o u n t 2 .first_name = "Jane” ;
a cc o u n t 2 .last_name = "Happy";
ac c o u n t 2 .savings = 312.43M;
a cc o u n t 2 .checking = 2 134.65M;
if (input == account1.pin_number) {
C o n s o l e .W r i t e L i n e ("Account Number: {0}",
a c c o u n t l .account_number);
C o n s o l e .W r i t e L i n e ("Identi ty : {0} {1}",
ac c o u n t l .first_name, a cc o u n t l .last_name);
C o n s o l e .W r i t e L i n e ("Savings Account Balance: {0}",
a c c o u n t l .savings);
Consol e. Wri te Li ne ("Checking Account Balance: {0}",
a c c o u n t l .checking);
} else if (input == ac c o u n t 2 .pin _n um be r) {
C o n s o l e .W r i t e L i n e ("Account Number: {0}",
a cc ou n t 2 .account_number);
C o n s o l e .W r i t e L i n e ("Ide nt it y: {0} {1}",
a c c o u n t 2 .first_name,
a c c o u n t 2 .last_name);
C o n s o l e .W r i t e L i n e ("Savings Account Balance: {0}",
a c c o u n t 2 .savings);
C o n s o l e .W r i t e L i n e ("Checking Account Balance: {0}",
a cc o u n t 2 .checking);
Multiple Structures
Another useful technique w hen dealing w ith stru ctu res is the use of an array of struc
tures. This can quickly become a necessity w hen dealing w ith large groups of instances
th a t also share a common set of comparisons. Notice how the stru ctu re’s nam e is used in
place of the basic d ata type, and how its form at em ulates th a t of a basic array style
reference. This array is also subject to the lim itation of size, b ut it also inherently takes on
some of the capabilities of a m ultidim ensional arra y (see Exam ples 5.4). While arrays of
313
C# and Game Programming
stru ctu res are allowed, in te rn al stru c tu ra l array s are not. This is due to the fact th a t
structures by definition are value based, while arrays rely on referenced-based structures
(which, in C#, is defined as a class).
namespace Chapter5 {
struct BankAccount {
public string first_name;
public string last_name;
public long account_number;
public decimal checking;
public decimal savings;
public short pin_number;
}
class Classl {
public static void Main() {
B a n k A c c o u n t [] account = new B an k A c c o u n t [3];
a c c o u n t [0].pin_number = 2000;
a c c o u n t [0].account_number = 78434;
a c c o u n t [0].first_name = "Bad";
a c c o u n t [0].last_name = "Dog";
a c c o u n t [0].savings = 1000.15M;
a c c o u n t [0].checking = 43.12M;
a c c o u n t [1].pin_number = 2001;
a c c o u n t [1].account_number = 43297;
a c c o u n t [1].first_name = "John";
a c c o u n t [1].last_name = "Doe";
a c c o u n t [1].savings = 0;
314
Chapter 5: Object-Oriented Design
a c c o u n t [1].checking = 112.53M;
a c c o u n t [2].pin_number = 2002;
a c c o u n t [2].account_number = 78978;
a c c o u n t [2].first_name = "Jane";
a c c o u n t [2].last_name = "Happy";
a c c o u n t [2].savings = 21 34.65M;
a c c o u n t [2].checking = 312.43M;
while (true) {
C o n s o l e .W r i t e ("Enter your pin number here: ");
short input = s h o r t .P a r s e (C o n s o l e .R e a d L i n e ());
for (int index = 0; index < 3; index++) {
if (input == a c c o u n t [i n d e x ] .pin_number) {
C o n s o l e .W r i t e L i n e ("Account Number: {0}",
a c c o u n t [in de x ] .account_number);
C o n s o l e .W r i t e L i n e ("I de ntity: {0} {1}",
a c c o u n t [index].first_name,
a c c o u n t [index].last_name);
Console .WriteLine (''savings Account Balance: {0}",
a c c o u n t [index].savings);
C o n s o l e .W r i t e L i n e ("checking Account Balance: {0}",
a c c o u n t [in de x] .checking);
Complex Structures
Complex structures are nothing more th a n stru ctu res th a t contain references to other
structures. These secondary stru ctu res are accessed in much the same m anner as s ta n
dard structures, with the addition of a secondary dot operator and an additional m em ber’s
name. The inclusion of one stru ctu re inside another is also referred to as composition
and/or nesting. Note th a t unlike C++, the referencing of an outer stru ctu re does not
inherently reference the inner values, thus; these two structures m ust be declared sepa
rately (see Example 5.5).
315
C# and Game Programming
namespace Chapter5 {
struct BankAccount {
public string first_name;
class Classl {
static void Main () {
BankAccount Account;
Ba nk Acc ou nt .NestedStruct HiddenAccount;
A c c o u n t .first_name = "MR.RICH";
Hidden Ac co un t.swiss_account = 5000000.00M;
}
}
}
using System;
namespace Chapter5 {
class Classl {
struct BankAccount {
public string first_name;
316
Chapter 5: Object-Oriented Design
short input;
a c c o u n t .pin_number = 2001;
a c c o u n t .savings = 0M;
a c c o u n t .checking = 112.53M;
if (a c c o u n t .pin_number == 2001) {
Console.WriteLine("savings");
a c c o u n t .savings = function(account.savings);
C o n s o l e .W r i t e L i n e ("checking");
a c c o u n t .checking = function(account.c hecking);
C o n s o l e .W r i t e L i n e ("Updating a c c o u n t ...");
C o n s o l e .W r i t e L i n e ("savings {0}", a c c o u n t .savings);
C o n s o l e .W r i t e L i n e ("checking {0}", a c c o u n t .checking);
}
}
317
C# and Game Programming
namespace Chapter5 {
class Classl {
struct BankAccount {
public string first_name;
public string last_name;
public long account_number;
public decimal checking;
public decimal savings;
public short pin_number;
}
a c c o u n t .pin_number = 2001;
a c c o u n t .savings = 10M;
a c c o u n t .checking = 112.53M;
C o n s o l e .W r i t e ("Enter you pin number now: ");
short input = s h o r t .Parse(Console.R e a d L i n e ());
if (account.pin_number == 2001) {
Console.WriteLine("savings");
function (ref a c c o u n t .savings);
C o n s o l e .W r i t e L i n e ("checking\n");
function (ref a c c o u n t .checking);
318
Chapter 5: Object-Oriented Design
namespace Chapter5 {
struct BankAccount {
public string first_name;
public string last_name;
public long account_number;
public decimal checking;
public decimal savings;
public short pin_number;
}
class Classl {
static void Main() {
BankAccount account;
a c c o u n t .pin_number = 2001;
a c c o u n t .account_number = 43297;
a c c o u n t .first_name = "John";
a c c o u n t .last_name = "Doe";
a c c o u n t .savings = 100.00M;
a c c o u n t .checking = 112.53M;
function(account);
function(account);
}
319
C# and Game Programming
if (input == a c c .pin_n u mb er ) {
C o n s o l e .W r i t e L i n e ("Account Number: {0}",
a c c .account_number);
C o n s o l e .W r i t e L i n e ("Ide nt it y: {0} {1}",
a c c .first_name, a c c .last_name);
C o n s o l e .W r i t e L i n e ("savings Account Balance: {0}",
a c c .s avings);
Co n s o l e .W r i t e L i n e ("checking Account Balance: {0}",
a c c .checking);
namespace Chapter5 {
struct BankAccount {
public string first_name;
public string last_name;
public long account_number;
public decimal Checking;
public decimal Savings;
public short pin_number;
}
class Classl {
static void Main() {
BankAccount account;
a c c o u n t .pin_number = 2001;
a c c o u n t .account number = 43297;
320
Chapter 5: Object-Oriented Design
a c c o u n t .first_name = "John";
a c c o u n t .last_name = "Doe";
a c c o u n t .Savings = 100M;
a c c o u n t .Checking = 112.53M;
function (ref a cc ount);
function (ref ac count);
}
321
C# and Game Programming
ReadLine and W riteLine references (see Exam ple 5.10). Note th a t you m ust create a file
before it can be viewed.
namespace Chapter5 {
struct BankAccount {
public string first_name;
public string last_name;
public long account_number;
public decimal checking;
public decimal savings;
public short pin_number;
}
class Classl {
static void Main() {
BankAccount accountl;
account1 .pin_number = 0;
a c c o u n t l .first_name = "";
account1.last_name = "";
a c c o u n t l .account_number = 0;
a cc o u n t l .checking = 0;
account1.savings = 0;
char input;
while (true) {
C o n s o l e .W r i t e L i n e ("Enter <C> to create new file or <V> " +
"to view a ccount");
input = c h a r .P arse(Console.R e a d L i n e ());
i f ( C h a r .T o U p p e r (i n put) == 'C') {
CreateFile(out a c countl);
} else if (Char.ToUpper (input) == 'V') {
ReadFile(ref accountl);
} else {
break;
}
322
Chapter 5: Object-Oriented Design
SaveFile(accountl, 0, 0) ;
}
}
SaveFile(acc, 0, 0);
}
323
C# and Game Programming
file.WriteLine(acc.first_name);
file.WriteLine(acc.last_name);
f i l e .C l o s e ();
In getting back to classes, I should mention that there are many aspects that
we’ll now cover for classes that are just as viable within the previously discussed
structure types. These, of course, include the private, protected, and
public references, as well as the basic member and method references.
Introducing Classes
As we’ve seen through this text, the application of classes is quite vital to the m anipulation
of the C# language. An im m ediate comparison betw een classes and stru ctu res can be
made, and all of the previous inform ation can be reapplied to class references. Note th a t
classes are both capable of using reference data types as well as single inheritance, but not
m ultiple inheritance as is available w ith C++. Classes mimic the nam ing references used
w ith structures, including tags, fields, m ethods, and d a ta blocks, as well as other key
reference points including p u b l i c , p r i v a t e , and p r o t e c t e d access (these concepts
will be explained shortly). A basic class reference can also be used to im plem ent a simple
do-nothing style program , but this tim e we’ll also need to include a dynam ically linked
instance (see Example 5.11).
324
Chapter 5: Object-Oriented Design
namespace Chapter5 {
class BankAccount {
string first_name;
string last_name;
long account_number;
decimal checking;
decimal savings;
short pin_number;
325
C# and Game Programming
namespace Chapter5 {
class BankAccount {
public string first_name;
public string last_name;
public long account_number;
public decimal checking;
public decimal savings;
public short pin_number;
class Classl {
static void Main() {
BankAccount accountl = new B a n k A c c o u n t ();
char input;
while (true) {
C o n s o l e .W r i t e L i n e ("Enter <C> to create new file or " +
"<V> to view account");
input = c h a r .Pa rs e(Console.R e a d L i n e ());
326
Chapter 5: Object-Oriented Design
SaveFile(accountl, 0, 0);
}
}
SaveFile(acc, 0, 0) ;
}
327
C# and Game Programming
file.WriteLine(acc.first_name);
file.WriteLine(acc.last_name);
f i l e .C l o s e ();
}
p r iv a t e and p r o t e c t e d Fields
A nother program m ing technique th a t can improve program portability is the use of
private and/or protected mem ber fields. These are class or structure mem bers th a t
allow for restricted or lim ited access based on user-defined methods w ritten specifically for
those values. These user-defined methods are declared as p art of th a t class’ internal struc
ture w ith the option of being declared as public, protected, or private m em ber func
tions.
Methods are user-defined functions th a t are declared from w ithin classes. These func
tions are given both sta n d a rd access to our m ain program and special access to our now
private m em ber variables. Public m em ber functions can be accessed through any user-
defined function th a t is aw are of th a t defined class. The call to th a t function will need to
include a class identifying statem en t and a dot m em ber selection operator, while these
user-defined functions include the class’ identity, a type qualifier (the function’s name),
and a connecting binary scope resolution operator. For obvious reasons, m ember functions
are also referred to as assessor functions (see Exam ples 5.13 and 5.14).
E x a m p le 5.13. P r iv a te m e m b e rs .
using System;
using System.10;
328
Chapter 5: Object-Oriented Design
namespace Chapter5 {
class BankAccount {
private string first_name;
private string last_name;
private long account_number;
private decimal checking;
private decimal savings;
private short pin_number;
SaveFile(acc, 0, 0) ;
}
329
C# and Game Programming
acc.pin_number = s h o r t .P a r s e (f i l e .R e a d L i n e ());
a c c .account_number = l o n g .P a r s e (f i l e .R e a d L i n e ());
acc.savings = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
acc.checking = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
a c c .first_name = f i l e .R e a d L i n e ();
a c c .last_name = f i l e .R e a d L i n e ();
f i l e .Close ();
class Classl {
static void Main() {
BankAccount account = new BankAccount ();
char input;
while (true) {
C o n s o l e .W r i t e L i n e ("Enter <C> to create new file or " +
"<V> to view ac count");
input = c h a r .Pa rs e(Console.R e a d L i n e ());
account.ViewFile(account);
a cc o u n t .SaveFile(account, 0, 0);
}
330
Chapter 5: Object-Oriented Design
namespace Chapter5 {
class B a n k A c c o u n t {
p r o t e c t e d s tri n g first_name;
p r o t e c t e d s tri ng last_name;
p r o t e c t e d long a c c o u n t _ n u m b e r ;
p r o t e c t e d d e c i m a l checking;
p r o t e c t e d d e c i m a l savings;
p r o t e c t e d short p i n_n umb er;
p u b l i c v o i d C r e a t e F i l e ( r e f B a n k A c c o u n t acc) {
C o n s o l e .W r i t e L i n e ("Enter Your Ne w Pin Number: ");
a c c .p i n _ n u m b e r = s h o r t .P a r s e ( C o n s o l e .R e a d L i n e ());
331
C# and Game Programming
p u b l i c v o i d R e a d F i l e ( r e f B a n k A c c o u n t acc) {
S t r e a m R e a d e r file = ne w S t r e a m R e a d e r (@ " C :\M yFi le .t x t 11) ;
a c c .p i n _ n u m b e r = s h o r t .P a r s e (f i l e .R e a d L i n e ());
a c c .a c c o u n t _ n u m b e r = l o n g .P a r s e (f i l e .R e a d L i n e ());
ac c . s a v i n g s = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
a c c . c h e c k i n g = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
a c c .f i r s t _ n a m e = f i l e .R e a d L i n e ();
a c c .l a s t _ n a m e = f i l e .R e a d L i n e ();
f i l e .C los e ();
}
p u b l i c v o i d V i e w F i l e ( B a n k A c c o u n t acc) {
C o n s o l e .W r i t e L i n e ("Pin Number: {0}", a c c .p i n _ n u m b e r );
C o n s o l e .W r i t e L i n e ("Acc oun t Number: {0}", a c c .a c c o u n t _ n u m b e r );
C o n s o l e .W r i t e L i n e (" N a m e : {0} {1}", a c c .f i r s t _ n a m e ,
a c c .l a s t _ n a m e ) ;
C o n s o l e .W r i t e L i n e ("Sa vings Balance: {0}", a c c .s a v i n g s );
C o n s o l e . W r i t e L i n e (" C h e c k i n g Balance: {0}", a c c .c h e c k i n g ) ;
class C lassl {
st ati c v oi d Main() {
B a n k A c c o u n t acc o u n t = new B a n k A c c o u n t ();
char input;
wh i l e (true) {
C o n s o l e .W r i t e L i n e ("Enter <C> to c r eat e ne w file or " +
332
Chapter 5: Object-Oriented Design
i f ( C h a r .T o U p p e r ( i n p u t ) == 'C') {
a c c o u n t .C r e a t e F i l e ( r e f a c c o u n t ) ;
} else if ( C h a r .T o U p p e r (input) == 'V') {
a c c o u n t .R e a d F i l e ( r e f account);
} else {
break;
}
account.ViewFile(account);
a c c o u n t .S a v e F i l e ( a c c o u n t , 0, 0);
namespace Chapter5 {
i n te rna l class B a n k A c c o u n t {
in ter nal p r o t e c t e d st ri n g first_name;
in ter nal p r o t e c t e d s t r ing last_name;
inte rna l p r o t e c t e d long a c c o u n t _ n u m b e r ;
in ter nal p r o t e c t e d dec i m a l Checking;
inte rna l p r o t e c t e d de ci m a l Savings;
int ern al p r o t e c t e d short p i n _ num ber ;
333
C# and Game Programming
a c c . p i n _ n u m b e r = s h o r t .P a r s e ( R e a d F i l e .R e a d L i n e ()) ;
a c c .a c c o u n t _ n u m b e r = l o n g .P a r s e ( R e a d F i l e .R e a d L i n e ());
a c c . S a v i n g s = d e c i m a l .P a r s e ( R e a d F i l e .R e a d L i n e ());
a c c . C h e c k i n g = d e c i m a l .P a r s e ( R e a d F i l e .R e a d L i n e ());
a c c .f i r s t _ n a m e = R e a d F i l e .R e a d L i n e ();
a c c .l a s t _ n a m e = R e a d F i l e .R e a d L i n e ();
R e a d F i l e .Clo se ();
i n te rna l v o i d V i e w F i l e s ( B a n k A c c o u n t acc) {
C o n s o l e . W r i t e L i n e ("Pin Number: {0}",
a c c .p i n _ n u m b e r );
C o n s o l e .W r i t e L i n e (" Account Number: {0}",
a c c . a c c o u n t number);
334
Chapter 5: Object-Oriented Design
class Cl ass l {
st ati c v o i d Main() {
B a n k A c c o u n t ac co u n t = ne w B a n k A c c o u n t ();
char input;
w h i l e (true) {
C o n s o l e . W r i t e L i n e ("Enter <C> to cr e a t e new file or +
"<V> to vi e w a ccount");
input = c h a r .P a r s e ( C o n s o l e .R e a d L i n e ());
i f ( C h a r .T o U p p e r ( i n p u t ) == 'C') {
a c c o u n t .C r e a t e F i l e s ( r e f a c c o u n t ) ;
} else if ( C h a r .T o U p p e r ( i n p u t ) == ' V 1 ) {
a c c o u n t .R e a d F i l e s ( r e f account);
} else
break;
a c c o u n t .V i e w F i l e s ( a c c o u n t ) ;
a c c o u n t .S a v e F i l e s ( a c c o u n t , 0, 0);
335
C# and Game Programming
n a m e s p a c e Cha p t e r 5 {
class D y n a m i c V a r i a b l e s {
p r i v a t e short [] ar r a y = new s h o r t [10];
p u b l i c D y n a m i c V a r i a b l e s (int n) {
a r r a y = new s h o r t [ n ] ;
}
p u b l i c voi d S e t E l e m e n t (short i) {
array[i] = i;
}
p u b l i c short R e a d E l e m e n t (short i) {
r e t u r n ( a r r a y [i ] );
}
336
Chapter 5: Object-Oriented Design
As you can see, the function in Example 5.18 could have been separated to include two
overloading functions, but w ith a simple adjustm ent using the zero input, our two func
tions become one.
337
C# and Game Programming
n a m e s p a c e C hap t e r 5 {
class B a n k A c c o u n t {
p r o t e c t e d st ri n g first_name;
p r o t e c t e d st r i n g last_name;
p r o t e c t e d long a c c o u n t _ n u m b e r ;
p r o t e c t e d d e c i m a l checking;
p r o t e c t e d d e c i m a l savings;
p r o t e c t e d short p i n_n umb er;
p r i v a t e v o i d R e a d F i l e ( r e f B a n k A c c o u n t acc) {
S t r e a m R e a d e r file = new S t r e a m R e a d e r (0" C : \ M y F i l e . t x t ");
a c c .p i n _ n u m b e r = s h o r t .P a r s e (f i l e .R e a d L i n e ());
a c c .a c c o u n t _ n u m b e r = l o n g .P a r s e (f i l e .R e a d L i n e ());
ac c . s a v i n g s = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
a c c . c h e c k i n g = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
a c c .fi r s t _ n a m e = f i l e .R e a d L i n e ();
a c c .l a s t _ n a m e = f i l e .R e a d L i n e ();
f i l e .Clos e ();
}
338
Chapter 5: Object-Oriented Design
f i l e . W r i t e L i n e ( ( a c c .c h e c k i n g + i n p u t 2 ) );
file.WriteLine(acc.first_name);
f i l e . W r i t e L i n e ( a c c .l a s t _ n a m e ) ;
f i l e .C l o s e ();
p u b l i c v o i d C r e a t e F i l e ( r e f B a n k A c c o u n t acc) {
C o n s o l e .W r i t e L i n e ("Enter Your New Pin Number: ");
a c c . p i n _ n u m b e r = s h o r t .P a r s e ( C o n s o l e .R e a d L i n e ());
pu b l i c v o i d V i e w F i l e ( B a n k A c c o u n t acc) {
C o n s o l e .W r i t e L i n e ("Pin Number: {0}", a c c .p i n _ n u m b e r );
C o n s o l e .W r i t e L i n e ("Ac cou nt Number: {0}", a c c .a c c o u n t _ n u m b e r );
C o n s o l e .W r i t e L i n e (" N a m e : {0} {1}", a c c .first_name,
a c c .l a s t _ n a m e ) ;
C o n s o l e . W r i t e L i n e (" Sav ing s Balance: {0}", a c c .s a v i n g s );
C o n s o l e . W r i t e L i n e (" C h e c k i n g Balance: {0}", a c c .c h e c k i n g ) ;
}
}
class Clas sl {
sta tic v o i d Main() {
B a n k A c c o u n t a cc o u n t = ne w B a n k A c c o u n t ();
char input;
wh i l e (true) {
C o n s o l e . W r i t e L i n e ("Enter <C> to cr eat e ne w file or " +
"<V> to vi ew ac count");
339
C# and Game Programming
input = c h a r .P a r s e ( C o n s o l e .R e a d L i n e ());
account.ViewFile(account);
Constructors are m em ber functions th a t are autom atically implem ented with the dec
laration of th a t class’instance. Each new instance triggers th is execution, and generally,
340
Chapter 5: Object-Oriented Design
those values are m ade specific to th a t instance’s reference. Constructors, like stan d ard
m em ber functions, are declared from w ithin those classes, but constructors do not require
a base d ata type. Constructors are defined using the same definition as th eir declaring
class, while their actual functions are expressed as a combination of both definitions and a
connecting binary scope resolution operator. Since constructors do n ot declare a data
type, they are also incapable of returning values (see Example 5.21).
namespace Chapter5 {
class B a n k A c c o u n t {
public decimal InterestRate;
pu b l i c d e c i m a l LoanRate;
// D e f aul t C o n s t r u c t o r
p u b l i c B a n k A c c o u n t () {
InterestRate = .03M; LoanRate = .13M;
}
class Cl ass l {
sta tic v o i d M a i n 0 {
B a n k A c c o u n t acco unt new B a n k A c c o u n t ()
1 W hile de stru cto rs are an im p o rta n t p a rt of native C++, th e ir im portance is minimized in C#, where the
process of destructing an object has become the prim ary concern of the compiler, normally occurring
when the object is no longer referenced.
341
C# and Game Programming
Overloading Constructors
Constructors can be overloaded in num erous ways. Again, these functions will be au to
m atically referenced when the appropriate instances are declared, and again, th eir arg u
m ents will determ ine the accessible function. One such class revision m ight include a
secondary constructor th a t gives a special rate to some depositors and a th ird th a t deter
mines an altern ate rate for both th eir savings and loans (see Exam ple 5.22).
n a m e s p a c e C hap t e r 5 {
class B a n k A c c o u n t {
pu b l i c de c i m a l Interest Rat e;
p u b l i c d e c i m a l LoanRate;
// Def aul t C o n s t r u c t o r
pu b l i c B a n k A c c o u n t () {
I n t e r e s t R a t e = .03M; LoanRate = .13M;
}
// O v e r l o a d e d C o n s t r u c t o r
public BankAccount(decimal IRate) {
I n t e r e s t R a t e = .03M;
L o a n R a t e = .13M;
}
// O v e r l o a d e d C o n s t r u c t o r
p u b l i c B a n k A c c o u n t ( d e c i m a l IRate, d eci m a l LoanRate) {
In t e r e s t R a t e = .03M;
L o a n R a t e = .13M;
}
}
class Cl ass l {
st ati c vo i d Main() {
B a n k A c c o u n t ac co u n t = new B a n k A c c o u n t ();
}
}
}
342
Chapter 5: Object-Oriented Design
Assigning Instances
Once two or more instances are declared by the sam e class, the values of those instances
can be passed using the assignm ent statem ent; for example, accountl = account2; / / where
BankAccount accountl, a c c o u n t2 In Example 5.23, the values from account2 are passed
to accountl (this process is commonly referred to as a memberwise copy). It is w orth
noting th a t restrictions in system s im plem entations can potentially cause errors when
dealing with dynamically allocated storage.
na m e s p a c e C h a p t e r 5 {
class B a n k A c c o u n t {
p u b l i c d e c i m a l I nte restRate;
p u b l i c d e c i m a l LoanRate;
p u b l i c B a n k A c c o u n t () {
InterestRate = .03M;
LoanRate = .13M;
}
class C las sl {
st ati c v o i d Main() {
B a n k A c c o u n t acc o u n t = n ew B a n k A c c o u n t ();
B a n k A c c o u n t acc o u n t l = ne w B a n k A c c o u n t ();
B a n k A c c o u n t a c c o u n t 2 = n ew B a n k A c c o u n t (23);
343
C# and Game Programming
ac c oun t = accountl;
acco u n t = account2;
p u b l i c void S e t I n t e r e s t R a t e ( d e c i m a l IRate) {
I n t e r e s t R a t e = IRate;
}
The Keyword t h is
The keyword t h i s is a specialized reference signature used to indicate the referencing
object of a passing class, therefore, t h i s is a longhand version for the otherwise abbrevi
ated member. While the t h i s reference is implied, its definitions can become ambiguous
and should be included to prevent this error (see Exam ples 5.25 and 5.26).
344
Chapter 5: Object-Oriented Design
Unlike C++, C#’s single dot reference can be used for both reference and
nonreference. The proper notation for a this pointer depends upon the purpose
of its referencing class, e.g., the this->variable versus the (*this).variable.
na m e s p a c e C h a p t e r 5 {
class B a n k A c c o u n t {
p r o t e c t e d s tr ing first_name;
p r o t e c t e d stri ng last_name;
p r o t e c t e d long a c c o u n t _ n u m b e r ;
p r o t e c t e d de c i m a l checking;
p r o t e c t e d d eci m a l savings;
p r o t e c t e d short p i n _ nu mbe r;
p r i v a t e v o i d R e a d F i l e () {
S t r e a m R e a d e r file = ne w S t r e a m R e a d e r (@ "C :\MyF ile .t x t 11) ;
t h i s . p i n _ n u m b e r = s h o r t .P a r s e (f i l e .R e a d L i n e ());
t h i s .a c c o u n t _ n u m b e r = l o n g .P a r s e (f i l e .R e a d L i n e ());
t h i s . s a v i n g s = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
t h i s .c h e c k i n g = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
t h i s .f i r s t _ n a m e = f i l e .R e a d L i n e ();
t h i s .la s t _ n a m e = f i l e .R e a d L i n e ();
f i l e .Close ();
}
p u b l i c vo i d C r e a t e F i l e O {
C o n s o l e .W r i t e L i n e ("Enter Your New Pin Number: ");
t h i s .p i n _ n u m b e r = s h o r t .P a r s e ( C o n s o l e .R e a d L i n e ());
345
C# and Game Programming
public void V i e w F i l e O {
t h i s .R e a d F i l e ();
C o n s o l e .W r i t e L i n e ("Pin Number: {0}",
t h i s .p i n _ n u m b e r );
C o n s o l e .W r i t e L i n e ("Acco unt Number: {0}",
t h i s .a c c o u n t _ n u m b e r );
C o n s o l e .W r i t e L i n e (" N a m e : {0} {1}",
t h i s .first_name, t h i s .l a s t _ n a m e ) ;
C o n s o l e .W r i t e L i n e (" Savings Balance: {0}",
t h i s .s a v i n g s );
C o n s o l e .W r i t e L i n e (" Che c k i n g Balance: {0}",
t h i s .c h e c k i n g ) ;
class Clas sl {
s ta tic v o i d Main() {
B a n k A c c o u n t ac co u n t = ne w B a n k A c c o u n t ();
char input;
w h i l e (true) {
C o n s o l e .W r i t e L i n e ("Enter <C> to cr ea t e new file or " +
"<V> to v i e w a c c o u n t " ) ;
input = c h a r .P a r s e ( C o n s o l e .R e a d L i n e ());
346
Chapter 5: Object-Oriented Design
} else if ( C h a r .T o U p p e r (i n p u t ) == 'V') {
a c c o u n t . V i e w F i l e ();
} else {
break; .
}
a c c o u n t . V i e w F i l e ();
namespace Chapter5 {
class B a n k A c c o u n t {
p r o t e c t e d stri ng first_name;
p r o t e c t e d st rin g last_name;
p r o t e c t e d long a cco unt _ n u m b e r ;
p r o t e c t e d de c i m a l checking;
p r o t e c t e d d e c i m a l savings;
p r o t e c t e d short p i n _nu mbe r;
p r i v a t e v o i d R e a d F i l e () {
S t r e a m R e a d e r file = new S t r e a m R e a d e r (@ " C : \ M y F i l e . t x t ") ;
p i n _ n u m b e r = s h o r t .P a r s e (f i l e .R e a d L i n e ());
a c c o u n t _ n u m b e r = l o n g .P a r s e (f i l e .R e a d L i n e ());
savin gs = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
c h e c k i n g = d e c i m a l .P a r s e (f i l e .R e a d L i n e ());
f i r s t _ n a m e = f i l e .R e a d L i n e ();
la s t _ n a m e = f i l e .R e a d L i n e ();
f i l e .C l o s e ();
}
p u b l i c v oi d C r e a t e F i l e O {
C o n s o l e .W r i t e L i n e ("Enter Your N ew Pin Number: ");
p i n _ n u m b e r = s h o r t .P a r s e ( C o n s o l e .R e a d L i n e ());
R a n d o m rnd = new R a n d o m ();
a c c o u n t _ n u m b e r = rn d . N e x t (1, 100);
347
C# and Game Programming
p u b l i c v o i d V i e w F i l e () {
R e a d F i l e ();
C o n s o l e .W r i t e L i n e ("Pin Number: {0}",
pin_number);
C o n s o l e .W r i t e L i n e (" Account Number: {0}",
a c c o u n t _ n u m b e r );
C o n s o l e . W r i t e L i n e (" N a m e : {0} {1}",
first_name, last_name);
C o n s o l e .W r i t e L i n e ("Savi ngs Balance: {0}",
s a v i n g s );
C o n s o l e .W r i t e L i n e ("C hec k i n g Balance: {0}",
checking);
348
Chapter 5: Object-Oriented Design
char input;
while (true) {
C o n s o l e .W r i t e L i n e ("Enter <C> to c rea te ne w file or " +
"<V> to vie w a c c o u n t " ) ;
input = c h a r .P a r s e ( C o n s o l e .R e a d L i n e ());
if(Char.ToUpper(input) == ' C !) {
a c c o u n t .C r e a t e F i l e ();
} else if ( C h a r .T o U p p e r (input) == 'V') {
a c c o u n t . V i e w F i l e ();
} else {
break;
}
a c c o u n t .V i e w F i l e ();
}
}
}
}
Destructors
In addition to constructors, we can also use destructors to return the allocated portions of an
object’s memory back to the heap. This destruction, or deallocation, of system resources is
an extremely im portant systems saving technique, especially when dealing with thousands
of class objects th a t continue to exist even after they are no longer referenced. Again, while
M anaged C++ and C# do handle these instances automatically, it is still im portant to under
stand the concept of creating a destructor. Destructors are also autom atically referenced at
the term ination of a set of coding, but the exact internal structure will depend on the
constructor’s applications and thus is user-defined. The correct way to define a destructor is
to reproduce the class’ definition (as done for the constructor), but with the addition of the
tilde operator (~). Destructors contain no argum ents and do not require a data type. Classes
should be w ritten to include only one destructor. D estructors do not retu rn values, nor can
they be overloaded (see Example 5.27).
349
C# and Game Programming
na m e s p a c e Cha p t e r 5 {
class B a n k A c c o u n t {
p u b l i c dec i m a l Intere stR ate ;
p u b l i c de ci m a l LoanRate;
// Defa ult C o n s t r u c t o r
p u b l i c B a n k A c c o u n t () {
I n t e r e s t R a t e = .03M;
L o a n R a t e = .13M;
}
// O v e r l o a d e d C o n s t r u c t o r
public BankAccount(decimal IRate) {
I n t e r e s t R a t e = .03M;
L o a n R a t e = .13M;
}
// O v e r l o a d e d C o n s t r u c t o r
public BankAccount(decimal IRate, de c i m a l LoanRate) {
I n t e r e s t R a t e = .03M;
L o a n R a t e = .13M;
}
// D e s t r u c t o r
^ B a n k A c c o u n t (){}
}
class Class l {
s ta tic v o i d Main() {
B a n k A c c o u n t ac co u n t = new B a n k A c c o u n t ();
}
}
}
350
Chapter 5: Object-Oriented Design
when dealing with operator overloading is understanding th at all abbreviated forms should
be made implicit, th a t is, anyone who references it should inherently know any action
implied by an overloaded operator. To accomplish this we need only to take note of the
implied m eaning before the operator is expanded. For example when working with simple
addition, we might conclude th a t the equation x = 4 + 2 returns the value 6. This observation
would be based on the implied understanding of the “+” symbol. If we were to abuse the
overloading process to include x = 4/2 (equaling 6) this would not be inherently implied, thus
it could potentially confuse the programmer.
To understand the reasoning behind the application of overloaded operators, simply re
define the task to meet the need. For example, by converting the first value, 4, into a public
class member, (Class.number = 4; a n d X = Class.number + 2 ;) , the num eric
calculations would not be altered and operator overloading would not be necessary. In addi
tion, by converting th a t value into a private class member using a get or read function to
retriev e th a t value (s h o r t Class .ReadValue () {r e t u r n ( t h i s .number) ; } "X =
Class .ReadValue () + 2;"), overloading would rem ain unnecessary. Further, if we express
the object Class to imply Class.number, but replace the cumbersome operation of relaying
th a t value through a get or read function with th a t of a nested class component, the same
implicit reasoning still applies ("X = Class .ComponentNumber + 2; "). However, while
this is m athem atically sound, it is not inherently understood by the computer. Thus, in
order to define the action of adding an implied class member to th a t of a numeric value, it is
necessary to build a secondary application for the “+” operator, which, of course, is an over
loaded version of th a t operator, hence the term operator overloading.
+ - * / %
!=
> < >= <= ==
» « ! ++ —
351
C# and Game Programming
Again, while C# doesn’t formally allow for the overloading of the assignm ent operator
(=), classes can be copied using the built-in function. It should also be noted th a t whenever
any of the m athem atical operators (+, -,*,/) are overloaded, the companion shortcuts are
im plied (+=, -=, *=, /=); see Exam ple 5.28.
n am e s p a c e C o n s o l e A p p l i c a t i o n l {
p u b l i c class O bje c t s {
int Number;
p u b l i c O b j e c t s ( i n t value) {
t h i s . N u m b e r = value;
}
352
Chapter 5: Object-Oriented Design
s t at ic voi d Main() {
O b j e c t s Cl as s l = ne w O b j e c t s (4);
O b j e c t s C la ss2 = ne w O b j e c t s (2);
// S t a n d a r d a r i t h m e t i c
C l a s s l .N u m b e r += 2;
Console.WriteLine(Classl.Number);
C l a s s l .N u m b e r -= 2;
Console.WriteLine(Classl.Number);
C l a s s l .N u m b e r *= 2;
Console.WriteLine(Classl.Number);
C l a s s l .N u m b e r /= 2;
C o n s o l e .W r i t e L i n e ( C l a s s l . N u m b e r ) ;
// O b j e c t - t o - n u m e r i c v al u e (or variable)
Clas sl += 2;
C o n s o l e .W r i t e L i n e ( C l a s s l .N u m b e r ) ;
C la ssl -= 2;
C o n s o l e .W r i t e L i n e ( C l a s s l .N u m b e r ) ;
C la ssl *= 2;
C o n s o l e .W r i t e L i n e ( C l a s s l .N u m b e r ) ;
Cl ass l /= 2;
Console.WriteLine(Classl.Number);
353
C# and Game Programming
// O b j e c t - t o - O b j e c t
Class l += Class2;
Console.WriteLine(Classl.Number) ;
Classl -= Class2;
Console.WriteLine(Classl.Number);
Class l *= Class2;
C o n s o l e . W r i t e L i n e ( C l a s s l .N u m b e r ) ;
Classl /= Class2;
Console.WriteLine(Classl.Number);
}
}
}
na m e s p a c e Cha p t e r 5 {
class O b j e c t s {
int Number;
// C o n s t r u c t o r
p u b l i c O b j e c t s ( i n t Value) {
t h i s . N u m b e r = Value;
}
354
Chapter 5: Object-Oriented Design
// O b j e c t - t o - O b j e c t
if (Classl > Class2)
Console.WriteLine(true);
if (Classl < Class2)
C o n s o l e .W r i t e L i n e ( t r u e ) ; // false
if (Classl >= Class2)
Console.WriteLine(true);
355
C# and Game Programming
namespace Chapter5 {
p u b l i c class P e r i o d i c T a b l e {
p u b l i c class At o m s {
p u b l i c s t ri ng Symbol;
p u b l i c int Number;
p u b l i c d e c i m a l Weight;
p u b l i c A t o m s () {}
p u b l i c st at i c bool o p e r a t o r != (P e r i o d i c T a b l e .A t o m s NE,
A to ms At) {
re tur n (NE.Weight != At .We i g h t ) ;
}
356
Chapter 5: Object-Oriented Design
p u b l i c o v e r r i d e int G e t H a s h C o d e (){
r et urn t h i s .G e t H a s h C o d e ();
}
p u b l i c o v e r r i d e bool E q u a l s ( o b j e c t Ob) {
r e t u r n ( t h i s .E q u a l s ( O b ) );
}
pu b l i c P e r i o d i c T a b l e .A to m s H y d r o g e n =
new P e r i o d i c T a b l e . A t o m s (" H " , 1, 1.0079M);
public PeriodicTable.Atoms Helium =
ne w P e r i o d i c T a b l e . A t o m s (" H e " , 2, 4.00260M);
pu b l i c P e r i o d i c T a b l e .A to m s L i t h i u m =
new P e r i o d i c T a b l e . A t o m s (" L i " , 3, 6.941M);
public P e r i o d i c T a b l e .A to m s B e r y l l i u m =
n ew P e r i o d i c T a b l e . A t o m s (" B e " , 4, 9.01218M);
public P e r i o d i c T a b l e .A t o m s B oro n =
new P e r i o d i c T a b l e .A t o m s (" B " , 5, 10.81M);
// . . .
p u b l i c P e r i o d i c T a b l e .A t o m s U n n i l h e x i u m =
new P e r i o d i c T a b l e .A t o m s (" U n h " , 106, 2 6 3 M ) ;
s t at ic v o i d Main() {
P e r i o d i c T a b l e A l l E l e m e n t s = ne w P e r i o d i c T a b l e ();
PeriodicTable.Atoms NewElement =
new P e r i o d i c T a b l e . A t o m s (" X X X " , 10, 1.0079M);
if ( N e w E l e m e n t .W e i g h t == A l l E l e m e n t s .H y d r o g e n .W e i g h t )
C o n s o l e .W r i t e L i n e ("H ydr o g e n M a t c h !");
else if ( N e w E l e m e n t .W e i g h t == A l l E l e m e n t s .H e l i u m .W e i g h t )
C o n s o l e . W r i t e L i n e (" H eli um M a t c h !");
else if ( N e w E l e m e n t .W e i g h t == A l l E l e m e n t s .U n n i l h e x i u m .W e i g h t )
C o n s o l e . W r i t e L i n e ( " U n n i l h e x i u m M a t c h !");
else
C o n s o l e .W r i t e L i n e ("You 1ve d i s c o v e r e d a new element! \n");
357
C# and Game Programming
na m e s p a c e C h a p t e r 5 {
p u b l i c class T e l e v i s i o n {
pu b l i c bool Power;
p u b l i c short Channel;
pu b l i c T e l e v i s i o n () {
th i s . C h a n n e l = 2;
t h i s . P o w e r = false;
}
358
Chapter 5: Object-Oriented Design
TV++;
TV--;
}
}
}
Introducing Inheritance
It is through the use of inherited classes, th eir v irtu al functions, and the m ethods and
fields used to construct those classes th a t transform s this definition from abstraction to
a tangible coding methodology. The theory behind object-oriented program ming embraces
three key principles: encapsulation, inheritance, and polymorphism. It is natural, then, to
include in those principles, a generic reusability and a hierarchical structure.
Inheritance is the ability of a specialized, or derived, class to appropriate the coding
included in an abstract or base class. This appropriation allows for the readm inistration
of the base class’ a ttrib u tes w ithout the cost of redevelopm ent and testing usually found
when attem pting to expand upon a previously developed component. Hence, a derived
class is a combination of its unique coding and th a t of the linked coding. Once a derived
class is established, it too becomes subject to other derived classes, or w hat can be
thought of as a string of inherited classes. This should not be confused w ith the term
m ultiple inheritance, which signifies the conjoining of two or more distinctly different
classes to create an all-purpose class. W ith single inheritance, each level takes on the
attrib u tes of all of the previous levels, creating a hierarchical stru ctu re th a t is based on
abstraction rather than distinction, and is therefore the preferred method. Inherited classes
are also subject to the three levels of access: public, protected, and private. Our first
two examples define a simple, publicly inherited class as it relates to a set of public and
protected accessible member variables and functions (see Examples 5.32 and 5.33).
n a m e s p a c e Ch a p t e r 5 {
pu b l i c class B a s e C l a s s {
359
C# and Game Programming
pu b l i c B a s e C l a s s O {}
p u b l i c B a s e C l a s s (short w, short 1) {
W i d t h = w;
L e n g t h = 1;
}
p u b l i c s t ati c v o i d R e a d W i d t h ( B a s e C l a s s X) {
Console.WriteLine(X.Width);
}
p u b l i c s t ati c v o i d R e a d L e n g t h ( B a s e C l a s s X) {
C o n s o l e .W r i t e L i n e ( X .L e n g t h ) ;
}
}
p u b l i c c lass D e r i v e d C l a s s : BaseClass {
D e r i v e d C l a s s (short w, short 1) {
W i d t h = w;
L e n g t h = 1;
}
p u b l i c sta tic v o i d D i s p l a y A r e a (D e r i v e d C l a s s Y) {
C o n s o l e .W r i t e L i n e ("Area = " + Y .W i d t h * Y .L e n g t h ) ;
}
s t at ic v o i d Main() {
D e r i v e d C l a s s I n s tan ce = new D e r i v e d C l a s s (5, 6);
R e a d W i d t h (I n s t a n c e ) ;
R e a d L e n g t h (I n s t a n c e ) ;
D i s p l a y A r e a (I n s t a n c e ) ;
namespace Chapter5 {
p u b l i c class B a s e C l a s s {
p r o t e c t e d short Width, Length;
p u b l i c B a s e C l a s s O {}
p u b l i c B a s e C l a s s ( s h o r t w, short 1) {
W i d t h = w;
360
Chapter 5: Object-Oriented Design
L e n g t h = 1;
}
p u b l i c sta tic v o i d R e a d W i d t h ( B a s e C l a s s X) {
C o n s o l e .W r i t e L i n e ( X . W i d t h ) ;
}
p u b l i c s t ati c v o i d R e a d L e n g t h ( B a s e C l a s s X) {
C o n s o l e .W r i t e L i n e ( X .L e n g t h ) ;
}
}
p u b l i c class D e r i v e d C l a s s : BaseClass {
D e r i v e d C l a s s (short w, short 1) {
W i d t h = w;
L e n g t h = 1;
}
p u b l i c stat ic v o i d D i s p l a y A r e a (D e r i v e d C l a s s Y) {
C o n s o l e .W r i t e L i n e ("Area = " + Y . W i d t h * Y .Length);
}
st ati c v o i d Main() {
D e r i v e d C l a s s I nst anc e = new D e r i v e d C l a s s (5, 6);
R e a d W i d t h (I n s t a n c e );
R e a d L e n g t h (I n s t a n c e );
D i s p l a y A r e a (I n s t a n c e ) ;
}
}
}
361
C# and Game Programming
E xam ple 5.34. P u b lic in h e r ita n c e w ith p r o tec te d m eth o d s and field s.
using System;
n a m e s p a c e C h a pt e rs {
p u b l i c class B a s e C l a s s {
p r o t e c t e d short Width, Length;
p r o t e c t e d B a s e C l a s s () {}
p r o t e c t e d B a s e C l a s s (short w, short 1) {
362
Chapter 5: Object-Oriented Design
W i d t h = w;
L e n g t h = 1;
}
p r o t e c t e d st at i c short R e a d W i d t h ( B a s e C l a s s X) {
r e t u r n ( X .W i d t h ) ;
}
p r o t e c t e d s t a tic short R e a d L e n g t h ( B a s e C l a s s X) {
r e t u r n ( X .L e n g t h ) ;
}
}
p u b l i c class D e r i v e d C l a s s : B a s e C l a s s {
D e r i v e d C l a s s (short w, short 1) {
W i d t h = w; L e n g t h = 1;
}
p r o t e c t e d s ta tic v o i d D i s p l a y A r e a (D e r i v e d C l a s s Y) {
C o n s o l e . W r i t e L i n e ("Area = " + Y . W i d t h * Y. Length);
}
s tat ic v o i d Main() {
D e r i v e d C l a s s I n s ta nce = n ew D e r i v e d C l a s s (5, 6);
C o n s o l e .W r i t e L i n e ( R e a d W i d t h (I n s t a n c e ) );
C o n s o l e .W r i t e L i n e ( R e a d L e n g t h (I n s t a n c e ) );
D i s p l a y A r e a (I n s t a n c e ) ;
}
}
}
namespace Chapter5 {
p u b l i c class B a s e C l a s s {
p r i v a t e short Width;
p r i v a t e short Length;
p r o t e c t e d B a s e C l a s s O {}
p r o t e c t e d B a s e C l a s s ( s h o r t w, short 1) {
W i d t h = w;
L e n g t h = 1;
}
363
C# and Game Programming
p r o t e c t e d st ati c short R e a d W i d t h ( B a s e C l a s s X) {
return(X.Width);
}
p u b l i c s ta tic v o i d S e t W i d t h ( B a s e C l a s s X, short w) {
X . W i d t h = w;
}
p r o t e c t e d stat ic short R e a d L e n g t h ( B a s e C l a s s X) {
r e t u r n ( X .L e n g t h ) ;
}
p u b l i c s t ati c v o i d S e t L e n g t h ( B a s e C l a s s X, short 1) {
X . L e n g t h = 1;
}
}
p u b l i c c lass D e r i v e d C l a s s : B a s e C l a s s {
D e r i v e d C l a s s ( s h o r t w, short 1) {
S e t Wi dth (th is, w ) ;
S e t L e n g th( thi s, 1);
}
p r o t e c t e d s ta tic v o i d D i s p l a y A r e a (D e r i v e d C l a s s Y) {
C o n s o l e . W r i t e L i n e ("Area = " + Rea dWidth(Y) * R e a d L e n g t h ( Y ) );
}
s tat ic v o i d Main() {
D e r i v e d C l a s s In sta nce = new D e r i v e d C l a s s (5, 6);
C o n s o l e . W r i t e L i n e ( R e a d W i d t h (I n s t a n c e ) );
C o n s o l e .W r i t e L i n e ( R e a d L e n g t h (I n s t a n c e ) );
D i s p l a y A r e a (I n s t a n c e ) ;
}
}
}
364
Chapter 5: Object-Oriented Design
class is established, it too, becomes subject to other potentially inherited classes, and
again, all security levels are enforced (see Example 5.36).
namespace Chapter5 {
p u b l i c c lass B a s e C l a s s {
p r o t e c t e d short Width, Length;
p r o t e c t e d B a s e C l a s s () {}
p r o t e c t e d B a s e C l a s s ( s h o r t w, short 1) {
W i d t h = w;
Le n g t h = 1;
}
p r o t e c t e d s t ati c short R e a d W i d t h ( B a s e C l a s s X) {
ret u r n (X.Width);
}
p r o t e c t e d s ta tic short R e a d L e n g t h ( B a s e C l a s s X) {
r e t u r n ( X .L e n g t h ) ;
}
}
p u b l i c class D e r i v e d C l a s s : BaseClass {
p r o t e c t e d D e r i v e d C l a s s () {}
p r o t e c t e d D e r i v e d C l a s s (short w, short 1) {
W i d t h = w;
L e n g t h = 1;
}
p r o t e c t e d s ta tic v oi d D i s p l a y A r e a (D e r i v e d C l a s s Y) {
C o n s o l e .W r i t e L i n e ("Area = " + Y .W i d t h * Y .L e n g t h ) ;
}
}
p u b l i c class D e r i v e d X : DerivedClass {
p r o t e c t e d D e r i v e d X ( s h o r t w, short 1) {
W i d t h = w;
365
C# and Game Programming
Le n g t h = 1;
}
p r o t e c t e d stati c vo id D i s p l a y A r e a (D e r i v e d X Z) {
C o n s o l e .W r i t e L i n e ("Area = " + Z . Wid th * Z.Length);
}
p r o t e c t e d stat ic v o i d T r i a n g l e (D e r i v e d X Z) {
C o n s o l e .W r i t e L i n e ("The Ar e a of the T r i a n g l e is " + .5 *
Z . Wi dth * Z.Length);
}
stat ic vo i d Main() {
De r i v e d X Ins tan ce = n ew D e r i v e d X (5, 6);
C o n s o l e . W r i t e L i n e ( R e a d W i d t h (I n s t a n c e ) );
C o n s o l e . W r i t e L i n e ( R e a d L e n g t h ( I n s t a n c e ) );
D i s p l a y A r e a (I n s t a n c e );
Triangle(Instance);
366
Chapter 5: Object-Oriented Design
n a m e s p a c e Ch a p t e r 5 {
p u b l i c class A r e a {
p u b l i c short Base, Height;
p u b l i c dou b l e Radius;
p u b l i c short Base2;
367
C# and Game Programming
p u b l i c A r e a () { }
p u b lic A re a (s h o rt w, sh o rt h) {
B a s e = w;
H e ig h t = h ;
}
p u b lic A re a (d o u b le r) {
R a d iu s = r ;
}
p u b lic A re a (s h o rt a, sh o rt b, sh o rt h) {
Base = a ;
Base2 = b ;
H e ig h t = h ;
}
p u b l i c s t a t i c s h o r t R e a d B a s e (A re a X) {
re tu rn (X . B a se );
}
p u b lic s t a t i c v o id S e tB a se 2 (A re a X, s h o r t b) {
X . Base2 = b ;
}
p u b l i c s t a t i c s h o r t R e a d H e ig h t (A r e a X) {
r e t u r n ( X . H e ig h t) ;
}
p u b l i c s t a t i c d o u b le R e a d R a d iu s (A r e a X) {
r e t u r n ( X . R a d iu s ) ;
}
p u b lic s t a t i c v o id S e tR a d iu s(A re a X, d o u b le r) {
X.R a d iu s = r ;
}
368
Chapter 5: Object-Oriented Design
p u b l i c s t a t i c d o u b le S u m O f B a s e s (A r e a X) {
r e t u r n ( X . Base+ X. B a se 2 ) ;
}
p u b l i c v i r t u a l v o i d C a l c u l a t e A r e a () {
C o n s o l e . W r i t e L i n e ( "No S h a p e F o u n d \ n " ) ;
}
}
o v e r r i d e p u b l i c v o i d C a l c u l a t e A r e a () {
C o n s o le .W r it e L in e ( "A rea = " + R e a d B a s e (th is) *
R e a d H e ig h t(th is )) ;
}
}
p u b lic c la s s T r ia n g le : A rea {
p u b l i c T r i a n g l e ( s h o r t w, s h o r t 1) {
S e t B a s e ( t h i s , w) ; S e t H e i g h t ( t h i s , 1 ) ; }
o v e r r i d e p u b l i c v o i d C a l c u l a t e A r e a () {
C o n s o le .W r ite L in e ( "\n A rea = " + (R e a d B a s e (th is ) *
R e a d H e ig h t(th is )) / 2 ) ; }
}
p u b lic c la s s C i r c l e : A rea {
p u b l i c d o u b le P I = 3 .1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 2 6 4 3 3 8 3 2 7 9 5 ;
p u b lic C irc le (d o u b le r) {
S e tR a d iu s (th is , r ) ;
}
o v e r r i d e p u b l i c v o i d C a l c u l a t e A r e a () {
C o n s o le .W r it e L in e ( "\n A rea = " + (P I * R e a d R a d iu s (th is ) *
R e a d R a d iu s (th is )) ) ;
}
}
p u b lic c la s s T ra p e z o id : A rea {
p u b lic T ra p e z o id (s h o rt a, sh o rt b, short h) {
S e tB a s e (th is , a );
369
C# and Game Programming
o v e r r i d e p u b l i c v o i d C a l c u l a t e A r e a () {
C o n s o l e .W r i t e L i n e (" \n Are a = " + Re adH e i g h t ( t h i s ) *
(S u m O f B a s e s (thi s)) / 2);
}
p u b l i c s t ati c v o i d C a l c u l a t e A r e a ( A r e a Relay) {
R e l a y .C a l c u l a t e A r e a ();
}
st ati c v o i d Main() {
A r e a Shape = ne w A r e a ();
370
Chapter 5: Object-Oriented Design
As stated and restated throughout this chapter, our primary goal is to develop
abstract objected-oriented classes to be used as both a foundation and a
reusable base that will move us into the higher levels of programming. Therefore,
our development of classes must include completely abstracted versions of
both member functions and their variables, so that base classes are capable of
adapting to a host of scenarios such as calculating either whole or floating
point values, defining Boolean types, and referencing characters without the
need to revise our coding. This should be a sustained goal as both a student of
C# and throughout your future as a programmer.
A bstract
Another useful feature when dealing with inheritance is the ability to declare a class using
an abstract modifier, which is a modifier th a t alters the application of a class by allowing
it to be used as a reference only by other inheriting classes. The practical application of
abstract modifiers becomes obvious as we restric base references in order to produce a
large base of generic classes. A bstract classes cannot be instan tiated , nor can they be
modified w ith a sealed modifier (sealed modifiers are defined later in this chapter). Only
ab stract classes may use abstract m ethods and abstract accessors, b ut all nonabstract
classes derived from such classes m ust include im plem entations of the abstract references
to guarantee th a t those methods will be referenced from the derived class. A bstract m eth
ods are also implicitly virtual, thus, th at distinction need not be declared. Inheriting classes
w ishing to duplicate static m ethods referenced from w ithin an abstract base m ust also
include an overriding modifier.
371
C# and Game Programming
namespace Chapter5 {
p u b l i c a b s t r a c t class A r e a {
p u b l i c short Base, Height;
p u b l i c dou b l e Radius;
p u b l i c short Base2;
p u b l i c A r e a () {}
p u b l i c A r e a ( s h o r t w, short h) {
Base = w;
He i g h t = h;
}
p u b l i c A r e a ( d o u b l e r) {
Ra diu s = r;
}
p u b l i c A r e a ( s h o r t a, short b, short h) {
Base = a;
Base2 = b;
He i g h t = h;
}
p u b l i c s t ati c v o i d S e t B a s e ( A r e a X, short a) {
X . B a s e = a;
}
p u b l i c s tatic short R e a d H e i g h t ( A r e a X) {
r e t u r n ( X .H e i g h t );
}
p u b l i c st ati c v o i d S e t H e i g h t ( A r e a X, short h) {
X . H e i g h t = h;
372
Chapter 5: Object-Oriented Design
p u b l i c s t a t i c d o u b le R e a d R a d i u s ( A r e a X) {
r e tu rn (X .R a d iu s );
}
p u b lic s t a t i c v o id S e tR a d iu s(A re a X, d o u b le r) {
X .R a d iu s = r ;
}
p u b l i c s t a t i c d o u b le S u m O f B a s e s (A r e a X) {
r e t u r n ( X . Base + X .B a s e 2 );
}
p u b l i c v i r t u a l v o i d C a l c u l a t e A r e a () {
C o n s o le .W r it e L in e (" N o Shape F o u n d \n " ) ;
}
p u b lic s t a t i c v o id C a lc u la t e A r e a (A re a R e la y ) {
R e la y . C a lc u la te A re a ( ) ;
}
s t a t i c v o id M a in () {
P a r a l l e l o g r a m S h a p e l = new P a r a l l e l o g r a m ( 5 , 5 );
C a lc u la te A re a (S h a p e l);
P a r a l l e l o g r a m S h a p e 2 = new P a r a l l e l o g r a m ( 5 , 6 );
C a lc u la te A re a (S h a p e 2 ) ;
T r i a n g l e S h a p e 3 = n ew T r i a n g l e ( 5 , 6 );
C a lc u la te A re a (S h a p e 3 );
C i r c l e S h a p e 4 = n ew C i r c l e ( 3 ) ;
C a lc u la te A re a (S h a p e 4 ) ;
T r a p e z o i d S h a p e 5 = n ew T r a p e z o i d ( 4 , 5, 6 );
C a lc u la te A re a (S h a p e 5 );
}
}
373
C# and Game Programming
o v e r r i d e p u b l i c v o i d C a l c u l a t e A r e a () {
C o n s o l e .W r i t e L i n e ("Area = " + R e a d B a s e (t h i s ) ★
R e a d H e i g h t ( t h i s ) );
}
p u b l i c class T r i a n g l e : A r e a {
pu b l i c T r i a n g l e ( s h o r t w, short 1) {
Set Bas e(t his , w ) ;
Se t H e i g ht( thi s, 1);
}
o v e r r i d e p u b l i c v o i d C a l c u l a t e A r e a () {
'k
C o n s o l e . W r i t e L i n e ("\n A r e a = " + (ReadBase(this)
R e a d H e i g h t ( t h i s ) ) / 2);
}
p u b l i c class C i r c l e : A r e a {
p u b l i c d ou b l e PI = 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 2 6 4 3 3 8 3 2 7 9 5 ;
p u b l i c C i r c l e ( d o u b l e r) {
S e t R a d ius (th is, r ) ;
}
o v e r r i d e p u b l i c v o i d C a l c u l a t e A r e a () {
C o n s o l e .W r i t e L i n e ("\n A r e a = " + (PI * R e a d R a d i u s ( t h i s )
R e a d R a d i u s ( t h i s ) ));
}
p u b l i c class T r a p e z o i d : A r e a {
p u b l i c T r a p e z o i d (short a, short b, short h) {
Set Bas e(t his , a);
S e t B ase 2(t his , b ) ;
SetHeight(this, h ) ;
}
o v e r r i d e p u b l i c v o i d C a l c u l a t e A r e a () {
C o n s o l e .W r i t e L i n e ("\n A r e a = " + R e a d H e i g h t ( t h i s ) ★
(SumOfBases ( thi s)) / 2);
}
374
Chapter 5: Object-Oriented Design
The Keyword b a s e
As we continue to work w ith inherited classes, we find ourselves running into the problem
of redundant m em ber references or repeated nam e use. This wouldn’t norm ally create a
problem, unless we also ra n into the special circum stance of needing to reference the
original base member from within an inherited class. The solution is fairly simple, achieved
by applying a base reference indicator, or delineated m em ber identifier, as shown in Ex
ample 5.39.
Base references can be used with all aspects of an inheriting class, but their
referencing methods cannot include a static modifier.
E x a m p le 5.39. T h e k e y w o r d b a se .
us ing System;
na m e s p a c e C h a p t e r 5 {
p u b l i c class B a s e C l a s s {
p r o t e c t e d short Width, Length;
pu b l i c B a s e C l a s s () {}
p u b l i c B a s e C l a s s (short w, short 1) {
W i d t h = w;
Le n g t h = 1;
p u b l i c st atic v o i d R e a d W i d t h ( B a s e C l a s s X) {
C o n s o l e .W r i t e L i n e ( X .W i d t h ) ;
}
p u b l i c stat ic v o i d R e a d L e n g t h ( B a s e C l a s s X) {
C o n s o l e . W r i t e L i n e ( X .L e n g t h ) ;
375
C# and Game Programming
p u b l i c vir t u a l vo i d D i s p l a y A r e a (D e r i v e d C l a s s Y) {
C o n s o l e .W r i t e L i n e ("Area = " + Y . W i d t h * Y.Length);
p u b l i c class D e r i v e d C l a s s : BaseClass {
D e r i v e d C l a s s (short w, short 1) {
W i d t h = w;
L e n g t h = 1;
p u b l i c o v e r r i d e v o i d D i s p l a y A r e a (D e r i v e d C l a s s Y) {
b a s e .D i s p l a y A r e a (Y ) ;
s tatic v o i d Main() {
DerivedClass In sta nce = new D e r i v e d C l a s s (5, 6)
R e a d W i d t h (I n s t a n c e );
R e a d L e n g t h (I n s t a n c e ) ;
I n s t a n c e .D i s p l a y A r e a ( I n s t a n c e );
Exception Handling
A nother feature th a t adds sophistication to our program s is the ability to catch excep
tion errors. Exception errors are errors throw n by a program/W indows during execu
tion, and can range from simple input errors to problems such as missing files, division by
zero, etc. All questionable coding is placed inside of w hat is known as a try block, which is
a block of coding th a t may or may not succeed. If this coding does fail, the program im m e
diately tu rn s to a catch block (or an assortm ent of catch blocks), which can be either
general or specific. Upon completion of either the try or the catch block, a tertiary block is
executed, known as the final or finally block, which is always executed upon the term in a
tion of try and catch blocks (see Exam ples 5.40 and 5.41).
376
Chapter 5: Object-Oriented Design
namespace Chapter5 {
p u b l i c class Err ors {
sta tic v o i d Main() {
int e ight = 8, zero = 0;
try {
Console.WriteLine(eight / zero);
} catc h {
C o n s o l e .W r i t e L i n e ("Error D e t e c t e d " ) ;
} finally {
C o n s o l e . W r i t e L i n e ("P r o g r a m C o m p l e t e !");
namespace Chapter5 {
p u b l i c class Err ors {
sta tic v o i d Main() {
int eight = 8, zero = 0;
try {
C o n s o l e . W r i t e L i n e ( e i g h t / zero);
} catch ( D i vid eBy Zer oEx cep tio n) {
C o n s o l e .W r i t e L i n e (" E r r o r : A t t e m p t i n g to Divide by Zero");
} catc h {
C o n s o l e .W r i t e L i n e ("Error D e t e c t e d " ) ;
} fi na l l y {
C o n s o l e . W r i t e L i n e ("P r o g r a m C o m p l e t e !");
}
}
}
}
377
C# and Game Programming
The null reference refers to an object that has not yet been assigned; it basically
serves as a blank or nonvalue that can be substituted for later. It is also the
default value to any nonassigned reference types, and it can be used to mark a
position where no actual reference is needed.
n a m e s p a c e Ch a p t e r 5 {
p u b l i c class Err ors {
s ta tic v o i d Main() {
int X, Y;
w h i l e (true) {
C o n s o l e .W r i t e ("Enter your n u m e r a t o r now: ");
X = i n t .P a r s e ( C o n s o l e .R e a d L i n e ());
C o n s o l e .W r i t e ("Enter your d e n o m i n a t o r now: ");
Y = i n t .P a r s e ( C o n s o l e .R e a d L i n e ());
try {
Console.WriteLine(X / Y ) ;
} cat c h (D i v i d e B y Z e r o E x c e p t i o n ) {
C o n s o l e .W r i t e L i n e ("Di v i s i o n by Zero A t t e m p t e d !\ n " );
C o n s o l e . W r i t e ("P lease ent e r a new d e n o m i n a t o r now: ");
Y = i n t .P a r s e ( C o n s o l e .R e a d L i n e ());
try {
C o n s o l e .W r i t e L i n e ( X / Y);
} c a tch {
C o n s o l e . W r i t e L i n e ( " E r r o r ! ");
break;
378
Chapter 5: Object-Oriented Design
} c atc h {
Console.WriteLine("Error Detected");
The Keyword th ro w
In addition to being able to t r y - c a t c h both generalized and specific exceptions, we can also
learn to throw, and, subsequently, re cat ch those exceptions. These new exceptions can then
be used to readdress our initial responses with specific error correction techniques and/or allow
for additional exceptions to be caught. However, if no associated catches are found, the line of
processing is sent back to the .Net framework, which ultim ately halts the program.
A specific response requires a static m ethod from w ithin the m ain class, or a nonstatic
m ethod as p art of a secondary class. The new exception will then be recaptured by the
secondary catch clause. Notice th a t the second clause is specifically set up to repeat w h at
ever quote is included with th a t m ethod’s exception; if needed, we could include a host of
exception classes, all using the same type of message reflecting (see Example 5.43).
namespace Chapter5 {
p u b l i c class Er rors {
sta tic vo i d Main() {
s tr ing Input;
int X, Y;
w hi le (true) {
C o n s o l e .W r i t e ("Enter your n u m e r a t o r now: ");
Input = C o n s o l e .R e a d L i n e ();
if (c h a r .I s N u m b e r (I n p u t , 0)) {
X = i n t .P a r s e (I n p u t );
379
C# and Game Programming
} else {
th r o w new D i v i d e B y Z e r o E x c e p t i o n ("\nPro gra m Error!");
}
if (c h a r .I s N u m b e r (I n p u t , 0)) {
Y = i n t .P a r s e (I n p u t );
} else {
t h r o w new D i v i d e B y Z e r o E x c e p t i o n ("\nPro gra m Error!");
}
try {C o n s o l e .W r i t e L i n e ( X / Y);
} catch(DivideByZeroException) {
C o n s o l e .W r i t e L i n e (" D i v isi on by Zero a t t e m p t e d !\ n " );
C o n s o l e . W r i t e ("Please e nt e r a n e w d e n o m i n a t o r now: ");
Y = c h a r .P a r s e ( C o n s o l e .R e a d L i n e ());
try {
C o n s o l e .W r i t e L i n e ( X / Y);
} ca tch {C o n s o l e .W r i t e L i n e (" E r r o r !");
break;
}
} ca t c h {
C o n s o l e .W r i t e L i n e ("Error D e t e c t e d " ) ;
}
}
}
}
}
380
Chapter 5: Object-Oriented Design
namespace Chapter5 {
p u b l i c class M y E x c e p t i o n : S y s t e m .A p p l i c a t i o n E x c e p t i o n {
p u b l i c M y E x c e p t i o n (s tr ing Comment) : b a s e ( C o m m e n t ) {}
}
p u b l i c class Error s {
s t at ic voi d Main() {
E rro rs Er = n ew E r ror s ();
E r .T r y M e t h o d ();
}
p u b l i c v o i d T r y M e t h o d () {
st ri n g Input;
int X, Y;
w hi le(true) {
C o n s o l e .W r i t e ("Enter your n u m e r a t o r now: ");
Input = C o n s o l e .R e a d L i n e ();
i f ( c h a r .I s N u m b e r (Input, 0)) {
X = i n t .P a r s e (I n p u t );
} else {
t h r o w new I n d e x O u t O f R a n g e E x c e p t i o n ("X n C h a r a c t e r " +
" D e t e c t e d wh ere I nte g e r V al u e was E x c e p ted !") ;
}
try {
Console.WriteLine(X / Y ) ;
} catch (D i v i d e B y Z e r o E x c e p t i o n ) {
C o n s o l e .W r i t e L i n e (" D i v i s i o n by Zero a t t e m p t e d !\ n " );
381
C# and Game Programming
try {
C o n s o l e .W r i t e L i n e ( X / Y ) ;
} c atc h {
C o n s o l e . W r i t e L i n e ( " E r r o r !");
break;
}
} c at c h {
C o n s o l e .W r i t e L i n e ("Error D e t e c t e d " ) ;
Nested Exceptions
In addition to creating simple t r y block structures, c a tc h e s , and class based exceptions,
we can nest those exceptions to provide an even greater level of protection. Placing a
second t r y - c a t c h block inside of a secondary catch exception allows us to add a th ird
catchall block, which will execute if the error was still not contained (see Examples 5.44a
and 5.45b)
382
Chapter 5: Object-Oriented Design
w h i l e (true) {
C o n s o l e .W r i t e ("Enter your n u m e r a t o r now: ");
Input = C o n s o l e .R e a d L i n e ();
X = i n t .P a r s e (I n p u t ) ;
try {
D i v i s i o n ( r e f X, ref Y ) ;
} cat ch ( D ivi deB yZe roE xce pti on) {
C o n s o l e .W r i t e L i n e (" A t t e m p t i n g to d i v i d e b y z e r o ! " ) ;
} catc h (S y s t e m .E x c e p t i o n e) {
C o n s o l e . W r i t e L i n e ( e .M e s s a g e ) ;
try {
D i v i s i o n ( r e f X, ref Y ) ;
} c a tch {
Console.WriteLine("Error Detected");
}
}
pu b l i c static v o i d Main() {
st rin g Input;
int X, Y;
wh i l e (true) {
383
C# and Game Programming
try {
X = i n t .P a r s e (I n p u t );
} c a tch ( S y s t e m .F o r mat Exc ept ion ) {
C o n s o l e . W r t i e L i n e ("\nlnva lid Input D ete cted!");
continue;
}
try {
Y = i n t .P a r s e (I n p u t );
} ca tch (S y s t e m .F o r mat Exc ept ion ) {
C o n s o l e .W r i t e L i n e ("I n v a l i d Input D e t e c t e d - " +
" C a l c u l a t i o n T e r m i n a t e d !\ n " );
continue;
}
try {
D i v i s i o n ( r e f X, ref Y ) ;
} ca tch (D i v i d e B y Z e r o E x c e p t i o n ) {
C o n s o l e .W r i t e L i n e (" A t t e m p t i n g to div i d e by z e r o ! " ) ;
} c a tch (S y s t e m .E x c e p t i o n e) {
C o n s o l e .W r i t e L i n e ( e . M e s s a g e ) ;
try {
D i v i s i o n ( r e f X, ref Y ) ;
} c at ch {
C o n s o l e .W r t i e L i n e (" U n r e c o v e r a b l e Er r o r De tected");
}
}
}
}
384
Chapter 5: Object-Oriented Design
reference type or object such as the form ula “expression is type,” which is also equivalent
to a single call to “expression is type? (type) expression: (type) null” (see Example 5.46).
The null reference refers to an object that has not yet been assigned; it basically
serves as a blank or nonvalue, which can be substituted for later. It is also the
default value to any nonassigned reference types, and can be used to mark a
position where no actual reference is needed.
namespace Chapter5 {
p u b l i c class Test AS {
p u b l i c sta tic v o i d M a i n 0 {
o bje ct M y S t r i n g = new ob ject ();
M y S t r i n g = 123;
s tr i n g s = M y S t r i n g as string;
if (s != null)
C o n s o l e .W r i t e L i n e ( M y S t r i n g ) ;
else
C o n s o l e .W r i t e L i n e ("Test F a i l e d !");
Delegates
D elegates are objects used as references to encapsulate specific methods, which include
signatures and formal return types. The delegate, while similar to the C++ function pointer,
is actually type safe and considered OOP (Object-Oriented Programming) compliant. Del
egates also allow for six key modifiers: new, public, protected, internal, private, and
unsafe (unsafe is only used when dealing w ith param eters th a t are also pointers). Del
egates are m ost frequently used to pass m ethods as param eters. Type safety is based on
the m atching of signatures as p a rt of th eir declaration—delegates need to be declared
before they are called (see Example 5.47).
385
C# and Game Programming
namespace Chapter5 {
// P r o t oty pe
p u b l i c d e l e g a t e v o i d T r y D e l e g a t e ();
pu b l i c c lass D e l e g a t e s {
s ta tic v o i d Main() {
T r y D e l e g a t e ();
}
p u b l i c stati c v o i d T r y D e l e g a t e () {
Console.WriteLine("Hello World!");
}
}
}
E ven ts
E v e n ts are used to pass inform ation betw een d e l e g a t e s ; they are null before they are
referenced, and their properties m ust include both an add and a remove accessor. Events
are used to specify delegates and are referenced a t runtim e; they can include m ultiple
methods, and are applicable to other programs. W hen defining events, we m ust m ake sure
to include a delegate. If the event is redefined, th en we’ll only need to reference th a t del
egate (see Exam ple 5.48).
na m e s p a c e C h a p t e r 5 {
p u b l i c d e l e g a t e vo i d T r y D e l e g a t e (int i);
p u b l i c class E v e n t S e t u p {
p r i v a t e H a s h t a b l e Test = ne w H a s h t a b l e O ;
p u b l i c event T r y D e l e g a t e Event {
add {
T e s t [" E v e n t "] = (T r y D e l e g a t e )T e s t [" E v e n t "] + value;
}
386
Chapter 5: Object-Oriented Design
remo ve {
Test ["Event"] = (T r y D e l e g a t e )T e s t [" E v e n t "] - value;
}
}
}
pu b l i c class Ev ents {
p u b l i c sta tic vo i d Main() {
}
}
}
Preprocessor Directives
Preprocessor directives redirect and/or skip different portions of coding. This becomes
necessary for a num ber of complex reasons, but the actual application of these direc
tives are ra th e r simple. For example, we can define an area of coding, in sert clauses for
execution, and include error w arnings and/or d a ta filters allowing us to te st specific a s
pects and/or troubleshoot otherwise untestable clauses. The most commonly used prepro
cessor directives are the #region and #endregion m arkers, which are a special set of direc
tives th a t can hide previously tested or otherwise cumbersome coding to allow the pro
gram m er a more comfortable view of the applications a t hand. For a complete list of
preprocessor definitions, see Table 5.2 (also see Example 5.49).
#if De bugTest
#undef DebugTest
#elif R el e a s e T e s t
# w a r n i n g "This is a w a r n i n g ! "
#else
#erro r "Error Detected"
#endif
using System;
namespace Chapter5 {
class Class l {
st atic v o i d Main() {}
387
C# and Game Programming
#define and #undef The defined value is used like a variable and can be
tested and even undefined.
#error and #warning Error and warning work in basically the same way;
both allow for a statement always placed in quotes.
#if, #elif, #else, and #endif #if works in basically the same manner as the if
statement, including the else-if (#elif) and I (#else)
statement. The only addition would be the #endif
which works like the standard Iblock.
#region and #endregion The region and end region markers are used to
mark a certain block of coding. That block can
then be collapsed and even given a name.
388
Chapter 5: Object-Oriented Design
p u b l i c class Classl {
[Dlllmport (" w i n m m .d l l 11) ]
p u b l i c static ex te r n long P l a y S o u n d (S tri ng IpszName, long hModule,
long d w F l a g s ) ;
stat ic v o i d Main() {
P l a y S o u n d ( @ nm e d i a \ M o u s e .w a v " , 0, 0);
}
}
}
The e x p l i c i t Operator
The keyword e x p l i c i t is used to define an explicit type conversion, which is a conversion
th a t would not normally be allowed by basic implicit reasoning. The standard implicit types
convert only from lower to higher accuracy, which prevents data loss. Occasionally, however,
the program m er will w ant to reverse th a t process and formally reduce the accuracy of the
data type, anticipating no relevant loss in computations. In such cases, an explicit modifier
can be applied (they are used with a standard class in Example 5.51).
namespace Chapter5 {
class IsByte {
byte value;
p u b l i c IsB yt e ( i n t value) {
if (value < 0 || val ue > 255)
th row ne w A r g u m e n t E x c e p t i o n ();
t h i s . v a l u e = (byte)value;
}
p u b l i c stat ic e x p l i c i t o p e r a t o r I s B y t e ( b y t e Byte) {
retu r n new I s B y t e ( B y t e ) ;
}
389
C# and Game Programming
The i m p l i c i t O perator
T h e k e y w o rd i m p l i c i t is u s e d w h e n d e c la rin g a u se r-d e fin e d c o n v e rsio n o p e ra to r. I m
p licit co n v ersio n s a re called im plicitly, th u s th e y do n o t n eed to be re fe re n c e d u sin g explicit
c a sts, in c re a s in g so u rce code r e a d a b ility a s w ell a s safety. H ow ever, since im p lic it c o n v e r
sio n c a n occur w ith o u t th e p r o g r a m m e r ’s k now ledge, c a re m u s t be ta k e n : Im p lic it c o n v er
sio n s sh o u ld n e v e r be allo w ed to th ro w ex cep tio n s, n o r s h o u ld th e y be allo w ed to tr u n c a te
r e le v a n t d a ta . Im p lic it c la ss e s c a n be d e fin e d u s in g s ta tic m o d ifie rs a n d a re re fe re n c e d
u s in g in s ta n c e s (see E x a m p le 5.52).
namespace Chapter5 {
class IsByte {
byte value;
Fixed Pointers
T he keyw ord fixed, u sed only in u n sa fe mode, is a m odifier th a t se ts u n m an aged p oin t
ers to m an aged variable locations. T h ese p ositions are th en fixed, w hich m ean s th a t th ey
w on’t be subject to autom atic garbage collection (or random relocation): th e term p in n e d is
also com m only a sso cia ted w ith th is process. P oin ters in itia lized in fixed sta tem e n ts can
not be m odified; how ever, once th e sta te m e n t is executed, th e variab les are no longer
390
Chapter 5: Object-Oriented Design
p in n e d , h e n c e a n y re fe re n c e s to th o s e v a ria b le s sh o u ld be d o n e in th e a p p r o p r ia te fix ed
re fe re n ce (see E x a m p le 5.53).
namespace Chapter5 {
class ClassFixed {
public int variable;
}
class Classl {
static unsafe void Main () {
ClassFixed TestFixed = new C l a s s F i x e d ();
391
C# and Game Programming
namespace Chapter5 {
public class BaseClass {
public short width, length;
protected BaseClass () {}
392
Chapter 5: Object-Oriented Design
p u b l i c new s h o r t L e n g t h {
get {
r e t u r n (le n g t h );
}
}
p r o t e c t e d s t a t i c v o id D is p la y A r e a ( D e r iv e d C la s s Y) {
C o n s o l e . W r i t e L i n e ( " A r e a = " + Y .W i d t h * Y . L e n g t h ) ;
}
}
p u b l i c c l a s s D e r iv e d X : D e r i v e d C l a s s {
p r o t e c t e d D e r iv e d X (s h o r t w, s h o r t 1) {
w id t h = w ;
le n g t h = 1 ;
}
p r o t e c t e d s t a t i c v o i d D i s p l a y A r e a ( D e r i v e d X Z) {
C o n s o l e . W r i t e L i n e ( " A r e a = " + Z .W i d t h * Z . L e n g t h ) ;
}
p r o t e c t e d s t a t i c v o i d T r i a n g l e ( D e r i v e d X Z) {
C o n s o le . W r i t e L i n e ( "T h e A re a o f th e T r ia n g le is " + .5 *
Z .W i d t h * Z . L e n g t h ) ;
}
s t a t i c v o id M a in () {
D e r iv e d X I n s t a n c e = n ew D e r i v e d X ( 5 , 6 );
C o n s o le .W r it e L in e ( I n s t a n c e . W id t h );
C o n s o le .W r it e L in e ( I n s t a n c e . L e n g t h ) ;
D is p la y A r e a ( In s t a n c e ) ;
T r ia n g le ( In s t a n c e );
}
}
Linking Interfaces
An interface is a structured set of coding used to guarantee a basic level of execution. An
interface's definition includes an attribute, an access modifier, the keyword interface, its
identifying value, and a base list. All five of the class modifiers are also compatible with
393
C# and Game Programming
namespace Chapter5 {
interface Baselnterface {
short Width {get; set;}
short Length {get; set;}
}
protected BaseClass () {}
394
Chapter 5: Object-Oriented Design
395
C# and Game Programming
The i s Operator
A s w e m ove in to th e u s e o f in te rfa c e s , w e ll n e e d to te s t o b je cts fo r c o m p a tib ility e rro rs .
T h e s e te s ts c a n b e d o n e m o s t e ffic ie n tly w ith th e i s o p e ra to r. T h e k e y w o rd i s , th e n , is a
p ra c tic a l e x p re s s io n u s e d to d e te r m in e if a n o b ject in c lu d e d a t r u n tim e is c o m p a tib le
w ith a g iv e n ty p e . T h e i s o p e r a to r w ill th e n e v a lu a te to tr u e if b o th of th e fo llow ing
c o n d itio n s a r e m e t: T h e e x p re s s io n m u s t n o t r e t u r n a n u ll v a lu e , a n d th e e x p re s s io n c a n
b e c a s t to ty p e (m e a n in g t h a t th e e x p re s s io n w ill n o t th ro w a n ex cep tio n ).
n a m e s p a c e Ch a p t e r 5 {
class T e s t C l a s s {
/* E m p t y */
}
p u b l i c class C lassl {
p u b l i c st ati c v o i d T e s t ( o b j e c t ob) {
T e s t C l a s s test;
if (ob is TestClass) {
test = (TestClass)ob;
C o n s o l e . W r i t e L i n e (" T r u e " );}
else {
C o n s o l e .W r i t e L i n e ( " f a l s e " );}
}
396
Chapter 5: Object-Oriented Design
The Keyword lo c k
A l o c k is a te m p o ra ry , m u tu a l e x c lu sio n u s e d to e n s u r e t h a t m u ltip le th r e a d s do n o t
in a d v e r te n tly a c c e ss th e s a m e s e c tio n of coding. T h e sp ec ifie d object, m u s t, of co u rse ,
b e a re fe re n c e ty p e . I f th e o b ject is a s ta tic v a ria b le , o r if th e c ritic a l se c tio n o ccu rs in a
s ta tic m eth o d , th e n th e g iv en c la ss’ e x p re ssio n w ill u s u a lly r e la te to a p ro te c te d in s ta n c e of
a v a r ia b le o r ty p e o f c la ss. E x p re s s io n s a r e w r itte n as: l o c k (e x p re ssio n ), e x e c u ta b le
block, w ith th e e x p re ssio n re p re s e n tin g th e re fere n ce ty p e, a n d th e s ta te m e n t block r e p r e
s e n tin g th e c ritic a l s e c tio n to b e p ro te c te d (see E x a m p le 5.57)
namespace Chapter5 {
class MyName {
private string name;
protected M y N a m e (string fn) {this.name = f n ; }
protected string TestName(string fn) {
if (fn == "Sal") {
throw new E x c e p t i o n ("Welcome Home!");
}
lock (this) {
if (fn != null) {
return ("nice to meet you" + this.name);
}
}
return "The End";
}
protected void Y o u r N a m e O {
C o n s o l e .W r i t e L i n e ("What is your name?");
string input = C o n s o l e .R e a d L i n e ();
TestName(input);
}
397
C# and Game Programming
namespace Chapter5 {
public class Classl {
public static void Params(params s t r i n g [] list) {
foreach(string i in list)
C o n s ol e. Wr it e("{0}", i ) ;
}
398
Chapter 5: Object-Oriented Design
The Keyword s e a le d
O ccasionally, w e ’ll w a n t to p r e v e n t o th e r p ro g ra m m e rs fro m o v e rrid in g o u r m issio n c r iti
c a l m e th o d s . T h is c a n b e d o n e th r o u g h th e u se of th e s e a l e d m odifier. O nce a c la ss is
s e a le d i t c a n no lo n g e r b e in h e r ite d , h e n c e it c a n n o t b e o v e rrid d e n o r a lte r e d in a n y o th e r
w ay ; fo r th is re a s o n , w e c a n n o t u s e s e a l e d w ith th e a b s tr a c t m odifier. R e fe r b a c k to th e
s tr u c t u r e s w e le a r n e d a b o u t a t th e s t a r t of th is c h a p te r a n d n o te t h a t th e y w e re also
im p lic itly se a le d , th u s th e y c a n n o t b e in h e rite d (see E x a m p le 5.59).
E xam p le 5.59. T he k ey w o rd s e a le d .
u s in g S y s te m ;
u s in g S y s t e m .1 0 ;
n am e sp ace C h a p te r5 {
s e a le d c l a s s B a n k A cco u n t {
p u b l i c d e c im a l I n t e r e s t R a t e ;
p u b l i c d e c im a l L o a n R a t e ;
/ / D e f a u lt C o n s t r u c t o r
p u b l i c B a n k A c c o u n t () {
I n t e r e s t R a t e = .0 3 M ;
L o a n R a t e = .1 3 M ;
}
/ / O v e r lo a d e d C o n s t r u c t o r
p u b l i c B a n k A c c o u n t (d e c im a l I R a t e , d e c im a l L o a n R a te ) {
I n t e r e s t R a t e = . 03M ;
L o a n R a t e = .1 3 M ;
}
}
c la s s C la s s l {
s t a t i c v o id M a in () {
B a n k A c c o u n t a c c o u n t = n ew B a n k A c c o u n t ();
}
}
}
399
C# and Game Programming
namespace Chapter5 {
class Classl {
public static unsafe void Main() {
int* pointerl = stackalloc i n t [3];
p o i n t e r l [0] = 1;
pointerl [1] = 2;
p o i n t e r l [2] = 3;
M etafiles Defined
400
Chapter 5: Object-Oriented Design
Game Classes—Animatedlmage.es
T h e c la s s n a m e d A n i m a t e d l m a g e w ill be u s e d to c o n tro l o u r c h a r a c te r s , in c lu d in g t h e i r
a p p e a r a n c e , m o v e m e n ts , a n d lim ita tio n s . P re c e d in g th is c la ss w e ll in c lu d e a s e t of S y s
te m re fe re n c e s ; th e s e a r e r e q u ir e d b y s e v e ra l o f th e m e th o d s in c lu d e d in th e n e x t few
se c tio n s. I t is a lw a y s n e c e s s a ry to w ra p o u r c la sse s in sid e of a c le a rly m a rk e d n a m e sp a c e ,
in t h is c a se th e n a m e s p a c e G a m e s. T h e n , w e ll d e c la re so m e fie ld s a n d c r e a te o u r c o n
s tr u c to r s (n o tice h o w e s s e n tia l c o n s tru c to r o v e rlo a d in g b eco m es w ith r e g a r d to m u ltip le
s e tu p s — se e A n i m a t e d l m a g e . c s in th e G a m e C la sse s fo ld er on th e CD -RO M ).
using System;
using System.Drawing;
namespace GameClasses {
public class Animatedlmage {
// Constants
public const int DEFAULTSTEP = 3;
public const int SOUTHWEST = 1;
public const int SOUTH = 2;
public const int SOUTHEAST = 3;
public const int EAST = 4;
public const int NORTHEAST = 5;
public const int NORTH = 6;
401
C# and Game Programming
// Member data
public int imageWidth; // Width of the image
public int imageHeight; // Height of the image
public int imagePosX; // X Position in containing object
public int imagePosY; // Y Position in containing object
public Image imageData; // The image itself
#region Constructors
public Animatedlmage () : t h i s (0,0) {} // default constructor
402
Chapter 5: Object-Oriented Design
Animation
A n im a tio n is th e illu s io n o f m o v e m e n t b a s e d o n a n u m b e r o f e le m e n ts , w h ic h in c lu d e a
c h a n g e in b a c k g ro u n d , a c h a n g e in c h a r a c te r a p p e a ra n c e , a n d th e a c tu a l p h y sic a l d is
p la c e m e n t o f a n ob ject. T h is se c tio n , th u s , is in te n d e d to re v ie w a n im a tio n n o t j u s t fro m
th e s ta n d p o in t of C a rte s ia n co o rd in ates, b u t also fro m th e v iew p o in t of th e g en eric m eth o d .
T h e m e th o d A n i m a t e () w ill b e in c lu d e d a s p a r t of th e A n im a te d lm a g e c la ss. A s a
g e n e ric c la ss/m e th o d , A n im a te d lm a g e a n d its c o m p o n e n t A n i m a t e w ill b e /h a v e b e e n r e
tr ie v a b le b y a ll o u r g a m e s. T h e e x p re ss io n u s in g G a m e C la sse s is w h a t m a k e s th e s e com
p o n e n ts u se a b le .
A n im a t e is a v ir tu a l p u b lic m e th o d t h a t d oes n o t r e tu r n a ty p e . T h e m e th o d in c lu d e s
a s w i t c h s t a te m e n t u s in g N o r t h , S o u t h , E a s t , a n d W e s t to in d ic a te U p, D ow n, L eft,
a n d R ig h t. S o u t h e a s t , S o u t h w e s t , N o r t h e a s t , a n d N o r t h w e s t allo w fo r d ia g o n a l
m o v em en ts.
H e re , w e l l w a n t to c re a te o u r f ir s t m e th o d -n o tic e ho w th e n a m e A n i m a t e () c o n v e y s it s
m e a n in g . O f co u rse , i t ’s r e a lly j u s t a sim p le s e t o f v a lu e m a n ip u la tio n s c o n tro lle d by a
s w itc h s ta te m e n t, b u t b y p la c in g it in s id e a c lass, w e d ra m a tic a lly in c re a s e its p o te n tia l.
/ / A n im a t e () p e r fo r m s a l l p o s i t io n m o v e m e n ts on t h e o b j e c t ,
v i r t u a l p u b l i c v o id A n im a t e () {
s w it c h ( d ir e c t io n ) {
c a s e SO U TH W EST:
t h i s . im a g e P o s X -= a n i m a t io n S t e p ;
t h i s . im a g e P o s Y += a n i m a t io n S t e p ;
b re a k ;
c a s e SO U TH :
t h i s . im a g e P o s Y += a n i m a t io n S t e p ;
b re a k ;
c a s e SO U TH EAST:
t h i s . im a g e P o s X += a n i m a t io n S t e p ;
t h i s . im a g e P o s Y += a n i m a t io n S t e p ;
b re a k ;
403
C# and Game Programming
case WEST:
t h i s .imagePosX -= animationStep;
break;
case EAST:
t h i s .imagePosX += animationStep;
break;
case NORTHWEST:
t h i s .imagePosX -= animationStep;
t h i s .imagePosY -= animationStep;
break;
case NORTH:
t h i s .imagePosY -= animationStep;
break;
case NORTHEAST:
t h i s .imagePosX += animationStep;
t h i s .imagePosY -= animationStep;
break;
Displaying
Rescaling Images
404
Chapter 5: Object-Oriented Design
E xam p le 5.63. C o n ta in sP o in t.
// Determines if the point is within the confines of this image
virtual public bool C o n t a i ns Po in t(int x, int y) {
return (x >= imagePosX && x <= imagePosX + imageWidth &&
y >= imagePosY && y <= imagePosY + imageHeight);
}
return ((x >= x && x <= x2) || (x2 >= x && x2 <= _x2) ||
405
C# and Game Programming
(_x >= x && _x <= x2) || (_x2 >= x && _x2 <= x2)) &&
( (y >= _y && y<= _y2) I I (y2 >= _y && y2 <= _y2) | |
(_y >= y && _y <= y2) | | (_y2 >= y && _y2 <= y 2 ) ) /
}
Now that we have a handle on the universe, w e ll want to focus our attention on
the motions used by m issiles and/or the ball. Here w e ll need to divide the
methods up between the potential games. Remember that we don't necessarily
know how our methods will be used and/or what new games might be created
after this text is published. The objects' movements break down into two
possible types: standard weapons fire and the bouncing effect of the ball.
T h e c o m m a n d C o n s t r a i n T o B o x k e e p s th e im a g e in sid e th e sc re e n — th e B o x b e in g
th e w in d o w a n d th e im a g e b e in g o u r a n im a te d c h a ra c te r. I f a c h a r a c te r a tte m p ts to m ove
b e y o n d th e lim it, th e X a n d Y c o o rd in a te s a r e a d ju s te d to m ove h im o r h e r b ac k .
if (!isActive)
return false;
406
Chapter 5: Object-Oriented Design
im a g e P o s X = c o n s t r a i n t B o x . X +
c o n s t r a i n t B o x . W i d t h - im a g e W id t h ;
re tV a l = tru e ;
}
if ( im a g e P o s Y < c o n s t r a i n t B o x . Y ) {
im a g e P o s Y = c o n s t r a i n t B o x . Y ;
re tV a l = tru e ;
} e l s e i f ( ( im a g e P o s Y + im a g e H e ig h t ) >
( c o n s t r a i n t B o x . Y + c o n s t r a in t B o x . H e ig h t ) ) {
im a g e P o s Y = c o n s t r a i n t B o x . Y +
c o n s t r a i n t B o x . H e ig h t - im a g e H e ig h t ;
re tV a l = tru e ;
}
re tu rn r e t V a l;
}
s w it c h ( d ir e c t io n ) {
c a s e SO U TH W EST:
i f (im a g e P o s X <== x ) {
d i r e c t i o n = SO U TH EAST;
} e ls e {
d i r e c t i o n = N O RTH W EST;
}
b re a k ;
c a s e SO U TH :
d ir e c t io n = N O RTH;
b re a k ;
407
C# and Game Programming
case SOUTHEAST:
if ((imagePosX + imageWidth) >= (x + width)) {
direction = SOUTHWEST;
} else {
direction = NORTHEAST;
}
break;
case WEST:
direction = EAST;
break;
case EAST:
direction = WEST;
break;
case NORTHWEST:
if (imagePosY <= y) {
direction = SOUTHWEST;
} else {
direction = NORTHEAST;
}
break;
case NORTH:
direction = SOUTH;
break;
case NORTHEAST:
if (imagePosY <= y) {
direction = SOUTHEAST;
} else {
direction = NORTHWEST;
}
break;
}
return true;
}
408
Chapter 5: Object-Oriented Design
409
C# and Game Programming
case WEST:
direction = EAST;
break;
case EAST:
direction = WEST;
break;
case NORTHWEST:
direction = SOUTHEAST;
break;
case NORTH:
direction = SOUTH;
break;
case NORTHEAST:
direction = SOUTHWEST;
break;
For the next few sections, w e ll be building on our list of subclasses, each
controlling one option per method. W ell use descriptive names to save time on
definitions; for example, the instance score refers to the character’s score, etc.
While not every method will apply to every game, the overall potential of these
subclasses should become obvious.
4 10
Chapter 5: Object-Oriented Design
namespace GameClasses {
public class Player : Animatedlmage {
using System;
using System.Drawing;
namespace GameClasses {
public class PlayerlmageArray : Player {
protected Image [] almages;
411
C# and Game Programming
almages[position] = U t i l s .L o a d l m a g e (fileName);
}
A g a in , w e ll w a n t to in c lu d e a few n ew b itm a p s , b u t a s u s u a l, w e ll w a n t to k e e p o u r
cod in g a s g e n e ric a s p o ssib le; th u s , w e ll re fe re n c e th o se im a g e s u s in g a few s ta n d a rd iz e d
m e th o d s . T h e d is tin c tio n h e r e is t h a t o u r m e th o d s a r e s p lit b e tw e e n a p r e s e t im a g e a n d
one t h a t is c o n s ta n tly b e in g u p d a te d ; if you rem em b er, o u r v e ry f ir s t g a m e in c lu d e d only a
s t a g n a n t p lay er, c re a tin g th e n e e d fo r b o th s e ts of coding.
4 12
Chapter 5: Object-Oriented Design
using GameClasses;
namespace Games {
public class MultilmagePlayer : PlayerlmageArray {
public bool isChomping;
switch (direction) {
case A n i m at ed lm ag e.N O R T H :
index = isChomping 1 1 : 6;
break;
case A n i m at ed lm ag e.S O U T H :
index = isChomping 1 1 : 0;
break;
413
C# and Game Programming
imageWidth, imageHeight);
}
public int D i s p l a y () {
int index;
switch (direction) {
case A n i ma te dl ma ge .N O R T H :
index = isChomping ? 7 : 6;
break;
case A n i m a t e dl ma ge .S O U T H :
index = isChomping ? 1 : 0;
break;
namespace GameClasses {
public class Shapes : PlayerlmageArray {
public Shapes(int n) : base(0) {}
414
Chapter 5: Object-Oriented Design
g .FillPolygon(bAlienColor, A l i e n ) ;
}
415
C# and Game Programming
g .FillPolygon(bAlienColor, A l i e n ) ;
}
416
Chapter 5: Object-Oriented Design
g .FillPolygon(bAlienColor, A l i e n ) ;
}
g .FillPolygon(bAlienColor, A l i e n ) ;
}
417
C# and Game Programming
g .FillPolygon(bTankColor, t a n k) ;
g .FillPie(bCannonColor, t h i s .imagePosX-12,
t h i s .imagePosY-12, t h i s .imageWidth, t h i s .imageHeight,
t h i s .imagePosX, t h i s .imageHeight);
}
T h e tra p e z o id r e f e r r e d to in C h a p te r 4 is u s e d to c re a te a n u m b e r of o b jects in c lu d in g
th e p o tte d p la n t (B a ttle T ennis).
4 18
Chapter 5: Object-Oriented Design
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace GameClasses {
public class Patterns : Shapes {
public Patterns(int n) : base(O) {}
419
C# and Game Programming
}
}
Gam eState.es
G a m e S ta te .e s c o n ta in s th e G a m e S ta te c la ss t h a t is re s p o n s ib le fo r m a in ta in in g sim p le
s ta te in fo rm a tio n a b o u t a g a m e su c h a s th e sp eed , s ta te ( s ta rte d , sto p p e d , etc), a n d m ode
(dem o, sin g le p la y e r, etc.). T h e G a m e S ta te c la ss is a n in d e p e n d e n t c la ss, b u t it is a v ita l
c o m p o n e n t of a ll th e g a m e s c o n s tru c te d in th is te x t (see E x a m p le 5.73 a n d G a m e S ta te .e s
on th e CD-ROM ).
using System;
namespace GameClasses {
public class GameState {
// Different speeds the game can be run in.
public const int SPEED__MINIMUM = 1;
public const int SPEED__DEFAULT = 3;
public const int SPEED__MAXIMUM = 10;
420
Chapter 5: Object-Oriented Design
// Member variables
public int currentSpeed;
public State currentState;
public Mode currentMode;
// Constructors
public GameState () {
currentSpeed = SPEED_DEFAULT;
currentState = S t a t e .Stopped;
currentMode = Mode.Normal;
}
421
C# and Game Programming
GameTimer.es
T h e G a m e T im e r C la ss s e rv e s a s a g a u g e fo r th e g a m e ’s e v e n ts; fo r ex am p le, a n e v e n t c a n
b e a d d e d , tim e d , o r re m o v e d — a d d E v e n t , T i m e d E v e n t , a n d r e m o v e E v e n t . T h e g a m e
r e lie s o n th e tim e d e v e n ts to allo w fo r a c tio n s n o t c o n tro lle d b y th e p la y e r (see E x a m p le
5.74 a n d G a m e T im e r.es o n th e CD -R O M ).
namespace GameClasses {
public class GameTimer {
// Member fields
Timer gameTimer; // main timer object
int b as el nterval; // base interval in ms
Hashtable events; // list of TimedEvent objects
// Default constructor
public G a m e T i m e r (int interval) {
events = new Hashtable ();
gameTimer = new T i m e r ();
g ame T i m e r .Interval = interval;
g am eT i m e r .Tick += new EventHandler(Tick);
baselnterval = interval;
}
422
Chapter 5: Object-Oriented Design
n o d e .stepCount = 0;
events.Add(key, node);
}
while (itemEnumerator.MoveNext()) {
node = (TimedEventNode) i temEnumerator.Value;
if (node.stepCount >= n o d e .timeStep) {
n o d e .stepCount = 0;
n o d e .d a t a .T i c k ();
} else {
n o d e .stepCount++;
}
}
}
423
C# and Game Programming
TimedEvent.es
using System;
namespace GameClasses {
public delegate void TickHandler(TimedEvent e, Object payload);
public T i m e d E v e n t () {
ticks = 0;
isCountdown = false;
SetTickHandler(new T ic k H a n d l e r (DoNothing));
}
424
Chapter 5: Object-Oriented Design
public void R e s e t () {
tickCounter = ticks;
isActive = true;
}
Utils.cs
425
C# and Game Programming
E x a m p l e 5 .7 6 . U t i l s .c s
using System;
using S ystem.Drawing;
using System.10;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Sys te m.Threading;
namespace GameClasses {
public class Utils {
// External function to play sounds
[Dlllmport(" win mm .d l l ")]
public static extern long PlaySound(String IpszName, long hModule,
long dwFlag s) ;
return imgLoad;
}
426
Chapter 5: Object-Oriented Design
class ThreadedSound {
public string strFileName;
public void P l a y O {
/ /Console.W r i t e L i n e ("P l ay in g: " + strFileName)
PlaySound(strFileName, 0, 0);
Wall.cs
using System;
using S ystem.Drawing;
namespace GameClasses {
public class Wall {
public const int HORIZONTAL = 1;
public const int VERTICAL = 2;
public const int DEF_THICKNESS = 8;
427
C# and Game Programming
E x a m p l e 5 .7 8 . I n t e r s e c t s .
return ((x >= _x && x<= _x2) || (x2 >= _x && x2 <= _x2) ||
(_x >= x && _x <= x2) || (_x2 >= x && _x2 <= x 2 ) ) &&
((y >= _y && y <= _y2) || (y2 >= _y && y2 <= _ y 2 ) ||
(_y >= y && _y <= y2) || (_y2 >= y && _y2 <= y 2 ));
E x a m p l e 5 .7 9 . D i s p l a y & R e c t a n g l e
428
Chapter 5: Object-Oriented Design
public Rectangle g et R e c t a n g l e () {
return(rect);
}
}
}
Introducing D irect3D
429
C# and Game Programming
D irect3D ’s 2D Animation—Basics
430
Chapter 5: Object-Oriented Design
Brainstorming
S ince th e p re m is e of G ro u n d A s s a u lt is t h a t th e a lie n s from th e la s t g am e a c tu a lly la n d e d ,
w e sh o u ld s ta r t th e re . F irst, w e’ll re d e sig n th e a lie n s to in clu d e w hole bodies (th e b e tte r for
a tta c k in g on foot, m y d ear). Second, w e’ll w a n t to re d e sig n o u r h e ro so t h a t h e ’s n o t a lw ay s
looking up. A s I s ta te d ju s t a m o m e n t ago, w e’ll also develop som e w alls, w h ich w ill be u se d
to sto p th e m issile s a n d force o u r c h a r a c te rs to w o rk a little for th e ir kills.
E x a m p l e 5 .8 3 . B r a i n s t o r m i n g G r o u n d A s s a u l t
431
C# and Game Programming
Graphics
W e’ll a lso n e e d to th i n k u p so m e c o lo rfu l d e sig n s. I n th is ca se , I u s e d e x te n d e d v e rs io n s
of o u r a lie n a tta c k e r . W e’ll once a g a in w a n t to u s e a sm o o th c h a n g e of colors. T h e co d in g
is a lso v e ry s im ila r to t h a t in th e la s t g am e, it u s e s a sim p le o v e rrid in g O n P a in t m e th o d
(as sh o w n in G ra n d A s s a u lt.e s on th e CD -RO M ).
E x a m p l e . 5 .8 4 . B r a i n s t o r m i n g R a t R a c e r .
Adding Animation
T h e m ice w ill h a v e fa c e s a n d b o d ie s t h a t c h a n g e slig h tly a s th e y w a lk a ro u n d th e
b o a rd . T h e y w ill o p e n a n d close th e ir m o u th s, c u rl a n d u n c u rl th e ir ta ils , a n d r o ta te th e ir
a rm s . In a d d itio n , th e y sh o u ld be a b le to m ove u p, dow n, left, a n d rig h t (see E x a m p le 5.85)
432
C h a p te r 5: O b je ct-O rie n te d D esign
E x a m p le 5.85. A n i m a t i o n s o f c h a r a c t e r s in R a t R a c e : a ) c a ts ; b ) m ic e ; c) c h e e s e
a) Cats.
b] m ice
433
C# and Game Programming
434
Chapter 5: Object-Oriented Design
Troubleshooting
If y o u ’ve g o tte n th e p re v io u s p ro g ra m s to ru n , b u t a re h a v in g tro u b le w ith th e s e new ones,
t h e n th e p ro b le m m u s t b e in th e s e tu p . T ry going b a c k ov er th e ste p s a n d re p e a tin g ste p s
fro m th e e a r lie r g a m e s. You m ig h t also w a n t to tr y in c lu d in g a ll th e c la sse s a s p a r t of th e
sa m e file. If th e co m b in ed file r u n s co rrec tly th e n th e r e m u s t be so m e th in g w ro n g w ith th e
w a y y o u ’re s e ttin g u p th e se c o n d a ry files.
Assignments
N ow t h a t y o u h a v e a w o rk in g k n o w le d g e of th e C# la n g u a g e a n d a b a sic g ra s p of g a m e
p ro g ra m m in g , i t ’s tim e t h a t you a tte m p t to develop y o u r ow n g am es. F irs t, tr y dev elo p in g
a n e ig h th g a m e t h a t tie s in to th e c la sse s a lre a d y d ev e lo p ed (N ote: N o n ew c la sse s sh o u ld
be ad d ed ). N ex t, tr y d e v elo p in g y o u r o w n s e t of classes, po ssib ly w ith tw o new g am es, a n d
th e n o n e m o re g a m e w h e re y ou a re a g a in n o t allo w ed to a lte r th o se c la sse s (in th e second
te s t, how ever, y o u m a y o p t to b u ild a d d itio n a l in h e r ite d classes).
Conclusion
So, y o u ’ve m a s te r e d th e g am es, a n d in d o ing so, h a v e m a s te re d b o th C# a n d th e concept of
o b je c t-o rien ted p ro g ra m m in g . You m ig h t now be w o n d erin g , “W h a t is n e x t— w h e re do I go
fro m h e re ? ” O r m o re im p o rta n tly , “H ow c a n I t u r n th e s e n ew fo u n d s k ills in to a p a y in g
435
C# and Game Programming
If you are using an older version of Windows and would like to access these
games without purchasing a .Net compiler, you can do so by downloading the
.Net framework which is currently located at http://msdn.microsoft.com/
netframework/downloads/default.asp.
T h a n k y o u a n d good lu ck .
436
Appendix A
Appendix A: Keywords/Reserved Identifiers
abstract decimal float namespace return try
437
Appendix B
A p p en d ix B: Reserved Identifiers Defined
abstract
A b s tra c t is a m o d ifie r u s e d to d e c la re a g e n e ric cla ss. A b s tr a c t c la s s e s c a n n o t be
i n s t a n t i a t e d ,n o r c a n th e y b e m o d ifie d w ith a s e a le d or s ta tic m o difier. O n ly a b s tr a c t
c la s s e s m a y u s e a b s t r a c t m e th o d s a n d a c c e sso rs, b u t a ll n o n a b s tr a c t c la s s e s d e riv e d
fro m th o s e c la s s e s m u s t in c lu d e im p le m e n ta tio n s of th o s e re fe re n c e s . A b s tr a c t m e th
o d s a r e a lso im p lic itly v i r tu a l a n d t h e ir in h e r itin g p r o p e rtie s m a y be o v e rrid d e n (see
E x a m p le B .l).
as
As is a b in a r y o p e ra to r t h a t allo w s for a co n v ersio n fro m a n e x p re ssio n to a d a ta ty p e . I t
is also a u s e fu l tool w h e n a tte m p tin g to av o id ex cep tio n s, sin ce it w ill r e t u r n a n u ll if th e
co n v ersio n fails (see E x a m p le B.2).
base
B ase is th e k e y w o rd u s e d to a c c e ss m e m b e rs of a b a s e c la s s fro m w ith in a n in h e r itin g
c la s s r e fe re n c e . I t is d e lin e a te d u s in g th e k e y w o rd b a s e fo llo w ed b y t h a t p a r t i c u l a r
m e m b e r ’s d e fin itio n . A b a s e c la s s c a n b e a c c e s s e d a s a c o n s tru c to r, in s ta n c e , a n d /o r
w ith a n o v e r r id in g m o d ifie r, b u t th e y c a n n o t b e u s e d w ith th e s ta tic m o d ifie r (see
E x a m p le B.3).
439
C# and Game Programming
bool
Boolean expressions a re m a th e m a tic a l re p r e s e n ta tio n s for th e co n cep ts of b o th tr u e a n d
false. T h a t is, w h ile th e ir a c tu a l e v a lu a tio n s a r e b a s e d on m a th e m a tic a l d a ta , th e ir o u t
com es a re d e te rm in e d b y a co n c e p tu a l u n d e rs ta n d in g . T h is ty p e of d e te rm in a tio n is re p r e
s e n te d in th e C # la n g u a g e s a s th e d a ta ty p e b o o l , w ith its v a ria b le s a s s ig n e d to th e
B o o lean c o n s ta n ts true o r false (see E x a m p le B.4)
E xam p le B.4.
class A p p e n d i x _ B {
st atic v o i d M a i n () {
bool V a r i a b l e l = true;
}
}
break
B r e a k , a s its n a m e im p lie s, te r m in a te s a n y en clo se d loop o r c o n d itio n a l s ta te m e n t (see
E x a m p le B.5).
E xam p le B.5.
class A p p e n d i x _ B {
static v o i d M a i n () {
while(true) {
break;
}
}
}
440
Appendix B: Reserved Identifiers Defined
byte
B y te is a n u n s ig n e d 8-bit in te g r a l d a te ty p e t h a t sto re s w hole n u m b e rs w ith a ra n g e from
0 to 255 (see E x a m p le B.6).
E x a m p l e B .6 .
class Appendix_B {
static void Main() {
byte Number = 100;
}
}
case
T h e k e y w o rd c a s e is w r itte n a n d u s e d m u ltip le tim e s fro m w ith in th e sw itch s ta te m e n t.
E a c h case s ta te m e n t h o ld s a n u m e ric o r c h a r a c te r v a lu e for co m p a riso n . I f th e v a lu e
h e ld b y a case s ta te m e n t m a tc h e s th e v a lu e r e a d b y th e sw itch s ta te m e n t, th e n e v e ry th in g
follow ing t h a t case s ta te m e n t w ill b e e x e c u te d (see E x a m p le B.7).
E x a m p l e B .7 .
class Appendix_B {
static void M a i n () {
char test = 'A' ;
switch (test) {
case ' A ' :
break;
}
}
}
catch
T h e c a t c h s ta te m e n t is p a r t of th e t r y block, a n d is u s e d to lite r a lly c a tc h a n d th e n
p o ssib ly r e p a ir a p ro g ra m w h e n a n e x c ep tio n is th ro w n . I ts c la u se s c a n in c lu d e sy ste m
e x c e p tio n s, u s e r-d e fin e d m a te ria l, a n d /o r a b la n k o r g e n e ra liz e d c a tch . N o te t h a t a try
blo ck n o rm a lly in c lu d e s m u ltip le c a tc h s ta te m e n ts , w ith th e m o st specific s ta te m e n ts
lis te d f ir s t a n d th e b la n k o r g e n e ra l s ta te m e n t p la c e d in th e f u r th e s t p o sitio n . F a ilu re to
lis t c a tc h e s in t h a t o rd e r m a y r e s u lt in a le ss specific c a tc h b e in g e x ec u ted . I t is also
p o ssib le to r e th ro w a n e x c e p tio n fro m w ith in th e c a t c h s ta te m e n t (see E x a m p le B.8).
441
C# and Game Programming
E xam p le B.8.
public class Appendix_B {
static void M a i n O {
try {}
catch {}
}
}
char
T h e c h a r a c te r re fe re n c e ( c h a r ) , is u s e d to d e c la re 16-bit Unicode c h a ra c te rs t h a t h a v e
r a n g e s from U + 0 0 0 0 to U+ffff. U nicode c h a ra c te rs a re 16-bit c h a ra c te rs u se d to re p re s e n t
n e a rly a ll of th e k n o w n la n g u a g e s a s w ell a s m ost, if n o t all, of th e tra d itio n a l m a th e m a ti
cal a n d lite r a r y sym bols. C h a r is also u s e d to r e p r e s e n t c o m b in ed v a lu e s su c h a s h e x a
d e c im a l codes a n d e scap e se q u e n c e s (see E x a m p le B.9).
checked
C h e c k e d is u s e d to m o n ito r b o th o p e ra to rs a n d s ta te m e n ts for n u m e ric overflow e rro rs a s
th e y o ccur in in te g ra l-ty p e a r ith m e tic o p e ra tio n s a n d c o n v e rsio n s (see E x a m p le B. 10).
442
Appendix B: Reserved Identifiers Defined
class
Classes a re a n a d v a n c e d d a ta ty p e, a few lev els b e y o n d a sim p le b y te , b u t n o t too d is s im i
lar. T h e y a re s im ila r to a rra y s , y e t th e y ’re c a p a b le of h o ld in g ta s k s a n d m u ltip le d a ta
ty p e s (m ore fo rm a lly k n o w n a s ta g s , fields, m e th o d s, etc.). T h ey a re c a lle d a s in s ta n c e s
(w h ich also c a n b e th o u g h t of a s v a ria b le s) t h a t ho ld m u ltip le b its of in fo rm a tio n . C la sse s
a re lim ite d a n d /o r e n h a n c e d by m o d ifiers, a n d c a n be in h e rite d (see E x a m p le B. 11).
E x a m p l e B .l l .
class Appendix_B {
static void M a i n () {}
}
const
T h e k e y w o rd constant ( c o n s t ) n o tifie s th e co m p iler of its u n c h a n g in g n a tu r e a n d allow s
it to o p tim ize t h a t a p p ro p ria te v a lu e s (see E x a m p le B.12).
E x a m p l e B.12.
class Appendix_B {
static void Main() {
const int OurVariable = 1;
continue
C o n t i n u e , lik e b r e a k , s h o rtc u ts its ite r a tio n s , b u t r a t h e r t h a n e n d in g th e loop, it m e r
rily b rin g s th e loop b a c k to th e top. T h e loop c o n tin u e s on w ith a n ew ite r a tio n a n d e v e ry
th in g else c o n tin u e s acco rd in g ly (see E x a m p le B.13).
E x a m p l e B .1 3 .
class Appendix_B {
static void Main() {
while (true) {
cont i nue ;
443
C# and Game Programming
decimal
D e c im a l is a 1 28-bit d a te ty p e t h a t s to re s ra tio n a l a n d ir r a tio n a l n u m b e rs w ith a ra n g e
lis te d fro m 1.0 x 1 0 28 to 7.9 x 1028. I ts p re c isio n lev el is b e tw e e n 2 8 -2 9 sig n ific a n t d ig its,
w h ic h m a k e s it s u ita b le fo r n e a rly a ll m o n e ta ry c a lc u la tio n s (see E x a m p le B.14).
default
D e f a u lt is u s u a lly p la c e d a t th e e n d of a s w i t c h s ta te m e n t, th u s allo w in g th e ex ecu tio n
of se le c te d s ta te m e n ts b a s e d on th e fa c t t h a t th e y do n o t m a tc h a n y of th e p re v io u s v a lu e s
(see E x a m p le B.15).
delegate
A d e le g a te ’s d e fin itio n in c lu d e s a p u b lic a ccess re fe re n ce , th e k ey w o rd d e l e g a t e , th e
d e le g a te ’s id e n tity (also follow ing th e s ta n d a r d ru le s of n am in g ), a d a ta ty p e referen ce, a n d
its s e t o f p a r a m e te rs . D e le g a te s a r e m o st com m only u s e d to h a n d le e v e n ts (See E x a m p le
B.16).
444
Appendix B: Reserved Identifiers Defined
do
D o, a s p a r t of th e d o - w h i l e c o m b in a tio n , allow s for th e e x e c u tio n of a s e t of s ta te m e n ts ,
o r block. T h is b lock w ill e x e c u te in d e fin itely , te r m in a tin g o n ly w h e n a fa lse e x p re ssio n is
fo u n d . D o - w h i l e loops b e g in b y e x e c u tin g th e ir blocks, th e n th e y te s t a n d re p e a t, g u a r a n
te e in g a t le a s t o ne e x e c u tio n b efo re th e p ro cess is te r m in a te d (see E x a m p le B.17).
E x a m p l e B .1 7 .
c l a s s A p p e n d ix _ B {
s t a t i c v o i d M a in ( ) {
do { }
w h ile (tru e );
}
}
double
D o u b le is a 6 4 -b it d a ta ty p e u s e d to s to re flo a tin g p o in t v a lu e s ra n g in g fro m ±5.0 x 1 0 324
to ±1.7 x 10308; its p re c isio n le v e l is 1 5 -1 6 d ig its (see E x a m p le B.18).
E x a m p l e B .1 8 .
c l a s s A p p e n d ix _ B {
s t a t i c v o i d M a in ( ) {
d o u b le N u m b e r l, N u m b e r2 ;
N u m b e rl = 1 . 0 ;
N um b er2 = 1 . 1 ;
}
}
445
C# and Game Programming
else
E ls e is th e f ir s t logical e x te n s io n to th e q u e s tio n in g i f s ta te m e n t: I t a d d s a n a d d itio n a l
lin e of re a s o n in g a n d a n a d d itio n a l p a th for p ro g ra m s to follow. E l s e c a n n o t be u s e d
in d e p e n d e n tly , y e t it lin k s e a sily to th e ta il e n d of th e i f s ta te m e n t (see E x a m p le B.19).
E xam p le B.19.
using System;
class Appendix_B {
static void Main() {
double Answer = d o u b l e .Parse(Console.R e a d L i n e ());
if (Answer == 5)
Co n s o l e .WriteLine ("\n That is co r r e c t !\ n" );
else
C on s o l e .W r i t e L i n e ("\n W r o n g ! !!\n");
}
}
enum
T h e enum erator (e n u m ) is a b a sic a g g re g a te d ty p e t h a t p ro m o te s sim p le re fe re n c e m a
n ip u la tio n s . I t also allo w s for som e u n iq u e re fe re n c e s su c h a s u se r-d e fin e d d a ta s tr u c
tu r e s a n d lis ts of a s s ig n m e n ts to th o s e d e c la ra tio n s. I n itia l s tr u c tu r e s a re d e c la re d u s
in g th e k ey w o rd en u m , w ith in s ta n c e s of th o se v a lu e s d ec lare d a n d a ssig n e d a s if th e y w ere
c la ss re fe re n ce s. If no v a lu e s a re a s s ig n e d to th e s e re feren ces, th e n th e in itia l p o in t w ould
be zero a n d e a c h n ew c o m p o n e n t w o u ld a u to m a tic a lly in c re m e n t by one. H ow ever, w e c a n
also s h o rt ste p th is p ro cess b y b e g in n in g a t som e a r b itr a r y p o in t, or in d iv id u a lly d e c la rin g
e a c h v a lu e (see E x a m p le B.20).
446
Appendix B: Reserved Identifiers Defined
event
E v e n t s a re u s e d to specify d e le g a te s t h a t a re re fe re n c e d a t ru n tim e ; th e y c a n in c lu d e
m u ltip le m e th o d s, a n d th e ir coding is a p p lica b le to o th e r p ro g ra m s. T h e se e v e n ts a re also
th e n d e p e n d e n t on th e p ro g ra m in c lu d in g a d e le g a te to re fe re n ce . E v e n ts a re also u s e d
w ith ac c e sso r fu n c tio n s a d d a n d rem o v e, w h ic h n e e d to be d e c la re d collectively (see E x
a m p le B.21).
E x a m p l e B .2 1 .
using S y s t e m .Collections;
namespace Appendix_B {
public delegate void D e l ( ) ;
public class EventSetup {
private Hashtable Test = new H a s h t a b l e O ;
public event Del Event {
add { T e s t ["Event"] = (Del)T e s t ["Event"] + value;
}
remove {T e s t ["Event"] = (Del)T e s t ["Event"] - value;
}
public class Events {
public static void M a i n O {}
explicit
A n e x p l i c i t d e c la ra tio n is a d e c la ra tio n u se d to e x p re ss a co n v e rsio n fro m a la rg e r to
s m a lle r v a lu e . E x p re s s p e rm is s io n is r e q u ire d b e c a u se of th e p o te n tia l for lo st d a ta . T h e
p r o g ra m m e r u s in g th is d e c la ra tio n m u s t also s a fe g u a rd a g a in s t e rro rs m a n u a lly (see
E x a m p le B.22).
E x a m p l e B .2 2 .
namespace Appendix_B {
class IsByte {
byte value;
public IsByte(int value) {this.value = (byte)value;}
public static explicit operator IsByte(byte Byte) {
return new IsByte(Byte);
}
public static void M a i n O {}
}
}
447
C# and Game Programming
extern
T h e e x t e r n m odifier, a s its n a m e im p lies, in d ic a te s t h a t th e m e th o d w ill be im p le m e n te d
e x te rn a lly , su c h a s w ith th e D lllm p o rt a ttr ib u te . T h e e x te r n a l m e th o d w ill c o n ta in a ll
a p p r o p r ia te d e c la ra tio n s ; it does n o t r e q u ire a fu n c tio n body, b u t it does re q u ire a te r m i
n a tin g sem icolon (see E x a m p le B.23).
E x a m p l e B .2 3 .
using System;
using S y s t e m .W i n d o w s .F or ms ;
using S y s t e m .R u n t i m e .InteropServices;
namespace Appendix_B {
public class Forml : S y s t e m .W i n d o w s .F o r m s .Form {
[Dlllmport("winmm.dll")]
public static extern long PlaySound(String IpszName,
long hModule, long dw Flags);
public F o r m l () {
PlaySound(@"C:\SourceCode\Mouse.w a v " , 0, 0);
}
static void Main() {
Application.Run(new F o r m l ());
}
}
}
false
F a l s e is a u s e r-d e fin e d B o o lean ty p e o p e ra to r t h a t r e tu r n s a v a lu e fa lse (see E x a m p le
B .24).
E x a m p l e B .2 4 .
class Appendix_B (
static void M a i n O {
bool Variablel = false;
finally
T h e f i n a l l y block is th e la s t blo ck lis te d in a t r y - c a t c h - f i n a l l y set; its s ta te m e n ts
a r e a lw a y s e x e c u te d w ith th e c o m p le tio n of t h a t s e t (see E x a m p le B.25).
448
Appendix B: Reserved Identifiers Defined
E xam p le B.25.
p u b l i c c l a s s A p p e n d ix _ B {
s t a t i c v o i d M a i n () {
try {}
f in a lly {}
}
}
fixed
T h e k e y w o rd f i x e d , u s e d o n ly in u n s a fe m ode, is a m o d ifie r t h a t se ts u n m a n a g e d p o in t
e rs to m a n a g e d v a ria b le lo catio n s. T h e se p o sitio n s a re th e n fixed to p re v e n t th e ir a u to
m a tic d e le tio n , a s is n o rm a lly d one w ith C # g a rb a g e collection (see E x a m p le B.26).
E xam p le B.26.
n a m e s p a c e A p p e n d ix _ B {
c la s s C la s s F ix e d {
p u b lic in t v a r ia b le ;
}
c la s s C la s s l {
s t a t i c u n s a f e v o i d M a in ( ) {
C l a s s F i x e d T e s t F i x e d = n ew C l a s s F i x e d ( ) ;
T e s t F ix e d . v a r ia b le = 7 ;
f ix e d ( i n t * p o in t e r = & T e s t F ix e d .v a r ia b le ) {}
}
}
}
float
F l o a t is a 3 2 -b it d a ta ty p e u s e d to s to re flo a tin g p o in t v a lu e s ra n g in g from ±1.5 x 10‘45 to
±3.4 x 1038, w ith a p re c isio n lev el of 7 d ig its. N o te t h a t since d o u b les a re th e d e fa u lt, it
is also im p o r ta n t to in c lu d e a su ffix w h e n a tte m p tin g to a s s ig n a n ir r a tio n a l n u m e ric ;
fa ilu re to do so w ill r e s u lt in a c o m p ila tio n e rr o r (see E x a m p le B.27).
E xam p le B.27.
n a m e s p a c e A p p e n d ix _ B {
c la s s C la s s l {
s t a t i c v o i d M a i n () {
f l o a t N u m b e r l, N u m b e r2 ;
449
C# and Game Programming
Numberl = l.Of;
Number2 = l.lf;
}
}
}
for
T h e f o r loop, also k n o w n a s th e f o r s ta te m e n t, is a re p e titiv e pro cess t h a t is se t u p u n d e r
c e r ta in c o n d itio n s to r u n a p a r tic u la r n u m b e r of tim e s. T h is te r m in a tin g fa c to r h e lp s to
s e p a ra te it from th e o th e r tw o looping processes b e cau se i t ’s n o t d e p e n d e n t on a n u n k n o w n
v a ria b le . T h e f o r loop th u s p re d e fin e s its v a ria b le a s p a r t of its in itia l s ta te m e n t. T h e
co m p a riso n o p e ra to rs a re s till u s e d to d e te rm in e w h e th e r to c o n tin u e or te r m in a te , b u t
th is w ill a lw a y s h a p p e n a t a p re d e te rm in e d p o in t in th e loop, w h e n o u r v a ria b le e q u a ls 10,
100, o r X n u m b e r of cycles. T h e f o r s ta te m e n t is c o n s tru c te d m u ch lik e th e w h ile - lo o p ,
b u t w ith its in itia liz in g v a ria b le a n d its in c re m e n tin g o p e ra to r b o th becom ing one w ith its
d e c la ra tio n (see E x a m p le B.28).
foreach
T h e f o r e a c h loop is a sp e c ia liz e d p ro cess t h a t is u s e d to sk im or sc a n th ro u g h a n a r r a y of
e le m e n ts w ith o u t th e co m m o n d ru d g e ry u s u a lly a sso c ia te d w ith lis tin g t h a t a r r a y ’s com
p o n e n ts. I t is g e n e ra lly w r itte n to in c lu d e b o th th e k ey w o rd s f o r e a c h a n d in , a n d for th e
m o st p a rt, it p h y sic a lly re se m b le s th e n o ta tio n u s e d w h e n d escrib in g th e for loop process.
O n e k e y d ifferen ce, how ever, is t h a t th e in d e x in g or s e a rc h in g v a lu e is n o t allo w ed to be
a lte r e d ; th is w o u ld in c lu d e e v e n s u b tle m a n ip u la tio n , su c h a s th e in c r e m e n tin g or
d e c re m e n tin g o p e ra to rs (see E x a m p le B.29).
450
Appendix B: Reserved Identifiers Defined
goto
T h e g o t o s ta te m e n t is p ro b a b ly th e m o st picked-on of a ll th e k ey w ords. Its u se is c o n sid e r
poor p ro g ra m m in g h a b it, y e t so m eh o w it m a n a g e s to e n d u re . I ts f a u lt lies in its a b ility to
tr a n s g r e s s o rd e r; th e C # h e lp files e v en m a rk it a s u se fu l w ay of g e ttin g o u t of n e s te d
s ta te m e n ts , b u t, of co u rse, t h a t w o u ld be b re a k in g th e ru le s. S till, th e r e is a t le a s t one
p ra c tic a l r e a s o n for u s in g th e g o t o s ta te m e n t in C#, w h ich is to allow for a rtific ia l d ro p s
w h e n d e a lin g w ith s w i t c h s ta te m e n ts . R e m e m b er C# no lo n g er allow s u s to drop b e tw e e n
s w i t c h s ta te m e n ts t h a t c o n ta in e x e c u ta b le s ta te m e n ts , so goto m a k e s a good fix. C #’s
g o t o also h a s som e lim ita tio n s , in c lu d in g n o t b e in g ab le to ju m p in to lo calized block or
b e tw e e n c la sse s, n o r sh o u ld it b e u s e d to a lte r o u r t r y - c a t c h blocks (see E x a m p le B.30).
E x a m p le B.30.
c l a s s A p p e n d ix _ B {
s t a t i c v o i d M a in O {
ch a r C h a ra c te r = ' 1 ' ;
s w it c h (C h a r a c t e r ) {
c a s e 11 1 :
g o to c a s e 2 ;
b re a k ;
case ' 2 ' :
case 2 :
g o to c a s e 3 ;
b re a k ;
case ' 3 ' :
case3 :
b re a k ;
}
}
}
if
T h e if s ta te m e n t is a c o n d itio n a l s ta te m e n t t h a t te s ts a n e x p re ssio n o r s e t of e x p re ssio n s
a n d e x e c u te s a s ta te m e n t o r block o f s ta te m e n ts w h e n t h a t e x p re ssio n is fo u n d to be tr u e
(see E x a m p le B.31).
451
C# and Game Programming
E xam p le B.31.
c l a s s A p p e n d ix _ 4 {
s t a t i c v o i d M a in ( ) {
i n t Num ber = 7 ;
if (N u m b er == 7 )
N u m b e r+ +;
}
}
implicit
T h e k e y w o rd i m p l i c i t is u s e d w h e n a tte m p tin g to d e c la re a u s e r-d e fin e d c o n v e rsio n
o p e ra to r. Im p lic it c o n v e rsio n s c a n im p ro v e so u rce code r e a d a b ility a n d safety, a n d g e n e r
ally occur w ith o u t th e p ro g ra m m e r’s a w a re n e ss. (Note: Im p licit o p e ra to rs sh o u ld n o t th ro w
ex ceptions— see E x a m p le B.32).
E xam p le B.32.
n a m e s p a c e A p p e n d ix _ B {
c la s s Is B y te {
b y te v a lu e ;
p u b lic Is B y t e ( b y t e v a lu e ) { t h i s .v a l u e = v a l u e ;}
p u b lic s t a t i c im p lic it o p e ra to r b y t e ( Is B y t e B y te ) {
r e t u r n B y t e .v a lu e ;
}
p u b lic s t a t ic v o id M a i n () {}
}
}
In
T h e k ey w o rd i n is u s e d w ith th e I n s ta te m e n t w h e n re a d in g th e c o n te n ts of a n a r r a y (see
E x a m p le B.33).
E xam p le B.33.
u s in g S y s te m ;
c l a s s A p p e n d ix _ B {
s t a t i c v o i d M a in O {
c h a r [ ] in t e g e r = { ' a 1, ' g' , ' n ' , ' u ' } ;
fo re a c h (c h a r f in d in in t e g e r ) { / * * / }
}
}
452
Appendix B: Reserved Identifiers Defined
int
Integer ( i n t ) is a 3 2-bit in te g ra l d a ta ty p e u se d to sto re v a lu e s ra n g in g from -2,147,483,648
to 2,1 4 7 ,4 8 3 ,6 4 7 (see E x a m p le B.34).
E x a m p le B.34.
class A p p e n d i x _ l {
static v o i d M a i n () {
int O u r V a r i a b l e = 1;
}
}
interface
To c r e a te a n i n t e r f a c e is to d e c la re a re fe re n c e ty p e t h a t is n o te d for h a v in g only
a b s tr a c t m e m b e rs. O nce c re a te d , it c a n e x is t e ith e r a s a n in d e p e n d e n t bo d y o r a s p a r t of
a c la s s re fe re n c e . I n te r f a c e s a r e also c a p a b le of in h e r itin g fro m o th e r in te rfa c e s , in c lu d
in g m u ltip le in h e r ita n c e s (n o t a llo w e d w ith C # c la sse s). N ote: W h e n c r e a tin g a n in h e r
ite d c la s s w ith a c o m b in e d in te rfa c e , re m e m b e r to in c lu d e th e b a s e c la ss f ir s t (see E x
a m p le B.35).
453
C# and Game Programming
internal
A n i n t e r n a l access m o d ifier is a ty p e m e m b e r u se d to access class com p o n en ts. T h e a d
v a n ta g e of th e i n t e r n a l m od ifier is t h a t it allow s for lim ite d access from w ith in a single
assem bly. A k ey d isa d v a n ta g e th e n is t h a t it is only accessible from w ith in th a t assem bly. In
a d d itio n to th e b asic in te r n a l m odifier, w e ca n also u se th e key w o rd i n t e r n a l in c o m b in a
tio n w ith p r o t e c t e d to c re a te a i n t e r n a l p r o t e c t e d m odifier (see E x a m p le B.36).
E xam p le B.36.
namespace Appendix_B {
internal class BankAccount {
internal protected string first_name;
internal void ViewFiles(BankAccount acc) {}
}
class Classl {
static void M a i n O {}
Is
T h e i s o p e ra to r is u s e d a s p a r t of a B oolean e x p re ssio n to te s t th e c o m p a tib ility of a
specific o bject ty p e . F o r e x a m p le , if a n object is a n i s e x p re ssio n , th e n it w ill e v a lu a te to
tr u e if th e e x p re s s io n is n o t n u ll a n d th e e x p re ssio n c a n be c a s t w ith o u t th ro w in g a n
ex cep tio n (see E x a m p le B.37).
E xam p le B.37.
using System;
namespace Appendix_B {
class TestClass {}
public class Classl {
454
Appendix B: Reserved Identifiers Defined
lock
A l o c k is a tem porary, m u tu a l exclusion u sed to e n su re th a t m ultiple th re a d s do n o t in a d v e rt
e n tly access th e sa m e section of coding, l o c k s a re u se d w ith th e t h i s s ta te m e n t a n d th e
t y p e o f com m and, a n d a re w ritte n as: l o c k (expression) executable block. N ote: l o c k s ta te
m e n ts also re q u ire t h a t th e ir exp ressio n s be referenced types (see E xam ple B.38).
E x a m p le B.38.
namespace Appendix_B {
class MyName {
private string name;
protected M y N a m e (string fn) {this.name = f n ; }
protected string TestName(string fn) {
lock (this) {
if (fn != null) {
return (this.name);
}
}
return(null);
}
public static void Main() {}
}
}
long
L ong is a 6 4 -b it d a ta ty p e u se d to sto re v a lu e s ra n g in g from —9,223,372,036,854,775,808 to
9,223,37 2 ,0 3 6 ,8 5 4 ,7 7 5 ,8 0 7 (see E x a m p le B.39).
455
C# and Game Programming
E xam p le B.39.
class A p p e n d i x _ B {
static v o i d M a i n O {
long Number;
namespace
W h e n w e en c o m p a ss o u r coding in s id e a n a m e s p a c e , w e a re a c tu a lly d e c la rin g a scope or
g lo b ally u n iq u e p a rtitio n . T h e ty p e s c o n ta in e d in t h a t n a m e s p a c e a re acce ssib le th r o u g h
d ire c t access (from w ith in t h a t body), a n d th ro u g h th e u sin g -n a m e sp a c e -d ire c tiv e , w h ic h
allo w s u s to u s e its v a lu e s w ith o u t q u a lific a tio n (see E x a m p le B.40)
E xam p le B.40.
namespace Appendix_B {
class Classl {
static v o i d M a i n O {}
}
}
new
T h e k e y w o rd new is u s e d a s b o th a n o p e ra to r a n d a m odifier. A s a n o p e ra to r, it is u s e d to
d e c la re in s ta n c e s a n d to c re a te objects. A s a m odifier, it is u s e d to h id e m e m b e rs in h e rite d
from a b a s e class. N ote t h a t th e n ew o p e ra to r c a n n o t be overloaded, n o r c a n it be u s e d w ith
th e o v e r r i d e s ta te m e n t (see E x a m p le B.41).
E xam p le B.41.
namespace Appendix_B {
p u b l i c class B a s e C l a s s {
p u b l i c short x;
p r o t e c t e d B a s e C l a s s () {}
p u b l i c short X {set{x = value;}}
}
p u b l i c class D e r i v e d C l a s s : B a s e C l a s s {
p r o t e c t e d D e r i v e d C l a s s () {}
456
Appendix B: Reserved Identifiers Defined
null
T h e n u l l re fe re n ce re fe rs to a n object th a t h a s n o t y e t b e e n a ssig n ed . I t b a sic a lly se rv e s a s
a b la n k o r n o n v a lu e , w h ic h c a n be s u b s titu te d for la te r (see E x a m p le B.42).
E xam p le B.42.
namespace Appendix_B {
public class TestAS {
public static void M a i n () {
object MyString = new object () ;
MyString = 123;
string s = MyString as string;
if (s != null)
MyString = "X";
}
}
}
object
T h e k ey w o rd o b j e c t is u s e d to a s s ig n v a lu e s to objects. We c a n ap p ly th e s e te c h n iq u e s to
in c lu d e b o th v a lu e -to -re fe re n c e a n d re fe re n c e -to -v a lu e co n v ersio n s. T h is p ro c ess is m o st
co m m o n ly re f e r r e d to a s boxing , w ith th e te r m unboxing d e n o tin g th e r e tu r n in g of th o se
v a lu e s to th e ir o rig in a l s ta te . T h e p ro ce ss follow s th e sa m e s te p s u s e d w ith b a sic ty p e
c a s tin g , b u t w ith a n a d d e d n o te of c a u tio n w h e n a tte m p tin g to r e tu r n o r u n b o x v a lu e s,
sin ce th e y c a n r e t u r n to n ew v a ria b le s, b u t th o se v a ria b le s m u s t be of th e o rig in a lly
b o x ed d a ta ty p e . T h e co n v e rsio n s a r e done u s in g th e k e y w o rd object a s is sh o w n below.
E xam p le B.43.
public class Appendix_B {
public static void Main() {
object MyString = new object ();
}
}
457
C# and Game Programming
operator
Operator overloading is th e re a p p lic a tio n of o p e ra to rs to in c lu d e c lass m a n ip u la tio n s. T h e
s ta n d a r d c la ss o p e r a t o r o v e rlo a d s in c lu d e object-to-object a n d o b je ct-to -n u m eric v a lu e s
(in clu d in g v a ria b le s). T h e m o st im p o r ta n t p o in t w h e n d e a lin g w ith o p e ra to r o v erlo ad in g is
th e u n d e r s ta n d in g t h a t a ll a b b re v ia te d fo rm s sh o u ld be m a d e im p licit.
E x a m p l e B.44.
namespace Appendix_B {
public class Objects {
int Number;
public Objects(int Value) (this.Number = Value;}
public static Objects operator + (Objects Ob, int Value) {
Ob.Number += Value; return(Ob);
}
static void Main() {}
out
T h e k e y w o rd o u t is a sp e c ia l e x c e p tio n m a r k e r t h a t n o tifie s th e c o m p iler so t h a t th e
v a ria b le u n d e r s c ru tin y does n o t n e e d to be a ssig n e d before it c a n be p a sse d a s a re fe re n ce d
v a ria b le . T h is is u s u a lly th e c a se w h e n d e a lin g w ith v a lu e s t h a t w o u ld n ’t o th e rw is e h a v e
a m e a n in g fu l v a lu e before th e a p p ro p ria te fu n ctio n s c a n be executed. Since a n o u t v a lu e is
also a re fe re n c e d v a lu e , th is k e y w o rd n e g a te s th e n e e d for th e seco n d reference ( r e f ) (see
E x a m p le B.45).
E x a m p l e B.45.
using System;
class Appendix_B {
static void Main() {
int iNumberl;
TheRace (out iNumberl);
}
458
Appendix B: Reserved Identifiers Defined
override
I n a d d itio n to b e in g a b le to o v e rlo a d a fu n c tio n (for e x a m p le , to c h a n g th e s ig n a tu r e or
p a r a m e t e r s o f t h a t fu n c tio n ), w e c a n a lso o v e r r i d e a fu n c tio n so a s to force th e co m
p ile r to a c c e p t a s e c o n d a ry v e rs io n o f t h a t fu n c tio n . A s its n a m e im p lie s, th e k e y w o rd
o v e r r i d e is u s e d to o v e rrid e m e m b e rs in h e r ite d fro m a b a s e c la ss. T h e s e in h e r ite d
m e th o d s m u s t h a v e m a tc h in g s ig n a tu r e s a n d b e e ith e r v ir tu a l, a b s tr a c t, o r p re v io u sly
o v e rrid d e n . T h is te c h n iq u e a lso a llo w s u s to m a n ip u la te t h a t p ro g r a m ’s d a ta so a s to
g ive it th e illu s io n o f co n sisten cy , o r to sa v e u s th e tro u b le of re v is in g o u r p re v io u s c lass.
T h e s e c o n d a ry v e rs io n , th e n , b e c o m e s th e o b v io u s choice, a s o u r in s ta n c e w a s d e c la re d
a s p a r t of t h a t in h e r ite d c la ss (see E x a m p le B.46). O n a c a u tio n a ry n o te, it sh o u ld also be
m e n tio n e d t h a t if a n o v e rrid in g fu n c tio n h a d a lso re fe re n c e d its b a s e v e rs io n (as is com
m o n ly d o n e w ith p r iv a te ly in h e r ite d c la sse s), t h a t fu n c tio n ’s re fe re n c e w o u ld th e n be
d iv e r te d b a c k to th e in h e r ite d fu n c tio n . N o te t h a t w e c a n also r e t u r n a cc ess to th e o rig i
n a l m e th o d v ia th e b a s e c o m m a n d .
E x a m p le B.46.
namespace Appendix_B {
public class Area {
public A r e a () {}
public virtual void C a l c ulateArea() {}
}
public class Parallelogram: Area {
override public void C a l c u l ateArea() {}
static void M a i n O {}
}
}
params
T h e k e y w o rd p a r a m s is u s e d to p a s s a n a r r a y of a n y object ty p e w ith o u t ex p licitly d e c la r
in g t h a t d a ta a s a n a rra y . O n ly one o bject m a y be p a s s e d a s a p a r a m s p e r d e c la ra tio n , a n d
a n y o th e r d e c la ra tio n m u s t p re c e d e t h a t s ta te m e n t (see E x a m p le B.47).
459
C# and Game Programming
E xam p le B.47.
public class Appendix_B {
public static void Params(params s t r i n g [] list) {
}
public static void Main() {
}
}
460
Appendix B: Reserved Identifiers Defined
readonly
R e a d o n l y is a c o n s ta n t d a t a ty p e u s e d a s p a r t of a c la ss re fe re n c e d e c la re d a s a field. I t
is a s s ig n a b le a t o n ly o n e p o in t in th e p ro g ra m a n d th e n a c ts a s a c o n s ta n t (see E x a m p le
B .51).
ref
T h e k e y w o rd r e f is u s e d to re fle c t a v a ria b le ’s co n tro l b a c k to th e o rig in a l p a ra m e te rs ,
th e r e b y a llo w in g th e m e th o d ’s, o r f u n c tio n ’s, a lte r a tio n s to b e k n o w n b y th e m a in o r c a ll
in g b ody (see E x a m p le B.52).
E xam p le B.52.
class Appendix_B {
static void M a i n () {
int iNumberl = 0;
TheRace(ref iNumberl);
}
461
C# and Game Programming
return
T h e k e y w o rd r e t u r n is u s e d to p a s s b a c k a sin g le v a lu e to t h a t of th e c a llin g fu n c tio n .
T h e v a lu e in q u e s tio n m u s t b e th e q u a lifie d ty p e, a n d in c a se s w h e re th e r e tu r n in g ty p e is
void, it c a n b e o m itte d . R e t u r n s ta te m e n ts a re re q u ir e d w ith a ll n o n v o id u s e r-d e fin e d
fu n c tio n s a n d m e th o d s (see E x a m p le B.53).
E xam p le B.53.
using System;
class Appendix_B {
static void Main() {
Rand o m N u m b e r ();
}
sbyte
T h e k e y w o rd s b y t e is a n 8 -b it in te g e r u s e d to sto re v a lu e s ra n g in g fro m -128 to 127 (see
E x a m p le B.54).
E xam p le B.54.
class Appendix_B {
static void Main() {
sbyte Numberl = 1;
}
}
sealed
O nce a c la ss is s e a l e d , it c a n no lo n g e r be in h e rite d , h e n c e it c a n n o t be o v e rrid d e n or
a lte r e d in a n y o th e r way. F o r th e sa m e re a so n , w e c a n n o t u s e s e a l e d w ith th e a b s t r a c t
m o d ifier (see E x a m p le B.55).
E xam p le B.55.
sealed class Appendix_B {
static void M a i n () {}
}
462
Appendix B: Reserved Identifiers Defined
short
T h e k ey w o rd s h o r t is a 16-bit in te g e r d a ta ty p e u se d to sto re v a lu e s ra n g in g from -32,768
to 32,767 (see E x a m p le B.56).
E xam p le B.56.
class Appendix_B {
static void M a i n O {
short Numberl = 1;
sizeof
T h e s i z e o f k ey w o rd is u s e d to g a th e r in fo rm a tio n p e rta in in g to th e size of o u r d a ta types.
U n fo rtu n a te ly , th is also r e q u ire s th e u s e of a se c o n d a ry co m m an d , u n s a f e , w h ich is u s e d
to m a r k th e u n s a fe n a tu r e of t h a t code (see E x a m p le B.57).
stackalloc
T h e k e y w o rd s t a c k a l l o c (sta c k a llo c atin g ), is u s e d to a llo c a te blocks of m e m o ry r e f e r
e n c e d fro m a s ta c k . T h e a d d re s s e s o f th e s e blocks a re s to re d a s p o in te rs a n d th e y a re
p ro te c te d from g a rb a g e collection, th u s th e y do n o t h a v e to be fixed/pinned. N ote: All blocks
a r e lo s t w h e n t h e ir m e th o d s a r e te r m in a te d (see E x a m p le B.58).
E xam p le B.58.
class Appendix_B {
public static unsafe void M a i n O {
int* pointerl = stackalloc i n t [3];
pointerl [0] = 1;
}
}
463
C# and Game Programming
s ta tic
T h e k ey w o rd s t a t i c is u s e d to m odify c o n stru c to rs, fields, m e th o d s, o p e ra to rs, a n d p ro p
e rtie s . S t a t i c c o n stru c to rs, for ex am p le, a re c a lle d a u to m a tic a lly , a n d a re u s e d to in itia l
ize th e r e s t of th e c la ss before a n y m e m b e rs a re referen ce d . S ta tic fields, th e n , a re n o t p a r t
of a specific in s ta n c e , a n d in s te a d a r e re fe re n c e d a s a sin g le m em o ry a d d re ss.
E xam p le B.59.
class Appendix_B {
static void Main() {}
}
s tr in g
A s t r i n g is a re fe re n c e d a ta ty p e t h a t e n c o m p a sse s th e m o re re c e n tly d ev eloped Unicode
c h a ra c te rs . T h e se c h a r a c te r s c a n b e tr a n s f e r r e d to s trin g re fe re n c e s u s in g sim p le q u o ta
tio n m a rk s , th e s e e x p re s s io n s c a n also be m a d e lite r a l b y f ir s t n o tin g th e m w ith th e @
sym bol (see E x a m p le B.60).
str u c t
Structures ( s t r u c t ) a r e u s e r-d e fin e d d a ta ty p e s t h a t allow for g ro u p in g s of s im ila r or
r e la te d d a ta t h a t do n o t h a v e a sin g le b a s e d a ta ty p e. T h e se g ro u p s c a n in c lu d e a ll th e
b a sic v a lu e d a ta -ty p e s a s w ell a s a lis t of m e th o d s u s e d to m a n ip u la te th o se v a lu e s. T h e
d a ta ty p e s d e c la re d in sid e a s tr u c tu r e a re re fe rre d to a s th e s tr u c tu r e ’s members (or fields ),
w h ile th e ir d e c la ra tio n s a re re fe rre d to a s its instances . T h e c o rre la tio n s b e tw e e n th e s e
in te r n a l v a lu e s a n d s tr u c tu r e s a re u s u a lly g u id e d by som e com m on th e m e or p u rp o se. A
s tr u c tu r e is m a d e u p of th e k ey w o rd s t r u c t , th e s tr u c tu r e ’s ta g (or nam e); a lis t of th e
fields (w ritte n as d ec la re d m em bers); a n d a list of possible m eth o d s u se d to m a n ip u la te t h a t
d a ta . S tru c tu re s a re g e n e ra lly c o n ta in e d w ith in a single block placed in sid e o u r re fe re n cin g
n am esp ace, b u t as show n in E x am p le B.61, th e y ca n also be u se d to invoke th e m a in m ethod.
464
Appendix B: Reserved Identifiers Defined
E xam p le B.61.
struct Appendix_B {
static void M a i n O {}
}
switch
T h e s w i t c h sta te m e n t, like th e i f a n d e l s e - i f sta te m e n ts, is u se d to execute a s ta te m e n t
or se t of s ta te m e n ts t h a t e q u a l th e v a ria b le ’s value. H ow ever, u n lik e th e i f and e l s e - i f
s ta te m e n ts ,th e s w i t c h s ta te m e n t doesn’t u se com parison operators; in stea d , it sim ply re a d s
th e v a lu e of th e v a ria b le a n d a tte m p ts to d irect th e p ro g ram to th e p ro p e r c h an n el. A second
keyw ord, c a s e , is also u se d in th is process. T he keyw ord c a s e is w ritte n a n d u se d m u ltip le
tim e s from w ith in th e s w i t c h s ta te m e n t. E ach c a s e sta te m e n t holds a n u m eric or c h a ra c te r
v alu e for com parison. If th e v a lu e h e ld by a c a s e s ta te m e n t m a tc h e s th e v a lu e re a d by th e
s w i t c h sta te m e n t, th e n e v e ry th in g following th a t c a s e s ta te m e n t w ill be executed.
this
T h e k e y w o rd t h i s is a sp e c ia liz e d re fe re n c e s ig n a tu r e u s e d to in d ic a te th e re fe re n c in g
object of a p a s s in g class; in o th e r w o rd s, it is a lo n g h a n d v e rsio n for th e o th e rw ise a b b re v i
a te d m em b er. W h ile th e t h i s re fe re n c e is im p lied , its d e fin itio n s c a n becom e a m b ig u o u s
a n d sh o u ld b e in c lu d e d to p re v e n t th is e r ro r (see E x a m p le B.63).
465
C# and Game Programming
E x a m p l e B .6 3 .
class Appendix_B {
protected short pin_number;
private void R e a d F i l e s O {
this.pin_number = 1;
}
static void M a i n O {}
}
th r o w
I n a d d itio n to b e in g a b le to c a tc h b o th g e n e ra liz e d a n d specific ex ce p tio n s, w e c a n also
le a r n to th ro w a few of o u r ow n. T h is is n o t u s u a lly n e c e s s a ry for th e c o n te x t of th is
book, b u t th e te c h n iq u e c a n se rv e to c larify th e d e fin itio n s of som e o th e rw ise co n fu sin g
e rro rs (see E x a m p le B.64).
E x a m p l e B .6 4 .
using System;
public class Appendix_B {
static void M a i n O {
int Y = 0;
if (Y == 0) {
throw new DivideByZeroException("\nProgram Error!");
}
}
}
tru e
A u s e r-d e fin e d B o o lean ty p e o p e ra to r t h a t r e tu r n s th e v a lu e t r u e (see E x a m p le B.65).
E x a m p l e B .6 5 .
class Appendix_B {
static void M a i n O {
bool Variablel = true;
}
}
try
W hen it com es to u s e r in p u t, w e c a n n e v er g u a ra n te e th e resu lts, therefore, w e n eed to th in k
a h e a d a n d p la n for possible erro rs. T h e t r y block scenario is a te s t application th a t is u se d in
466
Appendix B: Reserved Identifiers Defined
conjunction w ith sev eral c a t c h responses. T he inform ation in q uestion is placed betw een th e
t r y block’s p a ra m e te rs a n d is given only one chance to succeed (see E xam ple B.66).
E xam p le B.66.
p u b l i c c l a s s A p p e n d ix _ B {
s t a t i c v o i d M a in ( ) {
try {}
c a t c h j}
f in a lly {}
}
}
typeof
T h e t y p e o f o p e ra to r is u s e d to d e te rm in e a n object’s type, fields, m eth o d s, p ro p e rtie s (see
E x a m p le B.67)
E xam p le B.67.
u s in g S y s te m ;
n a m e s p a c e A p p e n d ix _ B {
p u b lic c la s s C la s s l {
p u b l i c s t a t i c v o i d M a in ( ) {
T y p e Ob = t y p e o f ( C l a s s l ) ;
C o n s o le . W r it e L in e (O b . G e t F i e l d s ( ) ) ;
C o n s o le . W r it e L in e (O b . G e tM e th o d s ( ) ) ;
}
}
}
uint
T h e k e y w o rd u i n t is a u n s ig n e d 3 2 -b it in te g r a l ty p e u s e d to s to re v a lu e s r a n g in g from 0
to 4,2 9 4 ,9 6 7 ,2 9 5 (see E x a m p le B.68).
E xam p le B.68.
c l a s s A p p e n d ix _ B {
s t a t i c v o i d M a in ( ) {
u i n t N u m b e rl = 1 ;
}
}
467
C# and Game Programming
ulong
T h e k e y w o rd u l o n g d e n o te s a u n s ig n e d 6 4 -b it in te g r a l ty p e u s e d to sto re v a lu e s ra n g in g
from 0 to 18,4 4 6 ,7 4 4 ,0 7 3 ,7 0 9 ,5 5 1 ,6 1 5 (see E x a m p le B.69).
unchecked
T h e k e y w o rd u n c h e c k e d is u s e d to block th e S o lu tio n E x p lo re rX C o n fig u ra tio n P ro p e r-
t i e s \ B u ild \ C h eck for a n a r ith m e tic o v erflow /underflow tr u e s ta te m e n t. T h is s ta te m e n t
is fa lse by d e fa u lt, b u t if w e w e re to c h a n g e th is d e fa u lt a n d th e n a tte m p t to b r e a k th e
b a r r ie r s of o u r d e s ig n a te d ty p e , w e co u ld block th e e rro r w ith th e u n c h e c k e d s ta te m e n t
(see E x a m p le B.70).
unsafe
T h e k e y w o rd u n s a f e d e n o te s a c h a n g e in s e ttin g s to u n s a fe m ode. T h e u n s a f e f e a tu re
w a s developed to a id in b rid g in g th e g ap b e tw e e n C++ a n d C# p ro g ra m m in g , allow ing u s to
u s e tim e te s te d te c h n iq u e s t h a t a re n o t officially p e rm itte d u n d e r Gtfs s a f e m ode (see
E x a m p le B.72). I n a d d itio n to in c lu d in g th e k ey w o rd u n s a f e to o u r coding, w e m u s t also
c h a n g e th e c o m p ile r’s s e ttin g s in C o n fig u ra tio n M a n a g e r (see C h a p te r 1— Sizeof a n d U n
safe C oding for d etails).
468
Appendix B: Reserved Identifiers Defined
ushort
T h e k ey w o rd u s h o r t d e n o te s a 16-bit in te g ra l d a ta ty p e u se d to sto re v a lu e s ra n g in g from
0 to 65,535 (see E x a m p le B.72).
using
T h e u s i n g d ire c tiv e allo w s u s to in c lu d e a h o s t of sy ste m a n d u s e r-d e fin e d n a m e sp a c e s
in c lu d in g a n a m e s p a c e is n o t e q u iv a le n t to in c lu d in g a file, a s w a s do n e in C++). H ere,
w e ’ll o n ly b e n o tify in g th e c o m p ile r of w h e re to fin d th e re fe re n c e s w r itte n in s h o rth a n d .
U se r-d e fin e d n a m e sp a c e s a re accessed in ex actly th e sa m e m a n n e r as th e sy ste m ty p e (see
E x a m p le B.73).
v ir tu a l
T h e k e y w o rd v i r t u a l d e n o te s a m o d ifie r t h a t s e ts a m e th o d of a b a se c la ss so t h a t it c a n
be o v e rrid d e n in a d e riv e d c la ss. W h e n a v i r t u a l fu n c tio n is re fe re n ce d , it se a rc h e s for
a n o v e rrid in g m eth o d .
469
C# and Game Programming
E xam p le B.74.
namespace Appendix_B {
public class Area {
public A r e a () {}
public virtual void Calcula t e A r e a () {}
}
public class Parallelogram : Area {
public P arallelogram() {}
override public void Calcu l a t e A r e a () {}
static void M a i n () {}
void
V o id is a d a ta ty p e t h a t h o ld s no d a ta , th u s , se rv e s th e p u rp o se of te llin g th e co m piler th a t
no d a ta w ill be re q u ire d b y th is v a ria b le or re tu r n in g fu n ction. T h is is logical, since th e
e n d in g of th e m a in fu n ctio n is also th e e n d in g of th e p ro g ram a n d th e re w ould be no p ro g ram
to w h ich in fo rm a tio n could b e se n t. V o i d is also m o st com m only a sso c ia te d w ith u ser-
defined functions th a t u se referen ce-v ariables (explained in C h a p te r 2) a n d g eneralized point-
e rs-v a ria b le s (e x p lain ed in C h a p te r 4). U n lik e th e o th e r d a ta ty p es, V o i d does n o t ta k e a
p o sitio n in m em ory, th e re fo re , w e w o n ’t n e e d to m e a s u re its size in bytes.
volatile
T h e k e y w o rd v o l a t i l e is u s e d to d e n o te a v a ria b le t h a t c a n n o t be o p tim ize d , w h ic h is
u s u a lly d u e to som e u n p re d ic ta b le c h a n g e or re fe re n c e m a d e to i t , fre q u e n tly from a n
o u ts id e so u rce su c h a s th e o p e ra tin g s y ste m o r h a rd w a r e device (see E x a m p le B.76).
470
Appendix B: Reserved Identifiers Defined
while
T h e w h i l e loop c a n b e s e t u p to r e p e a t a n d /o r te r m in a te in s e v e ra l d iffe re n t w ays. T h e
m o st co m m o n in c lu d e u s in g a p re d e te rm in e d c o u n t (as in to r e p e a t a n ite r a tio n five tim e s
t h e n en d ) a c c o rd in g to th e u s e r 's in p u t (e n d by re q u e s t), a n d a te r m in a tio n c o m m a n d (a
c o m m a n d t h a t s h o r ts te p s o r b r e a k s th e loop— see E x a m p le B.77).
471
Appendix C
Appendix C: Accessors
value
v a l u e ty p e s a re im p licit fields d e c la re d a s p a r t of a m e th o d s s ig n a tu re , a n d a re re fe re n ce d
a s if th e y w e re a c tu a l fields. T h ey h a v e th e sa m e lim ita tio n s a n d a b ilitie s a sso c ia te d w ith
a field o f th e ir d e c la re d ty p e a n d s h o u ld be tr e a te d a s su c h (see E x a m p le C.2).
473
C# and Game Programming
E xam p le C.2.
namespace Appendix_C {
public class Objects {
int Number;
public Objects(int value) {
this.Number = value;
}
static void M a i n (){}
}
}
474
□ xjpuaddv
Appendix D: Order of Precedence
S y m b o l(s) D e s c r ip tio n
D ot operator
[] A rray in d ex in g
0 F u n ction call
++ P ostfix in crem en t operator (placed after th e variable)
P ostfix d ecrem en t operator (placed after th e variable)
new, ty p eo f
checked, u n ch eck ed
++ P refix in crem en t operator (placed before th e variab le)
— P refix d ecrem en t operator (placed before th e variab le)
j N ot
- U n a ry m in u s
+ U n a ry P lu s
U n a ry
(T)x
* M u ltip ly
/ D iv id e
% R em a in d er
+ A d d ition
- S u b traction
« S h ift
» S h ift
< L ess th a n
> G reater th a n
<= L ess th a n or eq u al to
>= G reater th a n or eq u al to
as, is
== E qual to
t- N ot eq u al to
& L ogical A N D
A
L ogical XOR
1 L ogical OR
&& A nd
11 Or
?; IF
475
Appendix E
Appendix E: Displaying Message Boxes
M essage boxes a re p re d e fin e d d ialo g boxes t h a t a re u s e d to s e n d a n d receiv e sim p le d a ta
s tr e a m s b e tw e e n th e u s e r a n d th e p ro g ra m . T h e se m e ssa g e s m a y in c lu d e title s , com
m e n ts , a n d b u tto n s t h a t allow for a s h o rt lis t of re sp o n se s, su c h a s yes, no, ok, a n d ca n ce l
(see E x a m p le s E .1 -E .1 7 ).
namespace Appendix_E {
public class Forml : S y s t e m .W i n d o w s .F o r m s .Form {
[DllImport("winmm.dll")]
public static extern long PlaySound(String IpszName,
long hModule, long dwFla g s ) ;
public F o r m l () {
M e s s a g e B o x .S h o w ("Place message here");
}
[STAThread]
static void M a i n O {
A p p l i c a t i o n .Run(new F o r m l ());
}
We can also reuse this program to test the rest of the message box references— g r ^
please insert those changes as necessary.
477
C# and Game Programming
E xam p le E.3.
M e s sageBo x .S h o w ("Place message Here", "Place caption here",
MessageBoxButtons.O K ) ;
E xam p le E.4.
MessageBo x . S h o w ("Place message here", "Place caption here",
MessageBoxButtons.AbortRetrylgnore);
E xam p le E.5.
MessageBo x . S h o w ("Place message here", "Place caption here",
MessageBoxButtons.OKCancel);
E xam p le E.6.
M e s sageBo x .S h o w ("Place message here", "Place caption here",
MessageBoxButtons.RetryCancel);
E xam p le E.7.
M essag e B o x .S h o w ("Place message here", "Place caption here",
MessageBoxButtons.Y e s N o ) ;
E xam p le E.8.
M e s sageBo x .S h o w ("Place message here", "Place Caption here",
MessageBoxButtons.YesNoCancel);
E xam p le E.9.
M e s s ageBo x .S h o w ("Place message here", "Place caption here",
MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
E xam p le E.10.
MessageBo x . S h o w ("Place message here", "Place caption here",
MessageBoxButtons.OK, M essageBoxIcon.E r r o r );
478
Appendix E: Displaying Message Boxes
Example E .ll.
MessageBo x . S h o w ("Place message here", "Place caption here",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
E xam p le E.12.
M e s s ageBo x .S h o w ("Place message here", "Place caption here",
MessageBoxButtons.OK, M e s s ageBoxIcon.H a n d ) ;
E xam p le E.13.
M e s s ageBo x .S h o w ("Place message here", "Place caption here",
MessageBoxButtons.OK, M e ssageBoxIcon.Information);
E x a m p le E.14.
M e s s ageBo x .S h o w ("Place message here", "Place caption here",
MessageBoxButtons.OK, M e s s ageBoxIcon.N o n e );
E xam p le E.15.
M e s sageBo x .S h o w ("Place message here", "Place caption here",
MessageBoxButtons.OK, M e s sageBoxIcon.Quest i o n ) ;
E xam p le E.16.
Me s sageBo x .S h o w ("Place message here", "place caption here",
MessageBoxButtons.OK, M essageBoxIcon.S t o p ) ;
E xam p le E.17.
Messa g e B o x .S h o w ("Place message here", "Place caption here",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
479
C# and Game Programming
if (result == Dialog R e s u l t .Y e s ) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0);
}
E xam p le E.21.
DialogResult result = M e s s a g e B o x .S h o w ("Place message Here",
"Place caption here", MessageBoxButtons.Y e s N o ) ;
if (result == DialogResult.No) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0) ;
}
480
Appendix E: Displaying Message Boxes
Example E.23.
DialogResult result = M e s s a g e B o x .S h o w ("Place message here",
"Place caption here", MessageBoxButtons.AbortRetrylgnore);
if (result == DialogResult.Abort) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0) ;
}
E x a m p le E.24.
DialogResult result = M e s s a g e B o x .S h o w ("Place message here",
"Place caption here", MessageBoxButtons.AbortRetrylgnore);
if (result == D i alogResult.R e t r y ) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0) ;
}
if (result != DialogResult.None) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0);
}
We could have also inserted the MessageBoxIcon feature into any of these
examples.
481
C# and Game Programming
if (result == Dialog R e s u l t .Y e s ) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0 , 0 ) ;
if (result == DialogResult.No) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0);
}
if (result == DialogResultCancel) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0 , 0)
482
Appendix F
Appendix F: Graphics
W in d o w s F o rm s h a s p ro v id e d u s w ith s e v e ra l m e th o d s u s e d to p ro d u ce e v e ry th in g fro m
th e b a sic s h a p e s to som e in tr ic a te d e sig n s. H e re , Til in tro d u c e som e of th e a lte r n a tiv e
d ra w in g tools a n d m a n y of th e te c h n iq u e s a sso c ia te d w ith th e color re fe re n ce s.
483
C# and Game Programming
PointF and SizeF are used to indicate floating point values, which are necessary
when drawing with pixels.
E xam p le F.2.
using System;
using System.Drawing;
using S y s t e m .W i n d o w s .F o r m s ;
namespace Appendix_F {
public class Forml : S y s t e m .W i n d o w s .F o r m s .Form {
public F o r m l () {}
protected override void O n P a i n t (PaintEventArgs e) {
Graphics Figures = t h i s .C r e a t e Graphics();
Brush RedBrush = new SolidBrush(Color.R e d ) ;
Pen BluePen = new Pen(C o lo r .B l u e , 3);
F i g u r e s .FillRectangle(RedBrush, 10, 10, 25, 25);
F i g u r e s .DrawRectangle(BluePen, 20, 20, 25, 25);
}
static void M a i n O {
A p p l i c a t i o n .Run(new F o r m l ());
}
}
}
The second value associated with the pen statement, Pen(Color, int), is used to
reference its width.
484
Appendix F: Graphics
Lines
N ow th a t w e h a v e som e b a sic p o in ts to refere n ce a n d o u r p e n in h a n d , th e n e x t logical ste p
is to le a r n how to lin k th o se p o in ts to c re a te lin es a n d , of course, curves. L in es a re s tr a ig h t
f o r w a r d e n o u g h , w i th f o u r b a s ic r e f e r e n c e s : D r a w L in e ( C o lo r , P o i n t l , P o in t2 ) ,
D raw L in e(C o lo r, i n t x, i n t y, i n t x 2, i n t y 2), D raw L in e(C o lo r, P o in tF l, P o in tF 2 ), a n d
D raw L in e(C o lo r, f l o a t x, f l o a t y, f l o a t x2, f l o a t y 2)— see E x a m p le F.3.
E xam p le F.3.
using System;
using System.Drawing;
using S y s t e m .W i n d o w s .F o r m s ;
namespace Appendix_F {
public class Forml : S y s t e m .W i n d o w s .F o r m s .Form {
public F o r m l () {}
protected override void O n P a i n t (PaintEventArgs e) {
Point pointl = new P o i n t (10, 10);
Point point2 = new P o i n t (250, 250);
PointF pointfl = new PointF(125F, 1 0 F ) ;
PointF pointf2 = new PointF(125F, 2 5 0 F ) ;
Curves
C u rv e s a r e a b it m o re co m p le x w ith se v en , p o te n tia l re fe re n c e s: D ra w C u rv e (C o lo r,
A rra y O fP o in ts , O ffset, S e g m e n t, T ension); D raw C u rv e(C o lo r, A rra y O fP o in ts, T ension);
485
C# and Game Programming
Drawing Shapes
W e’ll d e fin ite ly w a n t to ta k e a d v a n ta g e of a ll th e p o te n tia l s h a p e s s to re d in th e W in
dow s F o rm s. W e’ll look a t th e b a sic ellip se, polygon, a n d re c ta n g le . W e’ll also w a n t to
h a v e a look a t th e F illP o ly g o n a n d F illP ie (see E x a m p le F.5).
486
Appendix F: Graphics
487
O nce w e h a v e th e b a sic sh a p e s, c re a tin g com plex d e sig n s b ecom es n o th in g m o re th a n
a q u e s tio n of in g e n u ity . H e re , w e’ll co m b in e a tria n g le , th r e e re c ta n g le s, a n d a few a r e a
fills to c re a te a sm a ll h o u se a n d a g a rd e n (see E x a m p le F.6).
E xam p le F.6.
using System;
using System.Drawing;
using System.Windows.F o rms;
namespace Chapter3 {
public class Forml : S y s t e m .W i n d o w s .F o r m s .Form {
public F o r m l () {}
protected override void O n P a i n t (PaintEventArgs e) {
//Triangle
PointF pointfl = new PointF(125F/ 5 0 F ) ;
PointF pointf2 = new PointF(50F/ 1 10F);
PointF pointf3 = new PointF(200F, 11 0 F ) ;
P o i n t F [] ArrayOfPoints = {pointfl, pointf2, pointf3};
488
Appendix G: Colors
T h e W indow s F o rm s colors a re b a s e d on th e A lp h a -B le n d in g R ed G re e n B lu e (ARGB)
m odel. T h e re a r e 140 p re d e fin e d colors a n d one u se r-d e fin e d color. To u s e a color it m u s t
f ir s t b e d e fin e d a s a n in s ta n c e , a n d th e n a s s ig n e d to a s specific b ru s h /p e n (see E x a m p le
G .l). F o r a c o m p le te lis t of colors, see T able G .l.
E xam p le G .l.
using System;
using System.Drawing;
using S y s t e m .W i n d o w s .Forms ;
namespace Appendix_G {
public class Forml : S y s t e m .W i n d o w s .F o r m s .Form {
public F o r m l () {InitializeComponent();}
private void InitializeComponent() {}
protected override void OnPaint(PaintEventArgs e) {
Graphics test = e.Graphics;
Font AlgerianFont = new F o n t ("Algerian", 10);
SolidBrush MyBrush = new SolidBrush(Color.R e d ) ;
t e s t .D r a w S t r i n g ("Salvatore A. Buono", AlgerianFont,
MyBrush, 60, 25);
}
static void M a i n () {
A p p l i c a t i o n .Run(new F o r m l ());
}
}
}
We ca n also define o u r ow n colors u sin g th e sta tic m eth o d s Color Color.From Argb(m £ ARGB);
C o lo r.F ro m A rg b (in t a lp h a , Color color); C o lo r.F ro m A rg b (in t red , i n t g reen , i n t blue);
a n d C o lo r.F ro m A rg b (in t a lp h a , i n t red , i n t g reen , i n t blue) (see E x am p le G.2).
E xam p le G.2.
using System;
using System.Drawing;
using System.Windows.F o r m s ;
namespace Appendix_F {
public class Forml : S y s t e m .W i n d o w s .F o r m s .Form {
public F o r m l () {InitializeComponent();}
private void InitializeComponent() {}
protected override void OnPaint(PaintEventArgs e) {
Graphics test = e.Graphics;
489
C# and Game Programming
490
Appendix H
Appendix H: Algorithms
F d lik e to ta k e a m o m e n t to d e m o n s tr a te a m ore ex p licit v e rsio n of a n a lg o rith m . H ere,
e v e ry d e ta il m u s t b e d o c u m e n te d a n d m a d e a s v ivid a s p o ssib le, w ith no a s s u m p tio n s
p la c e d on th e p a r t of th e p ro g ra m m e r(s). R e a so n a b le tim e lin e s sh o u ld be develo p ed
w ith a d d itio n a l e x it s tr a te g ie s p la c e d on o p tio n a l m a te r ia l a n d re s e a rc h . A te x t o u tlin e ,
d ra w in g s, a n d e v e n som e su g g e stiv e co ding could be in c lu d e d w ith th is m odel, b u t it
s h o u ld r e m a in o n ly a m odel.
Introduction
P a w n s is a g a m e I d ev elo p ed b a c k in th e la te 1980s a s a n a lte r n a tiv e to a tra d itio n a l
C h e ss g am e. I t re s e m b le s C h e ss dow n to its v e ry la s t d e ta il, b u t th e r e ’s one k ey d iffe r
ence: I n m y v e rsio n , th e p la y e rs a re no lo n g e r c o n sid e re d to be th e K in g s a n d in s te a d a re
fo rced to choose a lte r n a tiv e p e rs o n a . T h e y c a n se le c t th e ir ow n Q u een , a Rook, B ishop,
K n ig h t, o r a n y of th e ir p a w n s, b u t if th e ir p la y e r is c a p tu re d , th e y ’re c a p tu re d , m e a n in g
t h a t th e g a m e is o v er a n d th e o th e r p la y e r w ins. T h u s, th e tr u e p u rp o se of th e g am e is n o t
to c a p tu r e th e K ing, b u t in s te a d to a tte m p t to c a p tu re th e o th e r p la y e r ’s piece. B o th sid es
s h o u ld tr y th e ir b e s t to av o id re v e a lin g th e ir id e n titie s , b u t a t th e sa m e tim e th e y m u s t
d e fe n d th e K in g a n d p la y th e tr a d itio n a l gam e.
Basic Rules
T h e g a m e is p la y e d on a n e ig h t by e ig h t c h e c k e red b o a rd w ith a ll six ty -fo u r s q u a re s op en
for p la y (see F ig u re H .l) . Two p la y e rs, one lig h te r a n d th e o th e r d a rk e r, r o ta te b e tw e e n
m oves w ith th e lig h te r p la y e r b e g in n in g th e gam e.
Figure
H.1.
491
C# and Game Programming
Figure
H.2.
492
Appendix H: Algorithms
The King
E a c h piece h a s its ow n se t of m o v e m e n ts. B e g in n in g w ith th e K ing, w e fin d t h a t h e is
s u b je c t to s e v e ra l lim ita tio n s a n d o ne k e y exception: T h e K in g is o n ly ab le to s te p a
d is ta n c e of o n e sp ace, b u t h e c a n m ove in a n y d ire c tio n (see F ig u re H .3). H e is n o t ab le
to s te p o n to a s q u a re c o n tro lle d by h is enem y, n o r c a n h e r e m a in on a s q u a re t h a t h is
e n e m y h a s ta k e n c o n tro l over; th is second s itu a tio n is k n o w n a s c h eck in g th e K ing.
Figure
H.3.
493
C# and Game Programming
Figure
H.4.
Figure
H.5.
494
Appendix H: Algorithms
The Queen
T h e Q u e e n is c o n sid e re d to be th e s tro n g e s t piece on th e b o a rd b e cau se of h e r w ide ra n g e of
m o tio n . S h e is c a p a b le of tr a v e lin g a c ro ss th e e n tire b o a rd in one ste p , a n d ca n m ove
vertically, horizontally, a n d d iag o n ally (lim ited to only one d irection p e r move). T he Q u e e n s
only o b stacles a re th e o th e r pieces, since sh e c a n n o t le ap or sk ip over occupied s q u a re s (see
F ig u re H .6).
Figure
H.6.
The Rook
T h e R ook is th e n e x t s tr o n g e s t piece a f te r th e Q u een . I t is c a p a b le of tra v e lin g a cro ss
th e e n tir e b o a rd in one s te p ,a n d is c a p a b le of b o th v e rtic a l a n d h o riz o n ta l m o v e m e n ts
(lim ite d to o n ly o n e d ire c tio n p e r m ove). T h e R ook c a n n o t le a p or sk ip o v er occupied
s q u a r e s (see F ig u re H .7).
Figure
H.7.
495
C# and Game Programming
The Bishop
T h e B ish o p is c a p a b le of tr a v e lin g a c ro ss th e e n tir e b o a rd in one ste p , b u t is on ly c a
p a b le of d ia g o n a l m o v e m e n t (lim ite d to only one d ire c tio n p e r m ove). T h e B ish o p c a n n o t
le a p o r sk ip o v er occu p ied s q u a r e s (see F ig u re H .8).
Figure
H.8.
The Knight
T h e K n ig h t is c o n sid e re d e q u iv a le n t in s tr e n g th to th e B ishop. I t is, how ever, th e only
piece t h a t c a n b o th c h a n g e d ire c tio n s w h ile in p la y a n d ju m p ov er th e o th e r c h a ra c te rs .
I t m o v es in w h a t c a n b e d e sc rib e d a s a n “L” s h a p e d p a tte r n , i.e., one to tw o s q u a r e s in
a n y d ire c tio n follow ed by one to tw o s q u a re s on a left or r ig h t a n g le (for a to ta l of th r e e
s q u a r e s — see F ig u re H .9).
Figure
H.9.
496
Appendix H: Algorithms
The Pawn
T h e P a w n c a n o nly m ove fo rw a rd , s tr a ig h t, a n d d ia g o n a lly to c a p tu r e a n o p p o n e n t’s
piece. T h e P a w n is o nly allo w ed one s te p p e r m ove, ex ce p t on h is f irs t m ove, w h e n h e
h a s th e o p tio n of m o v in g u p to tw o s te p s (see F ig u re s H .10 a n d H .l l ) .
Figure
H.10.
Figure
H.11.
497
C# and Game Programming
h e is th e n p ro m o te d ; th is c a n b e to a n y one of th e o th e r ra n k in g p la y e rs — a Q u ee n , Rook,
B ish o p , o r K n ig h t (see F ig u re s H .12 a n d H .13).
EJ
Figure
H.12.
FI
Figure
H.13.
498
Appendix I
Appendix I: Adding DirectX References
to Windows Applications
S t e p 1. F ro m th e W in d o w ’s fold-dow n m e n u , f ir s t se le c t “P ro je c t,” a n d th e n “A dd R e fe r
e n c e ” (see S c re e n S h o t 1.1).
.. I < >
Output * X
■ £ Chspt«*.dnc- Micro...
499
C# and Game Programming
ion Explorer... 4 X
3 ti a
C:\WPiDOW5\Mfcrosoft.NET... lWlnctowsAppicabony
Mfcrosoft Visual Basic .NET Ru. C:\WINDOWS\Mfcrosoft.NET... ndowsAppKcation3
Mfcrosoft.DirectX C:\WINDOWS\Mcrosoft.NET... References
Mcrosoft. DirectX. AudtoVideo.. C:\WINDOWS\Mfcrosoft.NET... ;
Mcrosoft.DeectX.Diagnostics C:\WlNDOWS\Mfcrosoft.NET...
Mcrosoft.DirectX.Direct3D C:\WINDOWS\Mfcrosoft.NET...
Mcrosoft.DirectX. Direct3DX C:\WINDOWS\Mcrosoft.NET...
Mfcrosoft.DirectX.DirectDraw C:\WINDOWS\Mfcrosoft.NET...
Mcrosoft.DirectX.Directlnput C:\WINDOWS\Mfcrosoft.NET...
Mfcrosoft.DirectX.Dirt _CWPCCWStMfcrosoft.NET...
| C I * INC'C'WS\Microsoft.NET\Managed DirectX\v4.09.00.0900\Mcrosoft.DirectX.Din
C IWTNDOWSlMirrnsnfr.NFT W'
Screen
Shot 1.2 J.§g«gL. I Remove j
ft. DirectX
ft .DirectX.DfcectDraw
ft.DeectX.Drect Input
C:\WPOOWS\Mfcrosoft.NET\M...
C:\WPIDOWS\Mfcrosoft.NET\M...
C:\WPIDOWS\Mfcrosoft.NET\M...
C:\WWOOWS\Mlcrosoft.NET\M.,.
500
Index
501
C# and Game Programming
502
Index
503
C# and Game Programming
504
Index
505